From 7c12b05791ed629ec115e89050516d237a3e4058 Mon Sep 17 00:00:00 2001 From: Tony Hallworth Date: Tue, 17 Mar 2020 20:18:34 +1100 Subject: [PATCH 1/2] Working with Istio 1.3.5-1.50 --- Makefile | 139 + cloudbuild.yaml | 8 +- istio-1.3.5/LICENSE | 202 + istio-1.3.5/README.md | 110 + istio-1.3.5/install/README.md | 32 + istio-1.3.5/install/consul/README.md | 6 + .../consul/consul_config/agent-loglevel.json | 3 + .../install/consul/consul_config/agent.json | 8 + .../consul_config/disable_update_check.json | 3 + .../install/consul/consul_config/server.json | 6 + istio-1.3.5/install/consul/istio.yaml | 103 + istio-1.3.5/install/consul/kubeconfig | 11 + istio-1.3.5/install/gcp/README.md | 4 + .../gcp/bootstrap/gcp_envoy_bootstrap.json | 79 + istio-1.3.5/install/kubernetes/README.md | 6 + .../global-default-sidecar-scope.yaml | 20 + istio-1.3.5/install/kubernetes/helm/README.md | 7 + .../kubernetes/helm/helm-service-account.yaml | 21 + .../kubernetes/helm/istio-cni/Chart.yaml | 13 + .../helm/istio-cni/templates/_labels.tpl | 10 + .../helm/istio-cni/templates/istio-cni.yaml | 146 + .../kubernetes/helm/istio-cni/values.yaml | 21 + .../kubernetes/helm/istio-cni/values_gke.yaml | 18 + .../kubernetes/helm/istio-init/Chart.yaml | 13 + .../kubernetes/helm/istio-init/README.md | 77 + .../helm/istio-init/files/crd-10.yaml | 636 + .../helm/istio-init/files/crd-11.yaml | 26 + .../helm/istio-init/files/crd-12.yaml | 24 + .../istio-init/files/crd-certmanager-10.yaml | 91 + .../istio-init/files/crd-certmanager-11.yaml | 80 + .../istio-init/templates/clusterrole.yaml | 11 + .../templates/clusterrolebinding.yaml | 15 + .../templates/configmap-crd-10.yaml | 8 + .../templates/configmap-crd-11.yaml | 8 + .../templates/configmap-crd-12.yaml | 8 + .../configmap-crd-certmanager-10.yaml | 10 + .../configmap-crd-certmanager-11.yaml | 10 + .../helm/istio-init/templates/job-crd-10.yaml | 26 + .../helm/istio-init/templates/job-crd-11.yaml | 26 + .../helm/istio-init/templates/job-crd-12.yaml | 26 + .../templates/job-crd-certmanager-10.yaml | 28 + .../templates/job-crd-certmanager-11.yaml | 28 + .../istio-init/templates/serviceaccount.yaml | 15 + .../kubernetes/helm/istio-init/values.yaml | 16 + .../install/kubernetes/helm/istio/Chart.yaml | 17 + .../install/kubernetes/helm/istio/README.md | 140 + .../helm/istio/charts/certmanager/Chart.yaml | 6 + .../charts/certmanager/templates/NOTES.txt | 6 + .../charts/certmanager/templates/_helpers.tpl | 32 + .../certmanager/templates/deployment.yaml | 69 + .../charts/certmanager/templates/issuer.yaml | 37 + .../templates/poddisruptionbudget.yaml | 24 + .../charts/certmanager/templates/rbac.yaml | 37 + .../certmanager/templates/serviceaccount.yaml | 16 + .../helm/istio/charts/certmanager/values.yaml | 34 + .../helm/istio/charts/galley/Chart.yaml | 13 + .../charts/galley/templates/_helpers.tpl | 32 + .../charts/galley/templates/clusterrole.yaml | 42 + .../galley/templates/clusterrolebinding.yaml | 17 + .../charts/galley/templates/configmap.yaml | 16 + .../charts/galley/templates/deployment.yaml | 127 + .../galley/templates/poddisruptionbudget.yaml | 22 + .../charts/galley/templates/service.yaml | 21 + .../galley/templates/serviceaccount.yaml | 16 + .../validatingwebhookconfiguration.yaml.tpl | 118 + .../helm/istio/charts/galley/values.yaml | 31 + .../helm/istio/charts/gateways/Chart.yaml | 15 + .../charts/gateways/templates/_affinity.tpl | 93 + .../charts/gateways/templates/_helpers.tpl | 32 + .../charts/gateways/templates/autoscale.yaml | 31 + .../charts/gateways/templates/deployment.yaml | 330 + .../templates/poddisruptionbudget.yaml | 31 + .../gateways/templates/preconfigured.yaml | 239 + .../istio/charts/gateways/templates/role.yaml | 18 + .../gateways/templates/rolebindings.yaml | 21 + .../charts/gateways/templates/service.yaml | 59 + .../gateways/templates/serviceaccount.yaml | 24 + .../helm/istio/charts/gateways/values.yaml | 287 + .../helm/istio/charts/grafana/Chart.yaml | 6 + .../grafana/dashboards/citadel-dashboard.json | 1089 + .../grafana/dashboards/galley-dashboard.json | 1819 ++ .../dashboards/istio-mesh-dashboard.json | 1225 + .../istio-performance-dashboard.json | 1822 ++ .../dashboards/istio-service-dashboard.json | 2601 ++ .../dashboards/istio-workload-dashboard.json | 2303 ++ .../grafana/dashboards/mixer-dashboard.json | 1808 ++ .../grafana/dashboards/pilot-dashboard.json | 1591 + .../charts/grafana/templates/_helpers.tpl | 32 + .../templates/configmap-custom-resources.yaml | 16 + .../templates/configmap-dashboards.yaml | 18 + .../charts/grafana/templates/configmap.yaml | 25 + .../create-custom-resources-job.yaml | 101 + .../charts/grafana/templates/deployment.yaml | 138 + .../grafana/templates/grafana-ports-mtls.yaml | 17 + .../charts/grafana/templates/ingress.yaml | 40 + .../istio/charts/grafana/templates/pvc.yaml | 19 + .../charts/grafana/templates/service.yaml | 32 + .../tests/test-grafana-connection.yaml | 37 + .../helm/istio/charts/grafana/values.yaml | 117 + .../helm/istio/charts/istiocoredns/Chart.yaml | 6 + .../istiocoredns/templates/_helpers.tpl | 32 + .../istiocoredns/templates/clusterrole.yaml | 13 + .../templates/clusterrolebinding.yaml | 17 + .../istiocoredns/templates/configmap.yaml | 24 + .../istiocoredns/templates/deployment.yaml | 100 + .../istiocoredns/templates/service.yaml | 20 + .../templates/serviceaccount.yaml | 16 + .../istio/charts/istiocoredns/values.yaml | 35 + .../helm/istio/charts/kiali/Chart.yaml | 6 + .../istio/charts/kiali/templates/_helpers.tpl | 32 + .../charts/kiali/templates/clusterrole.yaml | 267 + .../kiali/templates/clusterrolebinding.yaml | 37 + .../charts/kiali/templates/configmap.yaml | 32 + .../charts/kiali/templates/demosecret.yaml | 16 + .../charts/kiali/templates/deployment.yaml | 100 + .../istio/charts/kiali/templates/ingress.yaml | 40 + .../istio/charts/kiali/templates/service.yaml | 17 + .../kiali/templates/serviceaccount.yaml | 16 + .../tests/test-kiali-connection.yaml | 37 + .../helm/istio/charts/kiali/values.yaml | 63 + .../helm/istio/charts/mixer/Chart.yaml | 13 + .../istio/charts/mixer/templates/_helpers.tpl | 32 + .../charts/mixer/templates/autoscale.yaml | 29 + .../charts/mixer/templates/clusterrole.yaml | 24 + .../mixer/templates/clusterrolebinding.yaml | 19 + .../istio/charts/mixer/templates/config.yaml | 1088 + .../charts/mixer/templates/deployment.yaml | 418 + .../mixer/templates/poddisruptionbudget.yaml | 32 + .../istio/charts/mixer/templates/service.yaml | 39 + .../mixer/templates/serviceaccount.yaml | 18 + .../helm/istio/charts/mixer/values.yaml | 99 + .../helm/istio/charts/nodeagent/Chart.yaml | 13 + .../charts/nodeagent/templates/_helpers.tpl | 32 + .../nodeagent/templates/clusterrole.yaml | 13 + .../templates/clusterrolebinding.yaml | 17 + .../charts/nodeagent/templates/daemonset.yaml | 70 + .../nodeagent/templates/serviceaccount.yaml | 16 + .../helm/istio/charts/nodeagent/values.yaml | 35 + .../helm/istio/charts/pilot/Chart.yaml | 13 + .../istio/charts/pilot/templates/_helpers.tpl | 32 + .../charts/pilot/templates/autoscale.yaml | 25 + .../charts/pilot/templates/clusterrole.yaml | 34 + .../pilot/templates/clusterrolebinding.yaml | 17 + .../charts/pilot/templates/deployment.yaml | 223 + .../charts/pilot/templates/meshexpansion.yaml | 91 + .../pilot/templates/poddisruptionbudget.yaml | 22 + .../istio/charts/pilot/templates/service.yaml | 23 + .../pilot/templates/serviceaccount.yaml | 16 + .../helm/istio/charts/pilot/values.yaml | 56 + .../helm/istio/charts/prometheus/Chart.yaml | 6 + .../charts/prometheus/templates/_helpers.tpl | 32 + .../prometheus/templates/clusterrole.yaml | 24 + .../templates/clusterrolebindings.yaml | 17 + .../prometheus/templates/configmap.yaml | 281 + .../prometheus/templates/deployment copy.yaml | 101 + .../prometheus/templates/deployment.yaml | 80 + .../charts/prometheus/templates/ingress.yaml | 40 + .../charts/prometheus/templates/service.yaml | 45 + .../prometheus/templates/serviceaccount.yaml | 16 + .../tests/test-prometheus-connection.yaml | 36 + .../helm/istio/charts/prometheus/values.yaml | 60 + .../helm/istio/charts/security/Chart.yaml | 13 + .../charts/security/templates/_helpers.tpl | 32 + .../security/templates/clusterrole.yaml | 22 + .../templates/clusterrolebinding.yaml | 17 + .../charts/security/templates/configmap.yaml | 20 + .../create-custom-resources-job.yaml | 107 + .../charts/security/templates/deployment.yaml | 120 + .../security/templates/enable-mesh-mtls.yaml | 63 + .../templates/enable-mesh-permissive.yaml | 16 + .../security/templates/meshexpansion.yaml | 56 + .../charts/security/templates/service.yaml | 23 + .../security/templates/serviceaccount.yaml | 16 + .../tests/test-citadel-connection.yaml | 36 + .../helm/istio/charts/security/values.yaml | 50 + .../charts/sidecarInjectorWebhook/Chart.yaml | 13 + .../templates/_helpers.tpl | 32 + .../templates/clusterrole.yaml | 17 + .../templates/clusterrolebinding.yaml | 18 + .../templates/deployment.yaml | 110 + .../templates/mutatingwebhook.yaml | 39 + .../templates/poddisruptionbudget.yaml | 18 + .../templates/service.yaml | 19 + .../templates/serviceaccount.yaml | 17 + .../charts/sidecarInjectorWebhook/values.yaml | 44 + .../helm/istio/charts/tracing/Chart.yaml | 6 + .../charts/tracing/templates/_helpers.tpl | 32 + .../tracing/templates/deployment-jaeger.yaml | 116 + .../tracing/templates/deployment-zipkin.yaml | 82 + .../charts/tracing/templates/ingress.yaml | 41 + .../istio/charts/tracing/templates/pvc.yaml | 21 + .../tracing/templates/service-jaeger.yaml | 94 + .../charts/tracing/templates/service.yaml | 56 + .../tests/test-tracing-connection.yaml | 40 + .../helm/istio/charts/tracing/values.yaml | 84 + .../helm/istio/example-values/README.md | 5 + .../values-istio-example-sds-vault.yaml | 26 + .../example-values/values-istio-gateways.yaml | 135 + .../example-values/values-istio-googleca.yaml | 28 + .../values-istio-meshexpansion-gateways.yaml | 28 + .../values-istio-multicluster-gateways.yaml | 27 + .../helm/istio/files/injection-template.yaml | 388 + .../kubernetes/helm/istio/requirements.yaml | 40 + .../kubernetes/helm/istio/templates/NOTES.txt | 29 + .../helm/istio/templates/_affinity.tpl | 93 + .../helm/istio/templates/_helpers.tpl | 46 + .../istio/templates/_podDisruptionBudget.tpl | 3 + .../helm/istio/templates/clusterrole.yaml | 11 + .../istio/templates/clusterrolebinding.yaml | 14 + .../helm/istio/templates/configmap.yaml | 307 + .../helm/istio/templates/endpoints.yaml | 63 + .../templates/install-custom-resources.sh.tpl | 32 + .../helm/istio/templates/service.yaml | 60 + .../helm/istio/templates/serviceaccount.yaml | 5 + .../templates/sidecar-injector-configmap.yaml | 25 + .../helm/istio/values-istio-demo-auth.yaml | 87 + .../helm/istio/values-istio-demo.yaml | 88 + .../helm/istio/values-istio-minimal.yaml | 46 + .../helm/istio/values-istio-remote.yaml | 34 + ...-sds-auth-control-plane-auth-disabled.yaml | 21 + .../helm/istio/values-istio-sds-auth.yaml | 21 + .../install/kubernetes/helm/istio/values.yaml | 564 + .../install/kubernetes/istio-demo-auth.yaml | 21075 +++++++++++++ .../install/kubernetes/istio-demo.yaml | 21021 +++++++++++++ .../install/kubernetes/mesh-expansion.yaml | 86 + istio-1.3.5/install/kubernetes/namespace.yaml | 7 + .../operator/charts/crds/Chart.yaml | 11 + .../operator/charts/crds/files/crd-10.yaml | 594 + .../operator/charts/crds/files/crd-11.yaml | 24 + .../operator/charts/crds/files/crd-12.yaml | 24 + .../charts/crds/files/crd-certmanager-10.yaml | 85 + .../charts/crds/files/crd-certmanager-11.yaml | 76 + .../operator/charts/crds/kustomization.yaml | 9 + .../operator/charts/crds/templates/crds.yaml | 9 + .../charts/crds/templates/namespaces.yaml | 64 + .../charts/gateways/istio-egress/Chart.yaml | 13 + .../charts/gateways/istio-egress/NOTES.txt | 45 + .../istio-egress/templates/_affinity.tpl | 93 + .../istio-egress/templates/_helpers.tpl | 34 + .../istio-egress/templates/autoscale.yaml | 24 + .../istio-egress/templates/deployment.yaml | 275 + .../templates/poddisruptionbudget.yaml | 19 + .../istio-egress/templates/preconfigured.yaml | 82 + .../istio-egress/templates/service.yaml | 25 + .../templates/serviceaccount.yaml | 40 + .../charts/gateways/istio-egress/values.yaml | 98 + .../charts/gateways/istio-ingress/Chart.yaml | 13 + .../charts/gateways/istio-ingress/NOTES.txt | 43 + .../istio-ingress/templates/_affinity.tpl | 93 + .../istio-ingress/templates/addongateway.yaml | 65 + .../istio-ingress/templates/autoscale.yaml | 24 + .../istio-ingress/templates/certificate.yaml | 45 + .../istio-ingress/templates/deployment.yaml | 317 + .../istio-ingress/templates/gateway.yaml | 40 + .../istio-ingress/templates/hosts.yaml | 50 + .../templates/meshexpansion.yaml | 97 + .../templates/poddisruptionbudget.yaml | 18 + .../templates/preconfigured.yaml | 102 + .../istio-ingress/templates/role.yaml | 15 + .../istio-ingress/templates/rolebindings.yaml | 18 + .../istio-ingress/templates/service.yaml | 52 + .../templates/serviceaccount.yaml | 14 + .../istio-ingress/templates/sidecar.yaml | 11 + .../charts/gateways/istio-ingress/values.yaml | 192 + .../operator/charts/istio-cni/Chart.yaml | 13 + .../istio-cni/templates/clusterrole.yaml | 14 + .../templates/clusterrolebinding.yaml | 15 + .../istio-cni/templates/configmap-cni.yaml | 21 + .../charts/istio-cni/templates/daemonset.yaml | 78 + .../istio-cni/templates/serviceaccount.yaml | 14 + .../operator/charts/istio-cni/values.yaml | 19 + .../operator/charts/istio-cni/values_gke.yaml | 19 + .../istio-control/istio-autoinject/Chart.yaml | 14 + .../istio-control/istio-autoinject/NOTES.txt | 33 + .../files/injection-template.yaml | 374 + .../istio-autoinject/templates/_affinity.tpl | 93 + .../istio-autoinject/templates/_helpers.tpl | 32 + .../templates/clusterrole.yaml | 17 + .../templates/clusterrolebinding.yaml | 16 + .../istio-autoinject/templates/configmap.yaml | 83 + .../templates/deployment.yaml | 125 + .../templates/mutatingwebhook.yaml | 71 + .../templates/poddisruptionbudget.yaml | 18 + .../istio-autoinject/templates/service.yaml | 15 + .../templates/serviceaccount.yaml | 15 + .../templates/sidecar-injector-configmap.yaml | 22 + .../istio-autoinject/values.yaml | 64 + .../istio-control/istio-config/Chart.yaml | 13 + .../charts/istio-control/istio-config/OWNERS | 5 + .../istio-control/istio-config/README.md | 35 + .../istio-config/templates/_affinity.tpl | 93 + .../istio-config/templates/_helpers.tpl | 36 + .../istio-config/templates/clusterrole.yaml | 40 + .../templates/clusterrolebinding.yaml | 15 + .../templates/configmap-envoy.yaml | 90 + .../templates/configmap-mesh.yaml | 13 + .../istio-config/templates/configmap.yaml | 13 + .../istio-config/templates/deployment.yaml | 190 + .../templates/poddisruptionbudget.yaml | 20 + .../istio-config/templates/service.yaml | 23 + .../templates/serviceaccount.yaml | 15 + .../validatingwebhookconfiguration.yaml.tpl | 118 + .../istio-control/istio-config/values.yaml | 40 + .../istio-control/istio-discovery/Chart.yaml | 12 + .../istio-control/istio-discovery/NOTES.txt | 5 + .../istio-discovery/templates/_affinity.tpl | 93 + .../istio-discovery/templates/_helpers.tpl | 4 + .../istio-discovery/templates/autoscale.yaml | 23 + .../templates/clusterrole.yaml | 35 + .../templates/clusterrolebinding.yaml | 18 + .../templates/configmap-envoy.yaml | 170 + .../istio-discovery/templates/configmap.yaml | 210 + .../istio-discovery/templates/deployment.yaml | 243 + .../templates/enable-mesh-mtls.yaml | 53 + .../templates/poddisruptionbudget.yaml | 22 + .../istio-discovery/templates/service.yaml | 27 + .../templates/serviceaccount.yaml | 17 + .../istio-control/istio-discovery/values.yaml | 113 + .../operator/charts/istio-policy/Chart.yaml | 13 + .../istio-policy/templates/_affinity.tpl | 93 + .../istio-policy/templates/_helpers.tpl | 32 + .../istio-policy/templates/autoscale.yaml | 23 + .../istio-policy/templates/clusterrole.yaml | 21 + .../templates/clusterrolebinding.yaml | 16 + .../charts/istio-policy/templates/config.yaml | 328 + .../istio-policy/templates/deployment.yaml | 209 + .../templates/poddisruptionbudget.yaml | 22 + .../istio-policy/templates/service.yaml | 24 + .../templates/serviceaccount.yaml | 15 + .../operator/charts/istio-policy/values.yaml | 45 + .../charts/istio-telemetry/grafana/Chart.yaml | 6 + .../grafana/dashboards/galley-dashboard.json | 1819 ++ .../dashboards/istio-mesh-dashboard.json | 953 + .../istio-performance-dashboard.json | 1822 ++ .../dashboards/istio-service-dashboard.json | 2601 ++ .../dashboards/istio-workload-dashboard.json | 2303 ++ .../grafana/dashboards/mixer-dashboard.json | 1808 ++ .../grafana/dashboards/pilot-dashboard.json | 1788 ++ .../grafana/fix_datasources.sh | 30 + .../grafana/templates/_affinity.tpl | 93 + .../templates/configmap-dashboards.yaml | 16 + .../grafana/templates/configmap.yaml | 42 + .../grafana/templates/deployment.yaml | 132 + .../grafana/templates/destination-rule.yaml | 10 + .../grafana/templates/grafana-policy.yaml | 13 + .../grafana/templates/pvc.yaml | 16 + .../grafana/templates/service.yaml | 30 + .../tests/test-grafana-connection.yaml | 28 + .../istio-telemetry/grafana/values.yaml | 121 + .../charts/istio-telemetry/kiali/Chart.yaml | 6 + .../kiali/templates/_affinity.tpl | 93 + .../kiali/templates/clusterrole.yaml | 237 + .../kiali/templates/clusterrolebinding.yaml | 33 + .../kiali/templates/configmap.yaml | 28 + .../kiali/templates/demosecret.yaml | 14 + .../kiali/templates/deployment.yaml | 99 + .../kiali/templates/service.yaml | 15 + .../kiali/templates/serviceaccount.yaml | 14 + .../charts/istio-telemetry/kiali/values.yaml | 65 + .../mixer-telemetry/Chart.yaml | 13 + .../mixer-telemetry/templates/_affinity.tpl | 93 + .../mixer-telemetry/templates/autoscale.yaml | 23 + .../templates/clusterrole.yaml | 21 + .../templates/clusterrolebinding.yaml | 16 + .../mixer-telemetry/templates/config.yaml | 1002 + .../templates/configmap-envoy.yaml | 299 + .../mixer-telemetry/templates/deployment.yaml | 212 + .../templates/poddisruptionbudget.yaml | 22 + .../mixer-telemetry/templates/service.yaml | 26 + .../templates/serviceaccount.yaml | 15 + .../templates/stackdriver.yaml | 889 + .../mixer-telemetry/values.yaml | 102 + .../prometheus-operator/Chart.yaml | 6 + .../templates/_affinity.tpl | 93 + .../templates/prometheus.yaml | 159 + .../templates/servicemonitors.yaml | 314 + .../prometheus-operator/values.yaml | 47 + .../istio-telemetry/prometheus/Chart.yaml | 6 + .../prometheus/templates/_affinity.tpl | 93 + .../prometheus/templates/clusterrole.yaml | 22 + .../templates/clusterrolebindings.yaml | 15 + .../prometheus/templates/configmap.yaml | 281 + .../prometheus/templates/deployment.yaml | 73 + .../templates/destination-rule.yaml | 21 + .../prometheus/templates/inrgess.yaml | 38 + .../prometheus/templates/service.yaml | 43 + .../prometheus/templates/serviceaccount.yaml | 14 + .../tests/test-prometheus-connection.yaml | 27 + .../istio-telemetry/prometheus/values.yaml | 62 + .../charts/istio-telemetry/tracing/Chart.yaml | 6 + .../tracing/templates/_affinity.tpl | 86 + .../tracing/templates/deployment-jaeger.yaml | 106 + .../templates/deployment-opencensus.yaml | 94 + .../tracing/templates/deployment-zipkin.yaml | 71 + .../tracing/templates/pvc.yaml | 19 + .../tracing/templates/service-jaeger.yaml | 46 + .../tracing/templates/service.yaml | 44 + .../istio-telemetry/tracing/values.yaml | 98 + .../operator/charts/istiocoredns/Chart.yaml | 6 + .../istiocoredns/templates/_affinity.tpl | 93 + .../istiocoredns/templates/clusterrole.yaml | 11 + .../templates/clusterrolebinding.yaml | 15 + .../istiocoredns/templates/configmap.yaml | 22 + .../istiocoredns/templates/deployment.yaml | 93 + .../istiocoredns/templates/service.yaml | 18 + .../templates/serviceaccount.yaml | 14 + .../operator/charts/istiocoredns/values.yaml | 36 + .../charts/security/certmanager/Chart.yaml | 6 + .../security/certmanager/templates/NOTES.txt | 6 + .../certmanager/templates/_affinity.tpl | 93 + .../certmanager/templates/deployment.yaml | 62 + .../certmanager/templates/issuer.yaml | 33 + .../templates/poddisruptionbudget.yaml | 19 + .../security/certmanager/templates/rbac.yaml | 33 + .../certmanager/templates/serviceaccount.yaml | 14 + .../charts/security/certmanager/values.yaml | 35 + .../charts/security/citadel/Chart.yaml | 13 + .../security/citadel/templates/NOTES.txt | 7 + .../security/citadel/templates/_affinity.tpl | 93 + .../security/citadel/templates/_helpers.tpl | 77 + .../citadel/templates/clusterrole.yaml | 24 + .../citadel/templates/clusterrolebinding.yaml | 17 + .../citadel/templates/deployment.yaml | 99 + .../templates/poddisruptionbudget.yaml | 17 + .../security/citadel/templates/service.yaml | 21 + .../citadel/templates/serviceaccount.yaml | 15 + .../charts/security/citadel/values.yaml | 67 + .../charts/security/nodeagent/Chart.yaml | 13 + .../nodeagent/templates/_affinity.tpl | 93 + .../nodeagent/templates/clusterrole.yaml | 11 + .../templates/clusterrolebinding.yaml | 15 + .../nodeagent/templates/daemonset.yaml | 67 + .../nodeagent/templates/serviceaccount.yaml | 14 + .../charts/security/nodeagent/values.yaml | 37 + .../kubernetes/operator/profiles/default.yaml | 701 + .../operator/profiles/demo-auth.yaml | 112 + .../kubernetes/operator/profiles/demo.yaml | 112 + .../kubernetes/operator/profiles/minimal.yaml | 36 + .../kubernetes/operator/profiles/sds.yaml | 24 + .../install/kubernetes/operator/version.yaml | 1 + .../install/kubernetes/operator/versions.yaml | 4 + istio-1.3.5/install/tools/setupIstioVM.sh | 112 + istio-1.3.5/install/tools/setupMeshEx.sh | 274 + istio-1.3.5/istio.VERSION | 16 + istio-1.3.5/samples/README.md | 4 + istio-1.3.5/samples/bookinfo/README.md | 25 + .../networking/ROUTING_RULE_MIGRATION.md | 32 + .../bookinfo/networking/bookinfo-gateway.yaml | 41 + .../networking/certmanager-gateway.yaml | 35 + .../networking/destination-rule-all-mtls.yaml | 74 + .../networking/destination-rule-all.yaml | 62 + .../networking/destination-rule-reviews.yaml | 19 + .../networking/egress-rule-google-apis.yaml | 46 + .../fault-injection-details-v1.yaml | 31 + .../networking/virtual-service-all-v1.yaml | 52 + .../virtual-service-details-v2.yaml | 12 + .../virtual-service-ratings-db.yaml | 26 + .../virtual-service-ratings-mysql-vm.yaml | 26 + .../virtual-service-ratings-mysql.yaml | 26 + .../virtual-service-ratings-test-abort.yaml | 25 + .../virtual-service-ratings-test-delay.yaml | 25 + .../virtual-service-reviews-50-v3.yaml | 17 + .../virtual-service-reviews-80-20.yaml | 17 + .../virtual-service-reviews-90-10.yaml | 17 + .../virtual-service-reviews-jason-v2-v3.yaml | 20 + .../virtual-service-reviews-test-v2.yaml | 20 + .../virtual-service-reviews-v2-v3.yaml | 17 + .../virtual-service-reviews-v3.yaml | 12 + .../bookinfo/platform/consul/README.md | 69 + .../platform/consul/bookinfo.sidecars.yaml | 163 + .../bookinfo/platform/consul/bookinfo.yaml | 128 + .../bookinfo/platform/consul/cleanup.sh | 61 + .../platform/consul/destination-rule-all.yaml | 53 + .../consul/virtual-service-all-v1.yaml | 52 + .../virtual-service-ratings-test-abort.yaml | 25 + .../virtual-service-ratings-test-delay.yaml | 25 + .../consul/virtual-service-reviews-50-v3.yaml | 17 + .../virtual-service-reviews-test-v2.yaml | 20 + .../consul/virtual-service-reviews-v2-v3.yaml | 17 + .../consul/virtual-service-reviews-v3.yaml | 12 + .../samples/bookinfo/platform/kube/README.md | 2 + .../platform/kube/bookinfo-certificate.yaml | 37 + .../bookinfo/platform/kube/bookinfo-db.yaml | 53 + .../platform/kube/bookinfo-details-v2.yaml | 46 + .../platform/kube/bookinfo-details.yaml | 56 + .../platform/kube/bookinfo-ingress.yaml | 44 + .../platform/kube/bookinfo-mysql.yaml | 72 + .../kube/bookinfo-ratings-discovery.yaml | 30 + .../kube/bookinfo-ratings-v2-mysql-vm.yaml | 53 + .../kube/bookinfo-ratings-v2-mysql.yaml | 56 + .../platform/kube/bookinfo-ratings-v2.yaml | 63 + .../platform/kube/bookinfo-ratings.yaml | 56 + .../platform/kube/bookinfo-reviews-v2.yaml | 43 + .../bookinfo/platform/kube/bookinfo.yaml | 264 + .../samples/bookinfo/platform/kube/cleanup.sh | 60 + .../platform/kube/productpage-nodeport.yaml | 32 + .../details-reviews-policy-permissive.yaml | 22 + .../kube/rbac/details-reviews-policy.yaml | 21 + .../platform/kube/rbac/mongodb-policy.yaml | 24 + .../platform/kube/rbac/namespace-policy.yaml | 27 + .../kube/rbac/productpage-policy.yaml | 21 + .../platform/kube/rbac/ratings-policy.yaml | 21 + .../platform/kube/rbac/rbac-config-ON.yaml | 8 + .../kube/rbac/rbac-config-on-mongodb.yaml | 9 + .../kube/rbac/rbac-config-on-permissive.yaml | 9 + .../kube/rbac/rbac-permissive-telemetry.yaml | 47 + .../policy/mixer-rule-deny-ip-crd.yaml | 29 + .../bookinfo/policy/mixer-rule-deny-ip.yaml | 32 + .../policy/mixer-rule-deny-label-crd.yaml | 24 + .../policy/mixer-rule-deny-label.yaml | 27 + .../mixer-rule-deny-serviceaccount.yaml | 27 + .../policy/mixer-rule-deny-whitelist-crd.yaml | 28 + .../policy/mixer-rule-deny-whitelist.yaml | 31 + .../policy/mixer-rule-ingress-denial.yaml | 30 + .../mixer-rule-kubernetesenv-telemetry.yaml | 56 + .../mixer-rule-productpage-ratelimit-crd.yaml | 81 + .../mixer-rule-productpage-ratelimit.yaml | 85 + ...-productpage-redis-quota-fixed-window.yaml | 83 + ...roductpage-redis-quota-rolling-window.yaml | 87 + .../policy/mixer-rule-ratings-denial.yaml | 31 + .../policy/mixer-rule-ratings-ratelimit.yaml | 81 + ...rule-ratings-redis-quota-fixed-window.yaml | 87 + ...le-ratings-redis-quota-rolling-window.yaml | 88 + .../policy/prometheus-adapter-deployment.yaml | 44 + .../bookinfo/policy/prometheus-oop-rule.yaml | 78 + .../bookinfo/src/mongodb/ratings_data.json | 2 + .../bookinfo/src/productpage/requirements.txt | 31 + .../src/productpage/test-requirements.txt | 1 + .../samples/bookinfo/src/ratings/package.json | 10 + istio-1.3.5/samples/bookinfo/swagger.yaml | 248 + .../bookinfo/telemetry/fluentd-istio-crd.yaml | 40 + .../bookinfo/telemetry/fluentd-istio.yaml | 44 + .../bookinfo/telemetry/log-entry-crd.yaml | 42 + .../samples/bookinfo/telemetry/log-entry.yaml | 46 + .../bookinfo/telemetry/metrics-crd.yaml | 45 + .../samples/bookinfo/telemetry/metrics.yaml | 46 + .../bookinfo/telemetry/tcp-metrics-crd.yaml | 67 + .../bookinfo/telemetry/tcp-metrics.yaml | 73 + istio-1.3.5/samples/certs/README.md | 37 + istio-1.3.5/samples/certs/ca-cert.pem | 22 + istio-1.3.5/samples/certs/ca-key.pem | 27 + istio-1.3.5/samples/certs/cert-chain.pem | 22 + istio-1.3.5/samples/certs/root-cert.pem | 24 + .../samples/custom-bootstrap/README.md | 52 + .../custom-bootstrap/custom-bootstrap.yaml | 19 + .../samples/custom-bootstrap/example-app.yaml | 27 + istio-1.3.5/samples/external/README.md | 34 + istio-1.3.5/samples/external/aptget.yaml | 20 + istio-1.3.5/samples/external/github.yaml | 53 + istio-1.3.5/samples/external/pypi.yaml | 44 + istio-1.3.5/samples/fortio/stackdriver.yaml | 245 + .../health-check/liveness-command.yaml | 57 + .../health-check/liveness-http-same-port.yaml | 39 + .../samples/health-check/liveness-http.yaml | 39 + istio-1.3.5/samples/helloworld/README.md | 69 + .../helloworld/helloworld-gateway.yaml | 33 + .../samples/helloworld/helloworld.yaml | 68 + .../samples/helloworld/src/requirements.txt | 7 + istio-1.3.5/samples/httpbin/README.md | 38 + .../samples/httpbin/httpbin-gateway.yaml | 30 + .../samples/httpbin/httpbin-nodeport.yaml | 54 + .../samples/httpbin/httpbin-vault.yaml | 54 + istio-1.3.5/samples/httpbin/httpbin.yaml | 53 + .../httpbin/policy/keyval-template.yaml | 10 + .../samples/httpbin/policy/keyval.yaml | 14 + .../httpbin/sample-client/fortio-deploy.yaml | 41 + istio-1.3.5/samples/https/default.conf | 10 + istio-1.3.5/samples/https/nginx-app.yaml | 43 + .../kubernetes-blog/bookinfo-ratings.yaml | 49 + .../kubernetes-blog/bookinfo-reviews-v2.yaml | 40 + .../samples/kubernetes-blog/bookinfo-v1.yaml | 131 + istio-1.3.5/samples/rawvm/README.md | 158 + .../samples/security/psp/all-pods-psp.yaml | 51 + .../security/psp/citadel-agent-psp.yaml | 48 + istio-1.3.5/samples/sleep/README.md | 30 + .../sleep/policy/sni-serviceaccount.yaml | 55 + .../samples/sleep/policy/sni-wikipedia.yaml | 32 + istio-1.3.5/samples/sleep/sleep-vault.yaml | 56 + istio-1.3.5/samples/sleep/sleep.yaml | 56 + .../samples/sleep/telemetry/sni-logging.yaml | 45 + istio-1.3.5/samples/tcp-echo/README.md | 38 + .../samples/tcp-echo/tcp-echo-20-v2.yaml | 39 + .../samples/tcp-echo/tcp-echo-all-v1.yaml | 61 + .../samples/tcp-echo/tcp-echo-services.yaml | 74 + istio-1.3.5/samples/tcp-echo/tcp-echo.yaml | 53 + istio-1.3.5/samples/websockets/README.md | 38 + istio-1.3.5/samples/websockets/app.yaml | 36 + istio-1.3.5/samples/websockets/route.yaml | 33 + istio-1.3.5/tools/README.md | 278 + istio-1.3.5/tools/_istioctl | 2155 ++ istio-1.3.5/tools/cache_buster.yaml | 31 + istio-1.3.5/tools/checker/README.md | 102 + istio-1.3.5/tools/checker/checker.go | 106 + .../tools/checker/envvarlinter/README.md | 29 + .../tools/checker/envvarlinter/envvar_test.go | 40 + .../tools/checker/envvarlinter/main.go | 53 + .../checker/envvarlinter/rules/no_os_env.go | 47 + .../tools/checker/envvarlinter/rules/util.go | 47 + .../checker/envvarlinter/rules_matcher.go | 40 + .../checker/envvarlinter/testdata/envuse.go | 8 + .../tools/checker/envvarlinter/whitelist.go | 20 + istio-1.3.5/tools/checker/report.go | 51 + istio-1.3.5/tools/checker/rule.go | 35 + .../tools/checker/testlinter/README.md | 96 + .../checker/testlinter/e2etest_lint_test.go | 52 + .../checker/testlinter/integtest_lint_test.go | 56 + .../checker/testlinter/lint_rules_list.go | 34 + istio-1.3.5/tools/checker/testlinter/main.go | 52 + .../checker/testlinter/rules/no_goroutine.go | 42 + .../checker/testlinter/rules/no_short.go | 44 + .../checker/testlinter/rules/no_sleep.go | 44 + .../checker/testlinter/rules/short_skip.go | 98 + .../checker/testlinter/rules/skip_issue.go | 64 + .../tools/checker/testlinter/rules/util.go | 79 + .../tools/checker/testlinter/rules_matcher.go | 68 + .../testlinter/testdata/e2e/e2e_test.go | 74 + .../testdata/integration/integtest_test.go | 74 + .../testdata/integtest_integ_test.go | 74 + .../checker/testlinter/testdata/unit_test.go | 71 + .../tools/checker/testlinter/testlinter | Bin 0 -> 2928760 bytes .../checker/testlinter/unittest_lint_test.go | 105 + .../tools/checker/testlinter/whitelist.go | 20 + istio-1.3.5/tools/checker/whitelist.go | 57 + ...convert_RbacConfig_to_ClusterRbacConfig.sh | 48 + istio-1.3.5/tools/convert_perf_results.py | 42 + istio-1.3.5/tools/docker-dev/Dockerfile | 73 + istio-1.3.5/tools/docker-dev/README.md | 67 + istio-1.3.5/tools/dump_kubernetes.sh | 341 + .../tools/githubContrib/Contributions.txt | 2 + istio-1.3.5/tools/hyperistio/README.md | 5 + istio-1.3.5/tools/hyperistio/hyperistio.go | 200 + .../tools/hyperistio/hyperistio_test.go | 75 + istio-1.3.5/tools/hyperistio/index.html | 42 + istio-1.3.5/tools/istio-docker.mk | 391 + istio-1.3.5/tools/istio-iptables/main.go | 520 + istio-1.3.5/tools/istioctl.bash | 2024 ++ istio-1.3.5/tools/license/README.md | 16 + istio-1.3.5/tools/license/get_dep_licenses.go | 577 + .../tools/license/manual_append/signalfx.txt | 8 + .../tools/license/manual_append/siphash.txt | 133 + .../common/envoy_bootstrap_drain.json | 2 + .../packaging/common/envoy_bootstrap_v2.json | 591 + .../common/istio-auth-node-agent.service | 12 + .../tools/packaging/common/istio-ca.sh | 37 + .../tools/packaging/common/istio-iptables.sh | 624 + .../common/istio-node-agent-start.sh | 66 + .../tools/packaging/common/istio-start.sh | 113 + .../tools/packaging/common/istio.service | 12 + .../tools/packaging/common/sidecar.env | 84 + istio-1.3.5/tools/packaging/deb/Dockerfile | 28 + istio-1.3.5/tools/packaging/deb/deb_test.sh | 49 + istio-1.3.5/tools/packaging/deb/istio.mk | 167 + istio-1.3.5/tools/packaging/deb/postinst.sh | 50 + istio-1.3.5/tools/packaging/packaging.mk | 8 + .../tools/packaging/rpm/Dockerfile.build | 22 + .../tools/packaging/rpm/build-istio-rpm.sh | 33 + .../tools/packaging/rpm/build-proxy-rpm.sh | 48 + .../tools/packaging/rpm/istio/istio.spec | 354 + istio-1.3.5/tools/packaging/rpm/proxy/bazelrc | 2 + .../packaging/rpm/proxy/istio-proxy.spec | 74 + istio-1.3.5/tools/packaging/rpm/rpm.mk | 38 + istio-1.3.5/tools/perf_istio_rules.yaml | 45 + istio-1.3.5/tools/perf_k8svcs.yaml | 72 + istio-1.3.5/tools/perf_setup.svg | 1 + istio-1.3.5/tools/rules.yml | 57 + istio-1.3.5/tools/run_canonical_perf_tests.sh | 52 + istio-1.3.5/tools/setup_perf_cluster.sh | 540 + istio-1.3.5/tools/setup_run | 19 + istio-1.3.5/tools/update_all | 13 + istio-1.3.5/tools/vagrant/Vagrantfile | 23 + .../tools/vagrant/provision-vagrant.sh | 79 + istio-1.5.0/LICENSE | 202 + istio-1.5.0/README.md | 112 + istio-1.5.0/install/README.md | 4 + istio-1.5.0/install/consul/README.md | 4 + .../consul/consul_config/agent-loglevel.json | 3 + .../install/consul/consul_config/agent.json | 8 + .../consul_config/disable_update_check.json | 3 + .../install/consul/consul_config/server.json | 6 + istio-1.5.0/install/gcp/README.md | 4 + .../gcp/bootstrap/gcp_envoy_bootstrap.json | 125 + istio-1.5.0/install/kubernetes/README.md | 6 + .../global-default-sidecar-scope.yaml | 20 + istio-1.5.0/install/kubernetes/helm/README.md | 7 + .../kubernetes/helm/helm-service-account.yaml | 21 + .../kubernetes/helm/istio-cni/Chart.yaml | 13 + .../helm/istio-cni/templates/_labels.tpl | 10 + .../helm/istio-cni/templates/istio-cni.yaml | 230 + .../kubernetes/helm/istio-cni/values.yaml | 45 + .../kubernetes/helm/istio-cni/values_gke.yaml | 22 + .../kubernetes/helm/istio-init/Chart.yaml | 13 + .../kubernetes/helm/istio-init/README.md | 82 + .../helm/istio-init/files/crd-all.gen.yaml | 5603 ++++ .../istio-init/files/crd-certmanager-10.yaml | 91 + .../istio-init/files/crd-certmanager-11.yaml | 80 + .../helm/istio-init/files/crd-mixer.yaml | 59 + .../istio-init/templates/clusterrole.yaml | 11 + .../templates/clusterrolebinding.yaml | 15 + .../templates/configmap-crd-all.yaml | 8 + .../configmap-crd-certmanager-10.yaml | 10 + .../configmap-crd-certmanager-11.yaml | 10 + .../templates/configmap-crd-mixer.yaml | 8 + .../istio-init/templates/job-crd-all.yaml | 30 + .../templates/job-crd-certmanager-10.yaml | 32 + .../templates/job-crd-certmanager-11.yaml | 32 + .../istio-init/templates/job-crd-mixer.yaml | 30 + .../istio-init/templates/serviceaccount.yaml | 15 + .../kubernetes/helm/istio-init/values.yaml | 25 + .../install/kubernetes/helm/istio/Chart.yaml | 17 + .../install/kubernetes/helm/istio/README.md | 149 + .../helm/istio/charts/certmanager/Chart.yaml | 6 + .../charts/certmanager/templates/NOTES.txt | 6 + .../charts/certmanager/templates/_helpers.tpl | 32 + .../certmanager/templates/deployment.yaml | 69 + .../charts/certmanager/templates/issuer.yaml | 37 + .../templates/poddisruptionbudget.yaml | 22 + .../charts/certmanager/templates/rbac.yaml | 37 + .../certmanager/templates/serviceaccount.yaml | 16 + .../helm/istio/charts/certmanager/values.yaml | 35 + .../helm/istio/charts/galley/Chart.yaml | 13 + .../charts/galley/templates/_helpers.tpl | 32 + .../charts/galley/templates/clusterrole.yaml | 53 + .../galley/templates/clusterrolebinding.yaml | 17 + .../charts/galley/templates/configmap.yaml | 16 + .../charts/galley/templates/deployment.yaml | 155 + .../galley/templates/poddisruptionbudget.yaml | 20 + .../charts/galley/templates/service.yaml | 22 + .../galley/templates/serviceaccount.yaml | 16 + .../validatingwebhookconfiguration.yaml | 108 + .../validatingwebhookconfiguration.yaml.tpl | 111 + .../helm/istio/charts/galley/values.yaml | 38 + .../helm/istio/charts/gateways/Chart.yaml | 15 + .../charts/gateways/templates/_affinity.tpl | 93 + .../charts/gateways/templates/_helpers.tpl | 32 + .../charts/gateways/templates/autoscale.yaml | 31 + .../charts/gateways/templates/deployment.yaml | 393 + .../templates/poddisruptionbudget.yaml | 29 + .../gateways/templates/preconfigured.yaml | 246 + .../istio/charts/gateways/templates/role.yaml | 18 + .../gateways/templates/rolebindings.yaml | 21 + .../charts/gateways/templates/service.yaml | 59 + .../gateways/templates/serviceaccount.yaml | 24 + .../helm/istio/charts/gateways/values.yaml | 282 + .../helm/istio/charts/grafana/Chart.yaml | 6 + .../grafana/dashboards/citadel-dashboard.json | 1089 + .../grafana/dashboards/galley-dashboard.json | 1734 + .../dashboards/istio-mesh-dashboard.json | 1225 + .../istio-performance-dashboard.json | 1822 ++ .../dashboards/istio-service-dashboard.json | 2601 ++ .../dashboards/istio-workload-dashboard.json | 2303 ++ .../grafana/dashboards/mixer-dashboard.json | 1808 ++ .../grafana/dashboards/pilot-dashboard.json | 1591 + .../charts/grafana/templates/_helpers.tpl | 32 + .../templates/configmap-custom-resources.yaml | 16 + .../templates/configmap-dashboards.yaml | 18 + .../charts/grafana/templates/configmap.yaml | 25 + .../create-custom-resources-job.yaml | 103 + .../charts/grafana/templates/deployment.yaml | 138 + .../grafana/templates/grafana-ports-mtls.yaml | 17 + .../charts/grafana/templates/ingress.yaml | 40 + .../istio/charts/grafana/templates/pvc.yaml | 19 + .../charts/grafana/templates/service.yaml | 32 + .../tests/test-grafana-connection.yaml | 37 + .../helm/istio/charts/grafana/values.yaml | 117 + .../helm/istio/charts/istiocoredns/Chart.yaml | 6 + .../istiocoredns/templates/_helpers.tpl | 32 + .../istiocoredns/templates/clusterrole.yaml | 13 + .../templates/clusterrolebinding.yaml | 17 + .../istiocoredns/templates/configmap.yaml | 32 + .../istiocoredns/templates/deployment.yaml | 103 + .../istiocoredns/templates/service.yaml | 20 + .../templates/serviceaccount.yaml | 16 + .../istio/charts/istiocoredns/values.yaml | 37 + .../helm/istio/charts/kiali/Chart.yaml | 6 + .../istio/charts/kiali/templates/_helpers.tpl | 32 + .../charts/kiali/templates/clusterrole.yaml | 134 + .../kiali/templates/clusterrolebinding.yaml | 37 + .../charts/kiali/templates/configmap.yaml | 42 + .../charts/kiali/templates/demosecret.yaml | 16 + .../charts/kiali/templates/deployment.yaml | 103 + .../istio/charts/kiali/templates/ingress.yaml | 40 + .../istio/charts/kiali/templates/service.yaml | 17 + .../kiali/templates/serviceaccount.yaml | 16 + .../tests/test-kiali-connection.yaml | 37 + .../helm/istio/charts/kiali/values.yaml | 80 + .../helm/istio/charts/mixer/Chart.yaml | 13 + .../istio/charts/mixer/templates/_helpers.tpl | 32 + .../charts/mixer/templates/autoscale.yaml | 29 + .../charts/mixer/templates/clusterrole.yaml | 24 + .../mixer/templates/clusterrolebinding.yaml | 19 + .../istio/charts/mixer/templates/config.yaml | 1084 + .../charts/mixer/templates/deployment.yaml | 447 + .../mixer/templates/poddisruptionbudget.yaml | 30 + .../istio/charts/mixer/templates/service.yaml | 39 + .../mixer/templates/serviceaccount.yaml | 18 + .../helm/istio/charts/mixer/values.yaml | 98 + .../helm/istio/charts/nodeagent/Chart.yaml | 13 + .../charts/nodeagent/templates/_helpers.tpl | 32 + .../nodeagent/templates/clusterrole.yaml | 13 + .../templates/clusterrolebinding.yaml | 17 + .../charts/nodeagent/templates/daemonset.yaml | 70 + .../nodeagent/templates/serviceaccount.yaml | 16 + .../helm/istio/charts/nodeagent/values.yaml | 36 + .../helm/istio/charts/pilot/Chart.yaml | 13 + .../istio/charts/pilot/templates/_helpers.tpl | 32 + .../charts/pilot/templates/autoscale.yaml | 25 + .../charts/pilot/templates/clusterrole.yaml | 39 + .../pilot/templates/clusterrolebinding.yaml | 17 + .../charts/pilot/templates/configmap.yaml | 14 + .../charts/pilot/templates/deployment.yaml | 242 + .../charts/pilot/templates/meshexpansion.yaml | 91 + .../pilot/templates/poddisruptionbudget.yaml | 20 + .../istio/charts/pilot/templates/service.yaml | 23 + .../pilot/templates/serviceaccount.yaml | 16 + .../helm/istio/charts/pilot/values.yaml | 63 + .../helm/istio/charts/prometheus/Chart.yaml | 6 + .../charts/prometheus/templates/_helpers.tpl | 32 + .../prometheus/templates/clusterrole.yaml | 24 + .../templates/clusterrolebindings.yaml | 17 + .../prometheus/templates/configmap.yaml | 294 + .../prometheus/templates/deployment.yaml | 80 + .../charts/prometheus/templates/ingress.yaml | 40 + .../charts/prometheus/templates/service.yaml | 45 + .../prometheus/templates/serviceaccount.yaml | 16 + .../tests/test-prometheus-connection.yaml | 36 + .../helm/istio/charts/prometheus/values.yaml | 60 + .../helm/istio/charts/security/Chart.yaml | 13 + .../charts/security/templates/_helpers.tpl | 32 + .../security/templates/clusterrole.yaml | 22 + .../templates/clusterrolebinding.yaml | 17 + .../charts/security/templates/configmap.yaml | 20 + .../create-custom-resources-job.yaml | 109 + .../charts/security/templates/deployment.yaml | 123 + .../security/templates/enable-mesh-mtls.yaml | 65 + .../templates/enable-mesh-permissive.yaml | 16 + .../security/templates/meshexpansion.yaml | 56 + .../templates/poddisruptionbudget.yaml | 20 + .../charts/security/templates/service.yaml | 23 + .../security/templates/serviceaccount.yaml | 16 + .../tests/test-citadel-connection.yaml | 36 + .../helm/istio/charts/security/values.yaml | 52 + .../charts/sidecarInjectorWebhook/Chart.yaml | 13 + .../templates/_helpers.tpl | 32 + .../templates/clusterrole.yaml | 19 + .../templates/clusterrolebinding.yaml | 18 + .../templates/deployment.yaml | 122 + .../templates/mutatingwebhook.yaml | 40 + .../templates/poddisruptionbudget.yaml | 18 + .../templates/service.yaml | 20 + .../templates/serviceaccount.yaml | 17 + .../charts/sidecarInjectorWebhook/values.yaml | 59 + .../helm/istio/charts/tracing/Chart.yaml | 6 + .../charts/tracing/templates/_helpers.tpl | 32 + .../tracing/templates/deployment-jaeger.yaml | 119 + .../tracing/templates/deployment-zipkin.yaml | 85 + .../charts/tracing/templates/ingress.yaml | 41 + .../istio/charts/tracing/templates/pvc.yaml | 21 + .../tracing/templates/service-jaeger.yaml | 114 + .../charts/tracing/templates/service.yaml | 56 + .../tests/test-tracing-connection.yaml | 40 + .../helm/istio/charts/tracing/values.yaml | 87 + .../helm/istio/example-values/README.md | 5 + .../example-values/values-istio-dns-cert.yaml | 6 + .../values-istio-example-sds-vault.yaml | 26 + .../example-values/values-istio-gateways.yaml | 135 + .../example-values/values-istio-googleca.yaml | 28 + .../values-istio-meshexpansion-gateways.yaml | 28 + .../values-istio-multicluster-gateways.yaml | 27 + .../helm/istio/files/injection-template.yaml | 445 + .../kubernetes/helm/istio/requirements.yaml | 40 + .../kubernetes/helm/istio/templates/NOTES.txt | 29 + .../helm/istio/templates/_affinity.tpl | 93 + .../helm/istio/templates/_helpers.tpl | 39 + .../istio/templates/_podDisruptionBudget.tpl | 3 + .../helm/istio/templates/clusterrole.yaml | 11 + .../istio/templates/clusterrolebinding.yaml | 29 + .../helm/istio/templates/configmap.yaml | 345 + .../helm/istio/templates/endpoints.yaml | 63 + .../templates/install-custom-resources.sh.tpl | 32 + .../helm/istio/templates/service.yaml | 60 + .../helm/istio/templates/serviceaccount.yaml | 11 + .../templates/sidecar-injector-configmap.yaml | 29 + .../helm/istio/test-values/README.md | 7 + .../helm/istio/test-values/values-e2e.yaml | 101 + .../helm/istio/test-values/values-integ.yaml | 94 + .../test-values/values-istio-auth-mcp.yaml | 17 + .../values-istio-auth-multicluster.yaml | 21 + .../values-istio-auth-non-mcp.yaml | 7 + .../test-values/values-istio-auth-sds.yaml | 24 + .../istio/test-values/values-istio-auth.yaml | 14 + .../test-values/values-istio-dns-cert.yaml | 7 + .../istio/test-values/values-istio-mcp.yaml | 18 + .../values-istio-mesh-networks.yaml | 16 + ...lues-istio-multicluster-split-horizon.yaml | 25 + .../values-istio-multicluster.yaml | 21 + .../test-values/values-istio-non-mcp.yaml | 2 + .../values-istio-one-namespace-auth.yaml | 17 + ...lues-istio-one-namespace-trust-domain.yaml | 19 + .../values-istio-one-namespace.yaml | 17 + .../helm/istio/test-values/values-istio.yaml | 7 + .../helm/istio/values-istio-demo.yaml | 81 + .../helm/istio/values-istio-minimal.yaml | 49 + .../helm/istio/values-istio-remote.yaml | 36 + ...-sds-auth-control-plane-auth-disabled.yaml | 21 + .../helm/istio/values-istio-sds-auth.yaml | 21 + .../install/kubernetes/helm/istio/values.yaml | 622 + .../install/kubernetes/istio-demo.yaml | 26097 ++++++++++++++++ .../install/kubernetes/mesh-expansion.yaml | 86 + istio-1.5.0/install/kubernetes/namespace.yaml | 7 + .../operator/charts/base/Chart.yaml | 11 + .../charts/base/files/crd-all.gen.yaml | 5603 ++++ .../operator/charts/base/files/crd-mixer.yaml | 60 + .../operator/charts/base/kustomization.yaml | 6 + .../charts/base/templates/clusterrole.yaml | 25 + .../base/templates/clusterrolebinding.yaml | 18 + .../operator/charts/base/templates/crds.yaml | 2 + .../charts/base/templates/endpoints.yaml | 72 + .../charts/base/templates/namespaces.yaml | 64 + .../charts/base/templates/serviceaccount.yaml | 17 + .../charts/base/templates/services.yaml | 67 + .../operator/charts/base/values.yaml | 0 .../charts/gateways/istio-egress/Chart.yaml | 13 + .../charts/gateways/istio-egress/NOTES.txt | 45 + .../istio-egress/templates/_affinity.tpl | 93 + .../istio-egress/templates/_helpers.tpl | 34 + .../istio-egress/templates/autoscale.yaml | 24 + .../istio-egress/templates/deployment.yaml | 314 + .../templates/poddisruptionbudget.yaml | 17 + .../istio-egress/templates/preconfigured.yaml | 82 + .../istio-egress/templates/service.yaml | 25 + .../templates/serviceaccount.yaml | 15 + .../charts/gateways/istio-egress/values.yaml | 103 + .../charts/gateways/istio-ingress/Chart.yaml | 13 + .../charts/gateways/istio-ingress/NOTES.txt | 43 + .../istio-ingress/templates/_affinity.tpl | 93 + .../istio-ingress/templates/addongateway.yaml | 65 + .../istio-ingress/templates/autoscale.yaml | 24 + .../istio-ingress/templates/certificate.yaml | 45 + .../istio-ingress/templates/deployment.yaml | 384 + .../istio-ingress/templates/gateway.yaml | 40 + .../istio-ingress/templates/hosts.yaml | 50 + .../templates/meshexpansion.yaml | 60 + .../templates/poddisruptionbudget.yaml | 17 + .../templates/preconfigured.yaml | 107 + .../istio-ingress/templates/role.yaml | 15 + .../istio-ingress/templates/rolebindings.yaml | 18 + .../istio-ingress/templates/service.yaml | 52 + .../templates/serviceaccount.yaml | 15 + .../istio-ingress/templates/sidecar.yaml | 11 + .../charts/gateways/istio-ingress/values.yaml | 200 + .../operator/charts/istio-cni/Chart.yaml | 11 + .../istio-cni/templates/clusterrole.yaml | 31 + .../templates/clusterrolebinding.yaml | 49 + .../istio-cni/templates/configmap-cni.yaml | 23 + .../charts/istio-cni/templates/daemonset.yaml | 124 + .../istio-cni/templates/serviceaccount.yaml | 14 + .../operator/charts/istio-cni/values.yaml | 47 + .../istio-control/istio-autoinject/Chart.yaml | 14 + .../istio-control/istio-autoinject/NOTES.txt | 33 + .../files/injection-template.yaml | 413 + .../istio-autoinject/templates/_affinity.tpl | 93 + .../istio-autoinject/templates/_helpers.tpl | 32 + .../templates/clusterrole.yaml | 19 + .../templates/clusterrolebinding.yaml | 16 + .../istio-autoinject/templates/configmap.yaml | 119 + .../templates/deployment.yaml | 142 + .../templates/mutatingwebhook.yaml | 86 + .../templates/poddisruptionbudget.yaml | 18 + .../istio-autoinject/templates/service.yaml | 15 + .../templates/serviceaccount.yaml | 15 + .../templates/sidecar-injector-configmap.yaml | 27 + .../istio-autoinject/values.yaml | 89 + .../istio-control/istio-config/Chart.yaml | 13 + .../charts/istio-control/istio-config/OWNERS | 5 + .../istio-control/istio-config/README.md | 27 + .../istio-config/templates/_affinity.tpl | 93 + .../istio-config/templates/_helpers.tpl | 36 + .../istio-config/templates/clusterrole.yaml | 57 + .../templates/clusterrolebinding.yaml | 15 + .../templates/configmap-envoy.yaml | 92 + .../templates/configmap-mesh.yaml | 11 + .../istio-config/templates/configmap.yaml | 13 + .../istio-config/templates/deployment.yaml | 229 + .../templates/poddisruptionbudget.yaml | 20 + .../istio-config/templates/service.yaml | 23 + .../templates/serviceaccount.yaml | 15 + .../validatingwebhookconfiguration.yaml | 90 + .../validatingwebhookconfiguration.yaml.tpl | 93 + .../istio-control/istio-config/values.yaml | 48 + .../istio-control/istio-discovery/Chart.yaml | 12 + .../istio-control/istio-discovery/NOTES.txt | 5 + .../files/injection-template.yaml | 477 + .../istio-discovery/templates/_affinity.tpl | 93 + .../istio-discovery/templates/_helpers.tpl | 0 .../istio-discovery/templates/autoscale.yaml | 25 + .../clusterrole-galley-disable-webhook.yaml | 57 + .../templates/clusterrole.yaml | 128 + .../templates/clusterrolebinding.yaml | 37 + .../templates/configmap-envoy.yaml | 173 + .../templates/configmap-jwks.yaml | 13 + .../istio-discovery/templates/configmap.yaml | 349 + .../istio-discovery/templates/deployment.yaml | 323 + .../templates/enable-mesh-mtls.yaml | 51 + .../templates/istiod-injector-configmap.yaml | 34 + .../templates/mutatingwebhook.yaml | 75 + .../templates/poddisruptionbudget.yaml | 24 + .../istio-discovery/templates/service.yaml | 63 + .../templates/serviceaccount.yaml | 17 + .../templates/telemetryv2_1.4.yaml | 235 + .../templates/telemetryv2_1.5.yaml | 419 + .../validatingwebhookconfiguration.yaml | 60 + .../istio-control/istio-discovery/values.yaml | 197 + .../operator/charts/istio-policy/Chart.yaml | 13 + .../istio-policy/templates/_affinity.tpl | 93 + .../istio-policy/templates/_helpers.tpl | 32 + .../istio-policy/templates/autoscale.yaml | 23 + .../istio-policy/templates/clusterrole.yaml | 21 + .../templates/clusterrolebinding.yaml | 16 + .../charts/istio-policy/templates/config.yaml | 330 + .../istio-policy/templates/deployment.yaml | 215 + .../templates/poddisruptionbudget.yaml | 21 + .../istio-policy/templates/service.yaml | 25 + .../templates/serviceaccount.yaml | 15 + .../operator/charts/istio-policy/values.yaml | 47 + .../charts/istio-telemetry/grafana/Chart.yaml | 6 + .../grafana/dashboards/citadel-dashboard.json | 1089 + .../grafana/dashboards/galley-dashboard.json | 1734 + .../dashboards/istio-mesh-dashboard.json | 1225 + .../istio-performance-dashboard.json | 1822 ++ .../dashboards/istio-service-dashboard.json | 2601 ++ .../dashboards/istio-workload-dashboard.json | 2303 ++ .../grafana/dashboards/mixer-dashboard.json | 1808 ++ .../grafana/dashboards/pilot-dashboard.json | 1591 + .../grafana/fix_datasources.sh | 30 + .../grafana/templates/_affinity.tpl | 93 + .../templates/configmap-dashboards.yaml | 16 + .../grafana/templates/configmap.yaml | 23 + .../grafana/templates/deployment.yaml | 138 + .../grafana/templates/grafana-policy.yaml | 13 + .../grafana/templates/pvc.yaml | 16 + .../grafana/templates/service.yaml | 30 + .../tests/test-grafana-connection.yaml | 28 + .../istio-telemetry/grafana/values.yaml | 126 + .../charts/istio-telemetry/kiali/Chart.yaml | 6 + .../kiali/templates/_affinity.tpl | 93 + .../kiali/templates/clusterrole.yaml | 130 + .../kiali/templates/clusterrolebinding.yaml | 33 + .../kiali/templates/configmap.yaml | 51 + .../kiali/templates/demosecret.yaml | 14 + .../kiali/templates/deployment.yaml | 99 + .../kiali/templates/service.yaml | 15 + .../kiali/templates/serviceaccount.yaml | 14 + .../charts/istio-telemetry/kiali/values.yaml | 85 + .../mixer-telemetry/Chart.yaml | 13 + .../mixer-telemetry/templates/_affinity.tpl | 93 + .../mixer-telemetry/templates/autoscale.yaml | 23 + .../templates/clusterrole.yaml | 21 + .../templates/clusterrolebinding.yaml | 16 + .../mixer-telemetry/templates/config.yaml | 994 + .../templates/configmap-envoy.yaml | 300 + .../mixer-telemetry/templates/deployment.yaml | 216 + .../templates/poddisruptionbudget.yaml | 21 + .../mixer-telemetry/templates/service.yaml | 26 + .../templates/serviceaccount.yaml | 15 + .../templates/stackdriver.yaml | 955 + .../mixer-telemetry/values.yaml | 111 + .../prometheus-operator/Chart.yaml | 6 + .../templates/_affinity.tpl | 93 + .../templates/prometheus.yaml | 137 + .../templates/servicemonitors.yaml | 320 + .../prometheus-operator/values.yaml | 47 + .../istio-telemetry/prometheus/Chart.yaml | 6 + .../prometheus/templates/_affinity.tpl | 93 + .../prometheus/templates/clusterrole.yaml | 22 + .../templates/clusterrolebindings.yaml | 15 + .../prometheus/templates/configmap.yaml | 291 + .../prometheus/templates/deployment.yaml | 269 + .../prometheus/templates/ingress.yaml | 38 + .../prometheus/templates/service.yaml | 43 + .../prometheus/templates/serviceaccount.yaml | 14 + .../tests/test-prometheus-connection.yaml | 27 + .../istio-telemetry/prometheus/values.yaml | 72 + .../charts/istio-telemetry/tracing/Chart.yaml | 6 + .../tracing/templates/_affinity.tpl | 93 + .../tracing/templates/deployment-jaeger.yaml | 115 + .../templates/deployment-opencensus.yaml | 104 + .../tracing/templates/deployment-zipkin.yaml | 81 + .../tracing/templates/pvc.yaml | 19 + .../tracing/templates/service-jaeger.yaml | 96 + .../tracing/templates/service.yaml | 44 + .../istio-telemetry/tracing/values.yaml | 106 + .../operator/charts/istiocoredns/Chart.yaml | 6 + .../istiocoredns/templates/_affinity.tpl | 93 + .../istiocoredns/templates/clusterrole.yaml | 11 + .../templates/clusterrolebinding.yaml | 15 + .../istiocoredns/templates/configmap.yaml | 30 + .../istiocoredns/templates/deployment.yaml | 99 + .../istiocoredns/templates/service.yaml | 18 + .../templates/serviceaccount.yaml | 14 + .../operator/charts/istiocoredns/values.yaml | 38 + .../charts/security/citadel/Chart.yaml | 13 + .../security/citadel/templates/NOTES.txt | 7 + .../security/citadel/templates/_affinity.tpl | 93 + .../security/citadel/templates/_helpers.tpl | 77 + .../citadel/templates/clusterrole.yaml | 24 + .../citadel/templates/clusterrolebinding.yaml | 17 + .../citadel/templates/deployment.yaml | 136 + .../templates/poddisruptionbudget.yaml | 17 + .../security/citadel/templates/service.yaml | 21 + .../citadel/templates/serviceaccount.yaml | 15 + .../charts/security/citadel/values.yaml | 74 + .../charts/security/nodeagent/Chart.yaml | 13 + .../nodeagent/templates/_affinity.tpl | 93 + .../nodeagent/templates/clusterrole.yaml | 11 + .../templates/clusterrolebinding.yaml | 15 + .../nodeagent/templates/daemonset.yaml | 73 + .../nodeagent/templates/serviceaccount.yaml | 14 + .../charts/security/nodeagent/values.yaml | 40 + .../operator/deploy/clusterrole.yaml | 114 + .../operator/deploy/clusterrole_binding.yaml | 14 + .../crds/istio_v1alpha1_istiooperator_cr.yaml | 9 + .../istio_v1alpha1_istiooperator_crd.yaml | 22 + .../operator/deploy/kustomization.yaml | 13 + .../kubernetes/operator/deploy/namespace.yaml | 6 + .../kubernetes/operator/deploy/operator.yaml | 45 + .../kubernetes/operator/deploy/service.yaml | 16 + .../operator/deploy/service_account.yaml | 7 + .../istio_v1alpha1_istiooperator_cr.yaml | 9 + .../googleca/values-istio-google-ca.yaml | 25 + .../values-istio-multicluster-gateways.yaml | 34 + .../values-istio-multicluster-primary.yaml | 34 + .../user-gateway/ingress-gateway-only.yaml | 10 + .../values-istio-meshexpansion-gateways.yaml | 22 + .../vm/values-istio-meshexpansion.yaml | 14 + .../kubernetes/operator/profiles/default.yaml | 719 + .../kubernetes/operator/profiles/demo.yaml | 138 + .../kubernetes/operator/profiles/empty.yaml | 52 + .../kubernetes/operator/profiles/minimal.yaml | 49 + .../kubernetes/operator/profiles/remote.yaml | 35 + .../operator/profiles/separate.yaml | 25 + .../install/kubernetes/operator/versions.yaml | 54 + istio-1.5.0/manifest.yaml | 21 + istio-1.5.0/path.txt | 1 + istio-1.5.0/samples/README.md | 3 + istio-1.5.0/samples/bookinfo/README.md | 31 + .../bookinfo/networking/bookinfo-gateway.yaml | 41 + .../networking/certmanager-gateway.yaml | 35 + .../networking/destination-rule-all-mtls.yaml | 74 + .../networking/destination-rule-all.yaml | 62 + .../networking/destination-rule-reviews.yaml | 19 + .../networking/egress-rule-google-apis.yaml | 46 + .../fault-injection-details-v1.yaml | 32 + .../networking/virtual-service-all-v1.yaml | 52 + .../virtual-service-details-v2.yaml | 12 + .../virtual-service-ratings-db.yaml | 26 + .../virtual-service-ratings-mysql-vm.yaml | 26 + .../virtual-service-ratings-mysql.yaml | 26 + .../virtual-service-ratings-test-abort.yaml | 25 + .../virtual-service-ratings-test-delay.yaml | 25 + .../virtual-service-reviews-50-v3.yaml | 17 + .../virtual-service-reviews-80-20.yaml | 17 + .../virtual-service-reviews-90-10.yaml | 17 + .../virtual-service-reviews-jason-v2-v3.yaml | 20 + .../virtual-service-reviews-test-v2.yaml | 20 + .../virtual-service-reviews-v2-v3.yaml | 17 + .../virtual-service-reviews-v3.yaml | 12 + .../bookinfo/platform/consul/README.md | 71 + .../bookinfo/platform/consul/bookinfo.yaml | 128 + .../bookinfo/platform/consul/cleanup.sh | 61 + .../platform/consul/destination-rule-all.yaml | 53 + .../consul/virtual-service-all-v1.yaml | 52 + .../virtual-service-ratings-test-abort.yaml | 25 + .../virtual-service-ratings-test-delay.yaml | 25 + .../consul/virtual-service-reviews-50-v3.yaml | 17 + .../virtual-service-reviews-test-v2.yaml | 20 + .../consul/virtual-service-reviews-v2-v3.yaml | 17 + .../consul/virtual-service-reviews-v3.yaml | 12 + .../samples/bookinfo/platform/kube/README.md | 2 + .../platform/kube/bookinfo-certificate.yaml | 37 + .../bookinfo/platform/kube/bookinfo-db.yaml | 53 + .../platform/kube/bookinfo-details-v2.yaml | 46 + .../platform/kube/bookinfo-details.yaml | 56 + .../platform/kube/bookinfo-ingress.yaml | 44 + .../platform/kube/bookinfo-mysql.yaml | 72 + .../kube/bookinfo-ratings-discovery.yaml | 30 + .../kube/bookinfo-ratings-v2-mysql-vm.yaml | 53 + .../kube/bookinfo-ratings-v2-mysql.yaml | 56 + .../platform/kube/bookinfo-ratings-v2.yaml | 63 + .../platform/kube/bookinfo-ratings.yaml | 56 + .../platform/kube/bookinfo-reviews-v2.yaml | 56 + .../bookinfo/platform/kube/bookinfo.yaml | 331 + .../samples/bookinfo/platform/kube/cleanup.sh | 60 + .../platform/kube/productpage-nodeport.yaml | 32 + .../details-reviews-policy-permissive.yaml | 22 + .../kube/rbac/details-reviews-policy.yaml | 21 + .../platform/kube/rbac/mongodb-policy.yaml | 24 + .../platform/kube/rbac/namespace-policy.yaml | 27 + .../kube/rbac/productpage-policy.yaml | 21 + .../platform/kube/rbac/ratings-policy.yaml | 21 + .../platform/kube/rbac/rbac-config-ON.yaml | 8 + .../kube/rbac/rbac-config-on-mongodb.yaml | 9 + .../kube/rbac/rbac-config-on-permissive.yaml | 9 + .../kube/rbac/rbac-permissive-telemetry.yaml | 47 + .../policy/mixer-rule-deny-ip-crd.yaml | 29 + .../bookinfo/policy/mixer-rule-deny-ip.yaml | 32 + .../policy/mixer-rule-deny-label-crd.yaml | 24 + .../policy/mixer-rule-deny-label.yaml | 27 + .../mixer-rule-deny-serviceaccount.yaml | 27 + .../policy/mixer-rule-deny-whitelist-crd.yaml | 28 + .../policy/mixer-rule-deny-whitelist.yaml | 31 + .../policy/mixer-rule-ingress-denial.yaml | 30 + .../mixer-rule-kubernetesenv-telemetry.yaml | 56 + .../mixer-rule-productpage-ratelimit-crd.yaml | 81 + .../mixer-rule-productpage-ratelimit.yaml | 85 + ...-productpage-redis-quota-fixed-window.yaml | 83 + ...roductpage-redis-quota-rolling-window.yaml | 87 + .../policy/mixer-rule-ratings-denial.yaml | 31 + .../policy/mixer-rule-ratings-ratelimit.yaml | 81 + ...rule-ratings-redis-quota-fixed-window.yaml | 87 + ...le-ratings-redis-quota-rolling-window.yaml | 88 + .../policy/prometheus-adapter-deployment.yaml | 44 + .../bookinfo/policy/prometheus-oop-rule.yaml | 78 + .../bookinfo/src/mongodb/ratings_data.json | 2 + .../bookinfo/src/productpage/requirements.txt | 31 + .../src/productpage/test-requirements.txt | 1 + .../samples/bookinfo/src/ratings/package.json | 10 + istio-1.5.0/samples/bookinfo/swagger.yaml | 248 + .../bookinfo/telemetry/fluentd-istio-crd.yaml | 40 + .../bookinfo/telemetry/fluentd-istio.yaml | 44 + .../bookinfo/telemetry/log-entry-crd.yaml | 42 + .../samples/bookinfo/telemetry/log-entry.yaml | 46 + .../bookinfo/telemetry/metrics-crd.yaml | 45 + .../samples/bookinfo/telemetry/metrics.yaml | 46 + .../bookinfo/telemetry/tcp-metrics-crd.yaml | 67 + .../bookinfo/telemetry/tcp-metrics.yaml | 73 + istio-1.5.0/samples/certs/README.md | 37 + istio-1.5.0/samples/certs/ca-cert.pem | 22 + istio-1.5.0/samples/certs/ca-key.pem | 27 + istio-1.5.0/samples/certs/cert-chain.pem | 22 + istio-1.5.0/samples/certs/root-cert.pem | 24 + .../samples/custom-bootstrap/README.md | 52 + .../custom-bootstrap/custom-bootstrap.yaml | 19 + .../samples/custom-bootstrap/example-app.yaml | 27 + istio-1.5.0/samples/external/README.md | 34 + istio-1.5.0/samples/external/aptget.yaml | 20 + istio-1.5.0/samples/external/github.yaml | 53 + istio-1.5.0/samples/external/pypi.yaml | 44 + istio-1.5.0/samples/fortio/stackdriver.yaml | 245 + .../health-check/liveness-command.yaml | 57 + .../health-check/liveness-http-same-port.yaml | 39 + .../samples/health-check/liveness-http.yaml | 39 + istio-1.5.0/samples/helloworld/README.md | 90 + .../helloworld/helloworld-gateway.yaml | 33 + .../samples/helloworld/helloworld.yaml | 68 + .../samples/helloworld/src/requirements.txt | 7 + istio-1.5.0/samples/httpbin/README.md | 39 + .../samples/httpbin/httpbin-gateway.yaml | 30 + .../samples/httpbin/httpbin-nodeport.yaml | 54 + .../samples/httpbin/httpbin-vault.yaml | 54 + istio-1.5.0/samples/httpbin/httpbin.yaml | 59 + .../httpbin/policy/keyval-template.yaml | 10 + .../samples/httpbin/policy/keyval.yaml | 14 + .../httpbin/sample-client/fortio-deploy.yaml | 41 + istio-1.5.0/samples/https/default.conf | 10 + istio-1.5.0/samples/https/nginx-app.yaml | 43 + .../kubernetes-blog/bookinfo-ratings.yaml | 49 + .../kubernetes-blog/bookinfo-reviews-v2.yaml | 40 + .../samples/kubernetes-blog/bookinfo-v1.yaml | 131 + istio-1.5.0/samples/multicluster/README.md | 77 + .../samples/operator/default-install.yaml | 8 + .../operator/pilot-advanced-override.yaml | 23 + istio-1.5.0/samples/operator/pilot-k8s.yaml | 22 + .../samples/operator/sds-policy-off.yaml | 6 + istio-1.5.0/samples/operator/sds.yaml | 4 + .../operator/trafficManagement-namespace.yaml | 6 + .../samples/operator/values-global.yaml | 7 + .../samples/operator/values-pilot.yaml | 6 + istio-1.5.0/samples/rawvm/README.md | 167 + .../samples/security/psp/all-pods-psp.yaml | 51 + .../security/psp/citadel-agent-psp.yaml | 48 + istio-1.5.0/samples/sleep/README.md | 37 + .../sleep/policy/sni-serviceaccount.yaml | 55 + .../samples/sleep/policy/sni-wikipedia.yaml | 32 + istio-1.5.0/samples/sleep/sleep-vault.yaml | 56 + istio-1.5.0/samples/sleep/sleep.yaml | 64 + .../samples/sleep/telemetry/sni-logging.yaml | 45 + istio-1.5.0/samples/tcp-echo/README.md | 38 + .../samples/tcp-echo/tcp-echo-20-v2.yaml | 39 + .../samples/tcp-echo/tcp-echo-all-v1.yaml | 61 + .../samples/tcp-echo/tcp-echo-services.yaml | 79 + istio-1.5.0/samples/tcp-echo/tcp-echo.yaml | 57 + istio-1.5.0/samples/websockets/README.md | 48 + istio-1.5.0/samples/websockets/app.yaml | 36 + istio-1.5.0/samples/websockets/route.yaml | 32 + istio-1.5.0/tools/_istioctl | 3520 +++ ...convert_RbacConfig_to_ClusterRbacConfig.sh | 63 + istio-1.5.0/tools/dump_kubernetes.sh | 358 + istio-1.5.0/tools/istioctl.bash | 3389 ++ istio-manifests/istio-demo.yaml | 20257 ++++++++++++ istio-manifests/namespace.yaml | 7 + kubernetes-manifests-tracing/README.md | 8 + kubernetes-manifests-tracing/adservice.yaml | 72 + kubernetes-manifests-tracing/cartservice.yaml | 69 + .../checkoutservice.yaml | 81 + .../currencyservice.yaml | 69 + .../emailservice.yaml | 68 + kubernetes-manifests-tracing/frontend.yaml | 106 + .../loadgenerator.yaml | 46 + .../paymentservice.yaml | 62 + .../productcatalogservice.yaml | 70 + .../recommendationservice.yaml | 72 + kubernetes-manifests-tracing/redis.yaml | 66 + .../shippingservice.yaml | 70 + kubernetes-manifests/adservice.yaml | 12 +- kubernetes-manifests/checkoutservice.yaml | 16 +- kubernetes-manifests/emailservice.yaml | 4 +- kubernetes-manifests/frontend.yaml | 12 +- .../productcatalogservice.yaml | 16 +- .../recommendationservice.yaml | 12 +- kubernetes-manifests/shippingservice.yaml | 16 +- skaffold.yaml | 26 +- 1321 files changed, 246876 insertions(+), 49 deletions(-) create mode 100644 Makefile create mode 100644 istio-1.3.5/LICENSE create mode 100644 istio-1.3.5/README.md create mode 100644 istio-1.3.5/install/README.md create mode 100644 istio-1.3.5/install/consul/README.md create mode 100644 istio-1.3.5/install/consul/consul_config/agent-loglevel.json create mode 100644 istio-1.3.5/install/consul/consul_config/agent.json create mode 100644 istio-1.3.5/install/consul/consul_config/disable_update_check.json create mode 100644 istio-1.3.5/install/consul/consul_config/server.json create mode 100644 istio-1.3.5/install/consul/istio.yaml create mode 100644 istio-1.3.5/install/consul/kubeconfig create mode 100644 istio-1.3.5/install/gcp/README.md create mode 100644 istio-1.3.5/install/gcp/bootstrap/gcp_envoy_bootstrap.json create mode 100644 istio-1.3.5/install/kubernetes/README.md create mode 100644 istio-1.3.5/install/kubernetes/global-default-sidecar-scope.yaml create mode 100644 istio-1.3.5/install/kubernetes/helm/README.md create mode 100644 istio-1.3.5/install/kubernetes/helm/helm-service-account.yaml create mode 100644 istio-1.3.5/install/kubernetes/helm/istio-cni/Chart.yaml create mode 100644 istio-1.3.5/install/kubernetes/helm/istio-cni/templates/_labels.tpl create mode 100644 istio-1.3.5/install/kubernetes/helm/istio-cni/templates/istio-cni.yaml create mode 100644 istio-1.3.5/install/kubernetes/helm/istio-cni/values.yaml create mode 100644 istio-1.3.5/install/kubernetes/helm/istio-cni/values_gke.yaml create mode 100644 istio-1.3.5/install/kubernetes/helm/istio-init/Chart.yaml create mode 100644 istio-1.3.5/install/kubernetes/helm/istio-init/README.md create mode 100644 istio-1.3.5/install/kubernetes/helm/istio-init/files/crd-10.yaml create mode 100644 istio-1.3.5/install/kubernetes/helm/istio-init/files/crd-11.yaml create mode 100644 istio-1.3.5/install/kubernetes/helm/istio-init/files/crd-12.yaml create mode 100644 istio-1.3.5/install/kubernetes/helm/istio-init/files/crd-certmanager-10.yaml create mode 100644 istio-1.3.5/install/kubernetes/helm/istio-init/files/crd-certmanager-11.yaml create mode 100644 istio-1.3.5/install/kubernetes/helm/istio-init/templates/clusterrole.yaml create mode 100644 istio-1.3.5/install/kubernetes/helm/istio-init/templates/clusterrolebinding.yaml create mode 100644 istio-1.3.5/install/kubernetes/helm/istio-init/templates/configmap-crd-10.yaml create mode 100644 istio-1.3.5/install/kubernetes/helm/istio-init/templates/configmap-crd-11.yaml create mode 100644 istio-1.3.5/install/kubernetes/helm/istio-init/templates/configmap-crd-12.yaml create mode 100644 istio-1.3.5/install/kubernetes/helm/istio-init/templates/configmap-crd-certmanager-10.yaml create mode 100644 istio-1.3.5/install/kubernetes/helm/istio-init/templates/configmap-crd-certmanager-11.yaml create mode 100644 istio-1.3.5/install/kubernetes/helm/istio-init/templates/job-crd-10.yaml create mode 100644 istio-1.3.5/install/kubernetes/helm/istio-init/templates/job-crd-11.yaml create mode 100644 istio-1.3.5/install/kubernetes/helm/istio-init/templates/job-crd-12.yaml create mode 100644 istio-1.3.5/install/kubernetes/helm/istio-init/templates/job-crd-certmanager-10.yaml create mode 100644 istio-1.3.5/install/kubernetes/helm/istio-init/templates/job-crd-certmanager-11.yaml create mode 100644 istio-1.3.5/install/kubernetes/helm/istio-init/templates/serviceaccount.yaml create mode 100644 istio-1.3.5/install/kubernetes/helm/istio-init/values.yaml create mode 100644 istio-1.3.5/install/kubernetes/helm/istio/Chart.yaml create mode 100644 istio-1.3.5/install/kubernetes/helm/istio/README.md create mode 100644 istio-1.3.5/install/kubernetes/helm/istio/charts/certmanager/Chart.yaml create mode 100644 istio-1.3.5/install/kubernetes/helm/istio/charts/certmanager/templates/NOTES.txt create mode 100644 istio-1.3.5/install/kubernetes/helm/istio/charts/certmanager/templates/_helpers.tpl create mode 100644 istio-1.3.5/install/kubernetes/helm/istio/charts/certmanager/templates/deployment.yaml create mode 100644 istio-1.3.5/install/kubernetes/helm/istio/charts/certmanager/templates/issuer.yaml create mode 100644 istio-1.3.5/install/kubernetes/helm/istio/charts/certmanager/templates/poddisruptionbudget.yaml create mode 100644 istio-1.3.5/install/kubernetes/helm/istio/charts/certmanager/templates/rbac.yaml create mode 100644 istio-1.3.5/install/kubernetes/helm/istio/charts/certmanager/templates/serviceaccount.yaml create mode 100644 istio-1.3.5/install/kubernetes/helm/istio/charts/certmanager/values.yaml create mode 100644 istio-1.3.5/install/kubernetes/helm/istio/charts/galley/Chart.yaml create mode 100644 istio-1.3.5/install/kubernetes/helm/istio/charts/galley/templates/_helpers.tpl create mode 100644 istio-1.3.5/install/kubernetes/helm/istio/charts/galley/templates/clusterrole.yaml create mode 100644 istio-1.3.5/install/kubernetes/helm/istio/charts/galley/templates/clusterrolebinding.yaml create mode 100644 istio-1.3.5/install/kubernetes/helm/istio/charts/galley/templates/configmap.yaml create mode 100644 istio-1.3.5/install/kubernetes/helm/istio/charts/galley/templates/deployment.yaml create mode 100644 istio-1.3.5/install/kubernetes/helm/istio/charts/galley/templates/poddisruptionbudget.yaml create mode 100644 istio-1.3.5/install/kubernetes/helm/istio/charts/galley/templates/service.yaml create mode 100644 istio-1.3.5/install/kubernetes/helm/istio/charts/galley/templates/serviceaccount.yaml create mode 100644 istio-1.3.5/install/kubernetes/helm/istio/charts/galley/templates/validatingwebhookconfiguration.yaml.tpl create mode 100644 istio-1.3.5/install/kubernetes/helm/istio/charts/galley/values.yaml create mode 100644 istio-1.3.5/install/kubernetes/helm/istio/charts/gateways/Chart.yaml create mode 100644 istio-1.3.5/install/kubernetes/helm/istio/charts/gateways/templates/_affinity.tpl create mode 100644 istio-1.3.5/install/kubernetes/helm/istio/charts/gateways/templates/_helpers.tpl create mode 100644 istio-1.3.5/install/kubernetes/helm/istio/charts/gateways/templates/autoscale.yaml create mode 100644 istio-1.3.5/install/kubernetes/helm/istio/charts/gateways/templates/deployment.yaml create mode 100644 istio-1.3.5/install/kubernetes/helm/istio/charts/gateways/templates/poddisruptionbudget.yaml create mode 100644 istio-1.3.5/install/kubernetes/helm/istio/charts/gateways/templates/preconfigured.yaml create mode 100644 istio-1.3.5/install/kubernetes/helm/istio/charts/gateways/templates/role.yaml create mode 100644 istio-1.3.5/install/kubernetes/helm/istio/charts/gateways/templates/rolebindings.yaml create mode 100644 istio-1.3.5/install/kubernetes/helm/istio/charts/gateways/templates/service.yaml create mode 100644 istio-1.3.5/install/kubernetes/helm/istio/charts/gateways/templates/serviceaccount.yaml create mode 100644 istio-1.3.5/install/kubernetes/helm/istio/charts/gateways/values.yaml create mode 100644 istio-1.3.5/install/kubernetes/helm/istio/charts/grafana/Chart.yaml create mode 100644 istio-1.3.5/install/kubernetes/helm/istio/charts/grafana/dashboards/citadel-dashboard.json create mode 100644 istio-1.3.5/install/kubernetes/helm/istio/charts/grafana/dashboards/galley-dashboard.json create mode 100644 istio-1.3.5/install/kubernetes/helm/istio/charts/grafana/dashboards/istio-mesh-dashboard.json create mode 100644 istio-1.3.5/install/kubernetes/helm/istio/charts/grafana/dashboards/istio-performance-dashboard.json create mode 100644 istio-1.3.5/install/kubernetes/helm/istio/charts/grafana/dashboards/istio-service-dashboard.json create mode 100644 istio-1.3.5/install/kubernetes/helm/istio/charts/grafana/dashboards/istio-workload-dashboard.json create mode 100644 istio-1.3.5/install/kubernetes/helm/istio/charts/grafana/dashboards/mixer-dashboard.json create mode 100644 istio-1.3.5/install/kubernetes/helm/istio/charts/grafana/dashboards/pilot-dashboard.json create mode 100644 istio-1.3.5/install/kubernetes/helm/istio/charts/grafana/templates/_helpers.tpl create mode 100644 istio-1.3.5/install/kubernetes/helm/istio/charts/grafana/templates/configmap-custom-resources.yaml create mode 100644 istio-1.3.5/install/kubernetes/helm/istio/charts/grafana/templates/configmap-dashboards.yaml create mode 100644 istio-1.3.5/install/kubernetes/helm/istio/charts/grafana/templates/configmap.yaml create mode 100644 istio-1.3.5/install/kubernetes/helm/istio/charts/grafana/templates/create-custom-resources-job.yaml create mode 100644 istio-1.3.5/install/kubernetes/helm/istio/charts/grafana/templates/deployment.yaml create mode 100644 istio-1.3.5/install/kubernetes/helm/istio/charts/grafana/templates/grafana-ports-mtls.yaml create mode 100644 istio-1.3.5/install/kubernetes/helm/istio/charts/grafana/templates/ingress.yaml create mode 100644 istio-1.3.5/install/kubernetes/helm/istio/charts/grafana/templates/pvc.yaml create mode 100644 istio-1.3.5/install/kubernetes/helm/istio/charts/grafana/templates/service.yaml create mode 100644 istio-1.3.5/install/kubernetes/helm/istio/charts/grafana/templates/tests/test-grafana-connection.yaml create mode 100644 istio-1.3.5/install/kubernetes/helm/istio/charts/grafana/values.yaml create mode 100644 istio-1.3.5/install/kubernetes/helm/istio/charts/istiocoredns/Chart.yaml create mode 100644 istio-1.3.5/install/kubernetes/helm/istio/charts/istiocoredns/templates/_helpers.tpl create mode 100644 istio-1.3.5/install/kubernetes/helm/istio/charts/istiocoredns/templates/clusterrole.yaml create mode 100644 istio-1.3.5/install/kubernetes/helm/istio/charts/istiocoredns/templates/clusterrolebinding.yaml create mode 100644 istio-1.3.5/install/kubernetes/helm/istio/charts/istiocoredns/templates/configmap.yaml create mode 100644 istio-1.3.5/install/kubernetes/helm/istio/charts/istiocoredns/templates/deployment.yaml create mode 100644 istio-1.3.5/install/kubernetes/helm/istio/charts/istiocoredns/templates/service.yaml create mode 100644 istio-1.3.5/install/kubernetes/helm/istio/charts/istiocoredns/templates/serviceaccount.yaml create mode 100644 istio-1.3.5/install/kubernetes/helm/istio/charts/istiocoredns/values.yaml create mode 100644 istio-1.3.5/install/kubernetes/helm/istio/charts/kiali/Chart.yaml create mode 100644 istio-1.3.5/install/kubernetes/helm/istio/charts/kiali/templates/_helpers.tpl create mode 100644 istio-1.3.5/install/kubernetes/helm/istio/charts/kiali/templates/clusterrole.yaml create mode 100644 istio-1.3.5/install/kubernetes/helm/istio/charts/kiali/templates/clusterrolebinding.yaml create mode 100644 istio-1.3.5/install/kubernetes/helm/istio/charts/kiali/templates/configmap.yaml create mode 100644 istio-1.3.5/install/kubernetes/helm/istio/charts/kiali/templates/demosecret.yaml create mode 100644 istio-1.3.5/install/kubernetes/helm/istio/charts/kiali/templates/deployment.yaml create mode 100644 istio-1.3.5/install/kubernetes/helm/istio/charts/kiali/templates/ingress.yaml create mode 100644 istio-1.3.5/install/kubernetes/helm/istio/charts/kiali/templates/service.yaml create mode 100644 istio-1.3.5/install/kubernetes/helm/istio/charts/kiali/templates/serviceaccount.yaml create mode 100644 istio-1.3.5/install/kubernetes/helm/istio/charts/kiali/templates/tests/test-kiali-connection.yaml create mode 100644 istio-1.3.5/install/kubernetes/helm/istio/charts/kiali/values.yaml create mode 100644 istio-1.3.5/install/kubernetes/helm/istio/charts/mixer/Chart.yaml create mode 100644 istio-1.3.5/install/kubernetes/helm/istio/charts/mixer/templates/_helpers.tpl create mode 100644 istio-1.3.5/install/kubernetes/helm/istio/charts/mixer/templates/autoscale.yaml create mode 100644 istio-1.3.5/install/kubernetes/helm/istio/charts/mixer/templates/clusterrole.yaml create mode 100644 istio-1.3.5/install/kubernetes/helm/istio/charts/mixer/templates/clusterrolebinding.yaml create mode 100644 istio-1.3.5/install/kubernetes/helm/istio/charts/mixer/templates/config.yaml create mode 100644 istio-1.3.5/install/kubernetes/helm/istio/charts/mixer/templates/deployment.yaml create mode 100644 istio-1.3.5/install/kubernetes/helm/istio/charts/mixer/templates/poddisruptionbudget.yaml create mode 100644 istio-1.3.5/install/kubernetes/helm/istio/charts/mixer/templates/service.yaml create mode 100644 istio-1.3.5/install/kubernetes/helm/istio/charts/mixer/templates/serviceaccount.yaml create mode 100644 istio-1.3.5/install/kubernetes/helm/istio/charts/mixer/values.yaml create mode 100644 istio-1.3.5/install/kubernetes/helm/istio/charts/nodeagent/Chart.yaml create mode 100644 istio-1.3.5/install/kubernetes/helm/istio/charts/nodeagent/templates/_helpers.tpl create mode 100644 istio-1.3.5/install/kubernetes/helm/istio/charts/nodeagent/templates/clusterrole.yaml create mode 100644 istio-1.3.5/install/kubernetes/helm/istio/charts/nodeagent/templates/clusterrolebinding.yaml create mode 100644 istio-1.3.5/install/kubernetes/helm/istio/charts/nodeagent/templates/daemonset.yaml create mode 100644 istio-1.3.5/install/kubernetes/helm/istio/charts/nodeagent/templates/serviceaccount.yaml create mode 100644 istio-1.3.5/install/kubernetes/helm/istio/charts/nodeagent/values.yaml create mode 100644 istio-1.3.5/install/kubernetes/helm/istio/charts/pilot/Chart.yaml create mode 100644 istio-1.3.5/install/kubernetes/helm/istio/charts/pilot/templates/_helpers.tpl create mode 100644 istio-1.3.5/install/kubernetes/helm/istio/charts/pilot/templates/autoscale.yaml create mode 100644 istio-1.3.5/install/kubernetes/helm/istio/charts/pilot/templates/clusterrole.yaml create mode 100644 istio-1.3.5/install/kubernetes/helm/istio/charts/pilot/templates/clusterrolebinding.yaml create mode 100644 istio-1.3.5/install/kubernetes/helm/istio/charts/pilot/templates/deployment.yaml create mode 100644 istio-1.3.5/install/kubernetes/helm/istio/charts/pilot/templates/meshexpansion.yaml create mode 100644 istio-1.3.5/install/kubernetes/helm/istio/charts/pilot/templates/poddisruptionbudget.yaml create mode 100644 istio-1.3.5/install/kubernetes/helm/istio/charts/pilot/templates/service.yaml create mode 100644 istio-1.3.5/install/kubernetes/helm/istio/charts/pilot/templates/serviceaccount.yaml create mode 100644 istio-1.3.5/install/kubernetes/helm/istio/charts/pilot/values.yaml create mode 100644 istio-1.3.5/install/kubernetes/helm/istio/charts/prometheus/Chart.yaml create mode 100644 istio-1.3.5/install/kubernetes/helm/istio/charts/prometheus/templates/_helpers.tpl create mode 100644 istio-1.3.5/install/kubernetes/helm/istio/charts/prometheus/templates/clusterrole.yaml create mode 100644 istio-1.3.5/install/kubernetes/helm/istio/charts/prometheus/templates/clusterrolebindings.yaml create mode 100644 istio-1.3.5/install/kubernetes/helm/istio/charts/prometheus/templates/configmap.yaml create mode 100644 istio-1.3.5/install/kubernetes/helm/istio/charts/prometheus/templates/deployment copy.yaml create mode 100644 istio-1.3.5/install/kubernetes/helm/istio/charts/prometheus/templates/deployment.yaml create mode 100644 istio-1.3.5/install/kubernetes/helm/istio/charts/prometheus/templates/ingress.yaml create mode 100644 istio-1.3.5/install/kubernetes/helm/istio/charts/prometheus/templates/service.yaml create mode 100644 istio-1.3.5/install/kubernetes/helm/istio/charts/prometheus/templates/serviceaccount.yaml create mode 100644 istio-1.3.5/install/kubernetes/helm/istio/charts/prometheus/templates/tests/test-prometheus-connection.yaml create mode 100644 istio-1.3.5/install/kubernetes/helm/istio/charts/prometheus/values.yaml create mode 100644 istio-1.3.5/install/kubernetes/helm/istio/charts/security/Chart.yaml create mode 100644 istio-1.3.5/install/kubernetes/helm/istio/charts/security/templates/_helpers.tpl create mode 100644 istio-1.3.5/install/kubernetes/helm/istio/charts/security/templates/clusterrole.yaml create mode 100644 istio-1.3.5/install/kubernetes/helm/istio/charts/security/templates/clusterrolebinding.yaml create mode 100644 istio-1.3.5/install/kubernetes/helm/istio/charts/security/templates/configmap.yaml create mode 100644 istio-1.3.5/install/kubernetes/helm/istio/charts/security/templates/create-custom-resources-job.yaml create mode 100644 istio-1.3.5/install/kubernetes/helm/istio/charts/security/templates/deployment.yaml create mode 100644 istio-1.3.5/install/kubernetes/helm/istio/charts/security/templates/enable-mesh-mtls.yaml create mode 100644 istio-1.3.5/install/kubernetes/helm/istio/charts/security/templates/enable-mesh-permissive.yaml create mode 100644 istio-1.3.5/install/kubernetes/helm/istio/charts/security/templates/meshexpansion.yaml create mode 100644 istio-1.3.5/install/kubernetes/helm/istio/charts/security/templates/service.yaml create mode 100644 istio-1.3.5/install/kubernetes/helm/istio/charts/security/templates/serviceaccount.yaml create mode 100644 istio-1.3.5/install/kubernetes/helm/istio/charts/security/templates/tests/test-citadel-connection.yaml create mode 100644 istio-1.3.5/install/kubernetes/helm/istio/charts/security/values.yaml create mode 100644 istio-1.3.5/install/kubernetes/helm/istio/charts/sidecarInjectorWebhook/Chart.yaml create mode 100644 istio-1.3.5/install/kubernetes/helm/istio/charts/sidecarInjectorWebhook/templates/_helpers.tpl create mode 100644 istio-1.3.5/install/kubernetes/helm/istio/charts/sidecarInjectorWebhook/templates/clusterrole.yaml create mode 100644 istio-1.3.5/install/kubernetes/helm/istio/charts/sidecarInjectorWebhook/templates/clusterrolebinding.yaml create mode 100644 istio-1.3.5/install/kubernetes/helm/istio/charts/sidecarInjectorWebhook/templates/deployment.yaml create mode 100644 istio-1.3.5/install/kubernetes/helm/istio/charts/sidecarInjectorWebhook/templates/mutatingwebhook.yaml create mode 100644 istio-1.3.5/install/kubernetes/helm/istio/charts/sidecarInjectorWebhook/templates/poddisruptionbudget.yaml create mode 100644 istio-1.3.5/install/kubernetes/helm/istio/charts/sidecarInjectorWebhook/templates/service.yaml create mode 100644 istio-1.3.5/install/kubernetes/helm/istio/charts/sidecarInjectorWebhook/templates/serviceaccount.yaml create mode 100644 istio-1.3.5/install/kubernetes/helm/istio/charts/sidecarInjectorWebhook/values.yaml create mode 100644 istio-1.3.5/install/kubernetes/helm/istio/charts/tracing/Chart.yaml create mode 100644 istio-1.3.5/install/kubernetes/helm/istio/charts/tracing/templates/_helpers.tpl create mode 100644 istio-1.3.5/install/kubernetes/helm/istio/charts/tracing/templates/deployment-jaeger.yaml create mode 100644 istio-1.3.5/install/kubernetes/helm/istio/charts/tracing/templates/deployment-zipkin.yaml create mode 100644 istio-1.3.5/install/kubernetes/helm/istio/charts/tracing/templates/ingress.yaml create mode 100644 istio-1.3.5/install/kubernetes/helm/istio/charts/tracing/templates/pvc.yaml create mode 100644 istio-1.3.5/install/kubernetes/helm/istio/charts/tracing/templates/service-jaeger.yaml create mode 100644 istio-1.3.5/install/kubernetes/helm/istio/charts/tracing/templates/service.yaml create mode 100644 istio-1.3.5/install/kubernetes/helm/istio/charts/tracing/templates/tests/test-tracing-connection.yaml create mode 100644 istio-1.3.5/install/kubernetes/helm/istio/charts/tracing/values.yaml create mode 100644 istio-1.3.5/install/kubernetes/helm/istio/example-values/README.md create mode 100644 istio-1.3.5/install/kubernetes/helm/istio/example-values/values-istio-example-sds-vault.yaml create mode 100644 istio-1.3.5/install/kubernetes/helm/istio/example-values/values-istio-gateways.yaml create mode 100644 istio-1.3.5/install/kubernetes/helm/istio/example-values/values-istio-googleca.yaml create mode 100644 istio-1.3.5/install/kubernetes/helm/istio/example-values/values-istio-meshexpansion-gateways.yaml create mode 100644 istio-1.3.5/install/kubernetes/helm/istio/example-values/values-istio-multicluster-gateways.yaml create mode 100644 istio-1.3.5/install/kubernetes/helm/istio/files/injection-template.yaml create mode 100644 istio-1.3.5/install/kubernetes/helm/istio/requirements.yaml create mode 100644 istio-1.3.5/install/kubernetes/helm/istio/templates/NOTES.txt create mode 100644 istio-1.3.5/install/kubernetes/helm/istio/templates/_affinity.tpl create mode 100644 istio-1.3.5/install/kubernetes/helm/istio/templates/_helpers.tpl create mode 100644 istio-1.3.5/install/kubernetes/helm/istio/templates/_podDisruptionBudget.tpl create mode 100644 istio-1.3.5/install/kubernetes/helm/istio/templates/clusterrole.yaml create mode 100644 istio-1.3.5/install/kubernetes/helm/istio/templates/clusterrolebinding.yaml create mode 100644 istio-1.3.5/install/kubernetes/helm/istio/templates/configmap.yaml create mode 100644 istio-1.3.5/install/kubernetes/helm/istio/templates/endpoints.yaml create mode 100644 istio-1.3.5/install/kubernetes/helm/istio/templates/install-custom-resources.sh.tpl create mode 100644 istio-1.3.5/install/kubernetes/helm/istio/templates/service.yaml create mode 100644 istio-1.3.5/install/kubernetes/helm/istio/templates/serviceaccount.yaml create mode 100644 istio-1.3.5/install/kubernetes/helm/istio/templates/sidecar-injector-configmap.yaml create mode 100644 istio-1.3.5/install/kubernetes/helm/istio/values-istio-demo-auth.yaml create mode 100644 istio-1.3.5/install/kubernetes/helm/istio/values-istio-demo.yaml create mode 100644 istio-1.3.5/install/kubernetes/helm/istio/values-istio-minimal.yaml create mode 100644 istio-1.3.5/install/kubernetes/helm/istio/values-istio-remote.yaml create mode 100644 istio-1.3.5/install/kubernetes/helm/istio/values-istio-sds-auth-control-plane-auth-disabled.yaml create mode 100644 istio-1.3.5/install/kubernetes/helm/istio/values-istio-sds-auth.yaml create mode 100644 istio-1.3.5/install/kubernetes/helm/istio/values.yaml create mode 100644 istio-1.3.5/install/kubernetes/istio-demo-auth.yaml create mode 100644 istio-1.3.5/install/kubernetes/istio-demo.yaml create mode 100644 istio-1.3.5/install/kubernetes/mesh-expansion.yaml create mode 100644 istio-1.3.5/install/kubernetes/namespace.yaml create mode 100644 istio-1.3.5/install/kubernetes/operator/charts/crds/Chart.yaml create mode 100644 istio-1.3.5/install/kubernetes/operator/charts/crds/files/crd-10.yaml create mode 100644 istio-1.3.5/install/kubernetes/operator/charts/crds/files/crd-11.yaml create mode 100644 istio-1.3.5/install/kubernetes/operator/charts/crds/files/crd-12.yaml create mode 100644 istio-1.3.5/install/kubernetes/operator/charts/crds/files/crd-certmanager-10.yaml create mode 100644 istio-1.3.5/install/kubernetes/operator/charts/crds/files/crd-certmanager-11.yaml create mode 100644 istio-1.3.5/install/kubernetes/operator/charts/crds/kustomization.yaml create mode 100644 istio-1.3.5/install/kubernetes/operator/charts/crds/templates/crds.yaml create mode 100644 istio-1.3.5/install/kubernetes/operator/charts/crds/templates/namespaces.yaml create mode 100644 istio-1.3.5/install/kubernetes/operator/charts/gateways/istio-egress/Chart.yaml create mode 100644 istio-1.3.5/install/kubernetes/operator/charts/gateways/istio-egress/NOTES.txt create mode 100644 istio-1.3.5/install/kubernetes/operator/charts/gateways/istio-egress/templates/_affinity.tpl create mode 100644 istio-1.3.5/install/kubernetes/operator/charts/gateways/istio-egress/templates/_helpers.tpl create mode 100644 istio-1.3.5/install/kubernetes/operator/charts/gateways/istio-egress/templates/autoscale.yaml create mode 100644 istio-1.3.5/install/kubernetes/operator/charts/gateways/istio-egress/templates/deployment.yaml create mode 100644 istio-1.3.5/install/kubernetes/operator/charts/gateways/istio-egress/templates/poddisruptionbudget.yaml create mode 100644 istio-1.3.5/install/kubernetes/operator/charts/gateways/istio-egress/templates/preconfigured.yaml create mode 100644 istio-1.3.5/install/kubernetes/operator/charts/gateways/istio-egress/templates/service.yaml create mode 100644 istio-1.3.5/install/kubernetes/operator/charts/gateways/istio-egress/templates/serviceaccount.yaml create mode 100644 istio-1.3.5/install/kubernetes/operator/charts/gateways/istio-egress/values.yaml create mode 100644 istio-1.3.5/install/kubernetes/operator/charts/gateways/istio-ingress/Chart.yaml create mode 100644 istio-1.3.5/install/kubernetes/operator/charts/gateways/istio-ingress/NOTES.txt create mode 100644 istio-1.3.5/install/kubernetes/operator/charts/gateways/istio-ingress/templates/_affinity.tpl create mode 100644 istio-1.3.5/install/kubernetes/operator/charts/gateways/istio-ingress/templates/addongateway.yaml create mode 100644 istio-1.3.5/install/kubernetes/operator/charts/gateways/istio-ingress/templates/autoscale.yaml create mode 100644 istio-1.3.5/install/kubernetes/operator/charts/gateways/istio-ingress/templates/certificate.yaml create mode 100644 istio-1.3.5/install/kubernetes/operator/charts/gateways/istio-ingress/templates/deployment.yaml create mode 100644 istio-1.3.5/install/kubernetes/operator/charts/gateways/istio-ingress/templates/gateway.yaml create mode 100644 istio-1.3.5/install/kubernetes/operator/charts/gateways/istio-ingress/templates/hosts.yaml create mode 100644 istio-1.3.5/install/kubernetes/operator/charts/gateways/istio-ingress/templates/meshexpansion.yaml create mode 100644 istio-1.3.5/install/kubernetes/operator/charts/gateways/istio-ingress/templates/poddisruptionbudget.yaml create mode 100644 istio-1.3.5/install/kubernetes/operator/charts/gateways/istio-ingress/templates/preconfigured.yaml create mode 100644 istio-1.3.5/install/kubernetes/operator/charts/gateways/istio-ingress/templates/role.yaml create mode 100644 istio-1.3.5/install/kubernetes/operator/charts/gateways/istio-ingress/templates/rolebindings.yaml create mode 100644 istio-1.3.5/install/kubernetes/operator/charts/gateways/istio-ingress/templates/service.yaml create mode 100644 istio-1.3.5/install/kubernetes/operator/charts/gateways/istio-ingress/templates/serviceaccount.yaml create mode 100644 istio-1.3.5/install/kubernetes/operator/charts/gateways/istio-ingress/templates/sidecar.yaml create mode 100644 istio-1.3.5/install/kubernetes/operator/charts/gateways/istio-ingress/values.yaml create mode 100644 istio-1.3.5/install/kubernetes/operator/charts/istio-cni/Chart.yaml create mode 100644 istio-1.3.5/install/kubernetes/operator/charts/istio-cni/templates/clusterrole.yaml create mode 100644 istio-1.3.5/install/kubernetes/operator/charts/istio-cni/templates/clusterrolebinding.yaml create mode 100644 istio-1.3.5/install/kubernetes/operator/charts/istio-cni/templates/configmap-cni.yaml create mode 100644 istio-1.3.5/install/kubernetes/operator/charts/istio-cni/templates/daemonset.yaml create mode 100644 istio-1.3.5/install/kubernetes/operator/charts/istio-cni/templates/serviceaccount.yaml create mode 100644 istio-1.3.5/install/kubernetes/operator/charts/istio-cni/values.yaml create mode 100644 istio-1.3.5/install/kubernetes/operator/charts/istio-cni/values_gke.yaml create mode 100644 istio-1.3.5/install/kubernetes/operator/charts/istio-control/istio-autoinject/Chart.yaml create mode 100644 istio-1.3.5/install/kubernetes/operator/charts/istio-control/istio-autoinject/NOTES.txt create mode 100644 istio-1.3.5/install/kubernetes/operator/charts/istio-control/istio-autoinject/files/injection-template.yaml create mode 100644 istio-1.3.5/install/kubernetes/operator/charts/istio-control/istio-autoinject/templates/_affinity.tpl create mode 100644 istio-1.3.5/install/kubernetes/operator/charts/istio-control/istio-autoinject/templates/_helpers.tpl create mode 100644 istio-1.3.5/install/kubernetes/operator/charts/istio-control/istio-autoinject/templates/clusterrole.yaml create mode 100644 istio-1.3.5/install/kubernetes/operator/charts/istio-control/istio-autoinject/templates/clusterrolebinding.yaml create mode 100644 istio-1.3.5/install/kubernetes/operator/charts/istio-control/istio-autoinject/templates/configmap.yaml create mode 100644 istio-1.3.5/install/kubernetes/operator/charts/istio-control/istio-autoinject/templates/deployment.yaml create mode 100644 istio-1.3.5/install/kubernetes/operator/charts/istio-control/istio-autoinject/templates/mutatingwebhook.yaml create mode 100644 istio-1.3.5/install/kubernetes/operator/charts/istio-control/istio-autoinject/templates/poddisruptionbudget.yaml create mode 100644 istio-1.3.5/install/kubernetes/operator/charts/istio-control/istio-autoinject/templates/service.yaml create mode 100644 istio-1.3.5/install/kubernetes/operator/charts/istio-control/istio-autoinject/templates/serviceaccount.yaml create mode 100644 istio-1.3.5/install/kubernetes/operator/charts/istio-control/istio-autoinject/templates/sidecar-injector-configmap.yaml create mode 100644 istio-1.3.5/install/kubernetes/operator/charts/istio-control/istio-autoinject/values.yaml create mode 100644 istio-1.3.5/install/kubernetes/operator/charts/istio-control/istio-config/Chart.yaml create mode 100644 istio-1.3.5/install/kubernetes/operator/charts/istio-control/istio-config/OWNERS create mode 100644 istio-1.3.5/install/kubernetes/operator/charts/istio-control/istio-config/README.md create mode 100644 istio-1.3.5/install/kubernetes/operator/charts/istio-control/istio-config/templates/_affinity.tpl create mode 100644 istio-1.3.5/install/kubernetes/operator/charts/istio-control/istio-config/templates/_helpers.tpl create mode 100644 istio-1.3.5/install/kubernetes/operator/charts/istio-control/istio-config/templates/clusterrole.yaml create mode 100644 istio-1.3.5/install/kubernetes/operator/charts/istio-control/istio-config/templates/clusterrolebinding.yaml create mode 100644 istio-1.3.5/install/kubernetes/operator/charts/istio-control/istio-config/templates/configmap-envoy.yaml create mode 100644 istio-1.3.5/install/kubernetes/operator/charts/istio-control/istio-config/templates/configmap-mesh.yaml create mode 100644 istio-1.3.5/install/kubernetes/operator/charts/istio-control/istio-config/templates/configmap.yaml create mode 100644 istio-1.3.5/install/kubernetes/operator/charts/istio-control/istio-config/templates/deployment.yaml create mode 100644 istio-1.3.5/install/kubernetes/operator/charts/istio-control/istio-config/templates/poddisruptionbudget.yaml create mode 100644 istio-1.3.5/install/kubernetes/operator/charts/istio-control/istio-config/templates/service.yaml create mode 100644 istio-1.3.5/install/kubernetes/operator/charts/istio-control/istio-config/templates/serviceaccount.yaml create mode 100644 istio-1.3.5/install/kubernetes/operator/charts/istio-control/istio-config/templates/validatingwebhookconfiguration.yaml.tpl create mode 100644 istio-1.3.5/install/kubernetes/operator/charts/istio-control/istio-config/values.yaml create mode 100644 istio-1.3.5/install/kubernetes/operator/charts/istio-control/istio-discovery/Chart.yaml create mode 100644 istio-1.3.5/install/kubernetes/operator/charts/istio-control/istio-discovery/NOTES.txt create mode 100644 istio-1.3.5/install/kubernetes/operator/charts/istio-control/istio-discovery/templates/_affinity.tpl create mode 100644 istio-1.3.5/install/kubernetes/operator/charts/istio-control/istio-discovery/templates/_helpers.tpl create mode 100644 istio-1.3.5/install/kubernetes/operator/charts/istio-control/istio-discovery/templates/autoscale.yaml create mode 100644 istio-1.3.5/install/kubernetes/operator/charts/istio-control/istio-discovery/templates/clusterrole.yaml create mode 100644 istio-1.3.5/install/kubernetes/operator/charts/istio-control/istio-discovery/templates/clusterrolebinding.yaml create mode 100644 istio-1.3.5/install/kubernetes/operator/charts/istio-control/istio-discovery/templates/configmap-envoy.yaml create mode 100644 istio-1.3.5/install/kubernetes/operator/charts/istio-control/istio-discovery/templates/configmap.yaml create mode 100644 istio-1.3.5/install/kubernetes/operator/charts/istio-control/istio-discovery/templates/deployment.yaml create mode 100644 istio-1.3.5/install/kubernetes/operator/charts/istio-control/istio-discovery/templates/enable-mesh-mtls.yaml create mode 100644 istio-1.3.5/install/kubernetes/operator/charts/istio-control/istio-discovery/templates/poddisruptionbudget.yaml create mode 100644 istio-1.3.5/install/kubernetes/operator/charts/istio-control/istio-discovery/templates/service.yaml create mode 100644 istio-1.3.5/install/kubernetes/operator/charts/istio-control/istio-discovery/templates/serviceaccount.yaml create mode 100644 istio-1.3.5/install/kubernetes/operator/charts/istio-control/istio-discovery/values.yaml create mode 100644 istio-1.3.5/install/kubernetes/operator/charts/istio-policy/Chart.yaml create mode 100644 istio-1.3.5/install/kubernetes/operator/charts/istio-policy/templates/_affinity.tpl create mode 100644 istio-1.3.5/install/kubernetes/operator/charts/istio-policy/templates/_helpers.tpl create mode 100644 istio-1.3.5/install/kubernetes/operator/charts/istio-policy/templates/autoscale.yaml create mode 100644 istio-1.3.5/install/kubernetes/operator/charts/istio-policy/templates/clusterrole.yaml create mode 100644 istio-1.3.5/install/kubernetes/operator/charts/istio-policy/templates/clusterrolebinding.yaml create mode 100644 istio-1.3.5/install/kubernetes/operator/charts/istio-policy/templates/config.yaml create mode 100644 istio-1.3.5/install/kubernetes/operator/charts/istio-policy/templates/deployment.yaml create mode 100644 istio-1.3.5/install/kubernetes/operator/charts/istio-policy/templates/poddisruptionbudget.yaml create mode 100644 istio-1.3.5/install/kubernetes/operator/charts/istio-policy/templates/service.yaml create mode 100644 istio-1.3.5/install/kubernetes/operator/charts/istio-policy/templates/serviceaccount.yaml create mode 100644 istio-1.3.5/install/kubernetes/operator/charts/istio-policy/values.yaml create mode 100644 istio-1.3.5/install/kubernetes/operator/charts/istio-telemetry/grafana/Chart.yaml create mode 100644 istio-1.3.5/install/kubernetes/operator/charts/istio-telemetry/grafana/dashboards/galley-dashboard.json create mode 100644 istio-1.3.5/install/kubernetes/operator/charts/istio-telemetry/grafana/dashboards/istio-mesh-dashboard.json create mode 100644 istio-1.3.5/install/kubernetes/operator/charts/istio-telemetry/grafana/dashboards/istio-performance-dashboard.json create mode 100644 istio-1.3.5/install/kubernetes/operator/charts/istio-telemetry/grafana/dashboards/istio-service-dashboard.json create mode 100644 istio-1.3.5/install/kubernetes/operator/charts/istio-telemetry/grafana/dashboards/istio-workload-dashboard.json create mode 100644 istio-1.3.5/install/kubernetes/operator/charts/istio-telemetry/grafana/dashboards/mixer-dashboard.json create mode 100644 istio-1.3.5/install/kubernetes/operator/charts/istio-telemetry/grafana/dashboards/pilot-dashboard.json create mode 100755 istio-1.3.5/install/kubernetes/operator/charts/istio-telemetry/grafana/fix_datasources.sh create mode 100644 istio-1.3.5/install/kubernetes/operator/charts/istio-telemetry/grafana/templates/_affinity.tpl create mode 100644 istio-1.3.5/install/kubernetes/operator/charts/istio-telemetry/grafana/templates/configmap-dashboards.yaml create mode 100644 istio-1.3.5/install/kubernetes/operator/charts/istio-telemetry/grafana/templates/configmap.yaml create mode 100644 istio-1.3.5/install/kubernetes/operator/charts/istio-telemetry/grafana/templates/deployment.yaml create mode 100644 istio-1.3.5/install/kubernetes/operator/charts/istio-telemetry/grafana/templates/destination-rule.yaml create mode 100644 istio-1.3.5/install/kubernetes/operator/charts/istio-telemetry/grafana/templates/grafana-policy.yaml create mode 100644 istio-1.3.5/install/kubernetes/operator/charts/istio-telemetry/grafana/templates/pvc.yaml create mode 100644 istio-1.3.5/install/kubernetes/operator/charts/istio-telemetry/grafana/templates/service.yaml create mode 100644 istio-1.3.5/install/kubernetes/operator/charts/istio-telemetry/grafana/templates/tests/test-grafana-connection.yaml create mode 100644 istio-1.3.5/install/kubernetes/operator/charts/istio-telemetry/grafana/values.yaml create mode 100644 istio-1.3.5/install/kubernetes/operator/charts/istio-telemetry/kiali/Chart.yaml create mode 100644 istio-1.3.5/install/kubernetes/operator/charts/istio-telemetry/kiali/templates/_affinity.tpl create mode 100644 istio-1.3.5/install/kubernetes/operator/charts/istio-telemetry/kiali/templates/clusterrole.yaml create mode 100644 istio-1.3.5/install/kubernetes/operator/charts/istio-telemetry/kiali/templates/clusterrolebinding.yaml create mode 100644 istio-1.3.5/install/kubernetes/operator/charts/istio-telemetry/kiali/templates/configmap.yaml create mode 100644 istio-1.3.5/install/kubernetes/operator/charts/istio-telemetry/kiali/templates/demosecret.yaml create mode 100644 istio-1.3.5/install/kubernetes/operator/charts/istio-telemetry/kiali/templates/deployment.yaml create mode 100644 istio-1.3.5/install/kubernetes/operator/charts/istio-telemetry/kiali/templates/service.yaml create mode 100644 istio-1.3.5/install/kubernetes/operator/charts/istio-telemetry/kiali/templates/serviceaccount.yaml create mode 100644 istio-1.3.5/install/kubernetes/operator/charts/istio-telemetry/kiali/values.yaml create mode 100644 istio-1.3.5/install/kubernetes/operator/charts/istio-telemetry/mixer-telemetry/Chart.yaml create mode 100644 istio-1.3.5/install/kubernetes/operator/charts/istio-telemetry/mixer-telemetry/templates/_affinity.tpl create mode 100644 istio-1.3.5/install/kubernetes/operator/charts/istio-telemetry/mixer-telemetry/templates/autoscale.yaml create mode 100644 istio-1.3.5/install/kubernetes/operator/charts/istio-telemetry/mixer-telemetry/templates/clusterrole.yaml create mode 100644 istio-1.3.5/install/kubernetes/operator/charts/istio-telemetry/mixer-telemetry/templates/clusterrolebinding.yaml create mode 100644 istio-1.3.5/install/kubernetes/operator/charts/istio-telemetry/mixer-telemetry/templates/config.yaml create mode 100644 istio-1.3.5/install/kubernetes/operator/charts/istio-telemetry/mixer-telemetry/templates/configmap-envoy.yaml create mode 100644 istio-1.3.5/install/kubernetes/operator/charts/istio-telemetry/mixer-telemetry/templates/deployment.yaml create mode 100644 istio-1.3.5/install/kubernetes/operator/charts/istio-telemetry/mixer-telemetry/templates/poddisruptionbudget.yaml create mode 100644 istio-1.3.5/install/kubernetes/operator/charts/istio-telemetry/mixer-telemetry/templates/service.yaml create mode 100644 istio-1.3.5/install/kubernetes/operator/charts/istio-telemetry/mixer-telemetry/templates/serviceaccount.yaml create mode 100644 istio-1.3.5/install/kubernetes/operator/charts/istio-telemetry/mixer-telemetry/templates/stackdriver.yaml create mode 100644 istio-1.3.5/install/kubernetes/operator/charts/istio-telemetry/mixer-telemetry/values.yaml create mode 100644 istio-1.3.5/install/kubernetes/operator/charts/istio-telemetry/prometheus-operator/Chart.yaml create mode 100644 istio-1.3.5/install/kubernetes/operator/charts/istio-telemetry/prometheus-operator/templates/_affinity.tpl create mode 100644 istio-1.3.5/install/kubernetes/operator/charts/istio-telemetry/prometheus-operator/templates/prometheus.yaml create mode 100644 istio-1.3.5/install/kubernetes/operator/charts/istio-telemetry/prometheus-operator/templates/servicemonitors.yaml create mode 100644 istio-1.3.5/install/kubernetes/operator/charts/istio-telemetry/prometheus-operator/values.yaml create mode 100644 istio-1.3.5/install/kubernetes/operator/charts/istio-telemetry/prometheus/Chart.yaml create mode 100644 istio-1.3.5/install/kubernetes/operator/charts/istio-telemetry/prometheus/templates/_affinity.tpl create mode 100644 istio-1.3.5/install/kubernetes/operator/charts/istio-telemetry/prometheus/templates/clusterrole.yaml create mode 100644 istio-1.3.5/install/kubernetes/operator/charts/istio-telemetry/prometheus/templates/clusterrolebindings.yaml create mode 100644 istio-1.3.5/install/kubernetes/operator/charts/istio-telemetry/prometheus/templates/configmap.yaml create mode 100644 istio-1.3.5/install/kubernetes/operator/charts/istio-telemetry/prometheus/templates/deployment.yaml create mode 100644 istio-1.3.5/install/kubernetes/operator/charts/istio-telemetry/prometheus/templates/destination-rule.yaml create mode 100644 istio-1.3.5/install/kubernetes/operator/charts/istio-telemetry/prometheus/templates/inrgess.yaml create mode 100644 istio-1.3.5/install/kubernetes/operator/charts/istio-telemetry/prometheus/templates/service.yaml create mode 100644 istio-1.3.5/install/kubernetes/operator/charts/istio-telemetry/prometheus/templates/serviceaccount.yaml create mode 100644 istio-1.3.5/install/kubernetes/operator/charts/istio-telemetry/prometheus/templates/tests/test-prometheus-connection.yaml create mode 100644 istio-1.3.5/install/kubernetes/operator/charts/istio-telemetry/prometheus/values.yaml create mode 100644 istio-1.3.5/install/kubernetes/operator/charts/istio-telemetry/tracing/Chart.yaml create mode 100644 istio-1.3.5/install/kubernetes/operator/charts/istio-telemetry/tracing/templates/_affinity.tpl create mode 100644 istio-1.3.5/install/kubernetes/operator/charts/istio-telemetry/tracing/templates/deployment-jaeger.yaml create mode 100644 istio-1.3.5/install/kubernetes/operator/charts/istio-telemetry/tracing/templates/deployment-opencensus.yaml create mode 100644 istio-1.3.5/install/kubernetes/operator/charts/istio-telemetry/tracing/templates/deployment-zipkin.yaml create mode 100644 istio-1.3.5/install/kubernetes/operator/charts/istio-telemetry/tracing/templates/pvc.yaml create mode 100644 istio-1.3.5/install/kubernetes/operator/charts/istio-telemetry/tracing/templates/service-jaeger.yaml create mode 100644 istio-1.3.5/install/kubernetes/operator/charts/istio-telemetry/tracing/templates/service.yaml create mode 100644 istio-1.3.5/install/kubernetes/operator/charts/istio-telemetry/tracing/values.yaml create mode 100644 istio-1.3.5/install/kubernetes/operator/charts/istiocoredns/Chart.yaml create mode 100644 istio-1.3.5/install/kubernetes/operator/charts/istiocoredns/templates/_affinity.tpl create mode 100644 istio-1.3.5/install/kubernetes/operator/charts/istiocoredns/templates/clusterrole.yaml create mode 100644 istio-1.3.5/install/kubernetes/operator/charts/istiocoredns/templates/clusterrolebinding.yaml create mode 100644 istio-1.3.5/install/kubernetes/operator/charts/istiocoredns/templates/configmap.yaml create mode 100644 istio-1.3.5/install/kubernetes/operator/charts/istiocoredns/templates/deployment.yaml create mode 100644 istio-1.3.5/install/kubernetes/operator/charts/istiocoredns/templates/service.yaml create mode 100644 istio-1.3.5/install/kubernetes/operator/charts/istiocoredns/templates/serviceaccount.yaml create mode 100644 istio-1.3.5/install/kubernetes/operator/charts/istiocoredns/values.yaml create mode 100644 istio-1.3.5/install/kubernetes/operator/charts/security/certmanager/Chart.yaml create mode 100644 istio-1.3.5/install/kubernetes/operator/charts/security/certmanager/templates/NOTES.txt create mode 100644 istio-1.3.5/install/kubernetes/operator/charts/security/certmanager/templates/_affinity.tpl create mode 100644 istio-1.3.5/install/kubernetes/operator/charts/security/certmanager/templates/deployment.yaml create mode 100644 istio-1.3.5/install/kubernetes/operator/charts/security/certmanager/templates/issuer.yaml create mode 100644 istio-1.3.5/install/kubernetes/operator/charts/security/certmanager/templates/poddisruptionbudget.yaml create mode 100644 istio-1.3.5/install/kubernetes/operator/charts/security/certmanager/templates/rbac.yaml create mode 100644 istio-1.3.5/install/kubernetes/operator/charts/security/certmanager/templates/serviceaccount.yaml create mode 100644 istio-1.3.5/install/kubernetes/operator/charts/security/certmanager/values.yaml create mode 100644 istio-1.3.5/install/kubernetes/operator/charts/security/citadel/Chart.yaml create mode 100644 istio-1.3.5/install/kubernetes/operator/charts/security/citadel/templates/NOTES.txt create mode 100644 istio-1.3.5/install/kubernetes/operator/charts/security/citadel/templates/_affinity.tpl create mode 100644 istio-1.3.5/install/kubernetes/operator/charts/security/citadel/templates/_helpers.tpl create mode 100644 istio-1.3.5/install/kubernetes/operator/charts/security/citadel/templates/clusterrole.yaml create mode 100644 istio-1.3.5/install/kubernetes/operator/charts/security/citadel/templates/clusterrolebinding.yaml create mode 100644 istio-1.3.5/install/kubernetes/operator/charts/security/citadel/templates/deployment.yaml create mode 100644 istio-1.3.5/install/kubernetes/operator/charts/security/citadel/templates/poddisruptionbudget.yaml create mode 100644 istio-1.3.5/install/kubernetes/operator/charts/security/citadel/templates/service.yaml create mode 100644 istio-1.3.5/install/kubernetes/operator/charts/security/citadel/templates/serviceaccount.yaml create mode 100644 istio-1.3.5/install/kubernetes/operator/charts/security/citadel/values.yaml create mode 100644 istio-1.3.5/install/kubernetes/operator/charts/security/nodeagent/Chart.yaml create mode 100644 istio-1.3.5/install/kubernetes/operator/charts/security/nodeagent/templates/_affinity.tpl create mode 100644 istio-1.3.5/install/kubernetes/operator/charts/security/nodeagent/templates/clusterrole.yaml create mode 100644 istio-1.3.5/install/kubernetes/operator/charts/security/nodeagent/templates/clusterrolebinding.yaml create mode 100644 istio-1.3.5/install/kubernetes/operator/charts/security/nodeagent/templates/daemonset.yaml create mode 100644 istio-1.3.5/install/kubernetes/operator/charts/security/nodeagent/templates/serviceaccount.yaml create mode 100644 istio-1.3.5/install/kubernetes/operator/charts/security/nodeagent/values.yaml create mode 100644 istio-1.3.5/install/kubernetes/operator/profiles/default.yaml create mode 100644 istio-1.3.5/install/kubernetes/operator/profiles/demo-auth.yaml create mode 100644 istio-1.3.5/install/kubernetes/operator/profiles/demo.yaml create mode 100644 istio-1.3.5/install/kubernetes/operator/profiles/minimal.yaml create mode 100644 istio-1.3.5/install/kubernetes/operator/profiles/sds.yaml create mode 100644 istio-1.3.5/install/kubernetes/operator/version.yaml create mode 100644 istio-1.3.5/install/kubernetes/operator/versions.yaml create mode 100755 istio-1.3.5/install/tools/setupIstioVM.sh create mode 100755 istio-1.3.5/install/tools/setupMeshEx.sh create mode 100644 istio-1.3.5/istio.VERSION create mode 100644 istio-1.3.5/samples/README.md create mode 100644 istio-1.3.5/samples/bookinfo/README.md create mode 100644 istio-1.3.5/samples/bookinfo/networking/ROUTING_RULE_MIGRATION.md create mode 100644 istio-1.3.5/samples/bookinfo/networking/bookinfo-gateway.yaml create mode 100644 istio-1.3.5/samples/bookinfo/networking/certmanager-gateway.yaml create mode 100644 istio-1.3.5/samples/bookinfo/networking/destination-rule-all-mtls.yaml create mode 100644 istio-1.3.5/samples/bookinfo/networking/destination-rule-all.yaml create mode 100644 istio-1.3.5/samples/bookinfo/networking/destination-rule-reviews.yaml create mode 100644 istio-1.3.5/samples/bookinfo/networking/egress-rule-google-apis.yaml create mode 100644 istio-1.3.5/samples/bookinfo/networking/fault-injection-details-v1.yaml create mode 100644 istio-1.3.5/samples/bookinfo/networking/virtual-service-all-v1.yaml create mode 100644 istio-1.3.5/samples/bookinfo/networking/virtual-service-details-v2.yaml create mode 100644 istio-1.3.5/samples/bookinfo/networking/virtual-service-ratings-db.yaml create mode 100644 istio-1.3.5/samples/bookinfo/networking/virtual-service-ratings-mysql-vm.yaml create mode 100644 istio-1.3.5/samples/bookinfo/networking/virtual-service-ratings-mysql.yaml create mode 100644 istio-1.3.5/samples/bookinfo/networking/virtual-service-ratings-test-abort.yaml create mode 100644 istio-1.3.5/samples/bookinfo/networking/virtual-service-ratings-test-delay.yaml create mode 100644 istio-1.3.5/samples/bookinfo/networking/virtual-service-reviews-50-v3.yaml create mode 100644 istio-1.3.5/samples/bookinfo/networking/virtual-service-reviews-80-20.yaml create mode 100644 istio-1.3.5/samples/bookinfo/networking/virtual-service-reviews-90-10.yaml create mode 100644 istio-1.3.5/samples/bookinfo/networking/virtual-service-reviews-jason-v2-v3.yaml create mode 100644 istio-1.3.5/samples/bookinfo/networking/virtual-service-reviews-test-v2.yaml create mode 100644 istio-1.3.5/samples/bookinfo/networking/virtual-service-reviews-v2-v3.yaml create mode 100644 istio-1.3.5/samples/bookinfo/networking/virtual-service-reviews-v3.yaml create mode 100644 istio-1.3.5/samples/bookinfo/platform/consul/README.md create mode 100644 istio-1.3.5/samples/bookinfo/platform/consul/bookinfo.sidecars.yaml create mode 100644 istio-1.3.5/samples/bookinfo/platform/consul/bookinfo.yaml create mode 100755 istio-1.3.5/samples/bookinfo/platform/consul/cleanup.sh create mode 100644 istio-1.3.5/samples/bookinfo/platform/consul/destination-rule-all.yaml create mode 100644 istio-1.3.5/samples/bookinfo/platform/consul/virtual-service-all-v1.yaml create mode 100644 istio-1.3.5/samples/bookinfo/platform/consul/virtual-service-ratings-test-abort.yaml create mode 100644 istio-1.3.5/samples/bookinfo/platform/consul/virtual-service-ratings-test-delay.yaml create mode 100644 istio-1.3.5/samples/bookinfo/platform/consul/virtual-service-reviews-50-v3.yaml create mode 100644 istio-1.3.5/samples/bookinfo/platform/consul/virtual-service-reviews-test-v2.yaml create mode 100644 istio-1.3.5/samples/bookinfo/platform/consul/virtual-service-reviews-v2-v3.yaml create mode 100644 istio-1.3.5/samples/bookinfo/platform/consul/virtual-service-reviews-v3.yaml create mode 100644 istio-1.3.5/samples/bookinfo/platform/kube/README.md create mode 100644 istio-1.3.5/samples/bookinfo/platform/kube/bookinfo-certificate.yaml create mode 100644 istio-1.3.5/samples/bookinfo/platform/kube/bookinfo-db.yaml create mode 100644 istio-1.3.5/samples/bookinfo/platform/kube/bookinfo-details-v2.yaml create mode 100644 istio-1.3.5/samples/bookinfo/platform/kube/bookinfo-details.yaml create mode 100644 istio-1.3.5/samples/bookinfo/platform/kube/bookinfo-ingress.yaml create mode 100644 istio-1.3.5/samples/bookinfo/platform/kube/bookinfo-mysql.yaml create mode 100644 istio-1.3.5/samples/bookinfo/platform/kube/bookinfo-ratings-discovery.yaml create mode 100644 istio-1.3.5/samples/bookinfo/platform/kube/bookinfo-ratings-v2-mysql-vm.yaml create mode 100644 istio-1.3.5/samples/bookinfo/platform/kube/bookinfo-ratings-v2-mysql.yaml create mode 100644 istio-1.3.5/samples/bookinfo/platform/kube/bookinfo-ratings-v2.yaml create mode 100644 istio-1.3.5/samples/bookinfo/platform/kube/bookinfo-ratings.yaml create mode 100644 istio-1.3.5/samples/bookinfo/platform/kube/bookinfo-reviews-v2.yaml create mode 100644 istio-1.3.5/samples/bookinfo/platform/kube/bookinfo.yaml create mode 100755 istio-1.3.5/samples/bookinfo/platform/kube/cleanup.sh create mode 100644 istio-1.3.5/samples/bookinfo/platform/kube/productpage-nodeport.yaml create mode 100644 istio-1.3.5/samples/bookinfo/platform/kube/rbac/details-reviews-policy-permissive.yaml create mode 100644 istio-1.3.5/samples/bookinfo/platform/kube/rbac/details-reviews-policy.yaml create mode 100644 istio-1.3.5/samples/bookinfo/platform/kube/rbac/mongodb-policy.yaml create mode 100644 istio-1.3.5/samples/bookinfo/platform/kube/rbac/namespace-policy.yaml create mode 100644 istio-1.3.5/samples/bookinfo/platform/kube/rbac/productpage-policy.yaml create mode 100644 istio-1.3.5/samples/bookinfo/platform/kube/rbac/ratings-policy.yaml create mode 100644 istio-1.3.5/samples/bookinfo/platform/kube/rbac/rbac-config-ON.yaml create mode 100644 istio-1.3.5/samples/bookinfo/platform/kube/rbac/rbac-config-on-mongodb.yaml create mode 100644 istio-1.3.5/samples/bookinfo/platform/kube/rbac/rbac-config-on-permissive.yaml create mode 100644 istio-1.3.5/samples/bookinfo/platform/kube/rbac/rbac-permissive-telemetry.yaml create mode 100644 istio-1.3.5/samples/bookinfo/policy/mixer-rule-deny-ip-crd.yaml create mode 100644 istio-1.3.5/samples/bookinfo/policy/mixer-rule-deny-ip.yaml create mode 100644 istio-1.3.5/samples/bookinfo/policy/mixer-rule-deny-label-crd.yaml create mode 100644 istio-1.3.5/samples/bookinfo/policy/mixer-rule-deny-label.yaml create mode 100644 istio-1.3.5/samples/bookinfo/policy/mixer-rule-deny-serviceaccount.yaml create mode 100644 istio-1.3.5/samples/bookinfo/policy/mixer-rule-deny-whitelist-crd.yaml create mode 100644 istio-1.3.5/samples/bookinfo/policy/mixer-rule-deny-whitelist.yaml create mode 100644 istio-1.3.5/samples/bookinfo/policy/mixer-rule-ingress-denial.yaml create mode 100644 istio-1.3.5/samples/bookinfo/policy/mixer-rule-kubernetesenv-telemetry.yaml create mode 100644 istio-1.3.5/samples/bookinfo/policy/mixer-rule-productpage-ratelimit-crd.yaml create mode 100644 istio-1.3.5/samples/bookinfo/policy/mixer-rule-productpage-ratelimit.yaml create mode 100644 istio-1.3.5/samples/bookinfo/policy/mixer-rule-productpage-redis-quota-fixed-window.yaml create mode 100644 istio-1.3.5/samples/bookinfo/policy/mixer-rule-productpage-redis-quota-rolling-window.yaml create mode 100644 istio-1.3.5/samples/bookinfo/policy/mixer-rule-ratings-denial.yaml create mode 100644 istio-1.3.5/samples/bookinfo/policy/mixer-rule-ratings-ratelimit.yaml create mode 100644 istio-1.3.5/samples/bookinfo/policy/mixer-rule-ratings-redis-quota-fixed-window.yaml create mode 100644 istio-1.3.5/samples/bookinfo/policy/mixer-rule-ratings-redis-quota-rolling-window.yaml create mode 100644 istio-1.3.5/samples/bookinfo/policy/prometheus-adapter-deployment.yaml create mode 100644 istio-1.3.5/samples/bookinfo/policy/prometheus-oop-rule.yaml create mode 100644 istio-1.3.5/samples/bookinfo/src/mongodb/ratings_data.json create mode 100644 istio-1.3.5/samples/bookinfo/src/productpage/requirements.txt create mode 100644 istio-1.3.5/samples/bookinfo/src/productpage/test-requirements.txt create mode 100644 istio-1.3.5/samples/bookinfo/src/ratings/package.json create mode 100644 istio-1.3.5/samples/bookinfo/swagger.yaml create mode 100644 istio-1.3.5/samples/bookinfo/telemetry/fluentd-istio-crd.yaml create mode 100644 istio-1.3.5/samples/bookinfo/telemetry/fluentd-istio.yaml create mode 100644 istio-1.3.5/samples/bookinfo/telemetry/log-entry-crd.yaml create mode 100644 istio-1.3.5/samples/bookinfo/telemetry/log-entry.yaml create mode 100644 istio-1.3.5/samples/bookinfo/telemetry/metrics-crd.yaml create mode 100644 istio-1.3.5/samples/bookinfo/telemetry/metrics.yaml create mode 100644 istio-1.3.5/samples/bookinfo/telemetry/tcp-metrics-crd.yaml create mode 100644 istio-1.3.5/samples/bookinfo/telemetry/tcp-metrics.yaml create mode 100644 istio-1.3.5/samples/certs/README.md create mode 100644 istio-1.3.5/samples/certs/ca-cert.pem create mode 100644 istio-1.3.5/samples/certs/ca-key.pem create mode 100644 istio-1.3.5/samples/certs/cert-chain.pem create mode 100644 istio-1.3.5/samples/certs/root-cert.pem create mode 100644 istio-1.3.5/samples/custom-bootstrap/README.md create mode 100644 istio-1.3.5/samples/custom-bootstrap/custom-bootstrap.yaml create mode 100644 istio-1.3.5/samples/custom-bootstrap/example-app.yaml create mode 100644 istio-1.3.5/samples/external/README.md create mode 100644 istio-1.3.5/samples/external/aptget.yaml create mode 100644 istio-1.3.5/samples/external/github.yaml create mode 100644 istio-1.3.5/samples/external/pypi.yaml create mode 100644 istio-1.3.5/samples/fortio/stackdriver.yaml create mode 100644 istio-1.3.5/samples/health-check/liveness-command.yaml create mode 100644 istio-1.3.5/samples/health-check/liveness-http-same-port.yaml create mode 100644 istio-1.3.5/samples/health-check/liveness-http.yaml create mode 100644 istio-1.3.5/samples/helloworld/README.md create mode 100644 istio-1.3.5/samples/helloworld/helloworld-gateway.yaml create mode 100644 istio-1.3.5/samples/helloworld/helloworld.yaml create mode 100644 istio-1.3.5/samples/helloworld/src/requirements.txt create mode 100644 istio-1.3.5/samples/httpbin/README.md create mode 100644 istio-1.3.5/samples/httpbin/httpbin-gateway.yaml create mode 100644 istio-1.3.5/samples/httpbin/httpbin-nodeport.yaml create mode 100644 istio-1.3.5/samples/httpbin/httpbin-vault.yaml create mode 100644 istio-1.3.5/samples/httpbin/httpbin.yaml create mode 100644 istio-1.3.5/samples/httpbin/policy/keyval-template.yaml create mode 100644 istio-1.3.5/samples/httpbin/policy/keyval.yaml create mode 100644 istio-1.3.5/samples/httpbin/sample-client/fortio-deploy.yaml create mode 100644 istio-1.3.5/samples/https/default.conf create mode 100644 istio-1.3.5/samples/https/nginx-app.yaml create mode 100644 istio-1.3.5/samples/kubernetes-blog/bookinfo-ratings.yaml create mode 100644 istio-1.3.5/samples/kubernetes-blog/bookinfo-reviews-v2.yaml create mode 100644 istio-1.3.5/samples/kubernetes-blog/bookinfo-v1.yaml create mode 100644 istio-1.3.5/samples/rawvm/README.md create mode 100644 istio-1.3.5/samples/security/psp/all-pods-psp.yaml create mode 100644 istio-1.3.5/samples/security/psp/citadel-agent-psp.yaml create mode 100644 istio-1.3.5/samples/sleep/README.md create mode 100644 istio-1.3.5/samples/sleep/policy/sni-serviceaccount.yaml create mode 100644 istio-1.3.5/samples/sleep/policy/sni-wikipedia.yaml create mode 100644 istio-1.3.5/samples/sleep/sleep-vault.yaml create mode 100644 istio-1.3.5/samples/sleep/sleep.yaml create mode 100644 istio-1.3.5/samples/sleep/telemetry/sni-logging.yaml create mode 100644 istio-1.3.5/samples/tcp-echo/README.md create mode 100644 istio-1.3.5/samples/tcp-echo/tcp-echo-20-v2.yaml create mode 100644 istio-1.3.5/samples/tcp-echo/tcp-echo-all-v1.yaml create mode 100644 istio-1.3.5/samples/tcp-echo/tcp-echo-services.yaml create mode 100644 istio-1.3.5/samples/tcp-echo/tcp-echo.yaml create mode 100644 istio-1.3.5/samples/websockets/README.md create mode 100644 istio-1.3.5/samples/websockets/app.yaml create mode 100644 istio-1.3.5/samples/websockets/route.yaml create mode 100644 istio-1.3.5/tools/README.md create mode 100644 istio-1.3.5/tools/_istioctl create mode 100644 istio-1.3.5/tools/cache_buster.yaml create mode 100644 istio-1.3.5/tools/checker/README.md create mode 100644 istio-1.3.5/tools/checker/checker.go create mode 100644 istio-1.3.5/tools/checker/envvarlinter/README.md create mode 100644 istio-1.3.5/tools/checker/envvarlinter/envvar_test.go create mode 100644 istio-1.3.5/tools/checker/envvarlinter/main.go create mode 100644 istio-1.3.5/tools/checker/envvarlinter/rules/no_os_env.go create mode 100644 istio-1.3.5/tools/checker/envvarlinter/rules/util.go create mode 100644 istio-1.3.5/tools/checker/envvarlinter/rules_matcher.go create mode 100644 istio-1.3.5/tools/checker/envvarlinter/testdata/envuse.go create mode 100644 istio-1.3.5/tools/checker/envvarlinter/whitelist.go create mode 100644 istio-1.3.5/tools/checker/report.go create mode 100644 istio-1.3.5/tools/checker/rule.go create mode 100644 istio-1.3.5/tools/checker/testlinter/README.md create mode 100644 istio-1.3.5/tools/checker/testlinter/e2etest_lint_test.go create mode 100644 istio-1.3.5/tools/checker/testlinter/integtest_lint_test.go create mode 100644 istio-1.3.5/tools/checker/testlinter/lint_rules_list.go create mode 100644 istio-1.3.5/tools/checker/testlinter/main.go create mode 100644 istio-1.3.5/tools/checker/testlinter/rules/no_goroutine.go create mode 100644 istio-1.3.5/tools/checker/testlinter/rules/no_short.go create mode 100644 istio-1.3.5/tools/checker/testlinter/rules/no_sleep.go create mode 100644 istio-1.3.5/tools/checker/testlinter/rules/short_skip.go create mode 100644 istio-1.3.5/tools/checker/testlinter/rules/skip_issue.go create mode 100644 istio-1.3.5/tools/checker/testlinter/rules/util.go create mode 100644 istio-1.3.5/tools/checker/testlinter/rules_matcher.go create mode 100644 istio-1.3.5/tools/checker/testlinter/testdata/e2e/e2e_test.go create mode 100644 istio-1.3.5/tools/checker/testlinter/testdata/integration/integtest_test.go create mode 100644 istio-1.3.5/tools/checker/testlinter/testdata/integtest_integ_test.go create mode 100644 istio-1.3.5/tools/checker/testlinter/testdata/unit_test.go create mode 100755 istio-1.3.5/tools/checker/testlinter/testlinter create mode 100644 istio-1.3.5/tools/checker/testlinter/unittest_lint_test.go create mode 100644 istio-1.3.5/tools/checker/testlinter/whitelist.go create mode 100644 istio-1.3.5/tools/checker/whitelist.go create mode 100755 istio-1.3.5/tools/convert_RbacConfig_to_ClusterRbacConfig.sh create mode 100644 istio-1.3.5/tools/convert_perf_results.py create mode 100644 istio-1.3.5/tools/docker-dev/Dockerfile create mode 100644 istio-1.3.5/tools/docker-dev/README.md create mode 100755 istio-1.3.5/tools/dump_kubernetes.sh create mode 100644 istio-1.3.5/tools/githubContrib/Contributions.txt create mode 100644 istio-1.3.5/tools/hyperistio/README.md create mode 100644 istio-1.3.5/tools/hyperistio/hyperistio.go create mode 100644 istio-1.3.5/tools/hyperistio/hyperistio_test.go create mode 100644 istio-1.3.5/tools/hyperistio/index.html create mode 100644 istio-1.3.5/tools/istio-docker.mk create mode 100644 istio-1.3.5/tools/istio-iptables/main.go create mode 100644 istio-1.3.5/tools/istioctl.bash create mode 100644 istio-1.3.5/tools/license/README.md create mode 100644 istio-1.3.5/tools/license/get_dep_licenses.go create mode 100644 istio-1.3.5/tools/license/manual_append/signalfx.txt create mode 100644 istio-1.3.5/tools/license/manual_append/siphash.txt create mode 100644 istio-1.3.5/tools/packaging/common/envoy_bootstrap_drain.json create mode 100644 istio-1.3.5/tools/packaging/common/envoy_bootstrap_v2.json create mode 100644 istio-1.3.5/tools/packaging/common/istio-auth-node-agent.service create mode 100755 istio-1.3.5/tools/packaging/common/istio-ca.sh create mode 100755 istio-1.3.5/tools/packaging/common/istio-iptables.sh create mode 100755 istio-1.3.5/tools/packaging/common/istio-node-agent-start.sh create mode 100755 istio-1.3.5/tools/packaging/common/istio-start.sh create mode 100644 istio-1.3.5/tools/packaging/common/istio.service create mode 100644 istio-1.3.5/tools/packaging/common/sidecar.env create mode 100644 istio-1.3.5/tools/packaging/deb/Dockerfile create mode 100755 istio-1.3.5/tools/packaging/deb/deb_test.sh create mode 100644 istio-1.3.5/tools/packaging/deb/istio.mk create mode 100755 istio-1.3.5/tools/packaging/deb/postinst.sh create mode 100644 istio-1.3.5/tools/packaging/packaging.mk create mode 100644 istio-1.3.5/tools/packaging/rpm/Dockerfile.build create mode 100755 istio-1.3.5/tools/packaging/rpm/build-istio-rpm.sh create mode 100755 istio-1.3.5/tools/packaging/rpm/build-proxy-rpm.sh create mode 100644 istio-1.3.5/tools/packaging/rpm/istio/istio.spec create mode 100644 istio-1.3.5/tools/packaging/rpm/proxy/bazelrc create mode 100644 istio-1.3.5/tools/packaging/rpm/proxy/istio-proxy.spec create mode 100644 istio-1.3.5/tools/packaging/rpm/rpm.mk create mode 100644 istio-1.3.5/tools/perf_istio_rules.yaml create mode 100644 istio-1.3.5/tools/perf_k8svcs.yaml create mode 100644 istio-1.3.5/tools/perf_setup.svg create mode 100644 istio-1.3.5/tools/rules.yml create mode 100755 istio-1.3.5/tools/run_canonical_perf_tests.sh create mode 100644 istio-1.3.5/tools/setup_perf_cluster.sh create mode 100644 istio-1.3.5/tools/setup_run create mode 100755 istio-1.3.5/tools/update_all create mode 100644 istio-1.3.5/tools/vagrant/Vagrantfile create mode 100644 istio-1.3.5/tools/vagrant/provision-vagrant.sh create mode 100644 istio-1.5.0/LICENSE create mode 100644 istio-1.5.0/README.md create mode 100644 istio-1.5.0/install/README.md create mode 100644 istio-1.5.0/install/consul/README.md create mode 100644 istio-1.5.0/install/consul/consul_config/agent-loglevel.json create mode 100644 istio-1.5.0/install/consul/consul_config/agent.json create mode 100644 istio-1.5.0/install/consul/consul_config/disable_update_check.json create mode 100644 istio-1.5.0/install/consul/consul_config/server.json create mode 100644 istio-1.5.0/install/gcp/README.md create mode 100644 istio-1.5.0/install/gcp/bootstrap/gcp_envoy_bootstrap.json create mode 100644 istio-1.5.0/install/kubernetes/README.md create mode 100644 istio-1.5.0/install/kubernetes/global-default-sidecar-scope.yaml create mode 100644 istio-1.5.0/install/kubernetes/helm/README.md create mode 100644 istio-1.5.0/install/kubernetes/helm/helm-service-account.yaml create mode 100644 istio-1.5.0/install/kubernetes/helm/istio-cni/Chart.yaml create mode 100644 istio-1.5.0/install/kubernetes/helm/istio-cni/templates/_labels.tpl create mode 100644 istio-1.5.0/install/kubernetes/helm/istio-cni/templates/istio-cni.yaml create mode 100644 istio-1.5.0/install/kubernetes/helm/istio-cni/values.yaml create mode 100644 istio-1.5.0/install/kubernetes/helm/istio-cni/values_gke.yaml create mode 100644 istio-1.5.0/install/kubernetes/helm/istio-init/Chart.yaml create mode 100644 istio-1.5.0/install/kubernetes/helm/istio-init/README.md create mode 100644 istio-1.5.0/install/kubernetes/helm/istio-init/files/crd-all.gen.yaml create mode 100644 istio-1.5.0/install/kubernetes/helm/istio-init/files/crd-certmanager-10.yaml create mode 100644 istio-1.5.0/install/kubernetes/helm/istio-init/files/crd-certmanager-11.yaml create mode 100644 istio-1.5.0/install/kubernetes/helm/istio-init/files/crd-mixer.yaml create mode 100644 istio-1.5.0/install/kubernetes/helm/istio-init/templates/clusterrole.yaml create mode 100644 istio-1.5.0/install/kubernetes/helm/istio-init/templates/clusterrolebinding.yaml create mode 100644 istio-1.5.0/install/kubernetes/helm/istio-init/templates/configmap-crd-all.yaml create mode 100644 istio-1.5.0/install/kubernetes/helm/istio-init/templates/configmap-crd-certmanager-10.yaml create mode 100644 istio-1.5.0/install/kubernetes/helm/istio-init/templates/configmap-crd-certmanager-11.yaml create mode 100644 istio-1.5.0/install/kubernetes/helm/istio-init/templates/configmap-crd-mixer.yaml create mode 100644 istio-1.5.0/install/kubernetes/helm/istio-init/templates/job-crd-all.yaml create mode 100644 istio-1.5.0/install/kubernetes/helm/istio-init/templates/job-crd-certmanager-10.yaml create mode 100644 istio-1.5.0/install/kubernetes/helm/istio-init/templates/job-crd-certmanager-11.yaml create mode 100644 istio-1.5.0/install/kubernetes/helm/istio-init/templates/job-crd-mixer.yaml create mode 100644 istio-1.5.0/install/kubernetes/helm/istio-init/templates/serviceaccount.yaml create mode 100644 istio-1.5.0/install/kubernetes/helm/istio-init/values.yaml create mode 100644 istio-1.5.0/install/kubernetes/helm/istio/Chart.yaml create mode 100644 istio-1.5.0/install/kubernetes/helm/istio/README.md create mode 100644 istio-1.5.0/install/kubernetes/helm/istio/charts/certmanager/Chart.yaml create mode 100644 istio-1.5.0/install/kubernetes/helm/istio/charts/certmanager/templates/NOTES.txt create mode 100644 istio-1.5.0/install/kubernetes/helm/istio/charts/certmanager/templates/_helpers.tpl create mode 100644 istio-1.5.0/install/kubernetes/helm/istio/charts/certmanager/templates/deployment.yaml create mode 100644 istio-1.5.0/install/kubernetes/helm/istio/charts/certmanager/templates/issuer.yaml create mode 100644 istio-1.5.0/install/kubernetes/helm/istio/charts/certmanager/templates/poddisruptionbudget.yaml create mode 100644 istio-1.5.0/install/kubernetes/helm/istio/charts/certmanager/templates/rbac.yaml create mode 100644 istio-1.5.0/install/kubernetes/helm/istio/charts/certmanager/templates/serviceaccount.yaml create mode 100644 istio-1.5.0/install/kubernetes/helm/istio/charts/certmanager/values.yaml create mode 100644 istio-1.5.0/install/kubernetes/helm/istio/charts/galley/Chart.yaml create mode 100644 istio-1.5.0/install/kubernetes/helm/istio/charts/galley/templates/_helpers.tpl create mode 100644 istio-1.5.0/install/kubernetes/helm/istio/charts/galley/templates/clusterrole.yaml create mode 100644 istio-1.5.0/install/kubernetes/helm/istio/charts/galley/templates/clusterrolebinding.yaml create mode 100644 istio-1.5.0/install/kubernetes/helm/istio/charts/galley/templates/configmap.yaml create mode 100644 istio-1.5.0/install/kubernetes/helm/istio/charts/galley/templates/deployment.yaml create mode 100644 istio-1.5.0/install/kubernetes/helm/istio/charts/galley/templates/poddisruptionbudget.yaml create mode 100644 istio-1.5.0/install/kubernetes/helm/istio/charts/galley/templates/service.yaml create mode 100644 istio-1.5.0/install/kubernetes/helm/istio/charts/galley/templates/serviceaccount.yaml create mode 100644 istio-1.5.0/install/kubernetes/helm/istio/charts/galley/templates/validatingwebhookconfiguration.yaml create mode 100644 istio-1.5.0/install/kubernetes/helm/istio/charts/galley/templates/validatingwebhookconfiguration.yaml.tpl create mode 100644 istio-1.5.0/install/kubernetes/helm/istio/charts/galley/values.yaml create mode 100644 istio-1.5.0/install/kubernetes/helm/istio/charts/gateways/Chart.yaml create mode 100644 istio-1.5.0/install/kubernetes/helm/istio/charts/gateways/templates/_affinity.tpl create mode 100644 istio-1.5.0/install/kubernetes/helm/istio/charts/gateways/templates/_helpers.tpl create mode 100644 istio-1.5.0/install/kubernetes/helm/istio/charts/gateways/templates/autoscale.yaml create mode 100644 istio-1.5.0/install/kubernetes/helm/istio/charts/gateways/templates/deployment.yaml create mode 100644 istio-1.5.0/install/kubernetes/helm/istio/charts/gateways/templates/poddisruptionbudget.yaml create mode 100644 istio-1.5.0/install/kubernetes/helm/istio/charts/gateways/templates/preconfigured.yaml create mode 100644 istio-1.5.0/install/kubernetes/helm/istio/charts/gateways/templates/role.yaml create mode 100644 istio-1.5.0/install/kubernetes/helm/istio/charts/gateways/templates/rolebindings.yaml create mode 100644 istio-1.5.0/install/kubernetes/helm/istio/charts/gateways/templates/service.yaml create mode 100644 istio-1.5.0/install/kubernetes/helm/istio/charts/gateways/templates/serviceaccount.yaml create mode 100644 istio-1.5.0/install/kubernetes/helm/istio/charts/gateways/values.yaml create mode 100644 istio-1.5.0/install/kubernetes/helm/istio/charts/grafana/Chart.yaml create mode 100644 istio-1.5.0/install/kubernetes/helm/istio/charts/grafana/dashboards/citadel-dashboard.json create mode 100644 istio-1.5.0/install/kubernetes/helm/istio/charts/grafana/dashboards/galley-dashboard.json create mode 100644 istio-1.5.0/install/kubernetes/helm/istio/charts/grafana/dashboards/istio-mesh-dashboard.json create mode 100644 istio-1.5.0/install/kubernetes/helm/istio/charts/grafana/dashboards/istio-performance-dashboard.json create mode 100644 istio-1.5.0/install/kubernetes/helm/istio/charts/grafana/dashboards/istio-service-dashboard.json create mode 100644 istio-1.5.0/install/kubernetes/helm/istio/charts/grafana/dashboards/istio-workload-dashboard.json create mode 100644 istio-1.5.0/install/kubernetes/helm/istio/charts/grafana/dashboards/mixer-dashboard.json create mode 100644 istio-1.5.0/install/kubernetes/helm/istio/charts/grafana/dashboards/pilot-dashboard.json create mode 100644 istio-1.5.0/install/kubernetes/helm/istio/charts/grafana/templates/_helpers.tpl create mode 100644 istio-1.5.0/install/kubernetes/helm/istio/charts/grafana/templates/configmap-custom-resources.yaml create mode 100644 istio-1.5.0/install/kubernetes/helm/istio/charts/grafana/templates/configmap-dashboards.yaml create mode 100644 istio-1.5.0/install/kubernetes/helm/istio/charts/grafana/templates/configmap.yaml create mode 100644 istio-1.5.0/install/kubernetes/helm/istio/charts/grafana/templates/create-custom-resources-job.yaml create mode 100644 istio-1.5.0/install/kubernetes/helm/istio/charts/grafana/templates/deployment.yaml create mode 100644 istio-1.5.0/install/kubernetes/helm/istio/charts/grafana/templates/grafana-ports-mtls.yaml create mode 100644 istio-1.5.0/install/kubernetes/helm/istio/charts/grafana/templates/ingress.yaml create mode 100644 istio-1.5.0/install/kubernetes/helm/istio/charts/grafana/templates/pvc.yaml create mode 100644 istio-1.5.0/install/kubernetes/helm/istio/charts/grafana/templates/service.yaml create mode 100644 istio-1.5.0/install/kubernetes/helm/istio/charts/grafana/templates/tests/test-grafana-connection.yaml create mode 100644 istio-1.5.0/install/kubernetes/helm/istio/charts/grafana/values.yaml create mode 100644 istio-1.5.0/install/kubernetes/helm/istio/charts/istiocoredns/Chart.yaml create mode 100644 istio-1.5.0/install/kubernetes/helm/istio/charts/istiocoredns/templates/_helpers.tpl create mode 100644 istio-1.5.0/install/kubernetes/helm/istio/charts/istiocoredns/templates/clusterrole.yaml create mode 100644 istio-1.5.0/install/kubernetes/helm/istio/charts/istiocoredns/templates/clusterrolebinding.yaml create mode 100644 istio-1.5.0/install/kubernetes/helm/istio/charts/istiocoredns/templates/configmap.yaml create mode 100644 istio-1.5.0/install/kubernetes/helm/istio/charts/istiocoredns/templates/deployment.yaml create mode 100644 istio-1.5.0/install/kubernetes/helm/istio/charts/istiocoredns/templates/service.yaml create mode 100644 istio-1.5.0/install/kubernetes/helm/istio/charts/istiocoredns/templates/serviceaccount.yaml create mode 100644 istio-1.5.0/install/kubernetes/helm/istio/charts/istiocoredns/values.yaml create mode 100644 istio-1.5.0/install/kubernetes/helm/istio/charts/kiali/Chart.yaml create mode 100644 istio-1.5.0/install/kubernetes/helm/istio/charts/kiali/templates/_helpers.tpl create mode 100644 istio-1.5.0/install/kubernetes/helm/istio/charts/kiali/templates/clusterrole.yaml create mode 100644 istio-1.5.0/install/kubernetes/helm/istio/charts/kiali/templates/clusterrolebinding.yaml create mode 100644 istio-1.5.0/install/kubernetes/helm/istio/charts/kiali/templates/configmap.yaml create mode 100644 istio-1.5.0/install/kubernetes/helm/istio/charts/kiali/templates/demosecret.yaml create mode 100644 istio-1.5.0/install/kubernetes/helm/istio/charts/kiali/templates/deployment.yaml create mode 100644 istio-1.5.0/install/kubernetes/helm/istio/charts/kiali/templates/ingress.yaml create mode 100644 istio-1.5.0/install/kubernetes/helm/istio/charts/kiali/templates/service.yaml create mode 100644 istio-1.5.0/install/kubernetes/helm/istio/charts/kiali/templates/serviceaccount.yaml create mode 100644 istio-1.5.0/install/kubernetes/helm/istio/charts/kiali/templates/tests/test-kiali-connection.yaml create mode 100644 istio-1.5.0/install/kubernetes/helm/istio/charts/kiali/values.yaml create mode 100644 istio-1.5.0/install/kubernetes/helm/istio/charts/mixer/Chart.yaml create mode 100644 istio-1.5.0/install/kubernetes/helm/istio/charts/mixer/templates/_helpers.tpl create mode 100644 istio-1.5.0/install/kubernetes/helm/istio/charts/mixer/templates/autoscale.yaml create mode 100644 istio-1.5.0/install/kubernetes/helm/istio/charts/mixer/templates/clusterrole.yaml create mode 100644 istio-1.5.0/install/kubernetes/helm/istio/charts/mixer/templates/clusterrolebinding.yaml create mode 100644 istio-1.5.0/install/kubernetes/helm/istio/charts/mixer/templates/config.yaml create mode 100644 istio-1.5.0/install/kubernetes/helm/istio/charts/mixer/templates/deployment.yaml create mode 100644 istio-1.5.0/install/kubernetes/helm/istio/charts/mixer/templates/poddisruptionbudget.yaml create mode 100644 istio-1.5.0/install/kubernetes/helm/istio/charts/mixer/templates/service.yaml create mode 100644 istio-1.5.0/install/kubernetes/helm/istio/charts/mixer/templates/serviceaccount.yaml create mode 100644 istio-1.5.0/install/kubernetes/helm/istio/charts/mixer/values.yaml create mode 100644 istio-1.5.0/install/kubernetes/helm/istio/charts/nodeagent/Chart.yaml create mode 100644 istio-1.5.0/install/kubernetes/helm/istio/charts/nodeagent/templates/_helpers.tpl create mode 100644 istio-1.5.0/install/kubernetes/helm/istio/charts/nodeagent/templates/clusterrole.yaml create mode 100644 istio-1.5.0/install/kubernetes/helm/istio/charts/nodeagent/templates/clusterrolebinding.yaml create mode 100644 istio-1.5.0/install/kubernetes/helm/istio/charts/nodeagent/templates/daemonset.yaml create mode 100644 istio-1.5.0/install/kubernetes/helm/istio/charts/nodeagent/templates/serviceaccount.yaml create mode 100644 istio-1.5.0/install/kubernetes/helm/istio/charts/nodeagent/values.yaml create mode 100644 istio-1.5.0/install/kubernetes/helm/istio/charts/pilot/Chart.yaml create mode 100644 istio-1.5.0/install/kubernetes/helm/istio/charts/pilot/templates/_helpers.tpl create mode 100644 istio-1.5.0/install/kubernetes/helm/istio/charts/pilot/templates/autoscale.yaml create mode 100644 istio-1.5.0/install/kubernetes/helm/istio/charts/pilot/templates/clusterrole.yaml create mode 100644 istio-1.5.0/install/kubernetes/helm/istio/charts/pilot/templates/clusterrolebinding.yaml create mode 100644 istio-1.5.0/install/kubernetes/helm/istio/charts/pilot/templates/configmap.yaml create mode 100644 istio-1.5.0/install/kubernetes/helm/istio/charts/pilot/templates/deployment.yaml create mode 100644 istio-1.5.0/install/kubernetes/helm/istio/charts/pilot/templates/meshexpansion.yaml create mode 100644 istio-1.5.0/install/kubernetes/helm/istio/charts/pilot/templates/poddisruptionbudget.yaml create mode 100644 istio-1.5.0/install/kubernetes/helm/istio/charts/pilot/templates/service.yaml create mode 100644 istio-1.5.0/install/kubernetes/helm/istio/charts/pilot/templates/serviceaccount.yaml create mode 100644 istio-1.5.0/install/kubernetes/helm/istio/charts/pilot/values.yaml create mode 100644 istio-1.5.0/install/kubernetes/helm/istio/charts/prometheus/Chart.yaml create mode 100644 istio-1.5.0/install/kubernetes/helm/istio/charts/prometheus/templates/_helpers.tpl create mode 100644 istio-1.5.0/install/kubernetes/helm/istio/charts/prometheus/templates/clusterrole.yaml create mode 100644 istio-1.5.0/install/kubernetes/helm/istio/charts/prometheus/templates/clusterrolebindings.yaml create mode 100644 istio-1.5.0/install/kubernetes/helm/istio/charts/prometheus/templates/configmap.yaml create mode 100644 istio-1.5.0/install/kubernetes/helm/istio/charts/prometheus/templates/deployment.yaml create mode 100644 istio-1.5.0/install/kubernetes/helm/istio/charts/prometheus/templates/ingress.yaml create mode 100644 istio-1.5.0/install/kubernetes/helm/istio/charts/prometheus/templates/service.yaml create mode 100644 istio-1.5.0/install/kubernetes/helm/istio/charts/prometheus/templates/serviceaccount.yaml create mode 100644 istio-1.5.0/install/kubernetes/helm/istio/charts/prometheus/templates/tests/test-prometheus-connection.yaml create mode 100644 istio-1.5.0/install/kubernetes/helm/istio/charts/prometheus/values.yaml create mode 100644 istio-1.5.0/install/kubernetes/helm/istio/charts/security/Chart.yaml create mode 100644 istio-1.5.0/install/kubernetes/helm/istio/charts/security/templates/_helpers.tpl create mode 100644 istio-1.5.0/install/kubernetes/helm/istio/charts/security/templates/clusterrole.yaml create mode 100644 istio-1.5.0/install/kubernetes/helm/istio/charts/security/templates/clusterrolebinding.yaml create mode 100644 istio-1.5.0/install/kubernetes/helm/istio/charts/security/templates/configmap.yaml create mode 100644 istio-1.5.0/install/kubernetes/helm/istio/charts/security/templates/create-custom-resources-job.yaml create mode 100644 istio-1.5.0/install/kubernetes/helm/istio/charts/security/templates/deployment.yaml create mode 100644 istio-1.5.0/install/kubernetes/helm/istio/charts/security/templates/enable-mesh-mtls.yaml create mode 100644 istio-1.5.0/install/kubernetes/helm/istio/charts/security/templates/enable-mesh-permissive.yaml create mode 100644 istio-1.5.0/install/kubernetes/helm/istio/charts/security/templates/meshexpansion.yaml create mode 100644 istio-1.5.0/install/kubernetes/helm/istio/charts/security/templates/poddisruptionbudget.yaml create mode 100644 istio-1.5.0/install/kubernetes/helm/istio/charts/security/templates/service.yaml create mode 100644 istio-1.5.0/install/kubernetes/helm/istio/charts/security/templates/serviceaccount.yaml create mode 100644 istio-1.5.0/install/kubernetes/helm/istio/charts/security/templates/tests/test-citadel-connection.yaml create mode 100644 istio-1.5.0/install/kubernetes/helm/istio/charts/security/values.yaml create mode 100644 istio-1.5.0/install/kubernetes/helm/istio/charts/sidecarInjectorWebhook/Chart.yaml create mode 100644 istio-1.5.0/install/kubernetes/helm/istio/charts/sidecarInjectorWebhook/templates/_helpers.tpl create mode 100644 istio-1.5.0/install/kubernetes/helm/istio/charts/sidecarInjectorWebhook/templates/clusterrole.yaml create mode 100644 istio-1.5.0/install/kubernetes/helm/istio/charts/sidecarInjectorWebhook/templates/clusterrolebinding.yaml create mode 100644 istio-1.5.0/install/kubernetes/helm/istio/charts/sidecarInjectorWebhook/templates/deployment.yaml create mode 100644 istio-1.5.0/install/kubernetes/helm/istio/charts/sidecarInjectorWebhook/templates/mutatingwebhook.yaml create mode 100644 istio-1.5.0/install/kubernetes/helm/istio/charts/sidecarInjectorWebhook/templates/poddisruptionbudget.yaml create mode 100644 istio-1.5.0/install/kubernetes/helm/istio/charts/sidecarInjectorWebhook/templates/service.yaml create mode 100644 istio-1.5.0/install/kubernetes/helm/istio/charts/sidecarInjectorWebhook/templates/serviceaccount.yaml create mode 100644 istio-1.5.0/install/kubernetes/helm/istio/charts/sidecarInjectorWebhook/values.yaml create mode 100644 istio-1.5.0/install/kubernetes/helm/istio/charts/tracing/Chart.yaml create mode 100644 istio-1.5.0/install/kubernetes/helm/istio/charts/tracing/templates/_helpers.tpl create mode 100644 istio-1.5.0/install/kubernetes/helm/istio/charts/tracing/templates/deployment-jaeger.yaml create mode 100644 istio-1.5.0/install/kubernetes/helm/istio/charts/tracing/templates/deployment-zipkin.yaml create mode 100644 istio-1.5.0/install/kubernetes/helm/istio/charts/tracing/templates/ingress.yaml create mode 100644 istio-1.5.0/install/kubernetes/helm/istio/charts/tracing/templates/pvc.yaml create mode 100644 istio-1.5.0/install/kubernetes/helm/istio/charts/tracing/templates/service-jaeger.yaml create mode 100644 istio-1.5.0/install/kubernetes/helm/istio/charts/tracing/templates/service.yaml create mode 100644 istio-1.5.0/install/kubernetes/helm/istio/charts/tracing/templates/tests/test-tracing-connection.yaml create mode 100644 istio-1.5.0/install/kubernetes/helm/istio/charts/tracing/values.yaml create mode 100644 istio-1.5.0/install/kubernetes/helm/istio/example-values/README.md create mode 100644 istio-1.5.0/install/kubernetes/helm/istio/example-values/values-istio-dns-cert.yaml create mode 100644 istio-1.5.0/install/kubernetes/helm/istio/example-values/values-istio-example-sds-vault.yaml create mode 100644 istio-1.5.0/install/kubernetes/helm/istio/example-values/values-istio-gateways.yaml create mode 100644 istio-1.5.0/install/kubernetes/helm/istio/example-values/values-istio-googleca.yaml create mode 100644 istio-1.5.0/install/kubernetes/helm/istio/example-values/values-istio-meshexpansion-gateways.yaml create mode 100644 istio-1.5.0/install/kubernetes/helm/istio/example-values/values-istio-multicluster-gateways.yaml create mode 100644 istio-1.5.0/install/kubernetes/helm/istio/files/injection-template.yaml create mode 100644 istio-1.5.0/install/kubernetes/helm/istio/requirements.yaml create mode 100644 istio-1.5.0/install/kubernetes/helm/istio/templates/NOTES.txt create mode 100644 istio-1.5.0/install/kubernetes/helm/istio/templates/_affinity.tpl create mode 100644 istio-1.5.0/install/kubernetes/helm/istio/templates/_helpers.tpl create mode 100644 istio-1.5.0/install/kubernetes/helm/istio/templates/_podDisruptionBudget.tpl create mode 100644 istio-1.5.0/install/kubernetes/helm/istio/templates/clusterrole.yaml create mode 100644 istio-1.5.0/install/kubernetes/helm/istio/templates/clusterrolebinding.yaml create mode 100644 istio-1.5.0/install/kubernetes/helm/istio/templates/configmap.yaml create mode 100644 istio-1.5.0/install/kubernetes/helm/istio/templates/endpoints.yaml create mode 100644 istio-1.5.0/install/kubernetes/helm/istio/templates/install-custom-resources.sh.tpl create mode 100644 istio-1.5.0/install/kubernetes/helm/istio/templates/service.yaml create mode 100644 istio-1.5.0/install/kubernetes/helm/istio/templates/serviceaccount.yaml create mode 100644 istio-1.5.0/install/kubernetes/helm/istio/templates/sidecar-injector-configmap.yaml create mode 100644 istio-1.5.0/install/kubernetes/helm/istio/test-values/README.md create mode 100644 istio-1.5.0/install/kubernetes/helm/istio/test-values/values-e2e.yaml create mode 100644 istio-1.5.0/install/kubernetes/helm/istio/test-values/values-integ.yaml create mode 100644 istio-1.5.0/install/kubernetes/helm/istio/test-values/values-istio-auth-mcp.yaml create mode 100644 istio-1.5.0/install/kubernetes/helm/istio/test-values/values-istio-auth-multicluster.yaml create mode 100644 istio-1.5.0/install/kubernetes/helm/istio/test-values/values-istio-auth-non-mcp.yaml create mode 100644 istio-1.5.0/install/kubernetes/helm/istio/test-values/values-istio-auth-sds.yaml create mode 100644 istio-1.5.0/install/kubernetes/helm/istio/test-values/values-istio-auth.yaml create mode 100644 istio-1.5.0/install/kubernetes/helm/istio/test-values/values-istio-dns-cert.yaml create mode 100644 istio-1.5.0/install/kubernetes/helm/istio/test-values/values-istio-mcp.yaml create mode 100644 istio-1.5.0/install/kubernetes/helm/istio/test-values/values-istio-mesh-networks.yaml create mode 100644 istio-1.5.0/install/kubernetes/helm/istio/test-values/values-istio-multicluster-split-horizon.yaml create mode 100644 istio-1.5.0/install/kubernetes/helm/istio/test-values/values-istio-multicluster.yaml create mode 100644 istio-1.5.0/install/kubernetes/helm/istio/test-values/values-istio-non-mcp.yaml create mode 100644 istio-1.5.0/install/kubernetes/helm/istio/test-values/values-istio-one-namespace-auth.yaml create mode 100644 istio-1.5.0/install/kubernetes/helm/istio/test-values/values-istio-one-namespace-trust-domain.yaml create mode 100644 istio-1.5.0/install/kubernetes/helm/istio/test-values/values-istio-one-namespace.yaml create mode 100644 istio-1.5.0/install/kubernetes/helm/istio/test-values/values-istio.yaml create mode 100644 istio-1.5.0/install/kubernetes/helm/istio/values-istio-demo.yaml create mode 100644 istio-1.5.0/install/kubernetes/helm/istio/values-istio-minimal.yaml create mode 100644 istio-1.5.0/install/kubernetes/helm/istio/values-istio-remote.yaml create mode 100644 istio-1.5.0/install/kubernetes/helm/istio/values-istio-sds-auth-control-plane-auth-disabled.yaml create mode 100644 istio-1.5.0/install/kubernetes/helm/istio/values-istio-sds-auth.yaml create mode 100644 istio-1.5.0/install/kubernetes/helm/istio/values.yaml create mode 100644 istio-1.5.0/install/kubernetes/istio-demo.yaml create mode 100644 istio-1.5.0/install/kubernetes/mesh-expansion.yaml create mode 100644 istio-1.5.0/install/kubernetes/namespace.yaml create mode 100644 istio-1.5.0/install/kubernetes/operator/charts/base/Chart.yaml create mode 100644 istio-1.5.0/install/kubernetes/operator/charts/base/files/crd-all.gen.yaml create mode 100644 istio-1.5.0/install/kubernetes/operator/charts/base/files/crd-mixer.yaml create mode 100644 istio-1.5.0/install/kubernetes/operator/charts/base/kustomization.yaml create mode 100644 istio-1.5.0/install/kubernetes/operator/charts/base/templates/clusterrole.yaml create mode 100644 istio-1.5.0/install/kubernetes/operator/charts/base/templates/clusterrolebinding.yaml create mode 100644 istio-1.5.0/install/kubernetes/operator/charts/base/templates/crds.yaml create mode 100644 istio-1.5.0/install/kubernetes/operator/charts/base/templates/endpoints.yaml create mode 100644 istio-1.5.0/install/kubernetes/operator/charts/base/templates/namespaces.yaml create mode 100644 istio-1.5.0/install/kubernetes/operator/charts/base/templates/serviceaccount.yaml create mode 100644 istio-1.5.0/install/kubernetes/operator/charts/base/templates/services.yaml create mode 100644 istio-1.5.0/install/kubernetes/operator/charts/base/values.yaml create mode 100644 istio-1.5.0/install/kubernetes/operator/charts/gateways/istio-egress/Chart.yaml create mode 100644 istio-1.5.0/install/kubernetes/operator/charts/gateways/istio-egress/NOTES.txt create mode 100644 istio-1.5.0/install/kubernetes/operator/charts/gateways/istio-egress/templates/_affinity.tpl create mode 100644 istio-1.5.0/install/kubernetes/operator/charts/gateways/istio-egress/templates/_helpers.tpl create mode 100644 istio-1.5.0/install/kubernetes/operator/charts/gateways/istio-egress/templates/autoscale.yaml create mode 100644 istio-1.5.0/install/kubernetes/operator/charts/gateways/istio-egress/templates/deployment.yaml create mode 100644 istio-1.5.0/install/kubernetes/operator/charts/gateways/istio-egress/templates/poddisruptionbudget.yaml create mode 100644 istio-1.5.0/install/kubernetes/operator/charts/gateways/istio-egress/templates/preconfigured.yaml create mode 100644 istio-1.5.0/install/kubernetes/operator/charts/gateways/istio-egress/templates/service.yaml create mode 100644 istio-1.5.0/install/kubernetes/operator/charts/gateways/istio-egress/templates/serviceaccount.yaml create mode 100644 istio-1.5.0/install/kubernetes/operator/charts/gateways/istio-egress/values.yaml create mode 100644 istio-1.5.0/install/kubernetes/operator/charts/gateways/istio-ingress/Chart.yaml create mode 100644 istio-1.5.0/install/kubernetes/operator/charts/gateways/istio-ingress/NOTES.txt create mode 100644 istio-1.5.0/install/kubernetes/operator/charts/gateways/istio-ingress/templates/_affinity.tpl create mode 100644 istio-1.5.0/install/kubernetes/operator/charts/gateways/istio-ingress/templates/addongateway.yaml create mode 100644 istio-1.5.0/install/kubernetes/operator/charts/gateways/istio-ingress/templates/autoscale.yaml create mode 100644 istio-1.5.0/install/kubernetes/operator/charts/gateways/istio-ingress/templates/certificate.yaml create mode 100644 istio-1.5.0/install/kubernetes/operator/charts/gateways/istio-ingress/templates/deployment.yaml create mode 100644 istio-1.5.0/install/kubernetes/operator/charts/gateways/istio-ingress/templates/gateway.yaml create mode 100644 istio-1.5.0/install/kubernetes/operator/charts/gateways/istio-ingress/templates/hosts.yaml create mode 100644 istio-1.5.0/install/kubernetes/operator/charts/gateways/istio-ingress/templates/meshexpansion.yaml create mode 100644 istio-1.5.0/install/kubernetes/operator/charts/gateways/istio-ingress/templates/poddisruptionbudget.yaml create mode 100644 istio-1.5.0/install/kubernetes/operator/charts/gateways/istio-ingress/templates/preconfigured.yaml create mode 100644 istio-1.5.0/install/kubernetes/operator/charts/gateways/istio-ingress/templates/role.yaml create mode 100644 istio-1.5.0/install/kubernetes/operator/charts/gateways/istio-ingress/templates/rolebindings.yaml create mode 100644 istio-1.5.0/install/kubernetes/operator/charts/gateways/istio-ingress/templates/service.yaml create mode 100644 istio-1.5.0/install/kubernetes/operator/charts/gateways/istio-ingress/templates/serviceaccount.yaml create mode 100644 istio-1.5.0/install/kubernetes/operator/charts/gateways/istio-ingress/templates/sidecar.yaml create mode 100644 istio-1.5.0/install/kubernetes/operator/charts/gateways/istio-ingress/values.yaml create mode 100644 istio-1.5.0/install/kubernetes/operator/charts/istio-cni/Chart.yaml create mode 100644 istio-1.5.0/install/kubernetes/operator/charts/istio-cni/templates/clusterrole.yaml create mode 100644 istio-1.5.0/install/kubernetes/operator/charts/istio-cni/templates/clusterrolebinding.yaml create mode 100644 istio-1.5.0/install/kubernetes/operator/charts/istio-cni/templates/configmap-cni.yaml create mode 100644 istio-1.5.0/install/kubernetes/operator/charts/istio-cni/templates/daemonset.yaml create mode 100644 istio-1.5.0/install/kubernetes/operator/charts/istio-cni/templates/serviceaccount.yaml create mode 100644 istio-1.5.0/install/kubernetes/operator/charts/istio-cni/values.yaml create mode 100644 istio-1.5.0/install/kubernetes/operator/charts/istio-control/istio-autoinject/Chart.yaml create mode 100644 istio-1.5.0/install/kubernetes/operator/charts/istio-control/istio-autoinject/NOTES.txt create mode 100644 istio-1.5.0/install/kubernetes/operator/charts/istio-control/istio-autoinject/files/injection-template.yaml create mode 100644 istio-1.5.0/install/kubernetes/operator/charts/istio-control/istio-autoinject/templates/_affinity.tpl create mode 100644 istio-1.5.0/install/kubernetes/operator/charts/istio-control/istio-autoinject/templates/_helpers.tpl create mode 100644 istio-1.5.0/install/kubernetes/operator/charts/istio-control/istio-autoinject/templates/clusterrole.yaml create mode 100644 istio-1.5.0/install/kubernetes/operator/charts/istio-control/istio-autoinject/templates/clusterrolebinding.yaml create mode 100644 istio-1.5.0/install/kubernetes/operator/charts/istio-control/istio-autoinject/templates/configmap.yaml create mode 100644 istio-1.5.0/install/kubernetes/operator/charts/istio-control/istio-autoinject/templates/deployment.yaml create mode 100644 istio-1.5.0/install/kubernetes/operator/charts/istio-control/istio-autoinject/templates/mutatingwebhook.yaml create mode 100644 istio-1.5.0/install/kubernetes/operator/charts/istio-control/istio-autoinject/templates/poddisruptionbudget.yaml create mode 100644 istio-1.5.0/install/kubernetes/operator/charts/istio-control/istio-autoinject/templates/service.yaml create mode 100644 istio-1.5.0/install/kubernetes/operator/charts/istio-control/istio-autoinject/templates/serviceaccount.yaml create mode 100644 istio-1.5.0/install/kubernetes/operator/charts/istio-control/istio-autoinject/templates/sidecar-injector-configmap.yaml create mode 100644 istio-1.5.0/install/kubernetes/operator/charts/istio-control/istio-autoinject/values.yaml create mode 100644 istio-1.5.0/install/kubernetes/operator/charts/istio-control/istio-config/Chart.yaml create mode 100644 istio-1.5.0/install/kubernetes/operator/charts/istio-control/istio-config/OWNERS create mode 100644 istio-1.5.0/install/kubernetes/operator/charts/istio-control/istio-config/README.md create mode 100644 istio-1.5.0/install/kubernetes/operator/charts/istio-control/istio-config/templates/_affinity.tpl create mode 100644 istio-1.5.0/install/kubernetes/operator/charts/istio-control/istio-config/templates/_helpers.tpl create mode 100644 istio-1.5.0/install/kubernetes/operator/charts/istio-control/istio-config/templates/clusterrole.yaml create mode 100644 istio-1.5.0/install/kubernetes/operator/charts/istio-control/istio-config/templates/clusterrolebinding.yaml create mode 100644 istio-1.5.0/install/kubernetes/operator/charts/istio-control/istio-config/templates/configmap-envoy.yaml create mode 100644 istio-1.5.0/install/kubernetes/operator/charts/istio-control/istio-config/templates/configmap-mesh.yaml create mode 100644 istio-1.5.0/install/kubernetes/operator/charts/istio-control/istio-config/templates/configmap.yaml create mode 100644 istio-1.5.0/install/kubernetes/operator/charts/istio-control/istio-config/templates/deployment.yaml create mode 100644 istio-1.5.0/install/kubernetes/operator/charts/istio-control/istio-config/templates/poddisruptionbudget.yaml create mode 100644 istio-1.5.0/install/kubernetes/operator/charts/istio-control/istio-config/templates/service.yaml create mode 100644 istio-1.5.0/install/kubernetes/operator/charts/istio-control/istio-config/templates/serviceaccount.yaml create mode 100644 istio-1.5.0/install/kubernetes/operator/charts/istio-control/istio-config/templates/validatingwebhookconfiguration.yaml create mode 100644 istio-1.5.0/install/kubernetes/operator/charts/istio-control/istio-config/templates/validatingwebhookconfiguration.yaml.tpl create mode 100644 istio-1.5.0/install/kubernetes/operator/charts/istio-control/istio-config/values.yaml create mode 100644 istio-1.5.0/install/kubernetes/operator/charts/istio-control/istio-discovery/Chart.yaml create mode 100644 istio-1.5.0/install/kubernetes/operator/charts/istio-control/istio-discovery/NOTES.txt create mode 100644 istio-1.5.0/install/kubernetes/operator/charts/istio-control/istio-discovery/files/injection-template.yaml create mode 100644 istio-1.5.0/install/kubernetes/operator/charts/istio-control/istio-discovery/templates/_affinity.tpl create mode 100644 istio-1.5.0/install/kubernetes/operator/charts/istio-control/istio-discovery/templates/_helpers.tpl create mode 100644 istio-1.5.0/install/kubernetes/operator/charts/istio-control/istio-discovery/templates/autoscale.yaml create mode 100644 istio-1.5.0/install/kubernetes/operator/charts/istio-control/istio-discovery/templates/clusterrole-galley-disable-webhook.yaml create mode 100644 istio-1.5.0/install/kubernetes/operator/charts/istio-control/istio-discovery/templates/clusterrole.yaml create mode 100644 istio-1.5.0/install/kubernetes/operator/charts/istio-control/istio-discovery/templates/clusterrolebinding.yaml create mode 100644 istio-1.5.0/install/kubernetes/operator/charts/istio-control/istio-discovery/templates/configmap-envoy.yaml create mode 100644 istio-1.5.0/install/kubernetes/operator/charts/istio-control/istio-discovery/templates/configmap-jwks.yaml create mode 100644 istio-1.5.0/install/kubernetes/operator/charts/istio-control/istio-discovery/templates/configmap.yaml create mode 100644 istio-1.5.0/install/kubernetes/operator/charts/istio-control/istio-discovery/templates/deployment.yaml create mode 100644 istio-1.5.0/install/kubernetes/operator/charts/istio-control/istio-discovery/templates/enable-mesh-mtls.yaml create mode 100644 istio-1.5.0/install/kubernetes/operator/charts/istio-control/istio-discovery/templates/istiod-injector-configmap.yaml create mode 100644 istio-1.5.0/install/kubernetes/operator/charts/istio-control/istio-discovery/templates/mutatingwebhook.yaml create mode 100644 istio-1.5.0/install/kubernetes/operator/charts/istio-control/istio-discovery/templates/poddisruptionbudget.yaml create mode 100644 istio-1.5.0/install/kubernetes/operator/charts/istio-control/istio-discovery/templates/service.yaml create mode 100644 istio-1.5.0/install/kubernetes/operator/charts/istio-control/istio-discovery/templates/serviceaccount.yaml create mode 100644 istio-1.5.0/install/kubernetes/operator/charts/istio-control/istio-discovery/templates/telemetryv2_1.4.yaml create mode 100644 istio-1.5.0/install/kubernetes/operator/charts/istio-control/istio-discovery/templates/telemetryv2_1.5.yaml create mode 100644 istio-1.5.0/install/kubernetes/operator/charts/istio-control/istio-discovery/templates/validatingwebhookconfiguration.yaml create mode 100644 istio-1.5.0/install/kubernetes/operator/charts/istio-control/istio-discovery/values.yaml create mode 100644 istio-1.5.0/install/kubernetes/operator/charts/istio-policy/Chart.yaml create mode 100644 istio-1.5.0/install/kubernetes/operator/charts/istio-policy/templates/_affinity.tpl create mode 100644 istio-1.5.0/install/kubernetes/operator/charts/istio-policy/templates/_helpers.tpl create mode 100644 istio-1.5.0/install/kubernetes/operator/charts/istio-policy/templates/autoscale.yaml create mode 100644 istio-1.5.0/install/kubernetes/operator/charts/istio-policy/templates/clusterrole.yaml create mode 100644 istio-1.5.0/install/kubernetes/operator/charts/istio-policy/templates/clusterrolebinding.yaml create mode 100644 istio-1.5.0/install/kubernetes/operator/charts/istio-policy/templates/config.yaml create mode 100644 istio-1.5.0/install/kubernetes/operator/charts/istio-policy/templates/deployment.yaml create mode 100644 istio-1.5.0/install/kubernetes/operator/charts/istio-policy/templates/poddisruptionbudget.yaml create mode 100644 istio-1.5.0/install/kubernetes/operator/charts/istio-policy/templates/service.yaml create mode 100644 istio-1.5.0/install/kubernetes/operator/charts/istio-policy/templates/serviceaccount.yaml create mode 100644 istio-1.5.0/install/kubernetes/operator/charts/istio-policy/values.yaml create mode 100644 istio-1.5.0/install/kubernetes/operator/charts/istio-telemetry/grafana/Chart.yaml create mode 100644 istio-1.5.0/install/kubernetes/operator/charts/istio-telemetry/grafana/dashboards/citadel-dashboard.json create mode 100644 istio-1.5.0/install/kubernetes/operator/charts/istio-telemetry/grafana/dashboards/galley-dashboard.json create mode 100644 istio-1.5.0/install/kubernetes/operator/charts/istio-telemetry/grafana/dashboards/istio-mesh-dashboard.json create mode 100644 istio-1.5.0/install/kubernetes/operator/charts/istio-telemetry/grafana/dashboards/istio-performance-dashboard.json create mode 100644 istio-1.5.0/install/kubernetes/operator/charts/istio-telemetry/grafana/dashboards/istio-service-dashboard.json create mode 100644 istio-1.5.0/install/kubernetes/operator/charts/istio-telemetry/grafana/dashboards/istio-workload-dashboard.json create mode 100644 istio-1.5.0/install/kubernetes/operator/charts/istio-telemetry/grafana/dashboards/mixer-dashboard.json create mode 100644 istio-1.5.0/install/kubernetes/operator/charts/istio-telemetry/grafana/dashboards/pilot-dashboard.json create mode 100755 istio-1.5.0/install/kubernetes/operator/charts/istio-telemetry/grafana/fix_datasources.sh create mode 100644 istio-1.5.0/install/kubernetes/operator/charts/istio-telemetry/grafana/templates/_affinity.tpl create mode 100644 istio-1.5.0/install/kubernetes/operator/charts/istio-telemetry/grafana/templates/configmap-dashboards.yaml create mode 100644 istio-1.5.0/install/kubernetes/operator/charts/istio-telemetry/grafana/templates/configmap.yaml create mode 100644 istio-1.5.0/install/kubernetes/operator/charts/istio-telemetry/grafana/templates/deployment.yaml create mode 100644 istio-1.5.0/install/kubernetes/operator/charts/istio-telemetry/grafana/templates/grafana-policy.yaml create mode 100644 istio-1.5.0/install/kubernetes/operator/charts/istio-telemetry/grafana/templates/pvc.yaml create mode 100644 istio-1.5.0/install/kubernetes/operator/charts/istio-telemetry/grafana/templates/service.yaml create mode 100644 istio-1.5.0/install/kubernetes/operator/charts/istio-telemetry/grafana/templates/tests/test-grafana-connection.yaml create mode 100644 istio-1.5.0/install/kubernetes/operator/charts/istio-telemetry/grafana/values.yaml create mode 100644 istio-1.5.0/install/kubernetes/operator/charts/istio-telemetry/kiali/Chart.yaml create mode 100644 istio-1.5.0/install/kubernetes/operator/charts/istio-telemetry/kiali/templates/_affinity.tpl create mode 100644 istio-1.5.0/install/kubernetes/operator/charts/istio-telemetry/kiali/templates/clusterrole.yaml create mode 100644 istio-1.5.0/install/kubernetes/operator/charts/istio-telemetry/kiali/templates/clusterrolebinding.yaml create mode 100644 istio-1.5.0/install/kubernetes/operator/charts/istio-telemetry/kiali/templates/configmap.yaml create mode 100644 istio-1.5.0/install/kubernetes/operator/charts/istio-telemetry/kiali/templates/demosecret.yaml create mode 100644 istio-1.5.0/install/kubernetes/operator/charts/istio-telemetry/kiali/templates/deployment.yaml create mode 100644 istio-1.5.0/install/kubernetes/operator/charts/istio-telemetry/kiali/templates/service.yaml create mode 100644 istio-1.5.0/install/kubernetes/operator/charts/istio-telemetry/kiali/templates/serviceaccount.yaml create mode 100644 istio-1.5.0/install/kubernetes/operator/charts/istio-telemetry/kiali/values.yaml create mode 100644 istio-1.5.0/install/kubernetes/operator/charts/istio-telemetry/mixer-telemetry/Chart.yaml create mode 100644 istio-1.5.0/install/kubernetes/operator/charts/istio-telemetry/mixer-telemetry/templates/_affinity.tpl create mode 100644 istio-1.5.0/install/kubernetes/operator/charts/istio-telemetry/mixer-telemetry/templates/autoscale.yaml create mode 100644 istio-1.5.0/install/kubernetes/operator/charts/istio-telemetry/mixer-telemetry/templates/clusterrole.yaml create mode 100644 istio-1.5.0/install/kubernetes/operator/charts/istio-telemetry/mixer-telemetry/templates/clusterrolebinding.yaml create mode 100644 istio-1.5.0/install/kubernetes/operator/charts/istio-telemetry/mixer-telemetry/templates/config.yaml create mode 100644 istio-1.5.0/install/kubernetes/operator/charts/istio-telemetry/mixer-telemetry/templates/configmap-envoy.yaml create mode 100644 istio-1.5.0/install/kubernetes/operator/charts/istio-telemetry/mixer-telemetry/templates/deployment.yaml create mode 100644 istio-1.5.0/install/kubernetes/operator/charts/istio-telemetry/mixer-telemetry/templates/poddisruptionbudget.yaml create mode 100644 istio-1.5.0/install/kubernetes/operator/charts/istio-telemetry/mixer-telemetry/templates/service.yaml create mode 100644 istio-1.5.0/install/kubernetes/operator/charts/istio-telemetry/mixer-telemetry/templates/serviceaccount.yaml create mode 100644 istio-1.5.0/install/kubernetes/operator/charts/istio-telemetry/mixer-telemetry/templates/stackdriver.yaml create mode 100644 istio-1.5.0/install/kubernetes/operator/charts/istio-telemetry/mixer-telemetry/values.yaml create mode 100644 istio-1.5.0/install/kubernetes/operator/charts/istio-telemetry/prometheus-operator/Chart.yaml create mode 100644 istio-1.5.0/install/kubernetes/operator/charts/istio-telemetry/prometheus-operator/templates/_affinity.tpl create mode 100644 istio-1.5.0/install/kubernetes/operator/charts/istio-telemetry/prometheus-operator/templates/prometheus.yaml create mode 100644 istio-1.5.0/install/kubernetes/operator/charts/istio-telemetry/prometheus-operator/templates/servicemonitors.yaml create mode 100644 istio-1.5.0/install/kubernetes/operator/charts/istio-telemetry/prometheus-operator/values.yaml create mode 100644 istio-1.5.0/install/kubernetes/operator/charts/istio-telemetry/prometheus/Chart.yaml create mode 100644 istio-1.5.0/install/kubernetes/operator/charts/istio-telemetry/prometheus/templates/_affinity.tpl create mode 100644 istio-1.5.0/install/kubernetes/operator/charts/istio-telemetry/prometheus/templates/clusterrole.yaml create mode 100644 istio-1.5.0/install/kubernetes/operator/charts/istio-telemetry/prometheus/templates/clusterrolebindings.yaml create mode 100644 istio-1.5.0/install/kubernetes/operator/charts/istio-telemetry/prometheus/templates/configmap.yaml create mode 100644 istio-1.5.0/install/kubernetes/operator/charts/istio-telemetry/prometheus/templates/deployment.yaml create mode 100644 istio-1.5.0/install/kubernetes/operator/charts/istio-telemetry/prometheus/templates/ingress.yaml create mode 100644 istio-1.5.0/install/kubernetes/operator/charts/istio-telemetry/prometheus/templates/service.yaml create mode 100644 istio-1.5.0/install/kubernetes/operator/charts/istio-telemetry/prometheus/templates/serviceaccount.yaml create mode 100644 istio-1.5.0/install/kubernetes/operator/charts/istio-telemetry/prometheus/templates/tests/test-prometheus-connection.yaml create mode 100644 istio-1.5.0/install/kubernetes/operator/charts/istio-telemetry/prometheus/values.yaml create mode 100644 istio-1.5.0/install/kubernetes/operator/charts/istio-telemetry/tracing/Chart.yaml create mode 100644 istio-1.5.0/install/kubernetes/operator/charts/istio-telemetry/tracing/templates/_affinity.tpl create mode 100644 istio-1.5.0/install/kubernetes/operator/charts/istio-telemetry/tracing/templates/deployment-jaeger.yaml create mode 100644 istio-1.5.0/install/kubernetes/operator/charts/istio-telemetry/tracing/templates/deployment-opencensus.yaml create mode 100644 istio-1.5.0/install/kubernetes/operator/charts/istio-telemetry/tracing/templates/deployment-zipkin.yaml create mode 100644 istio-1.5.0/install/kubernetes/operator/charts/istio-telemetry/tracing/templates/pvc.yaml create mode 100644 istio-1.5.0/install/kubernetes/operator/charts/istio-telemetry/tracing/templates/service-jaeger.yaml create mode 100644 istio-1.5.0/install/kubernetes/operator/charts/istio-telemetry/tracing/templates/service.yaml create mode 100644 istio-1.5.0/install/kubernetes/operator/charts/istio-telemetry/tracing/values.yaml create mode 100644 istio-1.5.0/install/kubernetes/operator/charts/istiocoredns/Chart.yaml create mode 100644 istio-1.5.0/install/kubernetes/operator/charts/istiocoredns/templates/_affinity.tpl create mode 100644 istio-1.5.0/install/kubernetes/operator/charts/istiocoredns/templates/clusterrole.yaml create mode 100644 istio-1.5.0/install/kubernetes/operator/charts/istiocoredns/templates/clusterrolebinding.yaml create mode 100644 istio-1.5.0/install/kubernetes/operator/charts/istiocoredns/templates/configmap.yaml create mode 100644 istio-1.5.0/install/kubernetes/operator/charts/istiocoredns/templates/deployment.yaml create mode 100644 istio-1.5.0/install/kubernetes/operator/charts/istiocoredns/templates/service.yaml create mode 100644 istio-1.5.0/install/kubernetes/operator/charts/istiocoredns/templates/serviceaccount.yaml create mode 100644 istio-1.5.0/install/kubernetes/operator/charts/istiocoredns/values.yaml create mode 100644 istio-1.5.0/install/kubernetes/operator/charts/security/citadel/Chart.yaml create mode 100644 istio-1.5.0/install/kubernetes/operator/charts/security/citadel/templates/NOTES.txt create mode 100644 istio-1.5.0/install/kubernetes/operator/charts/security/citadel/templates/_affinity.tpl create mode 100644 istio-1.5.0/install/kubernetes/operator/charts/security/citadel/templates/_helpers.tpl create mode 100644 istio-1.5.0/install/kubernetes/operator/charts/security/citadel/templates/clusterrole.yaml create mode 100644 istio-1.5.0/install/kubernetes/operator/charts/security/citadel/templates/clusterrolebinding.yaml create mode 100644 istio-1.5.0/install/kubernetes/operator/charts/security/citadel/templates/deployment.yaml create mode 100644 istio-1.5.0/install/kubernetes/operator/charts/security/citadel/templates/poddisruptionbudget.yaml create mode 100644 istio-1.5.0/install/kubernetes/operator/charts/security/citadel/templates/service.yaml create mode 100644 istio-1.5.0/install/kubernetes/operator/charts/security/citadel/templates/serviceaccount.yaml create mode 100644 istio-1.5.0/install/kubernetes/operator/charts/security/citadel/values.yaml create mode 100644 istio-1.5.0/install/kubernetes/operator/charts/security/nodeagent/Chart.yaml create mode 100644 istio-1.5.0/install/kubernetes/operator/charts/security/nodeagent/templates/_affinity.tpl create mode 100644 istio-1.5.0/install/kubernetes/operator/charts/security/nodeagent/templates/clusterrole.yaml create mode 100644 istio-1.5.0/install/kubernetes/operator/charts/security/nodeagent/templates/clusterrolebinding.yaml create mode 100644 istio-1.5.0/install/kubernetes/operator/charts/security/nodeagent/templates/daemonset.yaml create mode 100644 istio-1.5.0/install/kubernetes/operator/charts/security/nodeagent/templates/serviceaccount.yaml create mode 100644 istio-1.5.0/install/kubernetes/operator/charts/security/nodeagent/values.yaml create mode 100644 istio-1.5.0/install/kubernetes/operator/deploy/clusterrole.yaml create mode 100644 istio-1.5.0/install/kubernetes/operator/deploy/clusterrole_binding.yaml create mode 100644 istio-1.5.0/install/kubernetes/operator/deploy/crds/istio_v1alpha1_istiooperator_cr.yaml create mode 100644 istio-1.5.0/install/kubernetes/operator/deploy/crds/istio_v1alpha1_istiooperator_crd.yaml create mode 100644 istio-1.5.0/install/kubernetes/operator/deploy/kustomization.yaml create mode 100644 istio-1.5.0/install/kubernetes/operator/deploy/namespace.yaml create mode 100644 istio-1.5.0/install/kubernetes/operator/deploy/operator.yaml create mode 100644 istio-1.5.0/install/kubernetes/operator/deploy/service.yaml create mode 100644 istio-1.5.0/install/kubernetes/operator/deploy/service_account.yaml create mode 100644 istio-1.5.0/install/kubernetes/operator/examples/customresource/istio_v1alpha1_istiooperator_cr.yaml create mode 100644 istio-1.5.0/install/kubernetes/operator/examples/googleca/values-istio-google-ca.yaml create mode 100644 istio-1.5.0/install/kubernetes/operator/examples/multicluster/values-istio-multicluster-gateways.yaml create mode 100644 istio-1.5.0/install/kubernetes/operator/examples/multicluster/values-istio-multicluster-primary.yaml create mode 100644 istio-1.5.0/install/kubernetes/operator/examples/user-gateway/ingress-gateway-only.yaml create mode 100644 istio-1.5.0/install/kubernetes/operator/examples/vm/values-istio-meshexpansion-gateways.yaml create mode 100644 istio-1.5.0/install/kubernetes/operator/examples/vm/values-istio-meshexpansion.yaml create mode 100644 istio-1.5.0/install/kubernetes/operator/profiles/default.yaml create mode 100644 istio-1.5.0/install/kubernetes/operator/profiles/demo.yaml create mode 100644 istio-1.5.0/install/kubernetes/operator/profiles/empty.yaml create mode 100644 istio-1.5.0/install/kubernetes/operator/profiles/minimal.yaml create mode 100644 istio-1.5.0/install/kubernetes/operator/profiles/remote.yaml create mode 100644 istio-1.5.0/install/kubernetes/operator/profiles/separate.yaml create mode 100644 istio-1.5.0/install/kubernetes/operator/versions.yaml create mode 100644 istio-1.5.0/manifest.yaml create mode 100644 istio-1.5.0/path.txt create mode 100644 istio-1.5.0/samples/README.md create mode 100644 istio-1.5.0/samples/bookinfo/README.md create mode 100644 istio-1.5.0/samples/bookinfo/networking/bookinfo-gateway.yaml create mode 100644 istio-1.5.0/samples/bookinfo/networking/certmanager-gateway.yaml create mode 100644 istio-1.5.0/samples/bookinfo/networking/destination-rule-all-mtls.yaml create mode 100644 istio-1.5.0/samples/bookinfo/networking/destination-rule-all.yaml create mode 100644 istio-1.5.0/samples/bookinfo/networking/destination-rule-reviews.yaml create mode 100644 istio-1.5.0/samples/bookinfo/networking/egress-rule-google-apis.yaml create mode 100644 istio-1.5.0/samples/bookinfo/networking/fault-injection-details-v1.yaml create mode 100644 istio-1.5.0/samples/bookinfo/networking/virtual-service-all-v1.yaml create mode 100644 istio-1.5.0/samples/bookinfo/networking/virtual-service-details-v2.yaml create mode 100644 istio-1.5.0/samples/bookinfo/networking/virtual-service-ratings-db.yaml create mode 100644 istio-1.5.0/samples/bookinfo/networking/virtual-service-ratings-mysql-vm.yaml create mode 100644 istio-1.5.0/samples/bookinfo/networking/virtual-service-ratings-mysql.yaml create mode 100644 istio-1.5.0/samples/bookinfo/networking/virtual-service-ratings-test-abort.yaml create mode 100644 istio-1.5.0/samples/bookinfo/networking/virtual-service-ratings-test-delay.yaml create mode 100644 istio-1.5.0/samples/bookinfo/networking/virtual-service-reviews-50-v3.yaml create mode 100644 istio-1.5.0/samples/bookinfo/networking/virtual-service-reviews-80-20.yaml create mode 100644 istio-1.5.0/samples/bookinfo/networking/virtual-service-reviews-90-10.yaml create mode 100644 istio-1.5.0/samples/bookinfo/networking/virtual-service-reviews-jason-v2-v3.yaml create mode 100644 istio-1.5.0/samples/bookinfo/networking/virtual-service-reviews-test-v2.yaml create mode 100644 istio-1.5.0/samples/bookinfo/networking/virtual-service-reviews-v2-v3.yaml create mode 100644 istio-1.5.0/samples/bookinfo/networking/virtual-service-reviews-v3.yaml create mode 100644 istio-1.5.0/samples/bookinfo/platform/consul/README.md create mode 100644 istio-1.5.0/samples/bookinfo/platform/consul/bookinfo.yaml create mode 100755 istio-1.5.0/samples/bookinfo/platform/consul/cleanup.sh create mode 100644 istio-1.5.0/samples/bookinfo/platform/consul/destination-rule-all.yaml create mode 100644 istio-1.5.0/samples/bookinfo/platform/consul/virtual-service-all-v1.yaml create mode 100644 istio-1.5.0/samples/bookinfo/platform/consul/virtual-service-ratings-test-abort.yaml create mode 100644 istio-1.5.0/samples/bookinfo/platform/consul/virtual-service-ratings-test-delay.yaml create mode 100644 istio-1.5.0/samples/bookinfo/platform/consul/virtual-service-reviews-50-v3.yaml create mode 100644 istio-1.5.0/samples/bookinfo/platform/consul/virtual-service-reviews-test-v2.yaml create mode 100644 istio-1.5.0/samples/bookinfo/platform/consul/virtual-service-reviews-v2-v3.yaml create mode 100644 istio-1.5.0/samples/bookinfo/platform/consul/virtual-service-reviews-v3.yaml create mode 100644 istio-1.5.0/samples/bookinfo/platform/kube/README.md create mode 100644 istio-1.5.0/samples/bookinfo/platform/kube/bookinfo-certificate.yaml create mode 100644 istio-1.5.0/samples/bookinfo/platform/kube/bookinfo-db.yaml create mode 100644 istio-1.5.0/samples/bookinfo/platform/kube/bookinfo-details-v2.yaml create mode 100644 istio-1.5.0/samples/bookinfo/platform/kube/bookinfo-details.yaml create mode 100644 istio-1.5.0/samples/bookinfo/platform/kube/bookinfo-ingress.yaml create mode 100644 istio-1.5.0/samples/bookinfo/platform/kube/bookinfo-mysql.yaml create mode 100644 istio-1.5.0/samples/bookinfo/platform/kube/bookinfo-ratings-discovery.yaml create mode 100644 istio-1.5.0/samples/bookinfo/platform/kube/bookinfo-ratings-v2-mysql-vm.yaml create mode 100644 istio-1.5.0/samples/bookinfo/platform/kube/bookinfo-ratings-v2-mysql.yaml create mode 100644 istio-1.5.0/samples/bookinfo/platform/kube/bookinfo-ratings-v2.yaml create mode 100644 istio-1.5.0/samples/bookinfo/platform/kube/bookinfo-ratings.yaml create mode 100644 istio-1.5.0/samples/bookinfo/platform/kube/bookinfo-reviews-v2.yaml create mode 100644 istio-1.5.0/samples/bookinfo/platform/kube/bookinfo.yaml create mode 100755 istio-1.5.0/samples/bookinfo/platform/kube/cleanup.sh create mode 100644 istio-1.5.0/samples/bookinfo/platform/kube/productpage-nodeport.yaml create mode 100644 istio-1.5.0/samples/bookinfo/platform/kube/rbac/details-reviews-policy-permissive.yaml create mode 100644 istio-1.5.0/samples/bookinfo/platform/kube/rbac/details-reviews-policy.yaml create mode 100644 istio-1.5.0/samples/bookinfo/platform/kube/rbac/mongodb-policy.yaml create mode 100644 istio-1.5.0/samples/bookinfo/platform/kube/rbac/namespace-policy.yaml create mode 100644 istio-1.5.0/samples/bookinfo/platform/kube/rbac/productpage-policy.yaml create mode 100644 istio-1.5.0/samples/bookinfo/platform/kube/rbac/ratings-policy.yaml create mode 100644 istio-1.5.0/samples/bookinfo/platform/kube/rbac/rbac-config-ON.yaml create mode 100644 istio-1.5.0/samples/bookinfo/platform/kube/rbac/rbac-config-on-mongodb.yaml create mode 100644 istio-1.5.0/samples/bookinfo/platform/kube/rbac/rbac-config-on-permissive.yaml create mode 100644 istio-1.5.0/samples/bookinfo/platform/kube/rbac/rbac-permissive-telemetry.yaml create mode 100644 istio-1.5.0/samples/bookinfo/policy/mixer-rule-deny-ip-crd.yaml create mode 100644 istio-1.5.0/samples/bookinfo/policy/mixer-rule-deny-ip.yaml create mode 100644 istio-1.5.0/samples/bookinfo/policy/mixer-rule-deny-label-crd.yaml create mode 100644 istio-1.5.0/samples/bookinfo/policy/mixer-rule-deny-label.yaml create mode 100644 istio-1.5.0/samples/bookinfo/policy/mixer-rule-deny-serviceaccount.yaml create mode 100644 istio-1.5.0/samples/bookinfo/policy/mixer-rule-deny-whitelist-crd.yaml create mode 100644 istio-1.5.0/samples/bookinfo/policy/mixer-rule-deny-whitelist.yaml create mode 100644 istio-1.5.0/samples/bookinfo/policy/mixer-rule-ingress-denial.yaml create mode 100644 istio-1.5.0/samples/bookinfo/policy/mixer-rule-kubernetesenv-telemetry.yaml create mode 100644 istio-1.5.0/samples/bookinfo/policy/mixer-rule-productpage-ratelimit-crd.yaml create mode 100644 istio-1.5.0/samples/bookinfo/policy/mixer-rule-productpage-ratelimit.yaml create mode 100644 istio-1.5.0/samples/bookinfo/policy/mixer-rule-productpage-redis-quota-fixed-window.yaml create mode 100644 istio-1.5.0/samples/bookinfo/policy/mixer-rule-productpage-redis-quota-rolling-window.yaml create mode 100644 istio-1.5.0/samples/bookinfo/policy/mixer-rule-ratings-denial.yaml create mode 100644 istio-1.5.0/samples/bookinfo/policy/mixer-rule-ratings-ratelimit.yaml create mode 100644 istio-1.5.0/samples/bookinfo/policy/mixer-rule-ratings-redis-quota-fixed-window.yaml create mode 100644 istio-1.5.0/samples/bookinfo/policy/mixer-rule-ratings-redis-quota-rolling-window.yaml create mode 100644 istio-1.5.0/samples/bookinfo/policy/prometheus-adapter-deployment.yaml create mode 100644 istio-1.5.0/samples/bookinfo/policy/prometheus-oop-rule.yaml create mode 100644 istio-1.5.0/samples/bookinfo/src/mongodb/ratings_data.json create mode 100644 istio-1.5.0/samples/bookinfo/src/productpage/requirements.txt create mode 100644 istio-1.5.0/samples/bookinfo/src/productpage/test-requirements.txt create mode 100644 istio-1.5.0/samples/bookinfo/src/ratings/package.json create mode 100644 istio-1.5.0/samples/bookinfo/swagger.yaml create mode 100644 istio-1.5.0/samples/bookinfo/telemetry/fluentd-istio-crd.yaml create mode 100644 istio-1.5.0/samples/bookinfo/telemetry/fluentd-istio.yaml create mode 100644 istio-1.5.0/samples/bookinfo/telemetry/log-entry-crd.yaml create mode 100644 istio-1.5.0/samples/bookinfo/telemetry/log-entry.yaml create mode 100644 istio-1.5.0/samples/bookinfo/telemetry/metrics-crd.yaml create mode 100644 istio-1.5.0/samples/bookinfo/telemetry/metrics.yaml create mode 100644 istio-1.5.0/samples/bookinfo/telemetry/tcp-metrics-crd.yaml create mode 100644 istio-1.5.0/samples/bookinfo/telemetry/tcp-metrics.yaml create mode 100644 istio-1.5.0/samples/certs/README.md create mode 100644 istio-1.5.0/samples/certs/ca-cert.pem create mode 100644 istio-1.5.0/samples/certs/ca-key.pem create mode 100644 istio-1.5.0/samples/certs/cert-chain.pem create mode 100644 istio-1.5.0/samples/certs/root-cert.pem create mode 100644 istio-1.5.0/samples/custom-bootstrap/README.md create mode 100644 istio-1.5.0/samples/custom-bootstrap/custom-bootstrap.yaml create mode 100644 istio-1.5.0/samples/custom-bootstrap/example-app.yaml create mode 100644 istio-1.5.0/samples/external/README.md create mode 100644 istio-1.5.0/samples/external/aptget.yaml create mode 100644 istio-1.5.0/samples/external/github.yaml create mode 100644 istio-1.5.0/samples/external/pypi.yaml create mode 100644 istio-1.5.0/samples/fortio/stackdriver.yaml create mode 100644 istio-1.5.0/samples/health-check/liveness-command.yaml create mode 100644 istio-1.5.0/samples/health-check/liveness-http-same-port.yaml create mode 100644 istio-1.5.0/samples/health-check/liveness-http.yaml create mode 100644 istio-1.5.0/samples/helloworld/README.md create mode 100644 istio-1.5.0/samples/helloworld/helloworld-gateway.yaml create mode 100644 istio-1.5.0/samples/helloworld/helloworld.yaml create mode 100644 istio-1.5.0/samples/helloworld/src/requirements.txt create mode 100644 istio-1.5.0/samples/httpbin/README.md create mode 100644 istio-1.5.0/samples/httpbin/httpbin-gateway.yaml create mode 100644 istio-1.5.0/samples/httpbin/httpbin-nodeport.yaml create mode 100644 istio-1.5.0/samples/httpbin/httpbin-vault.yaml create mode 100644 istio-1.5.0/samples/httpbin/httpbin.yaml create mode 100644 istio-1.5.0/samples/httpbin/policy/keyval-template.yaml create mode 100644 istio-1.5.0/samples/httpbin/policy/keyval.yaml create mode 100644 istio-1.5.0/samples/httpbin/sample-client/fortio-deploy.yaml create mode 100644 istio-1.5.0/samples/https/default.conf create mode 100644 istio-1.5.0/samples/https/nginx-app.yaml create mode 100644 istio-1.5.0/samples/kubernetes-blog/bookinfo-ratings.yaml create mode 100644 istio-1.5.0/samples/kubernetes-blog/bookinfo-reviews-v2.yaml create mode 100644 istio-1.5.0/samples/kubernetes-blog/bookinfo-v1.yaml create mode 100644 istio-1.5.0/samples/multicluster/README.md create mode 100644 istio-1.5.0/samples/operator/default-install.yaml create mode 100644 istio-1.5.0/samples/operator/pilot-advanced-override.yaml create mode 100644 istio-1.5.0/samples/operator/pilot-k8s.yaml create mode 100644 istio-1.5.0/samples/operator/sds-policy-off.yaml create mode 100644 istio-1.5.0/samples/operator/sds.yaml create mode 100644 istio-1.5.0/samples/operator/trafficManagement-namespace.yaml create mode 100644 istio-1.5.0/samples/operator/values-global.yaml create mode 100644 istio-1.5.0/samples/operator/values-pilot.yaml create mode 100644 istio-1.5.0/samples/rawvm/README.md create mode 100644 istio-1.5.0/samples/security/psp/all-pods-psp.yaml create mode 100644 istio-1.5.0/samples/security/psp/citadel-agent-psp.yaml create mode 100644 istio-1.5.0/samples/sleep/README.md create mode 100644 istio-1.5.0/samples/sleep/policy/sni-serviceaccount.yaml create mode 100644 istio-1.5.0/samples/sleep/policy/sni-wikipedia.yaml create mode 100644 istio-1.5.0/samples/sleep/sleep-vault.yaml create mode 100644 istio-1.5.0/samples/sleep/sleep.yaml create mode 100644 istio-1.5.0/samples/sleep/telemetry/sni-logging.yaml create mode 100644 istio-1.5.0/samples/tcp-echo/README.md create mode 100644 istio-1.5.0/samples/tcp-echo/tcp-echo-20-v2.yaml create mode 100644 istio-1.5.0/samples/tcp-echo/tcp-echo-all-v1.yaml create mode 100644 istio-1.5.0/samples/tcp-echo/tcp-echo-services.yaml create mode 100644 istio-1.5.0/samples/tcp-echo/tcp-echo.yaml create mode 100644 istio-1.5.0/samples/websockets/README.md create mode 100644 istio-1.5.0/samples/websockets/app.yaml create mode 100644 istio-1.5.0/samples/websockets/route.yaml create mode 100644 istio-1.5.0/tools/_istioctl create mode 100644 istio-1.5.0/tools/convert_RbacConfig_to_ClusterRbacConfig.sh create mode 100644 istio-1.5.0/tools/dump_kubernetes.sh create mode 100644 istio-1.5.0/tools/istioctl.bash create mode 100644 istio-manifests/istio-demo.yaml create mode 100644 istio-manifests/namespace.yaml create mode 100644 kubernetes-manifests-tracing/README.md create mode 100644 kubernetes-manifests-tracing/adservice.yaml create mode 100644 kubernetes-manifests-tracing/cartservice.yaml create mode 100644 kubernetes-manifests-tracing/checkoutservice.yaml create mode 100644 kubernetes-manifests-tracing/currencyservice.yaml create mode 100644 kubernetes-manifests-tracing/emailservice.yaml create mode 100644 kubernetes-manifests-tracing/frontend.yaml create mode 100644 kubernetes-manifests-tracing/loadgenerator.yaml create mode 100644 kubernetes-manifests-tracing/paymentservice.yaml create mode 100644 kubernetes-manifests-tracing/productcatalogservice.yaml create mode 100644 kubernetes-manifests-tracing/recommendationservice.yaml create mode 100644 kubernetes-manifests-tracing/redis.yaml create mode 100644 kubernetes-manifests-tracing/shippingservice.yaml diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..470c4a7 --- /dev/null +++ b/Makefile @@ -0,0 +1,139 @@ +SHELL := /bin/bash #--rcfile ~/.bash_profile + +# COLORS +GREEN := $(shell tput -Txterm setaf 2) +YELLOW := $(shell tput -Txterm setaf 3) +WHITE := $(shell tput -Txterm setaf 7) +RESET := $(shell tput -Txterm sgr0) +TARGET_MAX_CHAR_NUM=20 + +CLUSTER_NAME=o11y-ob +PROJECTID=tonyh-gke-o11y-anz-openbanking +ZONE=australia-southeast1-a +ISTIO_VERSION=1.5.0 + +a: help + +## Use Istio Version 1.5.0 +istio150: + PATH=`echo $PATH | sed -e 's/istio-1.3.5/istio-1.5.0/g'` + +## Use Istio Version 1.3.5 +istio135: + PATH=`echo $\PATH | sed -e 's/istio-1.5.0/istio-1.3.5/g'` + +## Create GKE Cluster with istio enabled +cluster.create.istio: + @gcloud container clusters create ${CLUSTER_NAME} --enable-autoupgrade \ + --enable-autoscaling --min-nodes=1 --max-nodes=10 --num-nodes=4 --zone=${ZONE} \ + --addons=Istio --istio-config=auth=MTLS_PERMISSIVE \ + --machine-type=n1-standard-2 + +## Enable Istio on exisiting cluster +cluster.enable.istio: + @gcloud beta container clusters update ${CLUSTER_NAME} \ + --update-addons=Istio=ENABLED \ + --zone=${ZONE} + +## Increase Cluster Size +cluster.resize: + @gcloud container clusters resize o11y-ob --node-pool default-pool --num-nodes 6 --zone australia-southeast1-a + + +## Create GKE Cluster +cluster.create: + @gcloud container clusters create ${CLUSTER_NAME} --enable-autoupgrade \ + --enable-autoscaling --min-nodes=1 --max-nodes=10 --num-nodes=4 --zone=${ZONE} \ + --machine-type=n1-standard-2 + +## Get Cluster Creds +get.creds: + @gcloud container clusters get-credentials ${CLUSTER_NAME} \ + --zone ${ZONE} \ + --project ${PROJECTID} + +## Create istio-system namespace +ns.create.istio-system: + @kubectl create -f istio-manifests/namespace.yaml + +## default ns istio enabled +ns.istio.enabled: + @kubectl label namespace default istio-injection=enabled --overwrite +## default ns istio disabled +ns.istio.disabled: + @kubectl label namespace default istio-injection=disabled --overwrite + +## Installs Istio CRDS +istio.init: + @helm template istio-${ISTIO_VERSION}/install/kubernetes/helm/istio-init --name istio-init --namespace istio-system | kubectl apply -f - + +istio.init.delete: + @helm template istio-${ISTIO_VERSION}/install/kubernetes/helm/istio-init --name istio-init --namespace istio-system | kubectl delete -f - + + +## Generate Istio Template +istio.template: + @helm template istio-${ISTIO_VERSION}/install/kubernetes/helm/istio --name istio --namespace istio-system \ + --values istio-${ISTIO_VERSION}/install/kubernetes/helm/istio/values-istio-demo.yaml > istio-manifests/istio-demo.yaml + +## Deploy Istio Config +istio.deploy: istio.template + @kubectl apply -f istio-manifests/istio-demo.yaml + +## Delete Istio Config +istio.delete: + @kubectl delete -f istio-manifests/istio-demo.yaml + +##################################################### + +## Scale Loadgenartor to 0 +loadgen.off: + @kubectl scale deployment loadgenerator --replicas 0 + +## Scale Loadgenartor to 1 +loadgen.on: + @kubectl scale deployment loadgenerator --replicas 1 + +## Skaffold GCB +skaffold.dev.gcp: + @skaffold dev --default-repo=asia.gcr.io/${PROJECTID} -p gcb --tail=false + +## Skaffold GCB Istio +skaffold.dev.gcp.istio: + @skaffold dev --default-repo=asia.gcr.io/${PROJECTID} -p gcb-istio --tail=false + +## Skaffold GCB +skaffold.run.gcp: + @skaffold run --default-repo=asia.gcr.io/${PROJECTID} -p gcb --tail=false + +## Skaffold GCB Istio +skaffold.run.gcp.istio: + @skaffold run --default-repo=asia.gcr.io/${PROJECTID} -p gcb-istio --tail=false + +## Skaffold GCB Tracing +skaffold.run.gcp.tracing: + @skaffold run --default-repo=asia.gcr.io/${PROJECTID} -p gcb-tracing --tail=false + +## Skaffold GCB Build +skaffold.build.gcp: + @skaffold run --default-repo=asia.gcr.io/${PROJECTID} -p gcb --tail=false + +## Delete the GKE Cluster +cluster.delete: + @gcloud container clusters delete ${CLUSTER_NAME} --zone ${ZONE} + +help: + @echo '' + @echo 'Usage:' + @echo ' $(YELLOW)make$(RESET) $(GREEN)$(RESET)' + @echo '' + @echo 'Targets:' + @awk '/^[a-zA-Z\-\.\_0-9]+:/ { \ + helpMessage = match(lastLine, /^## (.*)/); \ + if (helpMessage) { \ + helpCommand = substr($$1, 0, index($$1, ":")-1); \ + helpMessage = substr(lastLine, RSTART + 3, RLENGTH); \ + printf " ${YELLOW}%-$(TARGET_MAX_CHAR_NUM)s${RESET} ${GREEN}%s${RESET}\n", helpCommand, helpMessage; \ + } \ + } \ + { lastLine = $$0 }' $(MAKEFILE_LIST) \ No newline at end of file diff --git a/cloudbuild.yaml b/cloudbuild.yaml index 2d031ce..a4d3aa0 100644 --- a/cloudbuild.yaml +++ b/cloudbuild.yaml @@ -1,4 +1,4 @@ -# This configuration file is used to build and deploy the app into a +# This configuration file is used to build and deploy the app into a # GKE cluster using Google Cloud Build. # # PREREQUISITES: @@ -13,11 +13,11 @@ steps: - id: 'Deploy application to cluster' name: 'gcr.io/k8s-skaffold/skaffold:v0.20.0' entrypoint: 'bash' - args: + args: - '-c' - - > + - > gcloud container clusters get-credentials --zone=$_ZONE $_CLUSTER; - skaffold run -f=skaffold.yaml --default-repo=gcr.io/$PROJECT_ID; + skaffold run -f=skaffold.yaml --default-repo=asia.gcr.io/$PROJECT_ID; # Add more power, and more time, for heavy Skaffold build timeout: '3600s' diff --git a/istio-1.3.5/LICENSE b/istio-1.3.5/LICENSE new file mode 100644 index 0000000..139182e --- /dev/null +++ b/istio-1.3.5/LICENSE @@ -0,0 +1,202 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "{}" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright 2016-2019 Istio Authors + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/istio-1.3.5/README.md b/istio-1.3.5/README.md new file mode 100644 index 0000000..e80fd1d --- /dev/null +++ b/istio-1.3.5/README.md @@ -0,0 +1,110 @@ +[![Go Report Card](https://goreportcard.com/badge/github.com/istio/istio)](https://goreportcard.com/report/github.com/istio/istio) +[![GoDoc](https://godoc.org/istio.io/istio?status.svg)](https://godoc.org/istio.io/istio) +[![codecov.io](https://codecov.io/github/istio/istio/coverage.svg?branch=master)](https://codecov.io/github/istio/istio?branch=master) +[![GolangCI](https://golangci.com/badges/github.com/istio/istio.svg)](https://golangci.com/r/github.com/istio/istio) + +# Istio + +An open platform to connect, manage, and secure microservices. + +- For in-depth information about how to use Istio, visit [istio.io](https://istio.io) +- To ask questions and get assistance from our community, visit [discuss.istio.io](https://discuss.istio.io) +- To learn how to participate in our overall community, visit [our community page](https://istio.io/about/community) + +In this README: + +- [Introduction](#introduction) +- [Repositories](#repositories) +- [Issue management](#issue-management) + +In addition, here are some other documents you may wish to read: + +- [Istio Community](https://github.com/istio/community) - describes how to get involved and contribute to the Istio project +- [Istio Developer's Guide](https://github.com/istio/istio/wiki/Preparing-for-Development) - explains how to set up and use an Istio development environment +- [Project Conventions](https://github.com/istio/istio/wiki/Development-Conventions) - describes the conventions we use within the code base +- [Creating Fast and Lean Code](https://github.com/istio/istio/wiki/Writing-Fast-and-Lean-Code) - performance-oriented advice and guidelines for the code base + +You'll find many other useful documents on our [Wiki](https://github.com/istio/istio/wiki). + +## Introduction + +Istio is an open platform for providing a uniform way to integrate +microservices, manage traffic flow across microservices, enforce policies +and aggregate telemetry data. Istio's control plane provides an abstraction +layer over the underlying cluster management platform, such as Kubernetes. + +Istio is composed of these components: + +- **Envoy** - Sidecar proxies per microservice to handle ingress/egress traffic + between services in the cluster and from a service to external + services. The proxies form a _secure microservice mesh_ providing a rich + set of functions like discovery, rich layer-7 routing, circuit breakers, + policy enforcement and telemetry recording/reporting + functions. + + > Note: The service mesh is not an overlay network. It + > simplifies and enhances how microservices in an application talk to each + > other over the network provided by the underlying platform. + +- **Mixer** - Central component that is leveraged by the proxies and microservices + to enforce policies such as authorization, rate limits, quotas, authentication, request + tracing and telemetry collection. + +- **Pilot** - A component responsible for configuring the proxies at runtime. + +- **Citadel** - A centralized component responsible for certificate issuance and rotation. + +- **Citadel Agent** - A per-node component responsible for certificate issuance and rotation. + +- **Galley**- Central component for validating, ingesting, aggregating, transforming and distributing config within Istio. + +Istio currently supports Kubernetes and Consul-based environments. We plan support for additional platforms such as +Cloud Foundry, and Mesos in the near future. + +## Repositories + +The Istio project is divided across a few GitHub repositories. + +- [istio/istio](README.md). This is the main repository that you are +currently looking at. It hosts Istio's core components and also +the sample programs and the various documents that govern the Istio open source +project. It includes: + - [security](security/). This directory contains security related code, +including Citadel (acting as Certificate Authority), citadel agent, etc. + - [pilot](pilot/). This directory +contains platform-specific code to populate the +[abstract service model](https://istio.io/docs/concepts/traffic-management/overview.html), dynamically reconfigure the proxies +when the application topology changes, as well as translate +[routing rules](https://istio.io/docs/reference/config/istio.networking.v1alpha3/) into proxy specific configuration. + - [istioctl](istioctl/). This directory contains code for the +[_istioctl_](https://istio.io/docs/reference/commands/istioctl.html) command line utility. + - [mixer](mixer/). This directory +contains code to enforce various policies for traffic passing through the +proxies, and collect telemetry data from proxies and services. There +are plugins for interfacing with various cloud platforms, policy +management services, and monitoring services. + +- [istio/api](https://github.com/istio/api). This repository defines +component-level APIs and common configuration formats for the Istio platform. + +- [istio/proxy](https://github.com/istio/proxy). The Istio proxy contains +extensions to the [Envoy proxy](https://github.com/envoyproxy/envoy) (in the form of +Envoy filters), that allow the proxy to delegate policy enforcement +decisions to Mixer. + +## Issue management + +We use GitHub combined with ZenHub to track all of our bugs and feature requests. Each issue we track has a variety of metadata: + +- **Epic**. An epic represents a feature area for Istio as a whole. Epics are fairly broad in scope and are basically product-level things. +Each issue is ultimately part of an epic. + +- **Milestone**. Each issue is assigned a milestone. This is 0.1, 0.2, ..., or 'Nebulous Future'. The milestone indicates when we +think the issue should get addressed. + +- **Priority/Pipeline**. Each issue has a priority which is represented by the Pipeline field within GitHub. Priority can be one of +P0, P1, P2, or >P2. The priority indicates how important it is to address the issue within the milestone. P0 says that the +milestone cannot be considered achieved if the issue isn't resolved. + +We don't annotate issues with Releases; Milestones are used instead. We don't use GitHub projects at all, that +support is disabled for our organization. diff --git a/istio-1.3.5/install/README.md b/istio-1.3.5/install/README.md new file mode 100644 index 0000000..d75cce2 --- /dev/null +++ b/istio-1.3.5/install/README.md @@ -0,0 +1,32 @@ +# Istio installation + +This directory contains the default Istio installation configuration in several +different flavors. Also contained is the script for updating it. + +## updateVersion.sh + +The [updateVersion.sh](updateVersion.sh) script is used to update image versions in +[../istio.VERSION](../istio.VERSION) and the istio installation yaml files. + +### Options + +* `-p ,` new pilot image +* `-x ,` new mixer image +* `-c ,` new citadel image +* `-g ,` new galley image +* `-a ,` specifies same hub and tag for pilot, mixer, proxy, citadel and galley containers +* `-o ,` new proxy image +* `-n ` namespace in which to install Istio control plane components (defaults to istio-system) +* `-P` URL to download pilot debian packages +* `-d ` directory to store updated/generated files (optional, defaults to source code tree) + +Default values for the `-p`, `-x`, `-c`, `-o`, `-g` and `-a` options are as specified in `istio.VERSION` +(i.e., they are left unchanged). + +### Examples + +Update the pilot and istioctl: + +``` +./updateVersion.sh -p "docker.io/istio,2017-05-09-06.14.22" +``` diff --git a/istio-1.3.5/install/consul/README.md b/istio-1.3.5/install/consul/README.md new file mode 100644 index 0000000..c602bb0 --- /dev/null +++ b/istio-1.3.5/install/consul/README.md @@ -0,0 +1,6 @@ +# Install Istio with Consul in a simple Docker Compose setup + +Please follow the installation instructions on [istio.io](https://istio.io/docs/setup/consul/). + +The install file `istio.yaml` deploys Istio Pilot, Consul, Registrator, and +the Istio API server with etcd as Docker containers. diff --git a/istio-1.3.5/install/consul/consul_config/agent-loglevel.json b/istio-1.3.5/install/consul/consul_config/agent-loglevel.json new file mode 100644 index 0000000..c594477 --- /dev/null +++ b/istio-1.3.5/install/consul/consul_config/agent-loglevel.json @@ -0,0 +1,3 @@ +{ + "log_level": "INFO" +} \ No newline at end of file diff --git a/istio-1.3.5/install/consul/consul_config/agent.json b/istio-1.3.5/install/consul/consul_config/agent.json new file mode 100644 index 0000000..8048959 --- /dev/null +++ b/istio-1.3.5/install/consul/consul_config/agent.json @@ -0,0 +1,8 @@ +{ + "client_addr": "0.0.0.0", + "leave_on_terminate": true, + "dns_config": { + "allow_stale": true, + "max_stale": "1s" + } +} \ No newline at end of file diff --git a/istio-1.3.5/install/consul/consul_config/disable_update_check.json b/istio-1.3.5/install/consul/consul_config/disable_update_check.json new file mode 100644 index 0000000..f375d7a --- /dev/null +++ b/istio-1.3.5/install/consul/consul_config/disable_update_check.json @@ -0,0 +1,3 @@ +{ + "disable_update_check": true +} \ No newline at end of file diff --git a/istio-1.3.5/install/consul/consul_config/server.json b/istio-1.3.5/install/consul/consul_config/server.json new file mode 100644 index 0000000..3db174e --- /dev/null +++ b/istio-1.3.5/install/consul/consul_config/server.json @@ -0,0 +1,6 @@ +{ + "ui": true, + "dns_config": { + "allow_stale": false + } +} \ No newline at end of file diff --git a/istio-1.3.5/install/consul/istio.yaml b/istio-1.3.5/install/consul/istio.yaml new file mode 100644 index 0000000..a2e0427 --- /dev/null +++ b/istio-1.3.5/install/consul/istio.yaml @@ -0,0 +1,103 @@ +# GENERATED FILE. Use with Docker-Compose and consul +# TO UPDATE, modify files in install/consul/templates and run install/updateVersion.sh +version: '2' +services: + etcd: + image: quay.io/coreos/etcd:latest + networks: + istiomesh: + aliases: + - etcd + ports: + - "4001:4001" + - "2380:2380" + - "2379:2379" + environment: + - SERVICE_IGNORE=1 + command: ["/usr/local/bin/etcd", "-advertise-client-urls=http://0.0.0.0:2379", "-listen-client-urls=http://0.0.0.0:2379"] + + istio-apiserver: + image: gcr.io/google_containers/kube-apiserver-amd64:v1.7.3 + networks: + istiomesh: + ipv4_address: 172.28.0.13 + aliases: + - apiserver + ports: + - "8080:8080" + privileged: true + environment: + - SERVICE_IGNORE=1 + command: ["kube-apiserver", "--etcd-servers", "http://etcd:2379", "--service-cluster-ip-range", "10.99.0.0/16", "--insecure-port", "8080", "-v", "2", "--insecure-bind-address", "0.0.0.0"] + + consul: + image: consul:1.3.0 + networks: + istiomesh: + aliases: + - consul + ports: + - "8500:8500" + - "${DOCKER_GATEWAY}53:8600/udp" + - "8400:8400" + - "8502:8502" + environment: + - SERVICE_IGNORE=1 + - DNS_RESOLVES=consul + - DNS_PORT=8600 + - CONSUL_DATA_DIR=/consul/data + - CONSUL_CONFIG_DIR=/consul/config + entrypoint: + - "docker-entrypoint.sh" + command: ["agent", "-bootstrap", "-server", "-ui", + "-grpc-port", "8502" + ] + volumes: + - ./consul_config:/consul/config + + registrator: + image: gliderlabs/registrator:master + networks: + istiomesh: + volumes: + - /var/run/docker.sock:/tmp/docker.sock + command: ["-internal", "-retry-attempts=-1", "consul://consul:8500"] + + pilot: + image: docker.io/istio/pilot:1.3.5 + networks: + istiomesh: + aliases: + - istio-pilot + expose: + - "15007" + - "15010" + - "15012" + ports: + - "8081:15007" + command: ["discovery", + "--httpAddr", ":15007", + "--registries", "Consul", + "--consulserverURL", "http://consul:8500", + "--kubeconfig", "/etc/istio/config/kubeconfig", + "--secureGrpcAddr", "", + ] + volumes: + - ./kubeconfig:/etc/istio/config/kubeconfig + + zipkin: + image: docker.io/openzipkin/zipkin:2.7 + networks: + istiomesh: + aliases: + - zipkin + ports: + - "9411:9411" + +networks: + istiomesh: + ipam: + driver: default + config: + - subnet: 172.28.0.0/16 + gateway: 172.28.0.1 diff --git a/istio-1.3.5/install/consul/kubeconfig b/istio-1.3.5/install/consul/kubeconfig new file mode 100644 index 0000000..5dd31e7 --- /dev/null +++ b/istio-1.3.5/install/consul/kubeconfig @@ -0,0 +1,11 @@ +apiVersion: v1 +clusters: +- cluster: + server: http://istio-apiserver:8080 + name: istio +contexts: +- context: + cluster: istio + user: "" + name: istio +current-context: istio \ No newline at end of file diff --git a/istio-1.3.5/install/gcp/README.md b/istio-1.3.5/install/gcp/README.md new file mode 100644 index 0000000..ee4fb3d --- /dev/null +++ b/istio-1.3.5/install/gcp/README.md @@ -0,0 +1,4 @@ +# Google Cloud Platform Installation + +This directory contains contributed solutions for installing Istio that are +specific to Google Cloud Platform. diff --git a/istio-1.3.5/install/gcp/bootstrap/gcp_envoy_bootstrap.json b/istio-1.3.5/install/gcp/bootstrap/gcp_envoy_bootstrap.json new file mode 100644 index 0000000..8162537 --- /dev/null +++ b/istio-1.3.5/install/gcp/bootstrap/gcp_envoy_bootstrap.json @@ -0,0 +1,79 @@ +{ + "node": { + "id": "{{ .nodeID }}", + "cluster": "{{ .cluster }}", + "locality": { + {{ if .region }} + "region": "{{ .region }}", + {{ end }} + {{ if .zone }} + "zone": "{{ .zone }}", + {{ end }} + {{ if .sub_zone }} + "sub_zone": "{{ .sub_zone }}", + {{ end }} + }, + "metadata": {{ .meta_json_str }} + }, + "dynamic_resources": { + "lds_config": { + "ads": {} + }, + "cds_config": { + "ads": {} + }, + "ads_config": { + "api_type": "GRPC", + "grpc_services": [ + { + "google_grpc": { + "target_uri": "{{ .discovery_address }}", + "stat_prefix": "googlegrpcxds", + "channel_credentials": { + "ssl_credentials": { + "root_certs": { + "filename": "/etc/ssl/certs/ca-certificates.crt" + } + } + }, + "call_credentials": { + "google_compute_engine": {} + } + } + } + ] + } + }, + "cluster_manager": { + "load_stats_config": { + "api_type": "GRPC", + "grpc_services": [ + { + "google_grpc": { + "target_uri": "{{ .discovery_address }}", + "stat_prefix": "googlegrpcxds", + "channel_credentials": { + "ssl_credentials": { + "root_certs": { + "filename": "/etc/ssl/certs/ca-certificates.crt" + } + } + }, + "call_credentials": { + "google_compute_engine": {} + } + } + } + ] + } + }, + "admin": { + "access_log_path": "/dev/null", + "address": { + "socket_address": { + "address": "127.0.0.1", + "port_value": {{ .config.ProxyAdminPort }} + } + } + } +} diff --git a/istio-1.3.5/install/kubernetes/README.md b/istio-1.3.5/install/kubernetes/README.md new file mode 100644 index 0000000..2a507a2 --- /dev/null +++ b/istio-1.3.5/install/kubernetes/README.md @@ -0,0 +1,6 @@ +# Install Istio on an existing Kubernetes cluster + +Please follow the installation instructions on [istio.io](https://istio.io/docs/setup/kubernetes/). + +If you want to install Istio using the istio/istio repository instead of downloading a release, +refer to the [developer wiki](https://github.com/istio/istio/wiki) for instructions. diff --git a/istio-1.3.5/install/kubernetes/global-default-sidecar-scope.yaml b/istio-1.3.5/install/kubernetes/global-default-sidecar-scope.yaml new file mode 100644 index 0000000..346c682 --- /dev/null +++ b/istio-1.3.5/install/kubernetes/global-default-sidecar-scope.yaml @@ -0,0 +1,20 @@ +apiVersion: v1 +kind: Namespace +metadata: + name: istio-config +--- +apiVersion: networking.istio.io/v1alpha3 +kind: Sidecar +metadata: + name: default-sidecar-scope + namespace: istio-config +spec: + egress: + # If this config is applied, sidecars will only be able to talk to + # other services in the same namespace, in addition to istio-telemetry + # and istio-policy + - hosts: + - "./*" + - "istio-system/istio-telemetry.istio-system.svc.cluster.local" + - "istio-system/istio-policy.istio-system.svc.cluster.local" +--- diff --git a/istio-1.3.5/install/kubernetes/helm/README.md b/istio-1.3.5/install/kubernetes/helm/README.md new file mode 100644 index 0000000..880e0c1 --- /dev/null +++ b/istio-1.3.5/install/kubernetes/helm/README.md @@ -0,0 +1,7 @@ +# Installation using Helm + +Please follow the installation instructions from [istio.io](https://istio.io/docs/setup/kubernetes/install/helm/). + +# Development + +Future development for the installer is taking place on [istio/installer](https://github.com/istio/installer). Please add new features to this repository, as only bug fixes will be allowed here. \ No newline at end of file diff --git a/istio-1.3.5/install/kubernetes/helm/helm-service-account.yaml b/istio-1.3.5/install/kubernetes/helm/helm-service-account.yaml new file mode 100644 index 0000000..0e1b083 --- /dev/null +++ b/istio-1.3.5/install/kubernetes/helm/helm-service-account.yaml @@ -0,0 +1,21 @@ +# Create a service account for Helm and grant the cluster admin role. +# It is assumed that helm should be installed with this service account +# (tiller). +apiVersion: v1 +kind: ServiceAccount +metadata: + name: tiller + namespace: kube-system +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: tiller +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: cluster-admin +subjects: +- kind: ServiceAccount + name: tiller + namespace: kube-system diff --git a/istio-1.3.5/install/kubernetes/helm/istio-cni/Chart.yaml b/istio-1.3.5/install/kubernetes/helm/istio-cni/Chart.yaml new file mode 100644 index 0000000..52fbaf9 --- /dev/null +++ b/istio-1.3.5/install/kubernetes/helm/istio-cni/Chart.yaml @@ -0,0 +1,13 @@ +apiVersion: v1 +name: istio-cni +version: 1.3.5 +appVersion: 1.3.5 +tillerVersion: ">=2.7.2" +description: Helm chart for istio-cni components +keywords: + - istio-cni + - istio +sources: + - http://github.com/istio/cni +engine: gotpl +icon: https://istio.io/favicons/android-192x192.png diff --git a/istio-1.3.5/install/kubernetes/helm/istio-cni/templates/_labels.tpl b/istio-1.3.5/install/kubernetes/helm/istio-cni/templates/_labels.tpl new file mode 100644 index 0000000..bc4a09f --- /dev/null +++ b/istio-1.3.5/install/kubernetes/helm/istio-cni/templates/_labels.tpl @@ -0,0 +1,10 @@ +{{- define "common_labels" }} + chart: {{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }} + release: {{ .Release.Name }} + version: {{ .Chart.Version }} + heritage: {{ .Release.Service }} +{{- end }} + +{{- define "common_template_labels" }} + version: {{ .Chart.Version }} +{{- end }} diff --git a/istio-1.3.5/install/kubernetes/helm/istio-cni/templates/istio-cni.yaml b/istio-1.3.5/install/kubernetes/helm/istio-cni/templates/istio-cni.yaml new file mode 100644 index 0000000..ebc64ee --- /dev/null +++ b/istio-1.3.5/install/kubernetes/helm/istio-cni/templates/istio-cni.yaml @@ -0,0 +1,146 @@ +# Istio-CNI Version v0.1-dev +# +# This manifest installs the following component versions: +# istio-cni:v0.1 + + +kind: ClusterRole +apiVersion: rbac.authorization.k8s.io/v1 +metadata: + name: istio-cni +rules: + - apiGroups: [""] + resources: + - pods + - nodes + verbs: + - get + +--- + +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: istio-cni +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: istio-cni +subjects: +- kind: ServiceAccount + name: istio-cni + namespace: {{ .Release.Namespace }} + +--- +# This ConfigMap is used to configure a self-hosted Istio CNI installation. +kind: ConfigMap +apiVersion: v1 +metadata: + name: istio-cni-config + namespace: {{ .Release.Namespace }} + labels: + {{- template "common_labels" . }} +data: + # The CNI network configuration to add to the plugin chain on each node. The special + # values in this config will be automatically populated. + cni_network_config: |- + { + "type": "istio-cni", + "log_level": {{ quote .Values.logLevel }}, + "kubernetes": { + "kubeconfig": "__KUBECONFIG_FILEPATH__", + "cni_bin_dir": {{ quote .Values.cniBinDir }}, + "exclude_namespaces": [ {{ range $idx, $ns := .Values.excludeNamespaces }}{{ if $idx }}, {{ end }}{{ quote $ns }}{{ end }} ] + } + } + +--- + +# This manifest installs the Istio install-cni container, as well +# as the Istio CNI plugin and config on +# each master and worker node in a Kubernetes cluster. +kind: DaemonSet +apiVersion: apps/v1 +metadata: + name: istio-cni-node + namespace: {{ .Release.Namespace }} + labels: + k8s-app: istio-cni-node + {{- template "common_labels" . }} +spec: + selector: + matchLabels: + k8s-app: istio-cni-node + updateStrategy: + type: RollingUpdate + rollingUpdate: + maxUnavailable: 1 + template: + metadata: + labels: + k8s-app: istio-cni-node + annotations: + # This, along with the CriticalAddonsOnly toleration below, + # marks the pod as a critical add-on, ensuring it gets + # priority scheduling and that its resources are reserved + # if it ever gets evicted. + scheduler.alpha.kubernetes.io/critical-pod: '' + spec: + nodeSelector: + beta.kubernetes.io/os: linux + hostNetwork: true + tolerations: + # Make sure istio-cni-node gets scheduled on all nodes. + - effect: NoSchedule + operator: Exists + # Mark the pod as a critical add-on for rescheduling. + - key: CriticalAddonsOnly + operator: Exists + - effect: NoExecute + operator: Exists + priorityClassName: system-cluster-critical + serviceAccountName: istio-cni + # Minimize downtime during a rolling upgrade or deletion; tell Kubernetes to do a "force + # deletion": https://kubernetes.io/docs/concepts/workloads/pods/pod/#termination-of-pods. + terminationGracePeriodSeconds: 5 + containers: + # This container installs the Istio CNI binaries + # and CNI network config file on each node. + - name: install-cni + image: {{ .Values.hub }}/install-cni:{{ .Values.tag }} + imagePullPolicy: {{ .Values.pullPolicy }} + command: ["/install-cni.sh"] + env: +{{- if .Values.cniConfFileName }} + # Name of the CNI config file to create. + - name: CNI_CONF_NAME + value: "{{ .Values.cniConfFileName }}" +{{- end }} + # The CNI network config to install on each node. + - name: CNI_NETWORK_CONFIG + valueFrom: + configMapKeyRef: + name: istio-cni-config + key: cni_network_config + - name: CNI_NET_DIR + value: {{ default "/etc/cni/net.d" .Values.cniConfDir }} + volumeMounts: + - mountPath: /host/opt/cni/bin + name: cni-bin-dir + - mountPath: /host/etc/cni/net.d + name: cni-net-dir + volumes: + # Used to install CNI. + - name: cni-bin-dir + hostPath: + path: {{ default "/opt/cni/bin" .Values.cniBinDir }} + - name: cni-net-dir + hostPath: + path: {{ default "/etc/cni/net.d" .Values.cniConfDir }} +--- + +apiVersion: v1 +kind: ServiceAccount +metadata: + name: istio-cni + namespace: {{ .Release.Namespace }} diff --git a/istio-1.3.5/install/kubernetes/helm/istio-cni/values.yaml b/istio-1.3.5/install/kubernetes/helm/istio-cni/values.yaml new file mode 100644 index 0000000..ee26cd4 --- /dev/null +++ b/istio-1.3.5/install/kubernetes/helm/istio-cni/values.yaml @@ -0,0 +1,21 @@ +hub: docker.io/istio +tag: 1.3.5 +pullPolicy: Always + +logLevel: info + +# Configuration file to insert istio-cni plugin configuration +# by default this will be the first file found in the cni-conf-dir +# Example +# cniConfFileName: 10-calico.conflist + +# CNI bin and conf dir override settings +# defaults: +cniBinDir: /opt/cni/bin +cniConfDir: /etc/cni/net.d +cniConfFileName: "" + +excludeNamespaces: + - istio-system + + diff --git a/istio-1.3.5/install/kubernetes/helm/istio-cni/values_gke.yaml b/istio-1.3.5/install/kubernetes/helm/istio-cni/values_gke.yaml new file mode 100644 index 0000000..91b6d5b --- /dev/null +++ b/istio-1.3.5/install/kubernetes/helm/istio-cni/values_gke.yaml @@ -0,0 +1,18 @@ +hub: docker.io/istio +tag: 1.3.5 +pullPolicy: Always + +logLevel: info + +# Configuration file to insert istio-cni plugin configuration +# by default this will be the first file found in the cni-conf-dir +# Example +# cniConfFileName: 10-calico.conflist + +# CNI bin and conf dir override settings +# defaults: +cniBinDir: /home/kubernetes/bin +cniConfDir: /etc/cni/net.d + +excludeNamespaces: + - istio-system diff --git a/istio-1.3.5/install/kubernetes/helm/istio-init/Chart.yaml b/istio-1.3.5/install/kubernetes/helm/istio-init/Chart.yaml new file mode 100644 index 0000000..c16a7a9 --- /dev/null +++ b/istio-1.3.5/install/kubernetes/helm/istio-init/Chart.yaml @@ -0,0 +1,13 @@ +apiVersion: v1 +name: istio-init +version: 1.3.5 +appVersion: 1.3.5 +tillerVersion: ">=2.7.2-0" +description: Helm chart to initialize Istio CRDs +keywords: + - istio + - crd +sources: + - http://github.com/istio/istio +engine: gotpl +icon: https://istio.io/favicons/android-192x192.png diff --git a/istio-1.3.5/install/kubernetes/helm/istio-init/README.md b/istio-1.3.5/install/kubernetes/helm/istio-init/README.md new file mode 100644 index 0000000..c0a0e34 --- /dev/null +++ b/istio-1.3.5/install/kubernetes/helm/istio-init/README.md @@ -0,0 +1,77 @@ +# Istio + +[Istio](https://istio.io/) is an open platform for providing a uniform way to integrate microservices, manage traffic flow across microservices, enforce policies and aggregate telemetry data. + +## Introduction + +This chart bootstraps Istio's [CRDs](https://kubernetes.io/docs/concepts/extend-kubernetes/api-extension/custom-resources/#customresourcedefinitions) +which are an internal implementation detail of Istio. CRDs define data structures for storing runtime configuration +specified by a human operator. + +This chart must be run to completion prior to running other Istio charts, or other Istio charts will fail to initialize. + +## Prerequisites + +- Kubernetes 1.9 or newer cluster with RBAC (Role-Based Access Control) enabled is required +- Helm 2.7.2 or newer or alternately the ability to modify RBAC rules is also required + +## Resources Required + +The chart deploys pods that consume minimal resources. + +## Installing the Chart + +1. If a service account has not already been installed for Tiller, install one: + ``` + $ kubectl apply -f install/kubernetes/helm/helm-service-account.yaml + ``` + +1. If Tiller has not already been installed in your cluster, Install Tiller on your cluster with the service account: + ``` + $ helm init --service-account tiller + ``` + +1. Install the Istio initializer chart: + ``` + $ helm install install/kubernetes/helm/istio-init --name istio-init --namespace istio-system + ``` + + > Although you can install the `istio-init` chart to any namespace, it is recommended to install `istio-init` in the same namespace(`istio-system`) as other Istio charts. + +## Configuration + +The Helm chart ships with reasonable defaults. There may be circumstances in which defaults require overrides. +To override Helm values, use `--set key=value` argument during the `helm install` command. Multiple `--set` operations may be used in the same Helm operation. + +Helm charts expose configuration options which are currently in alpha. The currently exposed options are explained in the following table: + +| Parameter | Description | Values | Default | +| --- | --- | --- | --- | +| `global.hub` | Specifies the HUB for most images used by Istio | registry/namespace | `docker.io/istio` | +| `global.tag` | Specifies the TAG for most images used by Istio | valid image tag | `0.8.latest` | +| `global.imagePullPolicy` | Specifies the image pull policy | valid image pull policy | `IfNotPresent` | + + +## Uninstalling the Chart + +> Uninstalling this chart does not delete Istio's registered CRDs. Istio by design expects +> CRDs to leak into the Kubernetes environment. As CRDs contain all runtime configuration +> data in CustomResources the Istio designers feel it is better to explicitly delete this +> configuration rather then unexpectedly lose it. + +To uninstall/delete the `istio-init` release but continue to track the release: + ``` + $ helm delete istio-init + ``` + +To uninstall/delete the `istio-init` release completely and make its name free for later use: + ``` + $ helm delete --purge istio-init + ``` + +> Warning: Deleting CRDs will delete any configuration that you have made to Istio. + +To delete all CRDs, run the following command + ``` + $ for i in istio-init/files/*crd*yaml; do kubectl delete -f $i; done + ``` diff --git a/istio-1.3.5/install/kubernetes/helm/istio-init/files/crd-10.yaml b/istio-1.3.5/install/kubernetes/helm/istio-init/files/crd-10.yaml new file mode 100644 index 0000000..e76e50e --- /dev/null +++ b/istio-1.3.5/install/kubernetes/helm/istio-init/files/crd-10.yaml @@ -0,0 +1,636 @@ +apiVersion: apiextensions.k8s.io/v1beta1 +kind: CustomResourceDefinition +metadata: + name: virtualservices.networking.istio.io + labels: + app: istio-pilot + chart: istio + heritage: Tiller + release: istio + annotations: + "helm.sh/resource-policy": keep +spec: + group: networking.istio.io + names: + kind: VirtualService + listKind: VirtualServiceList + plural: virtualservices + singular: virtualservice + shortNames: + - vs + categories: + - istio-io + - networking-istio-io + scope: Namespaced + versions: + - name: v1alpha3 + served: true + storage: true + additionalPrinterColumns: + - JSONPath: .spec.gateways + description: The names of gateways and sidecars that should apply these routes + name: Gateways + type: string + - JSONPath: .spec.hosts + description: The destination hosts to which traffic is being sent + name: Hosts + type: string + - JSONPath: .metadata.creationTimestamp + description: |- + CreationTimestamp is a timestamp representing the server time when this object was created. It is not guaranteed to be set in happens-before order across separate operations. Clients may not set this value. It is represented in RFC3339 form and is in UTC. + + Populated by the system. Read-only. Null for lists. More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#metadata + name: Age + type: date +--- +apiVersion: apiextensions.k8s.io/v1beta1 +kind: CustomResourceDefinition +metadata: + name: destinationrules.networking.istio.io + labels: + app: istio-pilot + chart: istio + heritage: Tiller + release: istio + annotations: + "helm.sh/resource-policy": keep +spec: + group: networking.istio.io + names: + kind: DestinationRule + listKind: DestinationRuleList + plural: destinationrules + singular: destinationrule + shortNames: + - dr + categories: + - istio-io + - networking-istio-io + scope: Namespaced + versions: + - name: v1alpha3 + served: true + storage: true + additionalPrinterColumns: + - JSONPath: .spec.host + description: The name of a service from the service registry + name: Host + type: string + - JSONPath: .metadata.creationTimestamp + description: |- + CreationTimestamp is a timestamp representing the server time when this object was created. It is not guaranteed to be set in happens-before order across separate operations. Clients may not set this value. It is represented in RFC3339 form and is in UTC. + + Populated by the system. Read-only. Null for lists. More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#metadata + name: Age + type: date +--- +apiVersion: apiextensions.k8s.io/v1beta1 +kind: CustomResourceDefinition +metadata: + name: serviceentries.networking.istio.io + labels: + app: istio-pilot + chart: istio + heritage: Tiller + release: istio + annotations: + "helm.sh/resource-policy": keep +spec: + group: networking.istio.io + names: + kind: ServiceEntry + listKind: ServiceEntryList + plural: serviceentries + singular: serviceentry + shortNames: + - se + categories: + - istio-io + - networking-istio-io + scope: Namespaced + versions: + - name: v1alpha3 + served: true + storage: true + additionalPrinterColumns: + - JSONPath: .spec.hosts + description: The hosts associated with the ServiceEntry + name: Hosts + type: string + - JSONPath: .spec.location + description: Whether the service is external to the mesh or part of the mesh (MESH_EXTERNAL or MESH_INTERNAL) + name: Location + type: string + - JSONPath: .spec.resolution + description: Service discovery mode for the hosts (NONE, STATIC, or DNS) + name: Resolution + type: string + - JSONPath: .metadata.creationTimestamp + description: |- + CreationTimestamp is a timestamp representing the server time when this object was created. It is not guaranteed to be set in happens-before order across separate operations. Clients may not set this value. It is represented in RFC3339 form and is in UTC. + + Populated by the system. Read-only. Null for lists. More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#metadata + name: Age + type: date +--- +apiVersion: apiextensions.k8s.io/v1beta1 +kind: CustomResourceDefinition +metadata: + name: gateways.networking.istio.io + labels: + app: istio-pilot + chart: istio + heritage: Tiller + release: istio + annotations: + "helm.sh/resource-policy": keep +spec: + group: networking.istio.io + names: + kind: Gateway + plural: gateways + singular: gateway + shortNames: + - gw + categories: + - istio-io + - networking-istio-io + scope: Namespaced + versions: + - name: v1alpha3 + served: true + storage: true +--- +apiVersion: apiextensions.k8s.io/v1beta1 +kind: CustomResourceDefinition +metadata: + name: envoyfilters.networking.istio.io + labels: + app: istio-pilot + chart: istio + heritage: Tiller + release: istio + annotations: + "helm.sh/resource-policy": keep +spec: + group: networking.istio.io + names: + kind: EnvoyFilter + plural: envoyfilters + singular: envoyfilter + categories: + - istio-io + - networking-istio-io + scope: Namespaced + versions: + - name: v1alpha3 + served: true + storage: true +--- +kind: CustomResourceDefinition +apiVersion: apiextensions.k8s.io/v1beta1 +metadata: + name: clusterrbacconfigs.rbac.istio.io + labels: + app: istio-pilot + istio: rbac + heritage: Tiller + release: istio + annotations: + "helm.sh/resource-policy": keep +spec: + group: rbac.istio.io + names: + kind: ClusterRbacConfig + plural: clusterrbacconfigs + singular: clusterrbacconfig + categories: + - istio-io + - rbac-istio-io + scope: Cluster + versions: + - name: v1alpha1 + served: true + storage: true +--- +kind: CustomResourceDefinition +apiVersion: apiextensions.k8s.io/v1beta1 +metadata: + name: policies.authentication.istio.io + labels: + app: istio-citadel + chart: istio + heritage: Tiller + release: istio + annotations: + "helm.sh/resource-policy": keep +spec: + group: authentication.istio.io + names: + kind: Policy + plural: policies + singular: policy + categories: + - istio-io + - authentication-istio-io + scope: Namespaced + versions: + - name: v1alpha1 + served: true + storage: true +--- +kind: CustomResourceDefinition +apiVersion: apiextensions.k8s.io/v1beta1 +metadata: + name: meshpolicies.authentication.istio.io + labels: + app: istio-citadel + chart: istio + heritage: Tiller + release: istio + annotations: + "helm.sh/resource-policy": keep +spec: + group: authentication.istio.io + names: + kind: MeshPolicy + listKind: MeshPolicyList + plural: meshpolicies + singular: meshpolicy + categories: + - istio-io + - authentication-istio-io + scope: Cluster + versions: + - name: v1alpha1 + served: true + storage: true +--- +kind: CustomResourceDefinition +apiVersion: apiextensions.k8s.io/v1beta1 +metadata: + name: httpapispecbindings.config.istio.io + labels: + app: istio-mixer + chart: istio + heritage: Tiller + release: istio + annotations: + "helm.sh/resource-policy": keep +spec: + group: config.istio.io + names: + kind: HTTPAPISpecBinding + plural: httpapispecbindings + singular: httpapispecbinding + categories: + - istio-io + - apim-istio-io + scope: Namespaced + versions: + - name: v1alpha2 + served: true + storage: true +--- +kind: CustomResourceDefinition +apiVersion: apiextensions.k8s.io/v1beta1 +metadata: + name: httpapispecs.config.istio.io + labels: + app: istio-mixer + chart: istio + heritage: Tiller + release: istio + annotations: + "helm.sh/resource-policy": keep +spec: + group: config.istio.io + names: + kind: HTTPAPISpec + plural: httpapispecs + singular: httpapispec + categories: + - istio-io + - apim-istio-io + scope: Namespaced + versions: + - name: v1alpha2 + served: true + storage: true +--- +kind: CustomResourceDefinition +apiVersion: apiextensions.k8s.io/v1beta1 +metadata: + name: quotaspecbindings.config.istio.io + labels: + app: istio-mixer + chart: istio + heritage: Tiller + release: istio + annotations: + "helm.sh/resource-policy": keep +spec: + group: config.istio.io + names: + kind: QuotaSpecBinding + plural: quotaspecbindings + singular: quotaspecbinding + categories: + - istio-io + - apim-istio-io + scope: Namespaced + versions: + - name: v1alpha2 + served: true + storage: true +--- +kind: CustomResourceDefinition +apiVersion: apiextensions.k8s.io/v1beta1 +metadata: + name: quotaspecs.config.istio.io + labels: + app: istio-mixer + chart: istio + heritage: Tiller + release: istio + annotations: + "helm.sh/resource-policy": keep +spec: + group: config.istio.io + names: + kind: QuotaSpec + plural: quotaspecs + singular: quotaspec + categories: + - istio-io + - apim-istio-io + scope: Namespaced + versions: + - name: v1alpha2 + served: true + storage: true +--- +kind: CustomResourceDefinition +apiVersion: apiextensions.k8s.io/v1beta1 +metadata: + name: rules.config.istio.io + labels: + app: mixer + package: istio.io.mixer + istio: core + chart: istio + heritage: Tiller + release: istio + annotations: + "helm.sh/resource-policy": keep +spec: + group: config.istio.io + names: + kind: rule + plural: rules + singular: rule + categories: + - istio-io + - policy-istio-io + scope: Namespaced + versions: + - name: v1alpha2 + served: true + storage: true +--- +kind: CustomResourceDefinition +apiVersion: apiextensions.k8s.io/v1beta1 +metadata: + name: attributemanifests.config.istio.io + labels: + app: mixer + package: istio.io.mixer + istio: core + chart: istio + heritage: Tiller + release: istio + annotations: + "helm.sh/resource-policy": keep +spec: + group: config.istio.io + names: + kind: attributemanifest + plural: attributemanifests + singular: attributemanifest + categories: + - istio-io + - policy-istio-io + scope: Namespaced + versions: + - name: v1alpha2 + served: true + storage: true +--- +kind: CustomResourceDefinition +apiVersion: apiextensions.k8s.io/v1beta1 +metadata: + name: rbacconfigs.rbac.istio.io + labels: + app: mixer + package: istio.io.mixer + istio: rbac + chart: istio + heritage: Tiller + release: istio + annotations: + "helm.sh/resource-policy": keep +spec: + group: rbac.istio.io + names: + kind: RbacConfig + plural: rbacconfigs + singular: rbacconfig + categories: + - istio-io + - rbac-istio-io + scope: Namespaced + versions: + - name: v1alpha1 + served: true + storage: true +--- +kind: CustomResourceDefinition +apiVersion: apiextensions.k8s.io/v1beta1 +metadata: + name: serviceroles.rbac.istio.io + labels: + app: mixer + package: istio.io.mixer + istio: rbac + chart: istio + heritage: Tiller + release: istio + annotations: + "helm.sh/resource-policy": keep +spec: + group: rbac.istio.io + names: + kind: ServiceRole + plural: serviceroles + singular: servicerole + categories: + - istio-io + - rbac-istio-io + scope: Namespaced + versions: + - name: v1alpha1 + served: true + storage: true +--- +kind: CustomResourceDefinition +apiVersion: apiextensions.k8s.io/v1beta1 +metadata: + name: servicerolebindings.rbac.istio.io + labels: + app: mixer + package: istio.io.mixer + istio: rbac + chart: istio + heritage: Tiller + release: istio + annotations: + "helm.sh/resource-policy": keep +spec: + group: rbac.istio.io + names: + kind: ServiceRoleBinding + plural: servicerolebindings + singular: servicerolebinding + categories: + - istio-io + - rbac-istio-io + scope: Namespaced + versions: + - name: v1alpha1 + served: true + storage: true + additionalPrinterColumns: + - JSONPath: .spec.roleRef.name + description: The name of the ServiceRole object being referenced + name: Reference + type: string + - JSONPath: .metadata.creationTimestamp + description: |- + CreationTimestamp is a timestamp representing the server time when this object was created. It is not guaranteed to be set in happens-before order across separate operations. Clients may not set this value. It is represented in RFC3339 form and is in UTC. + + Populated by the system. Read-only. Null for lists. More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#metadata + name: Age + type: date +--- +kind: CustomResourceDefinition +apiVersion: apiextensions.k8s.io/v1beta1 +metadata: + name: adapters.config.istio.io + labels: + app: mixer + package: adapter + istio: mixer-adapter + chart: istio + heritage: Tiller + release: istio + annotations: + "helm.sh/resource-policy": keep +spec: + group: config.istio.io + names: + kind: adapter + plural: adapters + singular: adapter + categories: + - istio-io + - policy-istio-io + scope: Namespaced + versions: + - name: v1alpha2 + served: true + storage: true +--- +kind: CustomResourceDefinition +apiVersion: apiextensions.k8s.io/v1beta1 +metadata: + name: instances.config.istio.io + labels: + app: mixer + package: instance + istio: mixer-instance + chart: istio + heritage: Tiller + release: istio + annotations: + "helm.sh/resource-policy": keep +spec: + group: config.istio.io + names: + kind: instance + plural: instances + singular: instance + categories: + - istio-io + - policy-istio-io + scope: Namespaced + versions: + - name: v1alpha2 + served: true + storage: true +--- +kind: CustomResourceDefinition +apiVersion: apiextensions.k8s.io/v1beta1 +metadata: + name: templates.config.istio.io + labels: + app: mixer + package: template + istio: mixer-template + chart: istio + heritage: Tiller + release: istio + annotations: + "helm.sh/resource-policy": keep +spec: + group: config.istio.io + names: + kind: template + plural: templates + singular: template + categories: + - istio-io + - policy-istio-io + scope: Namespaced + versions: + - name: v1alpha2 + served: true + storage: true +--- +kind: CustomResourceDefinition +apiVersion: apiextensions.k8s.io/v1beta1 +metadata: + name: handlers.config.istio.io + labels: + app: mixer + package: handler + istio: mixer-handler + chart: istio + heritage: Tiller + release: istio + annotations: + "helm.sh/resource-policy": keep +spec: + group: config.istio.io + names: + kind: handler + plural: handlers + singular: handler + categories: + - istio-io + - policy-istio-io + scope: Namespaced + versions: + - name: v1alpha2 + served: true + storage: true +--- diff --git a/istio-1.3.5/install/kubernetes/helm/istio-init/files/crd-11.yaml b/istio-1.3.5/install/kubernetes/helm/istio-init/files/crd-11.yaml new file mode 100644 index 0000000..5087d38 --- /dev/null +++ b/istio-1.3.5/install/kubernetes/helm/istio-init/files/crd-11.yaml @@ -0,0 +1,26 @@ +apiVersion: apiextensions.k8s.io/v1beta1 +kind: CustomResourceDefinition +metadata: + name: sidecars.networking.istio.io + labels: + app: istio-pilot + chart: istio + heritage: Tiller + release: istio + annotations: + "helm.sh/resource-policy": keep +spec: + group: networking.istio.io + names: + kind: Sidecar + plural: sidecars + singular: sidecar + categories: + - istio-io + - networking-istio-io + scope: Namespaced + versions: + - name: v1alpha3 + served: true + storage: true +--- diff --git a/istio-1.3.5/install/kubernetes/helm/istio-init/files/crd-12.yaml b/istio-1.3.5/install/kubernetes/helm/istio-init/files/crd-12.yaml new file mode 100644 index 0000000..d9b3372 --- /dev/null +++ b/istio-1.3.5/install/kubernetes/helm/istio-init/files/crd-12.yaml @@ -0,0 +1,24 @@ +kind: CustomResourceDefinition +apiVersion: apiextensions.k8s.io/v1beta1 +metadata: + name: authorizationpolicies.rbac.istio.io + labels: + app: istio-pilot + istio: rbac + heritage: Tiller + release: istio +spec: + group: rbac.istio.io + names: + kind: AuthorizationPolicy + plural: authorizationpolicies + singular: authorizationpolicy + categories: + - istio-io + - rbac-istio-io + scope: Namespaced + versions: + - name: v1alpha1 + served: true + storage: true +--- diff --git a/istio-1.3.5/install/kubernetes/helm/istio-init/files/crd-certmanager-10.yaml b/istio-1.3.5/install/kubernetes/helm/istio-init/files/crd-certmanager-10.yaml new file mode 100644 index 0000000..d3a3069 --- /dev/null +++ b/istio-1.3.5/install/kubernetes/helm/istio-init/files/crd-certmanager-10.yaml @@ -0,0 +1,91 @@ +apiVersion: apiextensions.k8s.io/v1beta1 +kind: CustomResourceDefinition +metadata: + name: clusterissuers.certmanager.k8s.io + labels: + app: certmanager + chart: certmanager + heritage: Tiller + release: istio + annotations: + "helm.sh/resource-policy": keep +spec: + group: certmanager.k8s.io + versions: + - name: v1alpha1 + served: true + storage: true + names: + kind: ClusterIssuer + plural: clusterissuers + scope: Cluster +--- +apiVersion: apiextensions.k8s.io/v1beta1 +kind: CustomResourceDefinition +metadata: + name: issuers.certmanager.k8s.io + labels: + app: certmanager + chart: certmanager + heritage: Tiller + release: istio + annotations: + "helm.sh/resource-policy": keep +spec: + group: certmanager.k8s.io + versions: + - name: v1alpha1 + served: true + storage: true + names: + kind: Issuer + plural: issuers + scope: Namespaced +--- +apiVersion: apiextensions.k8s.io/v1beta1 +kind: CustomResourceDefinition +metadata: + name: certificates.certmanager.k8s.io + labels: + app: certmanager + chart: certmanager + heritage: Tiller + release: istio + annotations: + "helm.sh/resource-policy": keep +spec: + additionalPrinterColumns: + - JSONPath: .status.conditions[?(@.type=="Ready")].status + name: Ready + type: string + - JSONPath: .spec.secretName + name: Secret + type: string + - JSONPath: .spec.issuerRef.name + name: Issuer + type: string + priority: 1 + - JSONPath: .status.conditions[?(@.type=="Ready")].message + name: Status + type: string + priority: 1 + - JSONPath: .metadata.creationTimestamp + description: |- + CreationTimestamp is a timestamp representing the server time when this object was created. It is not guaranteed to be set in happens-before order across separate operations. Clients may not set this value. It is represented in RFC3339 form and is in UTC. + + Populated by the system. Read-only. Null for lists. More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#metadata + name: Age + type: date + group: certmanager.k8s.io + versions: + - name: v1alpha1 + served: true + storage: true + scope: Namespaced + names: + kind: Certificate + plural: certificates + shortNames: + - cert + - certs +--- diff --git a/istio-1.3.5/install/kubernetes/helm/istio-init/files/crd-certmanager-11.yaml b/istio-1.3.5/install/kubernetes/helm/istio-init/files/crd-certmanager-11.yaml new file mode 100644 index 0000000..f63787b --- /dev/null +++ b/istio-1.3.5/install/kubernetes/helm/istio-init/files/crd-certmanager-11.yaml @@ -0,0 +1,80 @@ +apiVersion: apiextensions.k8s.io/v1beta1 +kind: CustomResourceDefinition +metadata: + name: orders.certmanager.k8s.io + labels: + app: certmanager + chart: certmanager + heritage: Tiller + release: istio + annotations: + "helm.sh/resource-policy": keep +spec: + additionalPrinterColumns: + - JSONPath: .status.state + name: State + type: string + - JSONPath: .spec.issuerRef.name + name: Issuer + type: string + priority: 1 + - JSONPath: .status.reason + name: Reason + type: string + priority: 1 + - JSONPath: .metadata.creationTimestamp + description: |- + CreationTimestamp is a timestamp representing the server time when this object was created. It is not guaranteed to be set in happens-before order across separate operations. Clients may not set this value. It is represented in RFC3339 form and is in UTC. + + Populated by the system. Read-only. Null for lists. More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#metadata + name: Age + type: date + group: certmanager.k8s.io + versions: + - name: v1alpha1 + served: true + storage: true + names: + kind: Order + plural: orders + scope: Namespaced +--- +apiVersion: apiextensions.k8s.io/v1beta1 +kind: CustomResourceDefinition +metadata: + name: challenges.certmanager.k8s.io + labels: + app: certmanager + chart: certmanager + heritage: Tiller + release: istio + annotations: + "helm.sh/resource-policy": keep +spec: + additionalPrinterColumns: + - JSONPath: .status.state + name: State + type: string + - JSONPath: .spec.dnsName + name: Domain + type: string + - JSONPath: .status.reason + name: Reason + type: string + - JSONPath: .metadata.creationTimestamp + description: |- + CreationTimestamp is a timestamp representing the server time when this object was created. It is not guaranteed to be set in happens-before order across separate operations. Clients may not set this value. It is represented in RFC3339 form and is in UTC. + + Populated by the system. Read-only. Null for lists. More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#metadata + name: Age + type: date + group: certmanager.k8s.io + versions: + - name: v1alpha1 + served: true + storage: true + names: + kind: Challenge + plural: challenges + scope: Namespaced +--- diff --git a/istio-1.3.5/install/kubernetes/helm/istio-init/templates/clusterrole.yaml b/istio-1.3.5/install/kubernetes/helm/istio-init/templates/clusterrole.yaml new file mode 100644 index 0000000..0b7c50f --- /dev/null +++ b/istio-1.3.5/install/kubernetes/helm/istio-init/templates/clusterrole.yaml @@ -0,0 +1,11 @@ +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: istio-init-{{ .Release.Namespace }} + labels: + app: istio-init + istio: init +rules: +- apiGroups: ["apiextensions.k8s.io"] + resources: ["customresourcedefinitions"] + verbs: ["create", "get", "list", "watch", "patch"] diff --git a/istio-1.3.5/install/kubernetes/helm/istio-init/templates/clusterrolebinding.yaml b/istio-1.3.5/install/kubernetes/helm/istio-init/templates/clusterrolebinding.yaml new file mode 100644 index 0000000..481674c --- /dev/null +++ b/istio-1.3.5/install/kubernetes/helm/istio-init/templates/clusterrolebinding.yaml @@ -0,0 +1,15 @@ +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: istio-init-admin-role-binding-{{ .Release.Namespace }} + labels: + app: istio-init + istio: init +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: istio-init-{{ .Release.Namespace }} +subjects: + - kind: ServiceAccount + name: istio-init-service-account + namespace: {{ .Release.Namespace }} diff --git a/istio-1.3.5/install/kubernetes/helm/istio-init/templates/configmap-crd-10.yaml b/istio-1.3.5/install/kubernetes/helm/istio-init/templates/configmap-crd-10.yaml new file mode 100644 index 0000000..69e37fa --- /dev/null +++ b/istio-1.3.5/install/kubernetes/helm/istio-init/templates/configmap-crd-10.yaml @@ -0,0 +1,8 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + namespace: {{ .Release.Namespace }} + name: istio-crd-10 +data: + crd-10.yaml: |- +{{.Files.Get "files/crd-10.yaml" | printf "%s" | indent 4}} diff --git a/istio-1.3.5/install/kubernetes/helm/istio-init/templates/configmap-crd-11.yaml b/istio-1.3.5/install/kubernetes/helm/istio-init/templates/configmap-crd-11.yaml new file mode 100644 index 0000000..952640d --- /dev/null +++ b/istio-1.3.5/install/kubernetes/helm/istio-init/templates/configmap-crd-11.yaml @@ -0,0 +1,8 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + namespace: {{ .Release.Namespace }} + name: istio-crd-11 +data: + crd-11.yaml: |- +{{.Files.Get "files/crd-11.yaml" | printf "%s" | indent 4}} diff --git a/istio-1.3.5/install/kubernetes/helm/istio-init/templates/configmap-crd-12.yaml b/istio-1.3.5/install/kubernetes/helm/istio-init/templates/configmap-crd-12.yaml new file mode 100644 index 0000000..a497365 --- /dev/null +++ b/istio-1.3.5/install/kubernetes/helm/istio-init/templates/configmap-crd-12.yaml @@ -0,0 +1,8 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + namespace: {{ .Release.Namespace }} + name: istio-crd-12 +data: + crd-12.yaml: |- +{{.Files.Get "files/crd-12.yaml" | printf "%s" | indent 4}} diff --git a/istio-1.3.5/install/kubernetes/helm/istio-init/templates/configmap-crd-certmanager-10.yaml b/istio-1.3.5/install/kubernetes/helm/istio-init/templates/configmap-crd-certmanager-10.yaml new file mode 100644 index 0000000..8ab3e83 --- /dev/null +++ b/istio-1.3.5/install/kubernetes/helm/istio-init/templates/configmap-crd-certmanager-10.yaml @@ -0,0 +1,10 @@ +{{- if .Values.certmanager.enabled }} +apiVersion: v1 +kind: ConfigMap +metadata: + namespace: {{ .Release.Namespace }} + name: istio-crd-certmanager-10 +data: + crd-certmanager-10.yaml: |- +{{.Files.Get "files/crd-certmanager-10.yaml" | printf "%s" | indent 4}} +{{- end }} diff --git a/istio-1.3.5/install/kubernetes/helm/istio-init/templates/configmap-crd-certmanager-11.yaml b/istio-1.3.5/install/kubernetes/helm/istio-init/templates/configmap-crd-certmanager-11.yaml new file mode 100644 index 0000000..beef304 --- /dev/null +++ b/istio-1.3.5/install/kubernetes/helm/istio-init/templates/configmap-crd-certmanager-11.yaml @@ -0,0 +1,10 @@ +{{- if .Values.certmanager.enabled }} +apiVersion: v1 +kind: ConfigMap +metadata: + namespace: {{ .Release.Namespace }} + name: istio-crd-certmanager-11 +data: + crd-certmanager-11.yaml: |- +{{.Files.Get "files/crd-certmanager-11.yaml" | printf "%s" | indent 4}} +{{- end }} diff --git a/istio-1.3.5/install/kubernetes/helm/istio-init/templates/job-crd-10.yaml b/istio-1.3.5/install/kubernetes/helm/istio-init/templates/job-crd-10.yaml new file mode 100644 index 0000000..2f98bc5 --- /dev/null +++ b/istio-1.3.5/install/kubernetes/helm/istio-init/templates/job-crd-10.yaml @@ -0,0 +1,26 @@ +apiVersion: batch/v1 +kind: Job +metadata: + namespace: {{ .Release.Namespace }} + name: istio-init-crd-10-{{ .Values.global.tag | printf "%v" | trunc 32 }} +spec: + template: + metadata: + annotations: + sidecar.istio.io/inject: "false" + spec: + serviceAccountName: istio-init-service-account + containers: + - name: istio-init-crd-10 + image: "{{ .Values.global.hub }}/kubectl:{{ .Values.global.tag }}" + imagePullPolicy: {{ .Values.global.imagePullPolicy }} + volumeMounts: + - name: crd-10 + mountPath: /etc/istio/crd-10 + readOnly: true + command: ["kubectl", "apply", "-f", "/etc/istio/crd-10/crd-10.yaml"] + volumes: + - name: crd-10 + configMap: + name: istio-crd-10 + restartPolicy: OnFailure diff --git a/istio-1.3.5/install/kubernetes/helm/istio-init/templates/job-crd-11.yaml b/istio-1.3.5/install/kubernetes/helm/istio-init/templates/job-crd-11.yaml new file mode 100644 index 0000000..35996a0 --- /dev/null +++ b/istio-1.3.5/install/kubernetes/helm/istio-init/templates/job-crd-11.yaml @@ -0,0 +1,26 @@ +apiVersion: batch/v1 +kind: Job +metadata: + namespace: {{ .Release.Namespace }} + name: istio-init-crd-11-{{ .Values.global.tag | printf "%v" | trunc 32 }} +spec: + template: + metadata: + annotations: + sidecar.istio.io/inject: "false" + spec: + serviceAccountName: istio-init-service-account + containers: + - name: istio-init-crd-11 + image: "{{ .Values.global.hub }}/kubectl:{{ .Values.global.tag }}" + imagePullPolicy: {{ .Values.global.imagePullPolicy }} + volumeMounts: + - name: crd-11 + mountPath: /etc/istio/crd-11 + readOnly: true + command: ["kubectl", "apply", "-f", "/etc/istio/crd-11/crd-11.yaml"] + volumes: + - name: crd-11 + configMap: + name: istio-crd-11 + restartPolicy: OnFailure diff --git a/istio-1.3.5/install/kubernetes/helm/istio-init/templates/job-crd-12.yaml b/istio-1.3.5/install/kubernetes/helm/istio-init/templates/job-crd-12.yaml new file mode 100644 index 0000000..f404250 --- /dev/null +++ b/istio-1.3.5/install/kubernetes/helm/istio-init/templates/job-crd-12.yaml @@ -0,0 +1,26 @@ +apiVersion: batch/v1 +kind: Job +metadata: + namespace: {{ .Release.Namespace }} + name: istio-init-crd-12-{{ .Values.global.tag | printf "%v" | trunc 32 }} +spec: + template: + metadata: + annotations: + sidecar.istio.io/inject: "false" + spec: + serviceAccountName: istio-init-service-account + containers: + - name: istio-init-crd-12 + image: "{{ .Values.global.hub }}/kubectl:{{ .Values.global.tag }}" + imagePullPolicy: {{ .Values.global.imagePullPolicy }} + volumeMounts: + - name: crd-12 + mountPath: /etc/istio/crd-12 + readOnly: true + command: ["kubectl", "apply", "-f", "/etc/istio/crd-12/crd-12.yaml"] + volumes: + - name: crd-12 + configMap: + name: istio-crd-12 + restartPolicy: OnFailure diff --git a/istio-1.3.5/install/kubernetes/helm/istio-init/templates/job-crd-certmanager-10.yaml b/istio-1.3.5/install/kubernetes/helm/istio-init/templates/job-crd-certmanager-10.yaml new file mode 100644 index 0000000..5b4e0a2 --- /dev/null +++ b/istio-1.3.5/install/kubernetes/helm/istio-init/templates/job-crd-certmanager-10.yaml @@ -0,0 +1,28 @@ +{{- if .Values.certmanager.enabled }} +apiVersion: batch/v1 +kind: Job +metadata: + namespace: {{ .Release.Namespace }} + name: istio-init-crd-certmanager-10-{{ .Values.global.tag | printf "%v" | trunc 32 }} +spec: + template: + metadata: + annotations: + sidecar.istio.io/inject: "false" + spec: + serviceAccountName: istio-init-service-account + containers: + - name: istio-init-crd-certmanager-10 + image: "{{ .Values.global.hub }}/kubectl:{{ .Values.global.tag }}" + imagePullPolicy: {{ .Values.global.imagePullPolicy }} + volumeMounts: + - name: crd-certmanager-10 + mountPath: /etc/istio/crd-certmanager-10 + readOnly: true + command: ["kubectl", "apply", "-f", "/etc/istio/crd-certmanager-10/crd-certmanager-10.yaml"] + volumes: + - name: crd-certmanager-10 + configMap: + name: istio-crd-certmanager-10 + restartPolicy: OnFailure +{{- end }} diff --git a/istio-1.3.5/install/kubernetes/helm/istio-init/templates/job-crd-certmanager-11.yaml b/istio-1.3.5/install/kubernetes/helm/istio-init/templates/job-crd-certmanager-11.yaml new file mode 100644 index 0000000..06092cf --- /dev/null +++ b/istio-1.3.5/install/kubernetes/helm/istio-init/templates/job-crd-certmanager-11.yaml @@ -0,0 +1,28 @@ +{{- if .Values.certmanager.enabled }} +apiVersion: batch/v1 +kind: Job +metadata: + namespace: {{ .Release.Namespace }} + name: istio-init-crd-certmanager-11-{{ .Values.global.tag | printf "%v" | trunc 32 }} +spec: + template: + metadata: + annotations: + sidecar.istio.io/inject: "false" + spec: + serviceAccountName: istio-init-service-account + containers: + - name: istio-init-crd-certmanager-11 + image: "{{ .Values.global.hub }}/kubectl:{{ .Values.global.tag }}" + imagePullPolicy: {{ .Values.global.imagePullPolicy }} + volumeMounts: + - name: crd-certmanager-11 + mountPath: /etc/istio/crd-certmanager-11 + readOnly: true + command: ["kubectl", "apply", "-f", "/etc/istio/crd-certmanager-11/crd-certmanager-11.yaml"] + volumes: + - name: crd-certmanager-11 + configMap: + name: istio-crd-certmanager-11 + restartPolicy: OnFailure +{{- end }} diff --git a/istio-1.3.5/install/kubernetes/helm/istio-init/templates/serviceaccount.yaml b/istio-1.3.5/install/kubernetes/helm/istio-init/templates/serviceaccount.yaml new file mode 100644 index 0000000..3146662 --- /dev/null +++ b/istio-1.3.5/install/kubernetes/helm/istio-init/templates/serviceaccount.yaml @@ -0,0 +1,15 @@ +apiVersion: v1 +kind: ServiceAccount +{{- if .Values.global.imagePullSecrets }} +imagePullSecrets: +{{- range .Values.global.imagePullSecrets }} + - name: {{ . }} +{{- end }} +{{- end }} +metadata: + name: istio-init-service-account + namespace: {{ .Release.Namespace }} + labels: + app: istio-init + istio: init + diff --git a/istio-1.3.5/install/kubernetes/helm/istio-init/values.yaml b/istio-1.3.5/install/kubernetes/helm/istio-init/values.yaml new file mode 100644 index 0000000..17c35f2 --- /dev/null +++ b/istio-1.3.5/install/kubernetes/helm/istio-init/values.yaml @@ -0,0 +1,16 @@ +global: + # Default hub for Istio images. + # Releases are published to docker hub under 'istio' project. + # Daily builds from prow are on gcr.io + hub: docker.io/istio + + # Default tag for Istio images. + tag: 1.3.5 + + # imagePullPolicy is applied to istio control plane components. + # local tests require IfNotPresent, to avoid uploading to dockerhub. + # TODO: Switch to Always as default, and override in the local tests. + imagePullPolicy: IfNotPresent + +certmanager: + enabled: false diff --git a/istio-1.3.5/install/kubernetes/helm/istio/Chart.yaml b/istio-1.3.5/install/kubernetes/helm/istio/Chart.yaml new file mode 100644 index 0000000..1c0bc89 --- /dev/null +++ b/istio-1.3.5/install/kubernetes/helm/istio/Chart.yaml @@ -0,0 +1,17 @@ +apiVersion: v1 +name: istio +version: 1.3.5 +appVersion: 1.3.5 +tillerVersion: ">=2.7.2-0" +description: Helm chart for all istio components +keywords: + - istio + - security + - sidecarInjectorWebhook + - mixer + - pilot + - galley +sources: + - http://github.com/istio/istio +engine: gotpl +icon: https://istio.io/favicons/android-192x192.png diff --git a/istio-1.3.5/install/kubernetes/helm/istio/README.md b/istio-1.3.5/install/kubernetes/helm/istio/README.md new file mode 100644 index 0000000..de67ba2 --- /dev/null +++ b/istio-1.3.5/install/kubernetes/helm/istio/README.md @@ -0,0 +1,140 @@ +# Istio + +[Istio](https://istio.io/) is an open platform for providing a uniform way to integrate microservices, manage traffic flow across microservices, enforce policies and aggregate telemetry data. + + + +The documentation here is for developers only, please follow the installation instructions from [istio.io](https://istio.io/docs/setup/kubernetes/install/helm/) for all other uses. + +## Introduction + +This chart bootstraps all Istio [components](https://istio.io/docs/concepts/what-is-istio/) deployment on a [Kubernetes](http://kubernetes.io) cluster using the [Helm](https://helm.sh) package manager. + +## Chart Details + +This chart can install multiple Istio components as subcharts: +- ingressgateway +- egressgateway +- sidecarInjectorWebhook +- galley +- mixer +- pilot +- security(citadel) +- grafana +- prometheus +- tracing(jaeger) +- kiali + +To enable or disable each component, change the corresponding `enabled` flag. + +## Prerequisites + +- Kubernetes 1.9 or newer cluster with RBAC (Role-Based Access Control) enabled is required +- Helm 2.7.2 or newer or alternately the ability to modify RBAC rules is also required +- If you want to enable automatic sidecar injection, Kubernetes 1.9+ with `admissionregistration` API is required, and `kube-apiserver` process must have the `admission-control` flag set with the `MutatingAdmissionWebhook` and `ValidatingAdmissionWebhook` admission controllers added and listed in the correct order. +- The `istio-init` chart must be run to completion prior to install the `istio` chart. + +## Resources Required + +The chart deploys pods that consume minimum resources as specified in the resources configuration parameter. + +## Installing the Chart + +1. If a service account has not already been installed for Tiller, install one: + ``` + $ kubectl apply -f install/kubernetes/helm/helm-service-account.yaml + ``` + +1. Install Tiller on your cluster with the service account: + ``` + $ helm init --service-account tiller + ``` + +1. Set and create the namespace where Istio was installed: + ``` + $ NAMESPACE=istio-system + $ kubectl create ns $NAMESPACE + ``` + +1. If you are enabling `kiali`, you need to create the secret that contains the username and passphrase for `kiali` dashboard: + ``` + $ echo -n 'admin' | base64 + YWRtaW4= + $ echo -n '1f2d1e2e67df' | base64 + MWYyZDFlMmU2N2Rm + $ cat <=1.9.0): + ``` + $ helm install istio --name istio --namespace $NAMESPACE + ``` + + - Without the sidecar injection webhook: + ``` + $ helm install istio --name istio --namespace $NAMESPACE --set sidecarInjectorWebhook.enabled=false + ``` + +## Configuration + +The Helm chart ships with reasonable defaults. There may be circumstances in which defaults require overrides. +To override Helm values, use `--set key=value` argument during the `helm install` command. Multiple `--set` operations may be used in the same Helm operation. + +Helm charts expose configuration options which are currently in alpha. The currently exposed options can be found [here](https://istio.io/docs/reference/config/installation-options/). + +## Uninstalling the Chart + +To uninstall/delete the `istio` release but continue to track the release: + ``` + $ helm delete istio + ``` + +To uninstall/delete the `istio` release completely and make its name free for later use: + ``` + $ helm delete --purge istio + ``` diff --git a/istio-1.3.5/install/kubernetes/helm/istio/charts/certmanager/Chart.yaml b/istio-1.3.5/install/kubernetes/helm/istio/charts/certmanager/Chart.yaml new file mode 100644 index 0000000..a0bf99c --- /dev/null +++ b/istio-1.3.5/install/kubernetes/helm/istio/charts/certmanager/Chart.yaml @@ -0,0 +1,6 @@ +apiVersion: v1 +description: A Helm chart for Kubernetes +name: certmanager +version: 1.3.5 +appVersion: 0.6.2 +tillerVersion: ">=2.7.2" diff --git a/istio-1.3.5/install/kubernetes/helm/istio/charts/certmanager/templates/NOTES.txt b/istio-1.3.5/install/kubernetes/helm/istio/charts/certmanager/templates/NOTES.txt new file mode 100644 index 0000000..0307ede --- /dev/null +++ b/istio-1.3.5/install/kubernetes/helm/istio/charts/certmanager/templates/NOTES.txt @@ -0,0 +1,6 @@ +certmanager has been deployed successfully! + +More information on the different types of issuers and how to configure them +can be found in our documentation: + +https://cert-manager.readthedocs.io/en/latest/reference/issuers.html \ No newline at end of file diff --git a/istio-1.3.5/install/kubernetes/helm/istio/charts/certmanager/templates/_helpers.tpl b/istio-1.3.5/install/kubernetes/helm/istio/charts/certmanager/templates/_helpers.tpl new file mode 100644 index 0000000..331a91d --- /dev/null +++ b/istio-1.3.5/install/kubernetes/helm/istio/charts/certmanager/templates/_helpers.tpl @@ -0,0 +1,32 @@ +{{/* vim: set filetype=mustache: */}} +{{/* +Expand the name of the chart. +*/}} +{{- define "certmanager.name" -}} +{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" -}} +{{- end -}} + +{{/* +Create a default fully qualified app name. +We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). +If release name contains chart name it will be used as a full name. +*/}} +{{- define "certmanager.fullname" -}} +{{- if .Values.fullnameOverride -}} +{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" -}} +{{- else -}} +{{- $name := default .Chart.Name .Values.nameOverride -}} +{{- if contains $name .Release.Name -}} +{{- .Release.Name | trunc 63 | trimSuffix "-" -}} +{{- else -}} +{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" -}} +{{- end -}} +{{- end -}} +{{- end -}} + +{{/* +Create chart name and version as used by the chart label. +*/}} +{{- define "certmanager.chart" -}} +{{- .Chart.Name | trunc 63 | trimSuffix "-" -}} +{{- end -}} diff --git a/istio-1.3.5/install/kubernetes/helm/istio/charts/certmanager/templates/deployment.yaml b/istio-1.3.5/install/kubernetes/helm/istio/charts/certmanager/templates/deployment.yaml new file mode 100644 index 0000000..48e4731 --- /dev/null +++ b/istio-1.3.5/install/kubernetes/helm/istio/charts/certmanager/templates/deployment.yaml @@ -0,0 +1,69 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: certmanager + namespace: {{ .Release.Namespace }} + labels: + app: certmanager + chart: {{ template "certmanager.chart" . }} + heritage: {{ .Release.Service }} + release: {{ .Release.Name }} +spec: + replicas: {{ .Values.replicaCount }} + selector: + matchLabels: + app: certmanager + template: + metadata: + labels: + app: certmanager + chart: {{ template "certmanager.chart" . }} + heritage: {{ .Release.Service }} + release: {{ .Release.Name }} + {{- if .Values.podLabels }} +{{ toYaml .Values.podLabels | indent 8 }} + {{- end }} + annotations: + sidecar.istio.io/inject: "false" + {{- if .Values.podAnnotations }} +{{ toYaml .Values.podAnnotations | indent 8 }} + {{- end }} + spec: + serviceAccountName: certmanager +{{- if .Values.global.priorityClassName }} + priorityClassName: "{{ .Values.global.priorityClassName }}" +{{- end }} + containers: + - name: certmanager + image: "{{ .Values.hub }}/{{ .Values.image }}:{{ .Values.tag }}" + imagePullPolicy: {{ .Values.global.imagePullPolicy }} + args: + - --cluster-resource-namespace=$(POD_NAMESPACE) + - --leader-election-namespace=$(POD_NAMESPACE) + {{- if .Values.extraArgs }} +{{ toYaml .Values.extraArgs | indent 8 }} + {{- end }} + env: + - name: POD_NAMESPACE + valueFrom: + fieldRef: + fieldPath: metadata.namespace + resources: +{{ toYaml .Values.resources | indent 10 }} + {{- if .Values.podDnsPolicy }} + dnsPolicy: {{ .Values.podDnsPolicy }} + {{- end }} + {{- if .Values.podDnsConfig }} + dnsConfig: +{{ toYaml .Values.podDnsConfig | indent 8 }} + {{- end }} + affinity: + {{- include "nodeaffinity" . | indent 6 }} + {{- include "podAntiAffinity" . | indent 6 }} +{{- if .Values.tolerations }} + tolerations: +{{ toYaml .Values.tolerations | indent 6 }} + {{- else if .Values.global.defaultTolerations }} + tolerations: +{{ toYaml .Values.global.defaultTolerations | indent 6 }} + {{- end }} diff --git a/istio-1.3.5/install/kubernetes/helm/istio/charts/certmanager/templates/issuer.yaml b/istio-1.3.5/install/kubernetes/helm/istio/charts/certmanager/templates/issuer.yaml new file mode 100644 index 0000000..59402da --- /dev/null +++ b/istio-1.3.5/install/kubernetes/helm/istio/charts/certmanager/templates/issuer.yaml @@ -0,0 +1,37 @@ +--- +apiVersion: certmanager.k8s.io/v1alpha1 +kind: ClusterIssuer +metadata: + name: letsencrypt-staging + namespace: {{ .Release.Namespace }} + labels: + app: certmanager + chart: {{ template "certmanager.chart" . }} + heritage: {{ .Release.Service }} + release: {{ .Release.Name }} +spec: + acme: + server: https://acme-staging-v02.api.letsencrypt.org/directory + email: {{ .Values.email }} + # Name of a secret used to store the ACME account private key + privateKeySecretRef: + name: letsencrypt-staging + http01: {} +--- +apiVersion: certmanager.k8s.io/v1alpha1 +kind: ClusterIssuer +metadata: + name: letsencrypt + namespace: {{ .Release.Namespace }} + labels: + app: certmanager + chart: {{ template "certmanager.chart" . }} + heritage: {{ .Release.Service }} + release: {{ .Release.Name }} +spec: + acme: + server: https://acme-v02.api.letsencrypt.org/directory + email: {{ .Values.email }} + privateKeySecretRef: + name: letsencrypt + http01: {} diff --git a/istio-1.3.5/install/kubernetes/helm/istio/charts/certmanager/templates/poddisruptionbudget.yaml b/istio-1.3.5/install/kubernetes/helm/istio/charts/certmanager/templates/poddisruptionbudget.yaml new file mode 100644 index 0000000..b251e36 --- /dev/null +++ b/istio-1.3.5/install/kubernetes/helm/istio/charts/certmanager/templates/poddisruptionbudget.yaml @@ -0,0 +1,24 @@ +{{- if .Values.global.defaultPodDisruptionBudget.enabled }} +apiVersion: policy/v1beta1 +kind: PodDisruptionBudget +metadata: + name: certmanager + namespace: {{ .Release.Namespace }} + labels: + app: certmanager + chart: {{ template "certmanager.chart" . }} + heritage: {{ .Release.Service }} + release: {{ .Release.Name }} + version: {{ .Chart.Version }} + {{- if .Values.podLabels }} +{{ toYaml .Values.podLabels | indent 4 }} + {{- end }} +spec: +{{- if .Values.global.defaultPodDisruptionBudget.enabled }} +{{ include "podDisruptionBudget.spec" .Values.global.defaultPodDisruptionBudget }} +{{- end }} + selector: + matchLabels: + app: certmanager + release: {{ .Release.Name }} +{{- end }} diff --git a/istio-1.3.5/install/kubernetes/helm/istio/charts/certmanager/templates/rbac.yaml b/istio-1.3.5/install/kubernetes/helm/istio/charts/certmanager/templates/rbac.yaml new file mode 100644 index 0000000..b3a4ef3 --- /dev/null +++ b/istio-1.3.5/install/kubernetes/helm/istio/charts/certmanager/templates/rbac.yaml @@ -0,0 +1,37 @@ +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: certmanager + labels: + app: certmanager + chart: {{ template "certmanager.chart" . }} + heritage: {{ .Release.Service }} + release: {{ .Release.Name }} +rules: + - apiGroups: ["certmanager.k8s.io"] + resources: ["certificates", "certificates/finalizers", "issuers", "clusterissuers", "orders", "orders/finalizers", "challenges"] + verbs: ["*"] + - apiGroups: [""] + resources: ["configmaps", "secrets", "events", "services", "pods"] + verbs: ["*"] + - apiGroups: ["extensions"] + resources: ["ingresses"] + verbs: ["*"] +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: certmanager + labels: + app: certmanager + chart: {{ template "certmanager.chart" . }} + heritage: {{ .Release.Service }} + release: {{ .Release.Name }} +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: certmanager +subjects: + - name: certmanager + namespace: {{ .Release.Namespace }} + kind: ServiceAccount diff --git a/istio-1.3.5/install/kubernetes/helm/istio/charts/certmanager/templates/serviceaccount.yaml b/istio-1.3.5/install/kubernetes/helm/istio/charts/certmanager/templates/serviceaccount.yaml new file mode 100644 index 0000000..f875435 --- /dev/null +++ b/istio-1.3.5/install/kubernetes/helm/istio/charts/certmanager/templates/serviceaccount.yaml @@ -0,0 +1,16 @@ +apiVersion: v1 +kind: ServiceAccount +{{- if .Values.global.imagePullSecrets }} +imagePullSecrets: +{{- range .Values.global.imagePullSecrets }} + - name: {{ . }} +{{- end }} +{{- end }} +metadata: + name: certmanager + namespace: {{ .Release.Namespace }} + labels: + app: certmanager + chart: {{ template "certmanager.chart" . }} + heritage: {{ .Release.Service }} + release: {{ .Release.Name }} diff --git a/istio-1.3.5/install/kubernetes/helm/istio/charts/certmanager/values.yaml b/istio-1.3.5/install/kubernetes/helm/istio/charts/certmanager/values.yaml new file mode 100644 index 0000000..775cbeb --- /dev/null +++ b/istio-1.3.5/install/kubernetes/helm/istio/charts/certmanager/values.yaml @@ -0,0 +1,34 @@ +# Certmanager uses ACME to sign certificates. Since Istio gateways are +# mounting the TLS secrets the Certificate CRDs must be created in the +# istio-system namespace. Once the certificate has been created, the +# gateway must be updated by adding 'secretVolumes'. After the gateway +# restart, DestinationRules can be created using the ACME-signed certificates. +enabled: false +replicaCount: 1 +hub: quay.io/jetstack +image: cert-manager-controller +tag: v0.6.2 +resources: {} +nodeSelector: {} +tolerations: [] + +# Specify the pod anti-affinity that allows you to constrain which nodes +# your pod is eligible to be scheduled based on labels on pods that are +# already running on the node rather than based on labels on nodes. +# There are currently two types of anti-affinity: +# "requiredDuringSchedulingIgnoredDuringExecution" +# "preferredDuringSchedulingIgnoredDuringExecution" +# which denote "hard" vs. "soft" requirements, you can define your values +# in "podAntiAffinityLabelSelector" and "podAntiAffinityTermLabelSelector" +# correspondingly. +# For example: +# podAntiAffinityLabelSelector: +# - key: security +# operator: In +# values: S1,S2 +# topologyKey: "kubernetes.io/hostname" +# This pod anti-affinity rule says that the pod requires not to be scheduled +# onto a node if that node is already running a pod with label having key +# "security" and value "S1". +podAntiAffinityLabelSelector: [] +podAntiAffinityTermLabelSelector: [] diff --git a/istio-1.3.5/install/kubernetes/helm/istio/charts/galley/Chart.yaml b/istio-1.3.5/install/kubernetes/helm/istio/charts/galley/Chart.yaml new file mode 100644 index 0000000..65dfc3b --- /dev/null +++ b/istio-1.3.5/install/kubernetes/helm/istio/charts/galley/Chart.yaml @@ -0,0 +1,13 @@ +apiVersion: v1 +name: galley +version: 1.3.5 +appVersion: 1.3.5 +tillerVersion: ">=2.7.2" +description: Helm chart for galley deployment +keywords: + - istio + - galley +sources: + - http://github.com/istio/istio +engine: gotpl +icon: https://istio.io/favicons/android-192x192.png diff --git a/istio-1.3.5/install/kubernetes/helm/istio/charts/galley/templates/_helpers.tpl b/istio-1.3.5/install/kubernetes/helm/istio/charts/galley/templates/_helpers.tpl new file mode 100644 index 0000000..5d42f4a --- /dev/null +++ b/istio-1.3.5/install/kubernetes/helm/istio/charts/galley/templates/_helpers.tpl @@ -0,0 +1,32 @@ +{{/* vim: set filetype=mustache: */}} +{{/* +Expand the name of the chart. +*/}} +{{- define "galley.name" -}} +{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" -}} +{{- end -}} + +{{/* +Create a default fully qualified app name. +We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). +If release name contains chart name it will be used as a full name. +*/}} +{{- define "galley.fullname" -}} +{{- if .Values.fullnameOverride -}} +{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" -}} +{{- else -}} +{{- $name := default .Chart.Name .Values.nameOverride -}} +{{- if contains $name .Release.Name -}} +{{- .Release.Name | trunc 63 | trimSuffix "-" -}} +{{- else -}} +{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" -}} +{{- end -}} +{{- end -}} +{{- end -}} + +{{/* +Create chart name and version as used by the chart label. +*/}} +{{- define "galley.chart" -}} +{{- .Chart.Name | trunc 63 | trimSuffix "-" -}} +{{- end -}} diff --git a/istio-1.3.5/install/kubernetes/helm/istio/charts/galley/templates/clusterrole.yaml b/istio-1.3.5/install/kubernetes/helm/istio/charts/galley/templates/clusterrole.yaml new file mode 100644 index 0000000..8abc797 --- /dev/null +++ b/istio-1.3.5/install/kubernetes/helm/istio/charts/galley/templates/clusterrole.yaml @@ -0,0 +1,42 @@ +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: istio-galley-{{ .Release.Namespace }} + labels: + app: {{ template "galley.name" . }} + chart: {{ template "galley.chart" . }} + heritage: {{ .Release.Service }} + release: {{ .Release.Name }} +rules: +- apiGroups: ["admissionregistration.k8s.io"] + resources: ["validatingwebhookconfigurations"] + verbs: ["*"] +- apiGroups: ["config.istio.io"] # istio mixer CRD watcher + resources: ["*"] + verbs: ["get", "list", "watch"] +- apiGroups: ["networking.istio.io"] + resources: ["*"] + verbs: ["get", "list", "watch"] +- apiGroups: ["authentication.istio.io"] + resources: ["*"] + verbs: ["get", "list", "watch"] +- apiGroups: ["rbac.istio.io"] + resources: ["*"] + verbs: ["get", "list", "watch"] +- apiGroups: ["extensions","apps"] + resources: ["deployments"] + resourceNames: ["istio-galley"] + verbs: ["get"] +- apiGroups: [""] + resources: ["pods", "nodes", "services", "endpoints", "namespaces"] + verbs: ["get", "list", "watch"] +- apiGroups: ["extensions"] + resources: ["ingresses"] + verbs: ["get", "list", "watch"] +- apiGroups: ["extensions"] + resources: ["deployments/finalizers"] + resourceNames: ["istio-galley"] + verbs: ["update"] +- apiGroups: ["apiextensions.k8s.io"] + resources: ["customresourcedefinitions"] + verbs: ["get", "list", "watch"] diff --git a/istio-1.3.5/install/kubernetes/helm/istio/charts/galley/templates/clusterrolebinding.yaml b/istio-1.3.5/install/kubernetes/helm/istio/charts/galley/templates/clusterrolebinding.yaml new file mode 100644 index 0000000..88cde25 --- /dev/null +++ b/istio-1.3.5/install/kubernetes/helm/istio/charts/galley/templates/clusterrolebinding.yaml @@ -0,0 +1,17 @@ +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: istio-galley-admin-role-binding-{{ .Release.Namespace }} + labels: + app: {{ template "galley.name" . }} + chart: {{ template "galley.chart" . }} + heritage: {{ .Release.Service }} + release: {{ .Release.Name }} +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: istio-galley-{{ .Release.Namespace }} +subjects: + - kind: ServiceAccount + name: istio-galley-service-account + namespace: {{ .Release.Namespace }} diff --git a/istio-1.3.5/install/kubernetes/helm/istio/charts/galley/templates/configmap.yaml b/istio-1.3.5/install/kubernetes/helm/istio/charts/galley/templates/configmap.yaml new file mode 100644 index 0000000..662c960 --- /dev/null +++ b/istio-1.3.5/install/kubernetes/helm/istio/charts/galley/templates/configmap.yaml @@ -0,0 +1,16 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: istio-galley-configuration + namespace: {{ .Release.Namespace }} + labels: + app: {{ template "galley.name" . }} + chart: {{ template "galley.chart" . }} + heritage: {{ .Release.Service }} + release: {{ .Release.Name }} + istio: galley +data: +{{- if .Values.global.configValidation }} + validatingwebhookconfiguration.yaml: |- + {{- include "validatingwebhookconfiguration.yaml.tpl" . | indent 4}} +{{- end}} diff --git a/istio-1.3.5/install/kubernetes/helm/istio/charts/galley/templates/deployment.yaml b/istio-1.3.5/install/kubernetes/helm/istio/charts/galley/templates/deployment.yaml new file mode 100644 index 0000000..af417ee --- /dev/null +++ b/istio-1.3.5/install/kubernetes/helm/istio/charts/galley/templates/deployment.yaml @@ -0,0 +1,127 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: istio-galley + namespace: {{ .Release.Namespace }} + labels: + app: {{ template "galley.name" . }} + chart: {{ template "galley.chart" . }} + heritage: {{ .Release.Service }} + release: {{ .Release.Name }} + istio: galley +spec: + replicas: {{ .Values.replicaCount }} + selector: + matchLabels: + istio: galley + strategy: + rollingUpdate: + maxSurge: {{ .Values.rollingMaxSurge }} + maxUnavailable: {{ .Values.rollingMaxUnavailable }} + template: + metadata: + labels: + app: {{ template "galley.name" . }} + chart: {{ template "galley.chart" . }} + heritage: {{ .Release.Service }} + release: {{ .Release.Name }} + istio: galley + annotations: + sidecar.istio.io/inject: "false" + spec: + serviceAccountName: istio-galley-service-account +{{- if .Values.global.priorityClassName }} + priorityClassName: "{{ .Values.global.priorityClassName }}" +{{- end }} + containers: + - name: galley +{{- if contains "/" .Values.image }} + image: "{{ .Values.image }}" +{{- else }} + image: "{{ .Values.global.hub }}/{{ .Values.image }}:{{ .Values.global.tag }}" +{{- end }} + imagePullPolicy: {{ .Values.global.imagePullPolicy }} + ports: + - containerPort: 443 + - containerPort: {{ .Values.global.monitoringPort }} + - containerPort: 9901 + command: + - /usr/local/bin/galley + - server + - --meshConfigFile=/etc/mesh-config/mesh + - --livenessProbeInterval=1s + - --livenessProbePath=/healthliveness + - --readinessProbePath=/healthready + - --readinessProbeInterval=1s + - --deployment-namespace={{ .Release.Namespace }} +{{- if $.Values.global.controlPlaneSecurityEnabled}} + - --insecure=false +{{- else }} + - --insecure=true +{{- end }} +{{- if not $.Values.global.useMCP }} + - --enable-server=false +{{- end }} +{{- if not $.Values.global.configValidation }} + - --enable-validation=false +{{- end }} + - --validation-webhook-config-file + - /etc/config/validatingwebhookconfiguration.yaml + - --monitoringPort={{ .Values.global.monitoringPort }} +{{- if $.Values.global.logging.level }} + - --log_output_level={{ $.Values.global.logging.level }} +{{- end}} + volumeMounts: + - name: certs + mountPath: /etc/certs + readOnly: true + - name: config + mountPath: /etc/config + readOnly: true + - name: mesh-config + mountPath: /etc/mesh-config + readOnly: true + livenessProbe: + exec: + command: + - /usr/local/bin/galley + - probe + - --probe-path=/healthliveness + - --interval=10s + initialDelaySeconds: 5 + periodSeconds: 5 + readinessProbe: + exec: + command: + - /usr/local/bin/galley + - probe + - --probe-path=/healthready + - --interval=10s + initialDelaySeconds: 5 + periodSeconds: 5 + resources: +{{- if .Values.resources }} +{{ toYaml .Values.resources | indent 12 }} +{{- else }} +{{ toYaml .Values.global.defaultResources | indent 12 }} +{{- end }} + volumes: + - name: certs + secret: + secretName: istio.istio-galley-service-account + - name: config + configMap: + name: istio-galley-configuration + - name: mesh-config + configMap: + name: istio + affinity: + {{- include "nodeaffinity" . | indent 6 }} + {{- include "podAntiAffinity" . | indent 6 }} + {{- if .Values.tolerations }} + tolerations: +{{ toYaml .Values.tolerations | indent 6 }} + {{- else if .Values.global.defaultTolerations }} + tolerations: +{{ toYaml .Values.global.defaultTolerations | indent 6 }} + {{- end }} diff --git a/istio-1.3.5/install/kubernetes/helm/istio/charts/galley/templates/poddisruptionbudget.yaml b/istio-1.3.5/install/kubernetes/helm/istio/charts/galley/templates/poddisruptionbudget.yaml new file mode 100644 index 0000000..75bf778 --- /dev/null +++ b/istio-1.3.5/install/kubernetes/helm/istio/charts/galley/templates/poddisruptionbudget.yaml @@ -0,0 +1,22 @@ +{{- if .Values.global.defaultPodDisruptionBudget.enabled }} +apiVersion: policy/v1beta1 +kind: PodDisruptionBudget +metadata: + name: istio-galley + namespace: {{ .Release.Namespace }} + labels: + app: {{ template "galley.name" . }} + chart: {{ template "galley.chart" . }} + heritage: {{ .Release.Service }} + release: {{ .Release.Name }} + istio: galley +spec: +{{- if .Values.global.defaultPodDisruptionBudget.enabled }} +{{ include "podDisruptionBudget.spec" .Values.global.defaultPodDisruptionBudget }} +{{- end }} + selector: + matchLabels: + app: {{ template "galley.name" . }} + release: {{ .Release.Name }} + istio: galley +{{- end }} diff --git a/istio-1.3.5/install/kubernetes/helm/istio/charts/galley/templates/service.yaml b/istio-1.3.5/install/kubernetes/helm/istio/charts/galley/templates/service.yaml new file mode 100644 index 0000000..cd21fd1 --- /dev/null +++ b/istio-1.3.5/install/kubernetes/helm/istio/charts/galley/templates/service.yaml @@ -0,0 +1,21 @@ +apiVersion: v1 +kind: Service +metadata: + name: istio-galley + namespace: {{ .Release.Namespace }} + labels: + app: {{ template "galley.name" . }} + chart: {{ template "galley.chart" . }} + heritage: {{ .Release.Service }} + release: {{ .Release.Name }} + istio: galley +spec: + ports: + - port: 443 + name: https-validation + - port: {{ .Values.global.monitoringPort }} + name: http-monitoring + - port: 9901 + name: grpc-mcp + selector: + istio: galley diff --git a/istio-1.3.5/install/kubernetes/helm/istio/charts/galley/templates/serviceaccount.yaml b/istio-1.3.5/install/kubernetes/helm/istio/charts/galley/templates/serviceaccount.yaml new file mode 100644 index 0000000..1ff54c4 --- /dev/null +++ b/istio-1.3.5/install/kubernetes/helm/istio/charts/galley/templates/serviceaccount.yaml @@ -0,0 +1,16 @@ +apiVersion: v1 +kind: ServiceAccount +{{- if .Values.global.imagePullSecrets }} +imagePullSecrets: +{{- range .Values.global.imagePullSecrets }} + - name: {{ . }} +{{- end }} +{{- end }} +metadata: + name: istio-galley-service-account + namespace: {{ .Release.Namespace }} + labels: + app: {{ template "galley.name" . }} + chart: {{ template "galley.chart" . }} + heritage: {{ .Release.Service }} + release: {{ .Release.Name }} diff --git a/istio-1.3.5/install/kubernetes/helm/istio/charts/galley/templates/validatingwebhookconfiguration.yaml.tpl b/istio-1.3.5/install/kubernetes/helm/istio/charts/galley/templates/validatingwebhookconfiguration.yaml.tpl new file mode 100644 index 0000000..ce68fb8 --- /dev/null +++ b/istio-1.3.5/install/kubernetes/helm/istio/charts/galley/templates/validatingwebhookconfiguration.yaml.tpl @@ -0,0 +1,118 @@ +{{ define "validatingwebhookconfiguration.yaml.tpl" }} +apiVersion: admissionregistration.k8s.io/v1beta1 +kind: ValidatingWebhookConfiguration +metadata: + name: istio-galley + labels: + app: {{ template "galley.name" . }} + chart: {{ template "galley.chart" . }} + heritage: {{ .Release.Service }} + release: {{ .Release.Name }} + istio: galley +webhooks: + - name: pilot.validation.istio.io + clientConfig: + service: + name: istio-galley + namespace: {{ .Release.Namespace }} + path: "/admitpilot" + caBundle: "" + rules: + - operations: + - CREATE + - UPDATE + apiGroups: + - config.istio.io + apiVersions: + - v1alpha2 + resources: + - httpapispecs + - httpapispecbindings + - quotaspecs + - quotaspecbindings + - operations: + - CREATE + - UPDATE + apiGroups: + - rbac.istio.io + apiVersions: + - "*" + resources: + - "*" + - operations: + - CREATE + - UPDATE + apiGroups: + - authentication.istio.io + apiVersions: + - "*" + resources: + - "*" + - operations: + - CREATE + - UPDATE + apiGroups: + - networking.istio.io + apiVersions: + - "*" + resources: + - destinationrules + - envoyfilters + - gateways + - serviceentries + - sidecars + - virtualservices + failurePolicy: Fail + sideEffects: None + - name: mixer.validation.istio.io + clientConfig: + service: + name: istio-galley + namespace: {{ .Release.Namespace }} + path: "/admitmixer" + caBundle: "" + rules: + - operations: + - CREATE + - UPDATE + apiGroups: + - config.istio.io + apiVersions: + - v1alpha2 + resources: + - rules + - attributemanifests + - circonuses + - deniers + - fluentds + - kubernetesenvs + - listcheckers + - memquotas + - noops + - opas + - prometheuses + - rbacs + - solarwindses + - stackdrivers + - cloudwatches + - dogstatsds + - statsds + - stdios + - apikeys + - authorizations + - checknothings + # - kuberneteses + - listentries + - logentries + - metrics + - quotas + - reportnothings + - tracespans + - adapters + - handlers + - instances + - templates + - zipkins + failurePolicy: Fail + sideEffects: None +{{- end }} diff --git a/istio-1.3.5/install/kubernetes/helm/istio/charts/galley/values.yaml b/istio-1.3.5/install/kubernetes/helm/istio/charts/galley/values.yaml new file mode 100644 index 0000000..a1d3a8e --- /dev/null +++ b/istio-1.3.5/install/kubernetes/helm/istio/charts/galley/values.yaml @@ -0,0 +1,31 @@ +# +# galley configuration +# +enabled: true +replicaCount: 1 +rollingMaxSurge: 100% +rollingMaxUnavailable: 25% +image: galley +nodeSelector: {} +tolerations: [] + +# Specify the pod anti-affinity that allows you to constrain which nodes +# your pod is eligible to be scheduled based on labels on pods that are +# already running on the node rather than based on labels on nodes. +# There are currently two types of anti-affinity: +# "requiredDuringSchedulingIgnoredDuringExecution" +# "preferredDuringSchedulingIgnoredDuringExecution" +# which denote "hard" vs. "soft" requirements, you can define your values +# in "podAntiAffinityLabelSelector" and "podAntiAffinityTermLabelSelector" +# correspondingly. +# For example: +# podAntiAffinityLabelSelector: +# - key: security +# operator: In +# values: S1,S2 +# topologyKey: "kubernetes.io/hostname" +# This pod anti-affinity rule says that the pod requires not to be scheduled +# onto a node if that node is already running a pod with label having key +# "security" and value "S1". +podAntiAffinityLabelSelector: [] +podAntiAffinityTermLabelSelector: [] diff --git a/istio-1.3.5/install/kubernetes/helm/istio/charts/gateways/Chart.yaml b/istio-1.3.5/install/kubernetes/helm/istio/charts/gateways/Chart.yaml new file mode 100644 index 0000000..4dc601f --- /dev/null +++ b/istio-1.3.5/install/kubernetes/helm/istio/charts/gateways/Chart.yaml @@ -0,0 +1,15 @@ +apiVersion: v1 +name: gateways +version: 1.3.5 +appVersion: 1.3.5 +tillerVersion: ">=2.7.2" +description: Helm chart for deploying Istio gateways +keywords: + - istio + - ingressgateway + - egressgateway + - gateways +sources: + - http://github.com/istio/istio +engine: gotpl +icon: https://istio.io/favicons/android-192x192.png diff --git a/istio-1.3.5/install/kubernetes/helm/istio/charts/gateways/templates/_affinity.tpl b/istio-1.3.5/install/kubernetes/helm/istio/charts/gateways/templates/_affinity.tpl new file mode 100644 index 0000000..fbd0e9a --- /dev/null +++ b/istio-1.3.5/install/kubernetes/helm/istio/charts/gateways/templates/_affinity.tpl @@ -0,0 +1,93 @@ +{{/* affinity - https://kubernetes.io/docs/concepts/configuration/assign-pod-node/ */}} + +{{- define "gatewaynodeaffinity" }} + nodeAffinity: + requiredDuringSchedulingIgnoredDuringExecution: + {{- include "gatewayNodeAffinityRequiredDuringScheduling" . }} + preferredDuringSchedulingIgnoredDuringExecution: + {{- include "gatewayNodeAffinityPreferredDuringScheduling" . }} +{{- end }} + +{{- define "gatewayNodeAffinityRequiredDuringScheduling" }} + nodeSelectorTerms: + - matchExpressions: + - key: beta.kubernetes.io/arch + operator: In + values: + {{- range $key, $val := .root.Values.global.arch }} + {{- if gt ($val | int) 0 }} + - {{ $key | quote }} + {{- end }} + {{- end }} + {{- $nodeSelector := default .root.Values.global.defaultNodeSelector .nodeSelector -}} + {{- range $key, $val := $nodeSelector }} + - key: {{ $key }} + operator: In + values: + - {{ $val | quote }} + {{- end }} +{{- end }} + +{{- define "gatewayNodeAffinityPreferredDuringScheduling" }} + {{- range $key, $val := .root.Values.global.arch }} + {{- if gt ($val | int) 0 }} + - weight: {{ $val | int }} + preference: + matchExpressions: + - key: beta.kubernetes.io/arch + operator: In + values: + - {{ $key | quote }} + {{- end }} + {{- end }} +{{- end }} + +{{- define "gatewaypodAntiAffinity" }} +{{- if or .podAntiAffinityLabelSelector .podAntiAffinityTermLabelSelector}} + podAntiAffinity: + {{- if .podAntiAffinityLabelSelector }} + requiredDuringSchedulingIgnoredDuringExecution: + {{- include "gatewaypodAntiAffinityRequiredDuringScheduling" . }} + {{- end }} + {{- if .podAntiAffinityTermLabelSelector }} + preferredDuringSchedulingIgnoredDuringExecution: + {{- include "gatewaypodAntiAffinityPreferredDuringScheduling" . }} + {{- end }} +{{- end }} +{{- end }} + +{{- define "gatewaypodAntiAffinityRequiredDuringScheduling" }} + {{- range $index, $item := .podAntiAffinityLabelSelector }} + - labelSelector: + matchExpressions: + - key: {{ $item.key }} + operator: {{ $item.operator }} + {{- if $item.values }} + values: + {{- $vals := split "," $item.values }} + {{- range $i, $v := $vals }} + - {{ $v | quote }} + {{- end }} + {{- end }} + topologyKey: {{ $item.topologyKey }} + {{- end }} +{{- end }} + +{{- define "gatewaypodAntiAffinityPreferredDuringScheduling" }} + {{- range $index, $item := .podAntiAffinityTermLabelSelector }} + - podAffinityTerm: + labelSelector: + matchExpressions: + - key: {{ $item.key }} + operator: {{ $item.operator }} + {{- if $item.values }} + values: + {{- $vals := split "," $item.values }} + {{- range $i, $v := $vals }} + - {{ $v | quote }} + {{- end }} + {{- end }} + topologyKey: {{ $item.topologyKey }} + weight: 100 + {{- end }} +{{- end }} diff --git a/istio-1.3.5/install/kubernetes/helm/istio/charts/gateways/templates/_helpers.tpl b/istio-1.3.5/install/kubernetes/helm/istio/charts/gateways/templates/_helpers.tpl new file mode 100644 index 0000000..bfc8bc4 --- /dev/null +++ b/istio-1.3.5/install/kubernetes/helm/istio/charts/gateways/templates/_helpers.tpl @@ -0,0 +1,32 @@ +{{/* vim: set filetype=mustache: */}} +{{/* +Expand the name of the chart. +*/}} +{{- define "gateway.name" -}} +{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" -}} +{{- end -}} + +{{/* +Create a default fully qualified app name. +We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). +If release name contains chart name it will be used as a full name. +*/}} +{{- define "gateway.fullname" -}} +{{- if .Values.fullnameOverride -}} +{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" -}} +{{- else -}} +{{- $name := default .Chart.Name .Values.nameOverride -}} +{{- if contains $name .Release.Name -}} +{{- .Release.Name | trunc 63 | trimSuffix "-" -}} +{{- else -}} +{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" -}} +{{- end -}} +{{- end -}} +{{- end -}} + +{{/* +Create chart name and version as used by the chart label. +*/}} +{{- define "gateway.chart" -}} +{{- .Chart.Name | trunc 63 | trimSuffix "-" -}} +{{- end -}} diff --git a/istio-1.3.5/install/kubernetes/helm/istio/charts/gateways/templates/autoscale.yaml b/istio-1.3.5/install/kubernetes/helm/istio/charts/gateways/templates/autoscale.yaml new file mode 100644 index 0000000..2455ac3 --- /dev/null +++ b/istio-1.3.5/install/kubernetes/helm/istio/charts/gateways/templates/autoscale.yaml @@ -0,0 +1,31 @@ +{{- range $key, $spec := .Values }} +{{- if ne $key "enabled" }} +{{- if and $spec.enabled $spec.autoscaleEnabled $spec.autoscaleMin $spec.autoscaleMax }} +apiVersion: autoscaling/v2beta1 +kind: HorizontalPodAutoscaler +metadata: + name: {{ $key }} + namespace: {{ $spec.namespace | default $.Release.Namespace }} + labels: + chart: {{ template "gateway.chart" $ }} + heritage: {{ $.Release.Service }} + release: {{ $.Release.Name }} + {{- range $key, $val := $spec.labels }} + {{ $key }}: {{ $val }} + {{- end }} +spec: + maxReplicas: {{ $spec.autoscaleMax }} + minReplicas: {{ $spec.autoscaleMin }} + scaleTargetRef: + apiVersion: apps/v1 + kind: Deployment + name: {{ $key }} + metrics: + - type: Resource + resource: + name: cpu + targetAverageUtilization: {{ $spec.cpu.targetAverageUtilization }} +--- +{{- end }} +{{- end }} +{{- end }} diff --git a/istio-1.3.5/install/kubernetes/helm/istio/charts/gateways/templates/deployment.yaml b/istio-1.3.5/install/kubernetes/helm/istio/charts/gateways/templates/deployment.yaml new file mode 100644 index 0000000..4dcdef7 --- /dev/null +++ b/istio-1.3.5/install/kubernetes/helm/istio/charts/gateways/templates/deployment.yaml @@ -0,0 +1,330 @@ +{{- range $key, $spec := .Values }} +{{- if ne $key "enabled" }} +{{- if $spec.enabled }} +apiVersion: apps/v1 +kind: Deployment +metadata: + name: {{ $key }} + namespace: {{ $spec.namespace | default $.Release.Namespace }} + labels: + chart: {{ template "gateway.chart" $ }} + heritage: {{ $.Release.Service }} + release: {{ $.Release.Name }} + {{- range $key, $val := $spec.labels }} + {{ $key }}: {{ $val }} + {{- end }} +spec: +{{- if not $spec.autoscaleEnabled }} +{{- if $spec.replicaCount }} + replicas: {{ $spec.replicaCount }} +{{- else }} + replicas: 1 +{{- end }} +{{- end }} + selector: + matchLabels: + {{- range $key, $val := $spec.labels }} + {{ $key }}: {{ $val }} + {{- end }} + strategy: + rollingUpdate: + maxSurge: {{ $spec.rollingMaxSurge }} + maxUnavailable: {{ $spec.rollingMaxUnavailable }} + template: + metadata: + labels: + chart: {{ template "gateway.chart" $ }} + heritage: {{ $.Release.Service }} + release: {{ $.Release.Name }} + {{- range $key, $val := $spec.labels }} + {{ $key }}: {{ $val }} + {{- end }} + annotations: + sidecar.istio.io/inject: "false" +{{- if $spec.podAnnotations }} +{{ toYaml $spec.podAnnotations | indent 8 }} +{{ end }} + spec: + serviceAccountName: {{ $key }}-service-account +{{- if $.Values.global.priorityClassName }} + priorityClassName: "{{ $.Values.global.priorityClassName }}" +{{- end }} +{{- if $.Values.global.proxy.enableCoreDump }} + initContainers: + - name: enable-core-dump + image: {{ $.Values.global.proxy.enableCoreDumpImage }} + imagePullPolicy: {{ $.Values.global.imagePullPolicy }} + command: + - /bin/sh + args: + - -c + - sysctl -w kernel.core_pattern=/var/lib/istio/core.proxy && ulimit -c unlimited + securityContext: + privileged: true +{{- end }} + containers: +{{- if $spec.sds }} +{{- if $spec.sds.enabled }} + - name: ingress-sds +{{- if contains "/" $spec.sds.image }} + image: "{{ $spec.sds.image }}" +{{- else }} + image: "{{ $.Values.global.hub }}/{{ $spec.sds.image }}:{{ $.Values.global.tag }}" +{{- end }} + imagePullPolicy: {{ $.Values.global.imagePullPolicy }} + resources: +{{- if $spec.sds.resources }} +{{ toYaml $spec.sds.resources | indent 12 }} +{{- else }} +{{ toYaml $.Values.global.defaultResources | indent 12 }} +{{- end }} + env: + - name: "ENABLE_WORKLOAD_SDS" + value: "false" + - name: "ENABLE_INGRESS_GATEWAY_SDS" + value: "true" + - name: "INGRESS_GATEWAY_NAMESPACE" + valueFrom: + fieldRef: + apiVersion: v1 + fieldPath: metadata.namespace + volumeMounts: + - name: ingressgatewaysdsudspath + mountPath: /var/run/ingress_gateway +{{- end }} +{{- end }} + - name: istio-proxy +{{- if contains "/" $.Values.global.proxy.image }} + image: "{{ $.Values.global.proxy.image }}" +{{- else }} + image: "{{ $.Values.global.hub }}/{{ $.Values.global.proxy.image }}:{{ $.Values.global.tag }}" +{{- end }} + imagePullPolicy: {{ $.Values.global.imagePullPolicy }} + ports: + {{- range $key, $val := $spec.ports }} + - containerPort: {{ $val.port }} + {{- end }} + - containerPort: 15090 + protocol: TCP + name: http-envoy-prom + args: + - proxy + - router + - --domain + - $(POD_NAMESPACE).svc.{{ $.Values.global.proxy.clusterDomain }} + {{- if $.Values.global.proxy.logLevel }} + - --proxyLogLevel={{ $.Values.global.proxy.logLevel }} + {{- end}} + {{- if $.Values.global.proxy.componentLogLevel }} + - --proxyComponentLogLevel={{ $.Values.global.proxy.componentLogLevel }} + {{- end}} + {{- if $.Values.global.logging.level }} + - --log_output_level={{ $.Values.global.logging.level }} + {{- end}} + - --drainDuration + - '45s' #drainDuration + - --parentShutdownDuration + - '1m0s' #parentShutdownDuration + - --connectTimeout + - '10s' #connectTimeout + - --serviceCluster + - {{ $key }} + - --zipkinAddress + {{- if $.Values.global.tracer.zipkin.address }} + - {{ $.Values.global.tracer.zipkin.address }} + {{- else if $.Values.global.istioNamespace }} + - zipkin.{{ $.Values.global.istioNamespace }}:9411 + {{- else }} + - zipkin:9411 + {{- end }} + {{- if $.Values.global.proxy.envoyStatsd.enabled }} + - --statsdUdpAddress + - {{ $.Values.global.proxy.envoyStatsd.host }}:{{ $.Values.global.proxy.envoyStatsd.port }} + {{- end }} + {{- if $.Values.global.proxy.envoyMetricsService.enabled }} + - --envoyMetricsServiceAddress + - {{ $.Values.global.proxy.envoyMetricsService.host }}:{{ $.Values.global.proxy.envoyMetricsService.port }} + {{- end }} + {{- if $.Values.global.proxy.envoyAccessLogService.enabled }} + - --envoyAccessLogService + {{- with $.Values.global.proxy.envoyAccessLogService }} + - '{"address":"{{ .host }}:{{.port }}"{{ if .tlsSettings }},"tlsSettings":{{ .tlsSettings | toJson }}{{- end }}{{ if .tcpKeepalive }},"tcpKeepalive":{{ .tcpKeepalive | toJson }}{{- end }}}' + {{- end }} + {{- end }} + - --proxyAdminPort + - "15000" + - --statusPort + - "15020" + {{- if $.Values.global.controlPlaneSecurityEnabled }} + - --controlPlaneAuthPolicy + - MUTUAL_TLS + - --discoveryAddress + {{- if $.Values.global.istioNamespace }} + - istio-pilot.{{ $.Values.global.istioNamespace }}:15011 + {{- else }} + - istio-pilot:15011 + {{- end }} + {{- else }} + - --controlPlaneAuthPolicy + - NONE + - --discoveryAddress + {{- if $.Values.global.istioNamespace }} + - istio-pilot.{{ $.Values.global.istioNamespace }}:15010 + {{- else }} + - istio-pilot:15010 + {{- end }} + {{- if $spec.applicationPorts }} + - --applicationPorts + - "{{ $spec.applicationPorts }}" + {{- end }} + {{- end }} + {{- if $.Values.global.trustDomain }} + - --trust-domain={{ $.Values.global.trustDomain }} + {{- end }} + readinessProbe: + failureThreshold: 30 + httpGet: + path: /healthz/ready + port: 15020 + scheme: HTTP + initialDelaySeconds: 1 + periodSeconds: 2 + successThreshold: 1 + timeoutSeconds: 1 + resources: +{{- if $spec.resources }} +{{ toYaml $spec.resources | indent 12 }} +{{- else }} +{{ toYaml $.Values.global.defaultResources | indent 12 }} +{{- end }} + env: + - name: NODE_NAME + valueFrom: + fieldRef: + apiVersion: v1 + fieldPath: spec.nodeName + - name: POD_NAME + valueFrom: + fieldRef: + apiVersion: v1 + fieldPath: metadata.name + - name: POD_NAMESPACE + valueFrom: + fieldRef: + apiVersion: v1 + fieldPath: metadata.namespace + - name: INSTANCE_IP + valueFrom: + fieldRef: + apiVersion: v1 + fieldPath: status.podIP + - name: HOST_IP + valueFrom: + fieldRef: + apiVersion: v1 + fieldPath: status.hostIP + - name: SERVICE_ACCOUNT + valueFrom: + fieldRef: + fieldPath: spec.serviceAccountName + - name: ISTIO_META_POD_NAME + valueFrom: + fieldRef: + apiVersion: v1 + fieldPath: metadata.name + - name: ISTIO_META_CONFIG_NAMESPACE + valueFrom: + fieldRef: + fieldPath: metadata.namespace + - name: SDS_ENABLED + value: "{{ $.Values.global.sds.enabled }}" + - name: ISTIO_META_WORKLOAD_NAME + value: {{ $key }} + - name: ISTIO_META_OWNER + value: kubernetes://api/apps/v1/namespaces/{{ $spec.namespace | default $.Release.Namespace }}/deployments/{{ $key }} + {{- if $spec.sds }} + {{- if $spec.sds.enabled }} + - name: ISTIO_META_USER_SDS + value: "true" + {{- end }} + {{- end }} + {{- if $spec.env }} + {{- range $key, $val := $spec.env }} + - name: {{ $key }} + value: {{ $val }} + {{- end }} + {{- end }} + volumeMounts: + {{- if $.Values.global.sds.enabled }} + - name: sdsudspath + mountPath: /var/run/sds + readOnly: true + - name: istio-token + mountPath: /var/run/secrets/tokens + {{- end }} + {{- if $spec.sds }} + {{- if $spec.sds.enabled }} + - name: ingressgatewaysdsudspath + mountPath: /var/run/ingress_gateway + {{- end }} + {{- end }} + - name: istio-certs + mountPath: /etc/certs + readOnly: true + {{- range $spec.secretVolumes }} + - name: {{ .name }} + mountPath: {{ .mountPath | quote }} + readOnly: true + {{- end }} +{{- if $spec.additionalContainers }} +{{ toYaml $spec.additionalContainers | indent 8 }} +{{- end }} + volumes: + {{- if $spec.sds }} + {{- if $spec.sds.enabled }} + - name: ingressgatewaysdsudspath + emptyDir: {} + {{- end }} + {{- end }} + {{- if $.Values.global.sds.enabled }} + - name: sdsudspath + hostPath: + path: /var/run/sds + - name: istio-token + projected: + sources: + - serviceAccountToken: + path: istio-token + expirationSeconds: 43200 + audience: {{ $.Values.global.sds.token.aud }} + {{- end }} + - name: istio-certs + secret: + secretName: istio.{{ $key }}-service-account + optional: true + {{- range $spec.secretVolumes }} + - name: {{ .name }} + secret: + secretName: {{ .secretName | quote }} + optional: true + {{- end }} + {{- range $spec.configVolumes }} + - name: {{ .name }} + configMap: + name: {{ .configMapName | quote }} + optional: true + {{- end }} + affinity: + {{- include "gatewaynodeaffinity" (dict "root" $ "nodeSelector" $spec.nodeSelector) | indent 6 }} + {{- include "gatewaypodAntiAffinity" (dict "podAntiAffinityLabelSelector" $spec.podAntiAffinityLabelSelector "podAntiAffinityTermLabelSelector" $spec.podAntiAffinityTermLabelSelector) | indent 6 }} + {{- if $spec.tolerations }} + tolerations: +{{ toYaml $spec.tolerations | indent 6 }} + {{- else if $.Values.global.defaultTolerations }} + tolerations: +{{ toYaml $.Values.global.defaultTolerations | indent 6 }} + {{- end }} +--- +{{- end }} +{{- end }} +{{- end }} diff --git a/istio-1.3.5/install/kubernetes/helm/istio/charts/gateways/templates/poddisruptionbudget.yaml b/istio-1.3.5/install/kubernetes/helm/istio/charts/gateways/templates/poddisruptionbudget.yaml new file mode 100644 index 0000000..36a2d5a --- /dev/null +++ b/istio-1.3.5/install/kubernetes/helm/istio/charts/gateways/templates/poddisruptionbudget.yaml @@ -0,0 +1,31 @@ +{{- range $key, $spec := .Values }} +{{- if and (ne $key "enabled") }} +{{- if $spec.enabled }} +{{- if $.Values.global.defaultPodDisruptionBudget.enabled }} +apiVersion: policy/v1beta1 +kind: PodDisruptionBudget +metadata: + name: {{ $key }} + namespace: {{ $spec.namespace | default $.Release.Namespace }} + labels: + chart: {{ template "gateway.chart" $ }} + heritage: {{ $.Release.Service }} + release: {{ $.Release.Name }} + {{- range $key, $val := $spec.labels }} + {{ $key }}: {{ $val }} + {{- end }} +spec: +{{- if $.Values.global.defaultPodDisruptionBudget.enabled }} +{{ include "podDisruptionBudget.spec" $.Values.global.defaultPodDisruptionBudget }} +{{- end }} + selector: + matchLabels: + release: {{ $.Release.Name }} + {{- range $key, $val := $spec.labels }} + {{ $key }}: {{ $val }} + {{- end }} +--- +{{- end }} +{{- end }} +{{- end }} +{{- end }} diff --git a/istio-1.3.5/install/kubernetes/helm/istio/charts/gateways/templates/preconfigured.yaml b/istio-1.3.5/install/kubernetes/helm/istio/charts/gateways/templates/preconfigured.yaml new file mode 100644 index 0000000..8d3dee9 --- /dev/null +++ b/istio-1.3.5/install/kubernetes/helm/istio/charts/gateways/templates/preconfigured.yaml @@ -0,0 +1,239 @@ +{{- if .Values.global.k8sIngress.enabled }} +apiVersion: networking.istio.io/v1alpha3 +kind: Gateway +metadata: + name: istio-autogenerated-k8s-ingress + namespace: {{ .Release.Namespace }} + labels: + app: {{ template "gateway.name" . }} + chart: {{ template "gateway.chart" . }} + heritage: {{ .Release.Service }} + release: {{ .Release.Name }} +spec: + selector: + istio: {{ .Values.global.k8sIngress.gatewayName }} + servers: + - port: + number: 80 + protocol: HTTP2 + name: http + hosts: + - "*" +{{ if .Values.global.k8sIngress.enableHttps }} + - port: + number: 443 + protocol: HTTPS + name: https-default + tls: + mode: SIMPLE + serverCertificate: /etc/istio/ingress-certs/tls.crt + privateKey: /etc/istio/ingress-certs/tls.key + hosts: + - "*" +{{ end }} +--- +{{ end }} + +{{- if .Values.global.meshExpansion.enabled }} +{{- if .Values.global.meshExpansion.useILB }} +apiVersion: networking.istio.io/v1alpha3 +kind: Gateway +metadata: + name: meshexpansion-ilb-gateway + namespace: {{ .Release.Namespace }} + labels: + app: {{ template "gateway.name" . }} + chart: {{ template "gateway.chart" . }} + heritage: {{ .Release.Service }} + release: {{ .Release.Name }} +spec: + selector: + istio: ilbgateway + servers: + - port: + number: 15011 + protocol: TCP + name: tcp-pilot + hosts: + - "*" + - port: + number: 8060 + protocol: TCP + name: tcp-citadel + hosts: + - "*" + - port: + number: 15004 + name: tls-mixer + protocol: TLS + tls: + mode: AUTO_PASSTHROUGH + hosts: + - "*" +--- +{{- else }} +apiVersion: networking.istio.io/v1alpha3 +kind: Gateway +metadata: + name: meshexpansion-gateway + namespace: {{ .Release.Namespace }} + labels: + app: {{ template "gateway.name" . }} + chart: {{ template "gateway.chart" . }} + heritage: {{ .Release.Service }} + release: {{ .Release.Name }} +spec: + selector: + {{- range $key, $spec := .Values }} + {{- if eq $key "istio-ingressgateway" }} + {{- if $spec.enabled }} + {{- range $key, $val := $spec.labels }} + {{ $key }}: {{ $val }} + {{- end }} + {{- end }} + {{- end }} + {{- end }} + servers: + - port: + number: 15011 + protocol: TCP + name: tcp-pilot + hosts: + - "*" + - port: + number: 8060 + protocol: TCP + name: tcp-citadel + hosts: + - "*" + - port: + number: 15004 + name: tls-mixer + protocol: TLS + tls: + mode: AUTO_PASSTHROUGH + hosts: + - "*" +--- +{{- end }} +{{- end }} + +{{- if .Values.global.multiCluster.enabled }} +apiVersion: networking.istio.io/v1alpha3 +kind: Gateway +metadata: + name: istio-multicluster-egressgateway + namespace: {{ .Release.Namespace }} + labels: + app: {{ template "gateway.name" . }} + chart: {{ template "gateway.chart" . }} + heritage: {{ .Release.Service }} + release: {{ .Release.Name }} +spec: + selector: + {{- range $key, $spec := .Values }} + {{- if eq $key "istio-egressgateway" }} + {{- if $spec.enabled }} + {{- range $key, $val := $spec.labels }} + {{ $key }}: {{ $val }} + {{- end }} + {{- end }} + {{- end }} + {{- end }} + servers: + - hosts: + - "*.global" + port: + name: tls + number: 15443 + protocol: TLS + tls: + mode: AUTO_PASSTHROUGH +--- +apiVersion: networking.istio.io/v1alpha3 +kind: Gateway +metadata: + name: istio-multicluster-ingressgateway + namespace: {{ .Release.Namespace }} + labels: + app: {{ template "gateway.name" . }} + chart: {{ template "gateway.chart" . }} + heritage: {{ .Release.Service }} + release: {{ .Release.Name }} +spec: + selector: + {{- range $key, $spec := .Values }} + {{- if eq $key "istio-ingressgateway" }} + {{- if $spec.enabled }} + {{- range $key, $val := $spec.labels }} + {{ $key }}: {{ $val }} + {{- end }} + {{- end }} + {{- end }} + {{- end }} + servers: + - hosts: + - "*.global" + port: + name: tls + number: 15443 + protocol: TLS + tls: + mode: AUTO_PASSTHROUGH +--- +apiVersion: networking.istio.io/v1alpha3 +kind: EnvoyFilter +metadata: + name: istio-multicluster-ingressgateway + namespace: {{ .Release.Namespace }} + labels: + app: {{ template "gateway.name" . }} + chart: {{ template "gateway.chart" . }} + heritage: {{ .Release.Service }} + release: {{ .Release.Name }} +spec: + workloadLabels: + {{- range $key, $spec := .Values }} + {{- if eq $key "istio-ingressgateway" }} + {{- if $spec.enabled }} + {{- range $key, $val := $spec.labels }} + {{ $key }}: {{ $val }} + {{- end }} + {{- end }} + {{- end }} + {{- end }} + filters: + - listenerMatch: + portNumber: 15443 + listenerType: GATEWAY + insertPosition: + index: AFTER + relativeTo: envoy.filters.network.sni_cluster + filterName: envoy.filters.network.tcp_cluster_rewrite + filterType: NETWORK + filterConfig: + cluster_pattern: "\\.global$" + cluster_replacement: ".svc.{{ .Values.global.proxy.clusterDomain }}" +--- +## To ensure all traffic to *.global is using mTLS +apiVersion: networking.istio.io/v1alpha3 +kind: DestinationRule +metadata: + name: istio-multicluster-destinationrule + namespace: {{ .Release.Namespace }} + labels: + app: {{ template "gateway.name" . }} + chart: {{ template "gateway.chart" . }} + heritage: {{ .Release.Service }} + release: {{ .Release.Name }} +spec: + host: "*.global" + {{- if .Values.global.defaultConfigVisibilitySettings }} + exportTo: + - '*' + {{- end }} + trafficPolicy: + tls: + mode: ISTIO_MUTUAL +--- +{{- end }} diff --git a/istio-1.3.5/install/kubernetes/helm/istio/charts/gateways/templates/role.yaml b/istio-1.3.5/install/kubernetes/helm/istio/charts/gateways/templates/role.yaml new file mode 100644 index 0000000..37bdf3e --- /dev/null +++ b/istio-1.3.5/install/kubernetes/helm/istio/charts/gateways/templates/role.yaml @@ -0,0 +1,18 @@ +{{- range $key, $spec := .Values }} +{{- if ne $key "enabled" }} +{{- if $spec.enabled }} +{{- if ($spec.sds) and (eq $spec.sds.enabled true) }} +apiVersion: rbac.authorization.k8s.io/v1 +kind: Role +metadata: + name: {{ $key }}-sds + namespace: {{ $spec.namespace | default $.Release.Namespace }} +rules: +- apiGroups: [""] + resources: ["secrets"] + verbs: ["get", "watch", "list"] +--- +{{- end }} +{{- end }} +{{- end }} +{{- end }} diff --git a/istio-1.3.5/install/kubernetes/helm/istio/charts/gateways/templates/rolebindings.yaml b/istio-1.3.5/install/kubernetes/helm/istio/charts/gateways/templates/rolebindings.yaml new file mode 100644 index 0000000..cd3245b --- /dev/null +++ b/istio-1.3.5/install/kubernetes/helm/istio/charts/gateways/templates/rolebindings.yaml @@ -0,0 +1,21 @@ +{{- range $key, $spec := .Values }} +{{- if ne $key "enabled" }} +{{- if $spec.enabled }} +{{- if ($spec.sds) and (eq $spec.sds.enabled true) }} +apiVersion: rbac.authorization.k8s.io/v1 +kind: RoleBinding +metadata: + name: {{ $key }}-sds + namespace: {{ $spec.namespace | default $.Release.Namespace }} +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: Role + name: {{ $key }}-sds +subjects: +- kind: ServiceAccount + name: {{ $key }}-service-account +--- +{{- end }} +{{- end }} +{{- end }} +{{- end }} diff --git a/istio-1.3.5/install/kubernetes/helm/istio/charts/gateways/templates/service.yaml b/istio-1.3.5/install/kubernetes/helm/istio/charts/gateways/templates/service.yaml new file mode 100644 index 0000000..9474f04 --- /dev/null +++ b/istio-1.3.5/install/kubernetes/helm/istio/charts/gateways/templates/service.yaml @@ -0,0 +1,59 @@ +{{- range $key, $spec := .Values }} +{{- if ne $key "enabled" }} +{{- if $spec.enabled }} +apiVersion: v1 +kind: Service +metadata: + name: {{ $key }} + namespace: {{ $spec.namespace | default $.Release.Namespace }} + annotations: + {{- range $key, $val := $spec.serviceAnnotations }} + {{ $key }}: {{ $val | quote }} + {{- end }} + labels: + chart: {{ template "gateway.chart" $ }} + heritage: {{ $.Release.Service }} + release: {{ $.Release.Name }} + {{- range $key, $val := $spec.labels }} + {{ $key }}: {{ $val }} + {{- end }} +spec: +{{- if $spec.loadBalancerIP }} + loadBalancerIP: "{{ $spec.loadBalancerIP }}" +{{- end }} +{{- if $spec.loadBalancerSourceRanges }} + loadBalancerSourceRanges: +{{ toYaml $spec.loadBalancerSourceRanges | indent 4 }} +{{- end }} +{{- if $spec.externalTrafficPolicy }} + externalTrafficPolicy: {{$spec.externalTrafficPolicy }} +{{- end }} +{{- if $spec.externalIPs }} + externalIPs: +{{ toYaml $spec.externalIPs | indent 4 }} +{{- end }} + type: {{ .type }} + selector: + release: {{ $.Release.Name }} + {{- range $key, $val := $spec.labels }} + {{ $key }}: {{ $val }} + {{- end }} + ports: + {{- range $key, $val := $spec.ports }} + - + {{- range $pkey, $pval := $val }} + {{ $pkey}}: {{ $pval }} + {{- end }} + {{- end }} + {{- if $.Values.global.meshExpansion.enabled }} + {{- range $key, $val := $spec.meshExpansionPorts }} + - + {{- range $pkey, $pval := $val }} + {{ $pkey}}: {{ $pval }} + {{- end }} + {{- end }} + {{- end }} +--- +{{- end }} +{{- end }} +{{- end }} diff --git a/istio-1.3.5/install/kubernetes/helm/istio/charts/gateways/templates/serviceaccount.yaml b/istio-1.3.5/install/kubernetes/helm/istio/charts/gateways/templates/serviceaccount.yaml new file mode 100644 index 0000000..d4f6938 --- /dev/null +++ b/istio-1.3.5/install/kubernetes/helm/istio/charts/gateways/templates/serviceaccount.yaml @@ -0,0 +1,24 @@ +{{- range $key, $spec := .Values }} +{{- if ne $key "enabled" }} +{{- if $spec.enabled }} +apiVersion: v1 +kind: ServiceAccount +{{- if $.Values.global.imagePullSecrets }} +imagePullSecrets: +{{- range $.Values.global.imagePullSecrets }} + - name: {{ . }} +{{- end }} +{{- end }} +metadata: + name: {{ $key }}-service-account + namespace: {{ $spec.namespace | default $.Release.Namespace }} + labels: + app: {{ $spec.labels.app }} + chart: {{ template "gateway.chart" $ }} + heritage: {{ $.Release.Service }} + release: {{ $.Release.Name }} +--- +{{- end }} +{{- end }} +{{- end }} + diff --git a/istio-1.3.5/install/kubernetes/helm/istio/charts/gateways/values.yaml b/istio-1.3.5/install/kubernetes/helm/istio/charts/gateways/values.yaml new file mode 100644 index 0000000..2dc682a --- /dev/null +++ b/istio-1.3.5/install/kubernetes/helm/istio/charts/gateways/values.yaml @@ -0,0 +1,287 @@ +# +# Gateways Configuration +# By default (if enabled) a pair of Ingress and Egress Gateways will be created for the mesh. +# You can add more gateways in addition to the defaults but make sure those are uniquely named +# and that NodePorts are not conflicting. +# Disable specifc gateway by setting the `enabled` to false. +# +enabled: true + +istio-ingressgateway: + enabled: true + # + # Secret Discovery Service (SDS) configuration for ingress gateway. + # + sds: + # If true, ingress gateway fetches credentials from SDS server to handle TLS connections. + enabled: false + # SDS server that watches kubernetes secrets and provisions credentials to ingress gateway. + # This server runs in the same pod as ingress gateway. + image: node-agent-k8s + resources: + requests: + cpu: 100m + memory: 128Mi + limits: + cpu: 2000m + memory: 1024Mi + + labels: + app: istio-ingressgateway + istio: ingressgateway + autoscaleEnabled: true + autoscaleMin: 1 + autoscaleMax: 5 + # specify replicaCount when autoscaleEnabled: false + # replicaCount: 1 + rollingMaxSurge: 100% + rollingMaxUnavailable: 25% + resources: + requests: + cpu: 100m + memory: 128Mi + limits: + cpu: 2000m + memory: 1024Mi + cpu: + targetAverageUtilization: 80 + loadBalancerIP: "" + loadBalancerSourceRanges: [] + externalIPs: [] + serviceAnnotations: {} + podAnnotations: {} + type: LoadBalancer #change to NodePort, ClusterIP or LoadBalancer if need be + #externalTrafficPolicy: Local #change to Local to preserve source IP or Cluster for default behaviour or leave commented out + ports: + ## You can add custom gateway ports + # Note that AWS ELB will by default perform health checks on the first port + # on this list. Setting this to the health check port will ensure that health + # checks always work. https://github.com/istio/istio/issues/12503 + - port: 15020 + targetPort: 15020 + name: status-port + - port: 80 + targetPort: 80 + name: http2 + nodePort: 31380 + - port: 443 + name: https + nodePort: 31390 + # Example of a port to add. Remove if not needed + - port: 31400 + name: tcp + nodePort: 31400 + ### PORTS FOR UI/metrics ##### + ## Disable if not needed + - port: 15029 + targetPort: 15029 + name: https-kiali + - port: 15030 + targetPort: 15030 + name: https-prometheus + - port: 15031 + targetPort: 15031 + name: https-grafana + - port: 15032 + targetPort: 15032 + name: https-tracing + # This is the port where sni routing happens + - port: 15443 + targetPort: 15443 + name: tls + #### MESH EXPANSION PORTS ######## + # Pilot and Citadel MTLS ports are enabled in gateway - but will only redirect + # to pilot/citadel if global.meshExpansion settings are enabled. + # Delete these ports if mesh expansion is not enabled, to avoid + # exposing unnecessary ports on the web. + # You can remove these ports if you are not using mesh expansion + meshExpansionPorts: + - port: 15011 + targetPort: 15011 + name: tcp-pilot-grpc-tls + - port: 15004 + targetPort: 15004 + name: tcp-mixer-grpc-tls + - port: 8060 + targetPort: 8060 + name: tcp-citadel-grpc-tls + - port: 853 + targetPort: 853 + name: tcp-dns-tls + ####### end MESH EXPANSION PORTS ###### + ############## + secretVolumes: + - name: ingressgateway-certs + secretName: istio-ingressgateway-certs + mountPath: /etc/istio/ingressgateway-certs + - name: ingressgateway-ca-certs + secretName: istio-ingressgateway-ca-certs + mountPath: /etc/istio/ingressgateway-ca-certs + ### Advanced options ############ + + # Ports to explicitly check for readiness. If configured, the readiness check will expect a + # listener on these ports. A comma separated list is expected, such as "80,443". + # + # Warning: If you do not have a gateway configured for the ports provided, this check will always + # fail. This is intended for use cases where you always expect to have a listener on the port, + # such as 80 or 443 in typical setups. + applicationPorts: "" + + env: + # A gateway with this mode ensures that pilot generates an additional + # set of clusters for internal services but without Istio mTLS, to + # enable cross cluster routing. + ISTIO_META_ROUTER_MODE: "sni-dnat" + nodeSelector: {} + tolerations: [] + + # Specify the pod anti-affinity that allows you to constrain which nodes + # your pod is eligible to be scheduled based on labels on pods that are + # already running on the node rather than based on labels on nodes. + # There are currently two types of anti-affinity: + # "requiredDuringSchedulingIgnoredDuringExecution" + # "preferredDuringSchedulingIgnoredDuringExecution" + # which denote "hard" vs. "soft" requirements, you can define your values + # in "podAntiAffinityLabelSelector" and "podAntiAffinityTermLabelSelector" + # correspondingly. + # For example: + # podAntiAffinityLabelSelector: + # - key: security + # operator: In + # values: S1,S2 + # topologyKey: "kubernetes.io/hostname" + # This pod anti-affinity rule says that the pod requires not to be scheduled + # onto a node if that node is already running a pod with label having key + # "security" and value "S1". + podAntiAffinityLabelSelector: [] + podAntiAffinityTermLabelSelector: [] + +istio-egressgateway: + enabled: false + labels: + app: istio-egressgateway + istio: egressgateway + autoscaleEnabled: true + autoscaleMin: 1 + autoscaleMax: 5 + # specify replicaCount when autoscaleEnabled: false + # replicaCount: 1 + rollingMaxSurge: 100% + rollingMaxUnavailable: 25% + resources: + requests: + cpu: 100m + memory: 128Mi + limits: + cpu: 2000m + memory: 1024Mi + cpu: + targetAverageUtilization: 80 + serviceAnnotations: {} + podAnnotations: {} + type: ClusterIP #change to NodePort or LoadBalancer if need be + ports: + - port: 80 + name: http2 + - port: 443 + name: https + # This is the port where sni routing happens + - port: 15443 + targetPort: 15443 + name: tls + secretVolumes: + - name: egressgateway-certs + secretName: istio-egressgateway-certs + mountPath: /etc/istio/egressgateway-certs + - name: egressgateway-ca-certs + secretName: istio-egressgateway-ca-certs + mountPath: /etc/istio/egressgateway-ca-certs + #### Advanced options ######## + env: + # Set this to "external" if and only if you want the egress gateway to + # act as a transparent SNI gateway that routes mTLS/TLS traffic to + # external services defined using service entries, where the service + # entry has resolution set to DNS, has one or more endpoints with + # network field set to "external". By default its set to "" so that + # the egress gateway sees the same set of endpoints as the sidecars + # preserving backward compatibility + # ISTIO_META_REQUESTED_NETWORK_VIEW: "" + # A gateway with this mode ensures that pilot generates an additional + # set of clusters for internal services but without Istio mTLS, to + # enable cross cluster routing. + ISTIO_META_ROUTER_MODE: "sni-dnat" + nodeSelector: {} + tolerations: [] + + # Specify the pod anti-affinity that allows you to constrain which nodes + # your pod is eligible to be scheduled based on labels on pods that are + # already running on the node rather than based on labels on nodes. + # There are currently two types of anti-affinity: + # "requiredDuringSchedulingIgnoredDuringExecution" + # "preferredDuringSchedulingIgnoredDuringExecution" + # which denote "hard" vs. "soft" requirements, you can define your values + # in "podAntiAffinityLabelSelector" and "podAntiAffinityTermLabelSelector" + # correspondingly. + # For example: + # podAntiAffinityLabelSelector: + # - key: security + # operator: In + # values: S1,S2 + # topologyKey: "kubernetes.io/hostname" + # This pod anti-affinity rule says that the pod requires not to be scheduled + # onto a node if that node is already running a pod with label having key + # "security" and value "S1". + podAntiAffinityLabelSelector: [] + podAntiAffinityTermLabelSelector: [] + +# Mesh ILB gateway creates a gateway of type InternalLoadBalancer, +# for mesh expansion. It exposes the mtls ports for Pilot,CA as well +# as non-mtls ports to support upgrades and gradual transition. +istio-ilbgateway: + enabled: false + labels: + app: istio-ilbgateway + istio: ilbgateway + autoscaleEnabled: true + autoscaleMin: 1 + autoscaleMax: 5 + # specify replicaCount when autoscaleEnabled: false + # replicaCount: 1 + rollingMaxSurge: 100% + rollingMaxUnavailable: 25% + cpu: + targetAverageUtilization: 80 + resources: + requests: + cpu: 800m + memory: 512Mi + #limits: + # cpu: 1800m + # memory: 256Mi + loadBalancerIP: "" + serviceAnnotations: + cloud.google.com/load-balancer-type: "internal" + podAnnotations: {} + type: LoadBalancer + ports: + ## You can add custom gateway ports - google ILB default quota is 5 ports, + - port: 15011 + name: grpc-pilot-mtls + # Insecure port - only for migration from 0.8. Will be removed in 1.1 + - port: 15010 + name: grpc-pilot + - port: 8060 + targetPort: 8060 + name: tcp-citadel-grpc-tls + # Port 5353 is forwarded to kube-dns + - port: 5353 + name: tcp-dns + secretVolumes: + - name: ilbgateway-certs + secretName: istio-ilbgateway-certs + mountPath: /etc/istio/ilbgateway-certs + - name: ilbgateway-ca-certs + secretName: istio-ilbgateway-ca-certs + mountPath: /etc/istio/ilbgateway-ca-certs + nodeSelector: {} + tolerations: [] diff --git a/istio-1.3.5/install/kubernetes/helm/istio/charts/grafana/Chart.yaml b/istio-1.3.5/install/kubernetes/helm/istio/charts/grafana/Chart.yaml new file mode 100644 index 0000000..b2fb45b --- /dev/null +++ b/istio-1.3.5/install/kubernetes/helm/istio/charts/grafana/Chart.yaml @@ -0,0 +1,6 @@ +apiVersion: v1 +description: A Helm chart for Kubernetes +name: grafana +version: 1.3.5 +appVersion: 1.3.5 +tillerVersion: ">=2.7.2" diff --git a/istio-1.3.5/install/kubernetes/helm/istio/charts/grafana/dashboards/citadel-dashboard.json b/istio-1.3.5/install/kubernetes/helm/istio/charts/grafana/dashboards/citadel-dashboard.json new file mode 100644 index 0000000..ffe4551 --- /dev/null +++ b/istio-1.3.5/install/kubernetes/helm/istio/charts/grafana/dashboards/citadel-dashboard.json @@ -0,0 +1,1089 @@ +{ + "annotations": { + "list": [ + { + "builtIn": 1, + "datasource": "-- Grafana --", + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations & Alerts", + "type": "dashboard" + } + ] + }, + "description": "", + "editable": true, + "gnetId": null, + "graphTooltip": 0, + "links": [], + "panels": [ + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 0 + }, + "id": 8, + "panels": [], + "title": "Performance", + "type": "row" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "description": "CPU usage across Citadel instances.", + "fill": 1, + "gridPos": { + "h": 6, + "w": 8, + "x": 0, + "y": 1 + }, + "id": 10, + "legend": { + "alignAsTable": false, + "avg": false, + "current": false, + "max": false, + "min": false, + "rightSide": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(rate(container_cpu_usage_seconds_total{job=\"kubernetes-cadvisor\",container_name=~\"citadel\", pod_name=~\"istio-citadel-.*\"}[1m]))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Citadel CPU usage rate", + "refId": "A" + }, + { + "expr": "irate(process_cpu_seconds_total{job=\"citadel\"}[1m])", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Citadel CPU usage irate", + "refId": "C" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "CPU", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": "", + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "description": "Citadel process memory statistics.", + "fill": 1, + "gridPos": { + "h": 6, + "w": 8, + "x": 8, + "y": 1 + }, + "id": 12, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "process_virtual_memory_bytes{job=\"citadel\"}", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Virtual Memory", + "refId": "A" + }, + { + "expr": "process_resident_memory_bytes{job=\"citadel\"}", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Resident Memory", + "refId": "B" + }, + { + "expr": "go_memstats_heap_sys_bytes{job=\"citadel\"}", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Heap Memory Total", + "refId": "C" + }, + { + "expr": "go_memstats_alloc_bytes{job=\"citadel\"}", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Heap Memory Allocated", + "refId": "E" + }, + { + "expr": "go_memstats_heap_inuse_bytes{job=\"citadel\"}", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Heap Inuse", + "refId": "F" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Memory", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "fill": 1, + "gridPos": { + "h": 6, + "w": 8, + "x": 16, + "y": 1 + }, + "id": 14, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "go_goroutines{job=\"citadel\"}", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Goroutines", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Goroutines", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 7 + }, + "id": 28, + "panels": [], + "title": "General", + "type": "row" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "description": "Total number of CSR requests made to Citadel.", + "fill": 1, + "gridPos": { + "h": 5, + "w": 12, + "x": 0, + "y": 8 + }, + "id": 30, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "citadel_server_csr_count{job=\"citadel\"}", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "CSR Request Count", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "CSR Requests", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "description": "The number of certificates issuances that have succeeded.", + "fill": 1, + "gridPos": { + "h": 5, + "w": 12, + "x": 12, + "y": 8 + }, + "id": 32, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "citadel_server_success_cert_issuance_count{job=\"citadel\"}", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Certificates Issued", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Certificates Issued", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 13 + }, + "id": 23, + "panels": [], + "title": "Errors", + "type": "row" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "description": "The number of errors occurred when creating the CSR.", + "fill": 1, + "gridPos": { + "h": 5, + "w": 8, + "x": 0, + "y": 14 + }, + "id": 20, + "legend": { + "alignAsTable": false, + "avg": false, + "current": false, + "max": false, + "min": false, + "rightSide": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "citadel_secret_controller_csr_err_count{job=\"citadel\"}", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "CSR Creation Error Count", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "CSR Creation Errors", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": "", + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "fill": 1, + "gridPos": { + "h": 5, + "w": 8, + "x": 8, + "y": 14 + }, + "id": 24, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "citadel_server_csr_parsing_err_count{job=\"citadel\"}", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "CSR Parse Error Count", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "CSR Parse Errors", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "description": "The number of authentication failures.", + "fill": 1, + "gridPos": { + "h": 5, + "w": 8, + "x": 16, + "y": 14 + }, + "id": 26, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "citadel_server_authentication_failure_count{job=\"citadel\"}", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Authentication Failure Count", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Authentication Failures", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 19 + }, + "id": 4, + "panels": [], + "title": "Secret Controller", + "type": "row" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "description": "The number of certificates created due to service account creation.", + "fill": 1, + "gridPos": { + "h": 5, + "w": 8, + "x": 0, + "y": 20 + }, + "id": 2, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": true, + "targets": [ + { + "expr": "citadel_secret_controller_svc_acc_created_cert_count{job=\"citadel\"}", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "SA Secrets Created", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Service Account Secrets Created (due to SA creation)", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "decimals": null, + "format": "short", + "label": "Certs Created", + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "description": "The number of certificates deleted due to service account deletion.", + "fill": 1, + "gridPos": { + "h": 5, + "w": 8, + "x": 8, + "y": 20 + }, + "id": 16, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": true, + "targets": [ + { + "expr": "citadel_secret_controller_svc_acc_deleted_cert_count{job=\"citadel\"}", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "SA Secrets Deleted", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Service Account Secrets Deleted (due to SA deletion)", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "decimals": null, + "format": "short", + "label": "Certs Created", + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "description": "The number of certificates recreated due to secret deletion (service account still exists).", + "fill": 1, + "gridPos": { + "h": 5, + "w": 8, + "x": 16, + "y": 20 + }, + "id": 6, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": true, + "targets": [ + { + "expr": "citadel_secret_controller_secret_deleted_cert_count{job=\"citadel\"}", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "SA Secrets Recreated", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Service Account Secrets Recreated (due to errant deletion)", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "decimals": null, + "format": "short", + "label": "Certs Created", + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + } + ], + "refresh": "5s", + "schemaVersion": 18, + "style": "dark", + "tags": [], + "templating": { + "list": [] + }, + "time": { + "from": "now-5m", + "to": "now" + }, + "timepicker": { + "refresh_intervals": [ + "5s", + "10s", + "30s", + "1m", + "5m", + "15m", + "30m", + "1h", + "2h", + "1d" + ], + "time_options": [ + "5m", + "15m", + "1h", + "6h", + "12h", + "24h", + "2d", + "7d", + "30d" + ] + }, + "timezone": "", + "title": "Istio Citadel Dashboard", + "uid": "OOyOqb4Wz", + "version": 1 +} \ No newline at end of file diff --git a/istio-1.3.5/install/kubernetes/helm/istio/charts/grafana/dashboards/galley-dashboard.json b/istio-1.3.5/install/kubernetes/helm/istio/charts/grafana/dashboards/galley-dashboard.json new file mode 100644 index 0000000..b9b07da --- /dev/null +++ b/istio-1.3.5/install/kubernetes/helm/istio/charts/grafana/dashboards/galley-dashboard.json @@ -0,0 +1,1819 @@ +{ + "__inputs": [ + { + "name": "DS_PROMETHEUS", + "label": "Prometheus", + "description": "", + "type": "datasource", + "pluginId": "prometheus", + "pluginName": "Prometheus" + } + ], + "annotations": { + "list": [ + { + "builtIn": 1, + "datasource": "-- Grafana --", + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations & Alerts", + "type": "dashboard" + } + ] + }, + "editable": false, + "gnetId": null, + "graphTooltip": 0, + "links": [], + "panels": [ + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 5, + "w": 24, + "x": 0, + "y": 0 + }, + "id": 46, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(istio_build{component=\"galley\"}) by (tag)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{ tag }}", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Galley Versions", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 5 + }, + "id": 40, + "panels": [], + "title": "Resource Usage", + "type": "row" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 8, + "w": 6, + "x": 0, + "y": 6 + }, + "id": 36, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "process_virtual_memory_bytes{job=\"galley\"}", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "Virtual Memory", + "refId": "A" + }, + { + "expr": "process_resident_memory_bytes{job=\"galley\"}", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "Resident Memory", + "refId": "B" + }, + { + "expr": "go_memstats_heap_sys_bytes{job=\"galley\"}", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "heap sys", + "refId": "C" + }, + { + "expr": "go_memstats_heap_alloc_bytes{job=\"galley\"}", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "heap alloc", + "refId": "D" + }, + { + "expr": "go_memstats_alloc_bytes{job=\"galley\"}", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "Alloc", + "refId": "F" + }, + { + "expr": "go_memstats_heap_inuse_bytes{job=\"galley\"}", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "Heap in-use", + "refId": "G" + }, + { + "expr": "go_memstats_stack_inuse_bytes{job=\"galley\"}", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "Stack in-use", + "refId": "H" + }, + { + "expr": "sum(container_memory_usage_bytes{job=\"kubernetes-cadvisor\",container_name=~\"galley\", pod_name=~\"istio-galley-.*\"})", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Total (kis)", + "refId": "E" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Memory", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 8, + "w": 6, + "x": 6, + "y": 6 + }, + "id": 38, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(rate(container_cpu_usage_seconds_total{job=\"kubernetes-cadvisor\",container_name=~\"galley\", pod_name=~\"istio-galley-.*\"}[1m]))", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "Total (k8s)", + "refId": "A" + }, + { + "expr": "sum(rate(container_cpu_usage_seconds_total{job=\"kubernetes-cadvisor\",container_name=~\"galley\", pod_name=~\"istio-galley-.*\"}[1m])) by (container_name)", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "{{ container_name }} (k8s)", + "refId": "B" + }, + { + "expr": "irate(process_cpu_seconds_total{job=\"galley\"}[1m])", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "galley (self-reported)", + "refId": "C" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "CPU", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 8, + "w": 6, + "x": 12, + "y": 6 + }, + "id": 42, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "process_open_fds{job=\"galley\"}", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "Open FDs (galley)", + "refId": "A" + }, + { + "expr": "container_fs_usage_bytes{job=\"kubernetes-cadvisor\",container_name=~\"galley\", pod_name=~\"istio-galley-.*\"}", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "{{ container_name }} ", + "refId": "B" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Disk", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 8, + "w": 6, + "x": 18, + "y": 6 + }, + "id": 44, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "go_goroutines{job=\"galley\"}", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "goroutines_total", + "refId": "A" + }, + { + "expr": "istio_mcp_clients_total{component=\"galley\"}", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "clients_total", + "refId": "B" + }, + { + "expr": "go_goroutines{job=\"galley\"}/sum(istio_mcp_clients_total{component=\"galley\"}) without (component)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "avg_goroutines_per_client", + "refId": "C" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Goroutines", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 14 + }, + "id": 10, + "panels": [], + "title": "Runtime", + "type": "row" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 6, + "w": 8, + "x": 0, + "y": 15 + }, + "id": 2, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(rate(galley_runtime_strategy_on_change_total[1m])) * 60", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Strategy Change Events", + "refId": "A" + }, + { + "expr": "sum(rate(galley_runtime_processor_events_processed_total[1m])) * 60", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Processed Events", + "refId": "B" + }, + { + "expr": "sum(rate(galley_runtime_processor_snapshots_published_total[1m])) * 60", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Snapshot Published", + "refId": "C" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Event Rates", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": "Events/min", + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": "", + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 6, + "w": 8, + "x": 8, + "y": 15 + }, + "id": 4, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(rate(galley_runtime_strategy_timer_max_time_reached_total[1m])) * 60", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Max Time Reached", + "refId": "A" + }, + { + "expr": "sum(rate(galley_runtime_strategy_timer_quiesce_reached_total[1m])) * 60", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Quiesce Reached", + "refId": "B" + }, + { + "expr": "sum(rate(galley_runtime_strategy_timer_resets_total[1m])) * 60", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Timer Resets", + "refId": "C" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Timer Rates", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": "Events/min", + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 6, + "w": 8, + "x": 16, + "y": 15 + }, + "id": 8, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 3, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": true, + "steppedLine": false, + "targets": [ + { + "expr": "histogram_quantile(0.50, sum by (le) (galley_runtime_processor_snapshot_events_total_bucket))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "P50", + "refId": "A" + }, + { + "expr": "histogram_quantile(0.90, sum by (le) (galley_runtime_processor_snapshot_events_total_bucket))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "P90", + "refId": "B" + }, + { + "expr": "histogram_quantile(0.95, sum by (le) (galley_runtime_processor_snapshot_events_total_bucket))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "P95", + "refId": "C" + }, + { + "expr": "histogram_quantile(0.99, sum by (le) (galley_runtime_processor_snapshot_events_total_bucket))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "P99", + "refId": "D" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Events Per Snapshot", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 6, + "w": 8, + "x": 8, + "y": 21 + }, + "id": 6, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum by (typeURL) (galley_runtime_state_type_instances_total)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{ typeURL }}", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "State Type Instances", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": "Count", + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 27 + }, + "id": 34, + "panels": [], + "title": "Validation", + "type": "row" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 6, + "w": 8, + "x": 0, + "y": 28 + }, + "id": 28, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "galley_validation_cert_key_updates{job=\"galley\"}", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Key Updates", + "refId": "A" + }, + { + "expr": "galley_validation_cert_key_update_errors{job=\"galley\"}", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Key Update Errors: {{ error }}", + "refId": "B" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Validation Webhook Certificate", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 6, + "w": 8, + "x": 8, + "y": 28 + }, + "id": 30, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(galley_validation_passed{job=\"galley\"}) by (group, version, resource)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Passed: {{ group }}/{{ version }}/{{resource}}", + "refId": "A" + }, + { + "expr": "sum(galley_validation_failed{job=\"galley\"}) by (group, version, resource, reason)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Failed: {{ group }}/{{ version }}/{{resource}} ({{ reason}})", + "refId": "B" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Resource Validation", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 6, + "w": 8, + "x": 16, + "y": 28 + }, + "id": 32, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(galley_validation_http_error{job=\"galley\"}) by (status)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{ status }}", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Validation HTTP Errors", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 34 + }, + "id": 12, + "panels": [], + "title": "Kubernetes Source", + "type": "row" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 6, + "w": 8, + "x": 0, + "y": 35 + }, + "id": 14, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "rate(galley_source_kube_event_success_total[1m]) * 60", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Success", + "refId": "A" + }, + { + "expr": "rate(galley_source_kube_event_error_total[1m]) * 60", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Error", + "refId": "B" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Source Event Rate", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": "Events/min", + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 6, + "w": 8, + "x": 8, + "y": 35 + }, + "id": 16, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "rate(galley_source_kube_dynamic_converter_success_total[1m]) * 60", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{apiVersion=\"{{apiVersion}}\",group=\"{{group}}\",kind=\"{{kind}}\"}", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Kubernetes Object Conversion Successes", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": "Conversions/min", + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 6, + "w": 8, + "x": 16, + "y": 35 + }, + "id": 24, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "rate(galley_source_kube_dynamic_converter_failure_total[1m]) * 60", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Error", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Kubernetes Object Conversion Failures", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": "Failures/min", + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 41 + }, + "id": 18, + "panels": [], + "title": "Mesh Configuration Protocol", + "type": "row" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 6, + "w": 8, + "x": 0, + "y": 42 + }, + "id": 20, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(istio_mcp_clients_total{component=\"galley\"})", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Clients", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Connected Clients", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 6, + "w": 8, + "x": 8, + "y": 42 + }, + "id": 22, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum by(collection)(irate(istio_mcp_request_acks_total{component=\"galley\"}[1m]) * 60)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Request ACKs", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": "ACKs/min", + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 6, + "w": 8, + "x": 16, + "y": 42 + }, + "id": 26, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "rate(istio_mcp_request_nacks_total{component=\"galley\"}[1m]) * 60", + "format": "time_series", + "intervalFactor": 1, + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Request NACKs", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": "NACKs/min", + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + } + ], + "refresh": "5s", + "schemaVersion": 16, + "style": "dark", + "tags": [], + "templating": { + "list": [] + }, + "time": { + "from": "now-5m", + "to": "now" + }, + "timepicker": { + "refresh_intervals": [ + "5s", + "10s", + "30s", + "1m", + "5m", + "15m", + "30m", + "1h", + "2h", + "1d" + ], + "time_options": [ + "5m", + "15m", + "1h", + "6h", + "12h", + "24h", + "2d", + "7d", + "30d" + ] + }, + "timezone": "", + "title": "Istio Galley Dashboard", + "uid": "TSEY6jLmk", + "version": 1 +} diff --git a/istio-1.3.5/install/kubernetes/helm/istio/charts/grafana/dashboards/istio-mesh-dashboard.json b/istio-1.3.5/install/kubernetes/helm/istio/charts/grafana/dashboards/istio-mesh-dashboard.json new file mode 100644 index 0000000..1662e1f --- /dev/null +++ b/istio-1.3.5/install/kubernetes/helm/istio/charts/grafana/dashboards/istio-mesh-dashboard.json @@ -0,0 +1,1225 @@ +{ + "annotations": { + "list": [ + { + "builtIn": 1, + "datasource": "-- Grafana --", + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations & Alerts", + "type": "dashboard" + } + ] + }, + "editable": false, + "gnetId": null, + "graphTooltip": 0, + "id": null, + "links": [], + "panels": [ + { + "content": "
\n
\n Istio\n
\n
\n Istio is an open platform that provides a uniform way to connect,\n manage, and \n secure microservices.\n
\n Need help? Join the Istio community.\n
\n
", + "gridPos": { + "h": 3, + "w": 24, + "x": 0, + "y": 0 + }, + "height": "50px", + "id": 13, + "links": [], + "mode": "html", + "style": { + "font-size": "18pt" + }, + "title": "", + "transparent": true, + "type": "text" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "datasource": "Prometheus", + "format": "ops", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "gridPos": { + "h": 3, + "w": 6, + "x": 0, + "y": 3 + }, + "id": 20, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": true, + "lineColor": "rgb(31, 120, 193)", + "show": true + }, + "tableColumn": "", + "targets": [ + { + "expr": "round(sum(irate(istio_requests_total{reporter=\"destination\"}[1m])), 0.001)", + "intervalFactor": 1, + "refId": "A", + "step": 4 + } + ], + "thresholds": "", + "title": "Global Request Volume", + "type": "singlestat", + "valueFontSize": "80%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "avg" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "datasource": "Prometheus", + "format": "percentunit", + "gauge": { + "maxValue": 100, + "minValue": 80, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": false + }, + "gridPos": { + "h": 3, + "w": 6, + "x": 6, + "y": 3 + }, + "id": 21, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": true, + "lineColor": "rgb(31, 120, 193)", + "show": true + }, + "tableColumn": "", + "targets": [ + { + "expr": "sum(rate(istio_requests_total{reporter=\"destination\", response_code!~\"5.*\"}[1m])) / sum(rate(istio_requests_total{reporter=\"destination\"}[1m]))", + "format": "time_series", + "intervalFactor": 1, + "refId": "A", + "step": 4 + } + ], + "thresholds": "95, 99, 99.5", + "title": "Global Success Rate (non-5xx responses)", + "type": "singlestat", + "valueFontSize": "80%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "avg" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "datasource": "Prometheus", + "format": "ops", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "gridPos": { + "h": 3, + "w": 6, + "x": 12, + "y": 3 + }, + "id": 22, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": true, + "lineColor": "rgb(31, 120, 193)", + "show": true + }, + "tableColumn": "", + "targets": [ + { + "expr": "sum(irate(istio_requests_total{reporter=\"destination\", response_code=~\"4.*\"}[1m])) ", + "format": "time_series", + "intervalFactor": 1, + "refId": "A", + "step": 4 + } + ], + "thresholds": "", + "title": "4xxs", + "type": "singlestat", + "valueFontSize": "80%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "avg" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "datasource": "Prometheus", + "format": "ops", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "gridPos": { + "h": 3, + "w": 6, + "x": 18, + "y": 3 + }, + "id": 23, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": true, + "lineColor": "rgb(31, 120, 193)", + "show": true + }, + "tableColumn": "", + "targets": [ + { + "expr": "sum(irate(istio_requests_total{reporter=\"destination\", response_code=~\"5.*\"}[1m])) ", + "format": "time_series", + "intervalFactor": 1, + "refId": "A", + "step": 4 + } + ], + "thresholds": "", + "title": "5xxs", + "type": "singlestat", + "valueFontSize": "80%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "avg" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "#299c46", + "rgba(237, 129, 40, 0.89)", + "#d44a3a" + ], + "format": "none", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "gridPos": { + "h": 3, + "w": 6, + "x": 0, + "y": 6 + }, + "id": 113, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": false, + "lineColor": "rgb(31, 120, 193)", + "show": true + }, + "tableColumn": "", + "targets": [ + { + "expr": "sum(galley_istio_networking_virtualservices) / count(up{job=\"galley\"})", + "format": "time_series", + "intervalFactor": 1, + "refId": "A" + } + ], + "thresholds": "", + "timeFrom": null, + "timeShift": null, + "title": "Virtual Services", + "type": "singlestat", + "valueFontSize": "80%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "current" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "#299c46", + "rgba(237, 129, 40, 0.89)", + "#d44a3a" + ], + "format": "none", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "gridPos": { + "h": 3, + "w": 6, + "x": 6, + "y": 6 + }, + "id": 114, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": false, + "lineColor": "rgb(31, 120, 193)", + "show": true + }, + "tableColumn": "", + "targets": [ + { + "expr": "sum(galley_istio_networking_destinationrules) / count(up{job=\"galley\"})", + "format": "time_series", + "intervalFactor": 1, + "refId": "A" + } + ], + "thresholds": "", + "timeFrom": null, + "timeShift": null, + "title": "Destination Rules", + "type": "singlestat", + "valueFontSize": "80%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "current" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "#299c46", + "rgba(237, 129, 40, 0.89)", + "#d44a3a" + ], + "format": "none", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "gridPos": { + "h": 3, + "w": 6, + "x": 12, + "y": 6 + }, + "id": 115, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": false, + "lineColor": "rgb(31, 120, 193)", + "show": true + }, + "tableColumn": "", + "targets": [ + { + "expr": "sum(galley_istio_networking_gateways) / count(up{job=\"galley\"})", + "format": "time_series", + "intervalFactor": 1, + "refId": "A" + } + ], + "thresholds": "", + "timeFrom": null, + "timeShift": null, + "title": "Gateways", + "type": "singlestat", + "valueFontSize": "80%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "current" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "#299c46", + "rgba(237, 129, 40, 0.89)", + "#d44a3a" + ], + "format": "none", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "gridPos": { + "h": 3, + "w": 6, + "x": 18, + "y": 6 + }, + "id": 116, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": false, + "lineColor": "rgb(31, 120, 193)", + "show": true + }, + "tableColumn": "", + "targets": [ + { + "expr": "sum(galley_istio_authentication_meshpolicies) / count(up{job=\"galley\"})", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "refId": "A" + } + ], + "thresholds": "", + "timeFrom": null, + "timeShift": null, + "title": "Authentication Mesh Policies", + "type": "singlestat", + "valueFontSize": "80%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "current" + }, + { + "columns": [], + "datasource": "Prometheus", + "fontSize": "100%", + "gridPos": { + "h": 21, + "w": 24, + "x": 0, + "y": 9 + }, + "hideTimeOverride": false, + "id": 73, + "links": [], + "pageSize": null, + "repeat": null, + "repeatDirection": "v", + "scroll": true, + "showHeader": true, + "sort": { + "col": 4, + "desc": true + }, + "styles": [ + { + "alias": "Workload", + "colorMode": null, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "link": false, + "linkTargetBlank": false, + "linkTooltip": "Workload dashboard", + "linkUrl": "/dashboard/db/istio-workload-dashboard?var-namespace=$__cell_2&var-workload=$__cell_", + "pattern": "destination_workload", + "preserveFormat": false, + "sanitize": false, + "thresholds": [], + "type": "hidden", + "unit": "short" + }, + { + "alias": "", + "colorMode": null, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "pattern": "Time", + "thresholds": [], + "type": "hidden", + "unit": "short" + }, + { + "alias": "Requests", + "colorMode": null, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "pattern": "Value #A", + "thresholds": [], + "type": "number", + "unit": "ops" + }, + { + "alias": "P50 Latency", + "colorMode": null, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "pattern": "Value #B", + "thresholds": [], + "type": "number", + "unit": "s" + }, + { + "alias": "P90 Latency", + "colorMode": null, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "pattern": "Value #D", + "thresholds": [], + "type": "number", + "unit": "s" + }, + { + "alias": "P99 Latency", + "colorMode": null, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "pattern": "Value #E", + "thresholds": [], + "type": "number", + "unit": "s" + }, + { + "alias": "Success Rate", + "colorMode": "cell", + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "pattern": "Value #F", + "thresholds": [ + ".95", + " 1.00" + ], + "type": "number", + "unit": "percentunit" + }, + { + "alias": "Workload", + "colorMode": null, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "link": true, + "linkTooltip": "$__cell dashboard", + "linkUrl": "/dashboard/db/istio-workload-dashboard?var-workload=$__cell_2&var-namespace=$__cell_3", + "pattern": "destination_workload_var", + "thresholds": [], + "type": "number", + "unit": "short" + }, + { + "alias": "Service", + "colorMode": null, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "link": true, + "linkTooltip": "$__cell dashboard", + "linkUrl": "/dashboard/db/istio-service-dashboard?var-service=$__cell", + "pattern": "destination_service", + "thresholds": [], + "type": "string", + "unit": "short" + }, + { + "alias": "", + "colorMode": null, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "pattern": "destination_workload_namespace", + "thresholds": [], + "type": "hidden", + "unit": "short" + } + ], + "targets": [ + { + "expr": "label_join(sum(rate(istio_requests_total{reporter=\"destination\", response_code=\"200\"}[1m])) by (destination_workload, destination_workload_namespace, destination_service), \"destination_workload_var\", \".\", \"destination_workload\", \"destination_workload_namespace\")", + "format": "table", + "hide": false, + "instant": true, + "intervalFactor": 1, + "legendFormat": "{{ destination_workload}}.{{ destination_workload_namespace }}", + "refId": "A" + }, + { + "expr": "label_join((histogram_quantile(0.50, sum(rate(istio_request_duration_milliseconds_bucket{reporter=\"destination\"}[1m])) by (le, destination_workload, destination_workload_namespace)) / 1000) or histogram_quantile(0.50, sum(rate(istio_request_duration_seconds_bucket{reporter=\"destination\"}[1m])) by (le, destination_workload, destination_workload_namespace)), \"destination_workload_var\", \".\", \"destination_workload\", \"destination_workload_namespace\")", + "format": "table", + "hide": false, + "instant": true, + "intervalFactor": 1, + "legendFormat": "{{ destination_workload}}.{{ destination_workload_namespace }}", + "refId": "B" + }, + { + "expr": "label_join((histogram_quantile(0.90, sum(rate(istio_request_duration_milliseconds_bucket{reporter=\"destination\"}[1m])) by (le, destination_workload, destination_workload_namespace)) / 1000) or histogram_quantile(0.90, sum(rate(istio_request_duration_seconds_bucket{reporter=\"destination\"}[1m])) by (le, destination_workload, destination_workload_namespace)), \"destination_workload_var\", \".\", \"destination_workload\", \"destination_workload_namespace\")", + "format": "table", + "hide": false, + "instant": true, + "intervalFactor": 1, + "legendFormat": "{{ destination_workload }}.{{ destination_workload_namespace }}", + "refId": "D" + }, + { + "expr": "label_join((histogram_quantile(0.99, sum(rate(istio_request_duration_milliseconds_bucket{reporter=\"destination\"}[1m])) by (le, destination_workload, destination_workload_namespace)) / 1000) or histogram_quantile(0.99, sum(rate(istio_request_duration_seconds_bucket{reporter=\"destination\"}[1m])) by (le, destination_workload, destination_workload_namespace)), \"destination_workload_var\", \".\", \"destination_workload\", \"destination_workload_namespace\")", + "format": "table", + "hide": false, + "instant": true, + "intervalFactor": 1, + "legendFormat": "{{ destination_workload }}.{{ destination_workload_namespace }}", + "refId": "E" + }, + { + "expr": "label_join((sum(rate(istio_requests_total{reporter=\"destination\", response_code!~\"5.*\"}[1m])) by (destination_workload, destination_workload_namespace) / sum(rate(istio_requests_total{reporter=\"destination\"}[1m])) by (destination_workload, destination_workload_namespace)), \"destination_workload_var\", \".\", \"destination_workload\", \"destination_workload_namespace\")", + "format": "table", + "hide": false, + "instant": true, + "interval": "", + "intervalFactor": 1, + "legendFormat": "{{ destination_workload }}.{{ destination_workload_namespace }}", + "refId": "F" + } + ], + "timeFrom": null, + "title": "HTTP/GRPC Workloads", + "transform": "table", + "type": "table" + }, + { + "columns": [], + "datasource": "Prometheus", + "fontSize": "100%", + "gridPos": { + "h": 18, + "w": 24, + "x": 0, + "y": 30 + }, + "hideTimeOverride": false, + "id": 109, + "links": [], + "pageSize": null, + "repeatDirection": "v", + "scroll": true, + "showHeader": true, + "sort": { + "col": 2, + "desc": true + }, + "styles": [ + { + "alias": "Workload", + "colorMode": null, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "link": false, + "linkTargetBlank": false, + "linkTooltip": "$__cell dashboard", + "linkUrl": "/dashboard/db/istio-tcp-workload-dashboard?var-namespace=$__cell_2&&var-workload=$__cell", + "pattern": "destination_workload", + "preserveFormat": false, + "sanitize": false, + "thresholds": [], + "type": "hidden", + "unit": "short" + }, + { + "alias": "Bytes Sent", + "colorMode": null, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "pattern": "Value #A", + "thresholds": [ + "" + ], + "type": "number", + "unit": "Bps" + }, + { + "alias": "Bytes Received", + "colorMode": null, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "pattern": "Value #C", + "thresholds": [], + "type": "number", + "unit": "Bps" + }, + { + "alias": "", + "colorMode": null, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "pattern": "Time", + "thresholds": [], + "type": "hidden", + "unit": "short" + }, + { + "alias": "Workload", + "colorMode": null, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "link": true, + "linkTooltip": "$__cell dashboard", + "linkUrl": "/dashboard/db/istio-workload-dashboard?var-namespace=$__cell_3&var-workload=$__cell_2", + "pattern": "destination_workload_var", + "thresholds": [], + "type": "string", + "unit": "short" + }, + { + "alias": "", + "colorMode": null, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "pattern": "destination_workload_namespace", + "thresholds": [], + "type": "hidden", + "unit": "short" + }, + { + "alias": "Service", + "colorMode": null, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "link": true, + "linkTooltip": "$__cell dashboard", + "linkUrl": "/dashboard/db/istio-service-dashboard?var-service=$__cell", + "pattern": "destination_service", + "thresholds": [], + "type": "number", + "unit": "short" + } + ], + "targets": [ + { + "expr": "label_join(sum(rate(istio_tcp_received_bytes_total{reporter=\"source\"}[1m])) by (destination_workload, destination_workload_namespace, destination_service), \"destination_workload_var\", \".\", \"destination_workload\", \"destination_workload_namespace\")", + "format": "table", + "hide": false, + "instant": true, + "intervalFactor": 1, + "legendFormat": "{{ destination_workload }}", + "refId": "C" + }, + { + "expr": "label_join(sum(rate(istio_tcp_sent_bytes_total{reporter=\"source\"}[1m])) by (destination_workload, destination_workload_namespace, destination_service), \"destination_workload_var\", \".\", \"destination_workload\", \"destination_workload_namespace\")", + "format": "table", + "hide": false, + "instant": true, + "intervalFactor": 1, + "legendFormat": "{{ destination_workload }}", + "refId": "A" + } + ], + "timeFrom": null, + "title": "TCP Workloads", + "transform": "table", + "type": "table" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 9, + "w": 24, + "x": 0, + "y": 48 + }, + "id": 111, + "legend": { + "alignAsTable": false, + "avg": false, + "current": false, + "max": false, + "min": false, + "rightSide": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(istio_build) by (component, tag)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{ component }}: {{ tag }}", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Istio Components by Version", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + } + ], + "refresh": "5s", + "schemaVersion": 18, + "style": "dark", + "tags": [], + "templating": { + "list": [] + }, + "time": { + "from": "now-5m", + "to": "now" + }, + "timepicker": { + "refresh_intervals": [ + "5s", + "10s", + "30s", + "1m", + "5m", + "15m", + "30m", + "1h", + "2h", + "1d" + ], + "time_options": [ + "5m", + "15m", + "1h", + "6h", + "12h", + "24h", + "2d", + "7d", + "30d" + ] + }, + "timezone": "browser", + "title": "Istio Mesh Dashboard", + "uid": "G8wLrJIZk", + "version": 5 +} diff --git a/istio-1.3.5/install/kubernetes/helm/istio/charts/grafana/dashboards/istio-performance-dashboard.json b/istio-1.3.5/install/kubernetes/helm/istio/charts/grafana/dashboards/istio-performance-dashboard.json new file mode 100644 index 0000000..3826fba --- /dev/null +++ b/istio-1.3.5/install/kubernetes/helm/istio/charts/grafana/dashboards/istio-performance-dashboard.json @@ -0,0 +1,1822 @@ +{ + "annotations": { + "list": [ + { + "builtIn": 1, + "datasource": "-- Grafana --", + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations & Alerts", + "type": "dashboard" + } + ] + }, + "editable": false, + "gnetId": null, + "graphTooltip": 0, + "id": 9, + "links": [], + "panels": [ + { + "collapsed": true, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 0 + }, + "id": 21, + "panels": [ + { + "content": "The charts on this dashboard are intended to show Istio main components cost in terms resources utilization under steady load.\n\n- **vCPU/1k rps:** shows vCPU utilization by the main Istio components normalized by 1000 requests/second. When idle or low traffic, this chart will be blank. The curve for istio-proxy refers to the services sidecars only.\n- **vCPU:** vCPU utilization by Istio components, not normalized.\n- **Memory:** memory footprint for the components. Telemetry and policy are normalized by 1k rps, and no data is shown when there is no traffic. For ingress and istio-proxy, the data is per instance.\n- **Bytes transferred/ sec:** shows the number of bytes flowing through each Istio component.\n\n\n", + "gridPos": { + "h": 6, + "w": 24, + "x": 0, + "y": 1 + }, + "id": 19, + "links": [], + "mode": "markdown", + "timeFrom": null, + "timeShift": null, + "title": "Performance Dashboard README", + "transparent": true, + "type": "text" + } + ], + "title": "Performance Dashboard Notes", + "type": "row" + }, + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 1 + }, + "id": 6, + "panels": [], + "title": "vCPU Usage", + "type": "row" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "fill": 1, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 2 + }, + "id": 4, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "(sum(irate(container_cpu_usage_seconds_total{job=\"kubernetes-cadvisor\",pod_name=~\"istio-telemetry-.*\",container_name=~\"mixer|istio-proxy\"}[1m]))/ (round(sum(irate(istio_requests_total[1m])), 0.001)/1000))/ (sum(irate(istio_requests_total{source_workload=\"istio-ingressgateway\"}[1m])) >bool 10)", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "istio-telemetry", + "refId": "A" + }, + { + "expr": "(sum(irate(container_cpu_usage_seconds_total{job=\"kubernetes-cadvisor\",pod_name=~\"istio-ingressgateway-.*\",container_name=\"istio-proxy\"}[1m])) / (round(sum(irate(istio_requests_total{source_workload=\"istio-ingressgateway\", reporter=\"source\"}[1m])), 0.001)/1000))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "istio-ingressgateway", + "refId": "B" + }, + { + "expr": "(sum(irate(container_cpu_usage_seconds_total{job=\"kubernetes-cadvisor\",namespace!=\"istio-system\",container_name=\"istio-proxy\"}[1m]))/ (round(sum(irate(istio_requests_total[1m])), 0.001)/1000))/ (sum(irate(istio_requests_total{source_workload=\"istio-ingressgateway\"}[1m])) >bool 10)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "istio-proxy", + "refId": "C" + }, + { + "expr": "(sum(irate(container_cpu_usage_seconds_total{job=\"kubernetes-cadvisor\",pod_name=~\"istio-policy-.*\",container_name=~\"mixer|istio-proxy\"}[1m]))/ (round(sum(irate(istio_requests_total[1m])), 0.001)/1000))/ (sum(irate(istio_requests_total{source_workload=\"istio-ingressgateway\"}[1m])) >bool 10)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "istio-policy", + "refId": "D" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "vCPU / 1k rps", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "fill": 1, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 2 + }, + "id": 7, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(rate(container_cpu_usage_seconds_total{job=\"kubernetes-cadvisor\",pod_name=~\"istio-telemetry-.*\",container_name=~\"mixer|istio-proxy\"}[1m]))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "istio-telemetry", + "refId": "A" + }, + { + "expr": "sum(rate(container_cpu_usage_seconds_total{job=\"kubernetes-cadvisor\",pod_name=~\"istio-ingressgateway-.*\",container_name=\"istio-proxy\"}[1m]))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "istio-ingressgateway", + "refId": "B" + }, + { + "expr": "sum(rate(container_cpu_usage_seconds_total{job=\"kubernetes-cadvisor\",namespace!=\"istio-system\",container_name=\"istio-proxy\"}[1m]))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "istio-proxy", + "refId": "C" + }, + { + "expr": "sum(rate(container_cpu_usage_seconds_total{job=\"kubernetes-cadvisor\",pod_name=~\"istio-policy-.*\",container_name=~\"mixer|istio-proxy\"}[1m]))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "istio-policy", + "refId": "D" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "vCPU", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 10 + }, + "id": 13, + "panels": [], + "title": "Memory and Data Rates", + "type": "row" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "fill": 1, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 11 + }, + "id": 902, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "(sum(container_memory_usage_bytes{job=\"kubernetes-cadvisor\",pod_name=~\"istio-telemetry-.*\"}) / (sum(irate(istio_requests_total[1m])) / 1000)) / (sum(irate(istio_requests_total{source_workload=\"istio-ingressgateway\"}[1m])) >bool 10)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "istio-telemetry / 1k rps", + "refId": "A" + }, + { + "expr": "sum(container_memory_usage_bytes{job=\"kubernetes-cadvisor\",pod_name=~\"istio-ingressgateway-.*\"}) / count(container_memory_usage_bytes{job=\"kubernetes-cadvisor\",pod_name=~\"istio-ingressgateway-.*\",container_name!=\"POD\"})", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "per istio-ingressgateway", + "refId": "B" + }, + { + "expr": "sum(container_memory_usage_bytes{job=\"kubernetes-cadvisor\",namespace!=\"istio-system\",container_name=\"istio-proxy\"}) / count(container_memory_usage_bytes{job=\"kubernetes-cadvisor\",namespace!=\"istio-system\",container_name=\"istio-proxy\"})", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "per istio proxy", + "refId": "C" + }, + { + "expr": "(sum(container_memory_usage_bytes{job=\"kubernetes-cadvisor\",pod_name=~\"istio-policy-.*\"}) / (sum(irate(istio_requests_total[1m])) / 1000))/ (sum(irate(istio_requests_total{source_workload=\"istio-ingressgateway\"}[1m])) >bool 10)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "istio-policy / 1k rps", + "refId": "D" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Memory Usage", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "bytes", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "fill": 1, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 11 + }, + "id": 11, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(irate(istio_response_bytes_sum{destination_workload=\"istio-telemetry\"}[1m])) + sum(irate(istio_request_bytes_sum{destination_workload=\"istio-telemetry\"}[1m]))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "istio-telemetry", + "refId": "A" + }, + { + "expr": "sum(irate(istio_response_bytes_sum{source_workload=\"istio-ingressgateway\", reporter=\"source\"}[1m]))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "istio-ingressgateway", + "refId": "B" + }, + { + "expr": "sum(irate(istio_response_bytes_sum{source_workload_namespace!=\"istio-system\", reporter=\"source\"}[1m])) + sum(irate(istio_response_bytes_sum{destination_workload_namespace!=\"istio-system\", reporter=\"destination\"}[1m])) + sum(irate(istio_request_bytes_sum{source_workload_namespace!=\"istio-system\", reporter=\"source\"}[1m])) + sum(irate(istio_request_bytes_sum{destination_workload_namespace!=\"istio-system\", reporter=\"destination\"}[1m]))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "istio-proxy", + "refId": "C" + }, + { + "expr": "sum(irate(istio_response_bytes_sum{destination_workload=\"istio-policy\"}[1m])) + sum(irate(istio_request_bytes_sum{destination_workload=\"istio-policy\"}[1m]))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "istio_policy", + "refId": "D" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Bytes transferred / sec", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "Bps", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 19 + }, + "id": 17, + "panels": [], + "title": "Istio Component Versions", + "type": "row" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "fill": 1, + "gridPos": { + "h": 8, + "w": 24, + "x": 0, + "y": 20 + }, + "id": 15, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(istio_build) by (component, tag)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{ component }}: {{ tag }}", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Istio Components by Version", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 31 + }, + "id": 71, + "panels": [], + "title": "Proxy Resource Usage", + "type": "row" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 7, + "w": 6, + "x": 0, + "y": 32 + }, + "id": 72, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(container_memory_usage_bytes{job=\"kubernetes-cadvisor\",container_name=\"istio-proxy\"})", + "format": "time_series", + "hide": false, + "intervalFactor": 2, + "legendFormat": "{{ container_name }} (k8s)", + "refId": "B", + "step": 2 + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Memory", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "bytes", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 7, + "w": 6, + "x": 6, + "y": 32 + }, + "id": 73, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(rate(container_cpu_usage_seconds_total{job=\"kubernetes-cadvisor\",container_name=\"istio-proxy\"}[1m]))", + "format": "time_series", + "hide": false, + "intervalFactor": 2, + "legendFormat": "Total (k8s)", + "refId": "A", + "step": 2 + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "vCPU", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 7, + "w": 6, + "x": 12, + "y": 32 + }, + "id": 702, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(container_fs_usage_bytes{job=\"kubernetes-cadvisor\", container_name=\"istio-proxy\"})", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "{{ container_name }}", + "refId": "B", + "step": 2 + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Disk", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "bytes", + "label": "", + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "decimals": null, + "format": "none", + "label": "", + "logBase": 1024, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 39 + }, + "id": 69, + "panels": [], + "title": "Pilot Resource Usage", + "type": "row" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 7, + "w": 6, + "x": 0, + "y": 40 + }, + "id": 5, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "process_virtual_memory_bytes{job=\"pilot\"}", + "format": "time_series", + "instant": false, + "intervalFactor": 2, + "legendFormat": "Virtual Memory", + "refId": "I", + "step": 2 + }, + { + "expr": "process_resident_memory_bytes{job=\"pilot\"}", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "Resident Memory", + "refId": "H", + "step": 2 + }, + { + "expr": "go_memstats_heap_sys_bytes{job=\"pilot\"}", + "format": "time_series", + "hide": true, + "intervalFactor": 2, + "legendFormat": "heap sys", + "refId": "A" + }, + { + "expr": "go_memstats_heap_alloc_bytes{job=\"pilot\"}", + "format": "time_series", + "hide": true, + "intervalFactor": 2, + "legendFormat": "heap alloc", + "refId": "D" + }, + { + "expr": "go_memstats_alloc_bytes{job=\"pilot\"}", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "Alloc", + "refId": "F", + "step": 2 + }, + { + "expr": "go_memstats_heap_inuse_bytes{job=\"pilot\"}", + "format": "time_series", + "hide": false, + "intervalFactor": 2, + "legendFormat": "Heap in-use", + "refId": "E", + "step": 2 + }, + { + "expr": "go_memstats_stack_inuse_bytes{job=\"pilot\"}", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "Stack in-use", + "refId": "G", + "step": 2 + }, + { + "expr": "sum(container_memory_usage_bytes{job=\"kubernetes-cadvisor\",container_name=~\"discovery|istio-proxy\", pod_name=~\"istio-pilot-.*\"})", + "format": "time_series", + "hide": false, + "intervalFactor": 2, + "legendFormat": "Total (k8s)", + "refId": "C", + "step": 2 + }, + { + "expr": "container_memory_usage_bytes{job=\"kubernetes-cadvisor\",container_name=~\"discovery|istio-proxy\", pod_name=~\"istio-pilot-.*\"}", + "format": "time_series", + "hide": false, + "intervalFactor": 2, + "legendFormat": "{{ container_name }} (k8s)", + "refId": "B", + "step": 2 + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Memory", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "bytes", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 7, + "w": 6, + "x": 6, + "y": 40 + }, + "id": 602, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(rate(container_cpu_usage_seconds_total{job=\"kubernetes-cadvisor\",container_name=~\"discovery|istio-proxy\", pod_name=~\"istio-pilot-.*\"}[1m]))", + "format": "time_series", + "hide": false, + "intervalFactor": 2, + "legendFormat": "Total (k8s)", + "refId": "A", + "step": 2 + }, + { + "expr": "sum(rate(container_cpu_usage_seconds_total{job=\"kubernetes-cadvisor\",container_name=~\"discovery|istio-proxy\", pod_name=~\"istio-pilot-.*\"}[1m])) by (container_name)", + "format": "time_series", + "hide": false, + "intervalFactor": 2, + "legendFormat": "{{ container_name }} (k8s)", + "refId": "B", + "step": 2 + }, + { + "expr": "irate(process_cpu_seconds_total{job=\"pilot\"}[1m])", + "format": "time_series", + "hide": false, + "intervalFactor": 2, + "legendFormat": "pilot (self-reported)", + "refId": "C", + "step": 2 + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "vCPU", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 7, + "w": 6, + "x": 12, + "y": 40 + }, + "id": 74, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "process_open_fds{job=\"pilot\"}", + "format": "time_series", + "hide": true, + "instant": false, + "interval": "", + "intervalFactor": 2, + "legendFormat": "Open FDs (pilot)", + "refId": "A" + }, + { + "expr": "container_fs_usage_bytes{job=\"kubernetes-cadvisor\", container_name=~\"discovery|istio-proxy\", pod_name=~\"istio-pilot-.*\"}", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "{{ container_name }}", + "refId": "B", + "step": 2 + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Disk", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "bytes", + "label": "", + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "decimals": null, + "format": "none", + "label": "", + "logBase": 1024, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 7, + "w": 6, + "x": 18, + "y": 40 + }, + "id": 402, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": false, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "go_goroutines{job=\"pilot\"}", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "Number of Goroutines", + "refId": "A", + "step": 2 + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Goroutines", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": "", + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 47 + }, + "id": 93, + "panels": [], + "title": "Mixer Resource Usage", + "type": "row" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 7, + "w": 6, + "x": 0, + "y": 48 + }, + "id": 94, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "process_virtual_memory_bytes{job=~\"istio-telemetry|istio-policy\"}", + "format": "time_series", + "instant": false, + "intervalFactor": 2, + "legendFormat": "Virtual Memory", + "refId": "I", + "step": 2 + }, + { + "expr": "process_resident_memory_bytes{job=~\"istio-telemetry|istio-policy\"}", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "Resident Memory", + "refId": "H", + "step": 2 + }, + { + "expr": "go_memstats_heap_sys_bytes{job=~\"istio-telemetry|istio-policy\"}", + "format": "time_series", + "hide": true, + "intervalFactor": 2, + "legendFormat": "heap sys", + "refId": "A" + }, + { + "expr": "go_memstats_heap_alloc_bytes{job=~\"istio-telemetry|istio-policy\"}", + "format": "time_series", + "hide": true, + "intervalFactor": 2, + "legendFormat": "heap alloc", + "refId": "D" + }, + { + "expr": "go_memstats_alloc_bytes{job=~\"istio-telemetry|istio-policy\"}", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "Alloc", + "refId": "F", + "step": 2 + }, + { + "expr": "go_memstats_heap_inuse_bytes{job=~\"istio-telemetry|istio-policy\"}", + "format": "time_series", + "hide": false, + "intervalFactor": 2, + "legendFormat": "Heap in-use", + "refId": "E", + "step": 2 + }, + { + "expr": "go_memstats_stack_inuse_bytes{job=~\"istio-policy|istio-telemetry\"}", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "Stack in-use", + "refId": "G", + "step": 2 + }, + { + "expr": "sum(container_memory_usage_bytes{job=\"kubernetes-cadvisor\",container_name=~\"mixer|istio-proxy\", pod_name=~\"istio-telemetry-.*\"})", + "format": "time_series", + "hide": false, + "intervalFactor": 2, + "legendFormat": "Total (k8s)", + "refId": "C", + "step": 2 + }, + { + "expr": "container_memory_usage_bytes{job=\"kubernetes-cadvisor\",container_name=~\"mixer|istio-proxy\", pod_name=~\"istio-telemetry-.*\"}", + "format": "time_series", + "hide": false, + "intervalFactor": 2, + "legendFormat": "{{ container_name }} (k8s)", + "refId": "B", + "step": 2 + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Memory", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "bytes", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 7, + "w": 6, + "x": 6, + "y": 48 + }, + "id": 95, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(rate(container_cpu_usage_seconds_total{job=\"kubernetes-cadvisor\",container_name=~\"mixer|istio-proxy\", pod_name=~\"istio-telemetry-.*\"}[1m]))", + "format": "time_series", + "hide": false, + "intervalFactor": 2, + "legendFormat": "Total (k8s)", + "refId": "A", + "step": 2 + }, + { + "expr": "sum(rate(container_cpu_usage_seconds_total{job=\"kubernetes-cadvisor\",container_name=~\"mixer|istio-proxy\", pod_name=~\"istio-telemetry-.*\"}[1m])) by (container_name)", + "format": "time_series", + "hide": false, + "intervalFactor": 2, + "legendFormat": "{{ container_name }} (k8s)", + "refId": "B", + "step": 2 + }, + { + "expr": "irate(process_cpu_seconds_total{job=~\"istio-policy|istio-telemetry\"}[1m])", + "format": "time_series", + "hide": false, + "intervalFactor": 2, + "legendFormat": "mixer (self-reported)", + "refId": "C", + "step": 2 + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "vCPU", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 7, + "w": 6, + "x": 12, + "y": 48 + }, + "id": 96, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "process_open_fds{job=~\"istio-policy|istio-telemetry\"}", + "format": "time_series", + "hide": true, + "instant": false, + "interval": "", + "intervalFactor": 2, + "legendFormat": "Open FDs (pilot)", + "refId": "A" + }, + { + "expr": "container_fs_usage_bytes{job=\"kubernetes-cadvisor\", container_name=~\"mixer|istio-proxy\", pod_name=~\"istio-telemetry-.*\"}", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "{{ container_name }}", + "refId": "B", + "step": 2 + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Disk", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "bytes", + "label": "", + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "decimals": null, + "format": "none", + "label": "", + "logBase": 1024, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 7, + "w": 6, + "x": 18, + "y": 48 + }, + "id": 97, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": false, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "go_goroutines{job=\"istio-telemetry\"}", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "Number of Goroutines", + "refId": "A", + "step": 2 + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Goroutines", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": "", + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + } + ], + "refresh": "10s", + "schemaVersion": 18, + "style": "dark", + "tags": [], + "templating": { + "list": [] + }, + "time": { + "from": "now-5m", + "to": "now" + }, + "timepicker": { + "refresh_intervals": [ + "5s", + "10s", + "30s", + "1m", + "5m", + "15m", + "30m", + "1h", + "2h", + "1d" + ], + "time_options": [ + "5m", + "15m", + "1h", + "6h", + "12h", + "24h", + "2d", + "7d", + "30d" + ] + }, + "timezone": "", + "title": "Istio Performance Dashboard", + "uid": "vu8e0VWZk", + "version": 22 +} diff --git a/istio-1.3.5/install/kubernetes/helm/istio/charts/grafana/dashboards/istio-service-dashboard.json b/istio-1.3.5/install/kubernetes/helm/istio/charts/grafana/dashboards/istio-service-dashboard.json new file mode 100644 index 0000000..f4d58a2 --- /dev/null +++ b/istio-1.3.5/install/kubernetes/helm/istio/charts/grafana/dashboards/istio-service-dashboard.json @@ -0,0 +1,2601 @@ +{ + "annotations": { + "list": [ + { + "builtIn": 1, + "datasource": "-- Grafana --", + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations & Alerts", + "type": "dashboard" + } + ] + }, + "editable": false, + "gnetId": null, + "graphTooltip": 0, + "iteration": 1536442501501, + "links": [], + "panels": [ + { + "content": "
\nSERVICE: $service\n
", + "gridPos": { + "h": 3, + "w": 24, + "x": 0, + "y": 0 + }, + "id": 89, + "links": [], + "mode": "html", + "title": "", + "transparent": true, + "type": "text" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "datasource": "Prometheus", + "format": "ops", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "gridPos": { + "h": 4, + "w": 6, + "x": 0, + "y": 3 + }, + "id": 12, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": true, + "lineColor": "rgb(31, 120, 193)", + "show": true + }, + "tableColumn": "", + "targets": [ + { + "expr": "round(sum(irate(istio_requests_total{reporter=\"source\",destination_service=~\"$service\"}[5m])), 0.001)", + "format": "time_series", + "intervalFactor": 1, + "refId": "A", + "step": 4 + } + ], + "thresholds": "", + "title": "Client Request Volume", + "transparent": false, + "type": "singlestat", + "valueFontSize": "80%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "current" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "rgba(50, 172, 45, 0.97)", + "rgba(237, 129, 40, 0.89)", + "rgba(245, 54, 54, 0.9)" + ], + "datasource": "Prometheus", + "decimals": null, + "format": "percentunit", + "gauge": { + "maxValue": 100, + "minValue": 80, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": false + }, + "gridPos": { + "h": 4, + "w": 6, + "x": 6, + "y": 3 + }, + "id": 14, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": true, + "lineColor": "rgb(31, 120, 193)", + "show": true + }, + "tableColumn": "", + "targets": [ + { + "expr": "sum(irate(istio_requests_total{reporter=\"source\",destination_service=~\"$service\",response_code!~\"5.*\"}[5m])) / sum(irate(istio_requests_total{reporter=\"source\",destination_service=~\"$service\"}[5m]))", + "format": "time_series", + "intervalFactor": 1, + "refId": "B" + } + ], + "thresholds": "95, 99, 99.5", + "title": "Client Success Rate (non-5xx responses)", + "transparent": false, + "type": "singlestat", + "valueFontSize": "80%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "avg" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 4, + "w": 6, + "x": 12, + "y": 3 + }, + "id": 87, + "legend": { + "alignAsTable": false, + "avg": false, + "current": false, + "hideEmpty": false, + "hideZero": false, + "max": false, + "min": false, + "rightSide": true, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "(histogram_quantile(0.50, sum(irate(istio_request_duration_milliseconds_bucket{reporter=\"source\",destination_service=~\"$service\"}[1m])) by (le)) / 1000) or histogram_quantile(0.50, sum(irate(istio_request_duration_seconds_bucket{reporter=\"source\",destination_service=~\"$service\"}[1m])) by (le))", + "format": "time_series", + "interval": "", + "intervalFactor": 1, + "legendFormat": "P50", + "refId": "A" + }, + { + "expr": "(histogram_quantile(0.90, sum(irate(istio_request_duration_milliseconds_bucket{reporter=\"source\",destination_service=~\"$service\"}[1m])) by (le)) / 1000) or histogram_quantile(0.90, sum(irate(istio_request_duration_seconds_bucket{reporter=\"source\",destination_service=~\"$service\"}[1m])) by (le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "P90", + "refId": "B" + }, + { + "expr": "(histogram_quantile(0.99, sum(irate(istio_request_duration_milliseconds_bucket{reporter=\"source\",destination_service=~\"$service\"}[1m])) by (le)) / 1000) or histogram_quantile(0.99, sum(irate(istio_request_duration_seconds_bucket{reporter=\"source\",destination_service=~\"$service\"}[1m])) by (le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "P99", + "refId": "C" + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Client Request Duration", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "s", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "#299c46", + "rgba(237, 129, 40, 0.89)", + "#d44a3a" + ], + "datasource": "Prometheus", + "format": "Bps", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "gridPos": { + "h": 4, + "w": 6, + "x": 18, + "y": 3 + }, + "id": 84, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": true, + "lineColor": "rgb(31, 120, 193)", + "show": true + }, + "tableColumn": "", + "targets": [ + { + "expr": "sum(irate(istio_tcp_received_bytes_total{reporter=\"source\", destination_service=~\"$service\"}[1m]))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "", + "refId": "A" + } + ], + "thresholds": "", + "title": "TCP Received Bytes", + "transparent": false, + "type": "singlestat", + "valueFontSize": "80%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "avg" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "datasource": "Prometheus", + "format": "ops", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "gridPos": { + "h": 4, + "w": 6, + "x": 0, + "y": 7 + }, + "id": 97, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": true, + "lineColor": "rgb(31, 120, 193)", + "show": true + }, + "tableColumn": "", + "targets": [ + { + "expr": "round(sum(irate(istio_requests_total{reporter=\"destination\",destination_service=~\"$service\"}[5m])), 0.001)", + "format": "time_series", + "intervalFactor": 1, + "refId": "A", + "step": 4 + } + ], + "thresholds": "", + "title": "Server Request Volume", + "transparent": false, + "type": "singlestat", + "valueFontSize": "80%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "current" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "rgba(50, 172, 45, 0.97)", + "rgba(237, 129, 40, 0.89)", + "rgba(245, 54, 54, 0.9)" + ], + "datasource": "Prometheus", + "decimals": null, + "format": "percentunit", + "gauge": { + "maxValue": 100, + "minValue": 80, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": false + }, + "gridPos": { + "h": 4, + "w": 6, + "x": 6, + "y": 7 + }, + "id": 98, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": true, + "lineColor": "rgb(31, 120, 193)", + "show": true + }, + "tableColumn": "", + "targets": [ + { + "expr": "sum(irate(istio_requests_total{reporter=\"destination\",destination_service=~\"$service\",response_code!~\"5.*\"}[5m])) / sum(irate(istio_requests_total{reporter=\"destination\",destination_service=~\"$service\"}[5m]))", + "format": "time_series", + "intervalFactor": 1, + "refId": "B" + } + ], + "thresholds": "95, 99, 99.5", + "title": "Server Success Rate (non-5xx responses)", + "transparent": false, + "type": "singlestat", + "valueFontSize": "80%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "avg" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 4, + "w": 6, + "x": 12, + "y": 7 + }, + "id": 99, + "legend": { + "alignAsTable": false, + "avg": false, + "current": false, + "hideEmpty": false, + "hideZero": false, + "max": false, + "min": false, + "rightSide": true, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "(histogram_quantile(0.50, sum(irate(istio_request_duration_milliseconds_bucket{reporter=\"destination\",destination_service=~\"$service\"}[1m])) by (le)) / 1000) or histogram_quantile(0.50, sum(irate(istio_request_duration_seconds_bucket{reporter=\"destination\",destination_service=~\"$service\"}[1m])) by (le))", + "format": "time_series", + "interval": "", + "intervalFactor": 1, + "legendFormat": "P50", + "refId": "A" + }, + { + "expr": "(histogram_quantile(0.90, sum(irate(istio_request_duration_milliseconds_bucket{reporter=\"destination\",destination_service=~\"$service\"}[1m])) by (le)) / 1000) or histogram_quantile(0.90, sum(irate(istio_request_duration_seconds_bucket{reporter=\"destination\",destination_service=~\"$service\"}[1m])) by (le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "P90", + "refId": "B" + }, + { + "expr": "(histogram_quantile(0.99, sum(irate(istio_request_duration_milliseconds_bucket{reporter=\"destination\",destination_service=~\"$service\"}[1m])) by (le)) / 1000) or histogram_quantile(0.99, sum(irate(istio_request_duration_seconds_bucket{reporter=\"destination\",destination_service=~\"$service\"}[1m])) by (le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "P99", + "refId": "C" + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Server Request Duration", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "s", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "#299c46", + "rgba(237, 129, 40, 0.89)", + "#d44a3a" + ], + "datasource": "Prometheus", + "format": "Bps", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "gridPos": { + "h": 4, + "w": 6, + "x": 18, + "y": 7 + }, + "id": 100, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": true, + "lineColor": "rgb(31, 120, 193)", + "show": true + }, + "tableColumn": "", + "targets": [ + { + "expr": "sum(irate(istio_tcp_sent_bytes_total{reporter=\"source\", destination_service=~\"$service\"}[1m])) ", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "", + "refId": "A" + } + ], + "thresholds": "", + "title": "TCP Sent Bytes", + "transparent": false, + "type": "singlestat", + "valueFontSize": "80%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "avg" + }, + { + "content": "
\nCLIENT WORKLOADS\n
", + "gridPos": { + "h": 3, + "w": 24, + "x": 0, + "y": 11 + }, + "id": 45, + "links": [], + "mode": "html", + "title": "", + "transparent": true, + "type": "text" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 0, + "gridPos": { + "h": 6, + "w": 12, + "x": 0, + "y": 14 + }, + "id": 25, + "legend": { + "avg": false, + "current": false, + "hideEmpty": true, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null as zero", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "round(sum(irate(istio_requests_total{connection_security_policy=\"mutual_tls\",destination_service=~\"$service\",reporter=\"source\",source_workload=~\"$srcwl\",source_workload_namespace=~\"$srcns\"}[5m])) by (source_workload, source_workload_namespace, response_code), 0.001)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{ source_workload }}.{{ source_workload_namespace }} : {{ response_code }} (🔐mTLS)", + "refId": "B", + "step": 2 + }, + { + "expr": "round(sum(irate(istio_requests_total{connection_security_policy!=\"mutual_tls\", destination_service=~\"$service\", reporter=\"source\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[5m])) by (source_workload, source_workload_namespace, response_code), 0.001)", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ source_workload }}.{{ source_workload_namespace }} : {{ response_code }}", + "refId": "A", + "step": 2 + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Incoming Requests by Source And Response Code", + "tooltip": { + "shared": false, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [ + "total" + ] + }, + "yaxes": [ + { + "format": "ops", + "label": null, + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 6, + "w": 12, + "x": 12, + "y": 14 + }, + "id": 26, + "legend": { + "avg": false, + "current": false, + "hideEmpty": true, + "hideZero": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(irate(istio_requests_total{reporter=\"source\", connection_security_policy=\"mutual_tls\", destination_service=~\"$service\",response_code!~\"5.*\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[5m])) by (source_workload, source_workload_namespace) / sum(irate(istio_requests_total{reporter=\"source\", connection_security_policy=\"mutual_tls\", destination_service=~\"$service\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[5m])) by (source_workload, source_workload_namespace)", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ source_workload }}.{{ source_workload_namespace }} (🔐mTLS)", + "refId": "A", + "step": 2 + }, + { + "expr": "sum(irate(istio_requests_total{reporter=\"source\", connection_security_policy!=\"mutual_tls\", destination_service=~\"$service\",response_code!~\"5.*\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[5m])) by (source_workload, source_workload_namespace) / sum(irate(istio_requests_total{reporter=\"source\", connection_security_policy!=\"mutual_tls\", destination_service=~\"$service\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[5m])) by (source_workload, source_workload_namespace)", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ source_workload }}.{{ source_workload_namespace }}", + "refId": "B", + "step": 2 + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Incoming Success Rate (non-5xx responses) By Source", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "percentunit", + "label": null, + "logBase": 1, + "max": "1.01", + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "description": "", + "fill": 1, + "gridPos": { + "h": 6, + "w": 8, + "x": 0, + "y": 20 + }, + "id": 27, + "legend": { + "alignAsTable": false, + "avg": false, + "current": false, + "hideEmpty": true, + "hideZero": false, + "max": false, + "min": false, + "rightSide": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "(histogram_quantile(0.50, sum(irate(istio_request_duration_milliseconds_bucket{reporter=\"source\", connection_security_policy=\"mutual_tls\", destination_service=~\"$service\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le)) / 1000) or histogram_quantile(0.50, sum(irate(istio_request_duration_seconds_bucket{reporter=\"source\", connection_security_policy=\"mutual_tls\", destination_service=~\"$service\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{source_workload}}.{{source_workload_namespace}} P50 (🔐mTLS)", + "refId": "D", + "step": 2 + }, + { + "expr": "(histogram_quantile(0.90, sum(irate(istio_request_duration_milliseconds_bucket{reporter=\"source\", connection_security_policy=\"mutual_tls\", destination_service=~\"$service\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le)) / 1000) or histogram_quantile(0.90, sum(irate(istio_request_duration_seconds_bucket{reporter=\"source\", connection_security_policy=\"mutual_tls\", destination_service=~\"$service\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{source_workload}}.{{source_workload_namespace}} P90 (🔐mTLS)", + "refId": "A", + "step": 2 + }, + { + "expr": "(histogram_quantile(0.95, sum(irate(istio_request_duration_milliseconds_bucket{reporter=\"source\", connection_security_policy=\"mutual_tls\", destination_service=~\"$service\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le)) / 1000) or histogram_quantile(0.95, sum(irate(istio_request_duration_seconds_bucket{reporter=\"source\", connection_security_policy=\"mutual_tls\", destination_service=~\"$service\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{source_workload}}.{{source_workload_namespace}} P95 (🔐mTLS)", + "refId": "B", + "step": 2 + }, + { + "expr": "(histogram_quantile(0.99, sum(irate(istio_request_duration_milliseconds_bucket{reporter=\"source\", connection_security_policy=\"mutual_tls\", destination_service=~\"$service\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le)) / 1000) or histogram_quantile(0.99, sum(irate(istio_request_duration_seconds_bucket{reporter=\"source\", connection_security_policy=\"mutual_tls\", destination_service=~\"$service\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{source_workload}}.{{source_workload_namespace}} P99 (🔐mTLS)", + "refId": "C", + "step": 2 + }, + { + "expr": "(histogram_quantile(0.50, sum(irate(istio_request_duration_milliseconds_bucket{reporter=\"source\", connection_security_policy!=\"mutual_tls\", destination_service=~\"$service\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le)) / 1000) or histogram_quantile(0.50, sum(irate(istio_request_duration_seconds_bucket{reporter=\"source\", connection_security_policy!=\"mutual_tls\", destination_service=~\"$service\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{source_workload}}.{{source_workload_namespace}} P50", + "refId": "E", + "step": 2 + }, + { + "expr": "(histogram_quantile(0.90, sum(irate(istio_request_duration_milliseconds_bucket{reporter=\"source\", connection_security_policy!=\"mutual_tls\", destination_service=~\"$service\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le)) / 1000) or histogram_quantile(0.90, sum(irate(istio_request_duration_seconds_bucket{reporter=\"source\", connection_security_policy!=\"mutual_tls\", destination_service=~\"$service\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{source_workload}}.{{source_workload_namespace}} P90", + "refId": "F", + "step": 2 + }, + { + "expr": "(histogram_quantile(0.95, sum(irate(istio_request_duration_milliseconds_bucket{reporter=\"source\", connection_security_policy!=\"mutual_tls\", destination_service=~\"$service\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le)) / 1000) or histogram_quantile(0.95, sum(irate(istio_request_duration_seconds_bucket{reporter=\"source\", connection_security_policy!=\"mutual_tls\", destination_service=~\"$service\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{source_workload}}.{{source_workload_namespace}} P95", + "refId": "G", + "step": 2 + }, + { + "expr": "(histogram_quantile(0.99, sum(irate(istio_request_duration_milliseconds_bucket{reporter=\"source\", connection_security_policy!=\"mutual_tls\", destination_service=~\"$service\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le)) / 1000) or histogram_quantile(0.99, sum(irate(istio_request_duration_seconds_bucket{reporter=\"source\", connection_security_policy!=\"mutual_tls\", destination_service=~\"$service\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{source_workload}}.{{source_workload_namespace}} P99", + "refId": "H", + "step": 2 + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Incoming Request Duration by Source", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "s", + "label": null, + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 6, + "w": 8, + "x": 8, + "y": 20 + }, + "id": 28, + "legend": { + "alignAsTable": false, + "avg": false, + "current": false, + "hideEmpty": true, + "max": false, + "min": false, + "rightSide": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "histogram_quantile(0.50, sum(irate(istio_request_bytes_bucket{reporter=\"source\", connection_security_policy=\"mutual_tls\", destination_service=~\"$service\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{source_workload}}.{{source_workload_namespace}} P50 (🔐mTLS)", + "refId": "D", + "step": 2 + }, + { + "expr": "histogram_quantile(0.90, sum(irate(istio_request_bytes_bucket{reporter=\"source\", connection_security_policy=\"mutual_tls\", destination_service=~\"$service\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{source_workload}}.{{source_workload_namespace}} P90 (🔐mTLS)", + "refId": "A", + "step": 2 + }, + { + "expr": "histogram_quantile(0.95, sum(irate(istio_request_bytes_bucket{reporter=\"source\", connection_security_policy=\"mutual_tls\", destination_service=~\"$service\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{source_workload}}.{{source_workload_namespace}} P95 (🔐mTLS)", + "refId": "B", + "step": 2 + }, + { + "expr": "histogram_quantile(0.99, sum(irate(istio_request_bytes_bucket{reporter=\"source\", connection_security_policy=\"mutual_tls\", destination_service=~\"$service\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{source_workload}}.{{source_workload_namespace}} P99 (🔐mTLS)", + "refId": "C", + "step": 2 + }, + { + "expr": "histogram_quantile(0.50, sum(irate(istio_request_bytes_bucket{reporter=\"source\", connection_security_policy!=\"mutual_tls\", destination_service=~\"$service\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{source_workload}}.{{source_workload_namespace}} P50", + "refId": "E", + "step": 2 + }, + { + "expr": "histogram_quantile(0.90, sum(irate(istio_request_bytes_bucket{reporter=\"source\", connection_security_policy!=\"mutual_tls\", destination_service=~\"$service\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{source_workload}}.{{source_workload_namespace}} P90", + "refId": "F", + "step": 2 + }, + { + "expr": "histogram_quantile(0.95, sum(irate(istio_request_bytes_bucket{reporter=\"source\", connection_security_policy!=\"mutual_tls\", destination_service=~\"$service\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{source_workload}}.{{source_workload_namespace}} P95", + "refId": "G", + "step": 2 + }, + { + "expr": "histogram_quantile(0.99, sum(irate(istio_request_bytes_bucket{reporter=\"source\", connection_security_policy!=\"mutual_tls\", destination_service=~\"$service\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{source_workload}}.{{source_workload_namespace}} P99", + "refId": "H", + "step": 2 + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Incoming Request Size By Source", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "decbytes", + "label": null, + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 6, + "w": 8, + "x": 16, + "y": 20 + }, + "id": 68, + "legend": { + "alignAsTable": false, + "avg": false, + "current": false, + "hideEmpty": true, + "max": false, + "min": false, + "rightSide": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "histogram_quantile(0.50, sum(irate(istio_response_bytes_bucket{reporter=\"source\", connection_security_policy=\"mutual_tls\", destination_service=~\"$service\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{source_workload}}.{{source_workload_namespace}} P50 (🔐mTLS)", + "refId": "D", + "step": 2 + }, + { + "expr": "histogram_quantile(0.90, sum(irate(istio_response_bytes_bucket{reporter=\"source\", connection_security_policy=\"mutual_tls\", destination_service=~\"$service\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{source_workload}}.{{source_workload_namespace}} P90 (🔐mTLS)", + "refId": "A", + "step": 2 + }, + { + "expr": "histogram_quantile(0.95, sum(irate(istio_response_bytes_bucket{reporter=\"source\", connection_security_policy=\"mutual_tls\", destination_service=~\"$service\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{source_workload}}.{{source_workload_namespace}} P95 (🔐mTLS)", + "refId": "B", + "step": 2 + }, + { + "expr": "histogram_quantile(0.99, sum(irate(istio_response_bytes_bucket{reporter=\"source\", connection_security_policy=\"mutual_tls\", destination_service=~\"$service\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{source_workload}}.{{source_workload_namespace}} P99 (🔐mTLS)", + "refId": "C", + "step": 2 + }, + { + "expr": "histogram_quantile(0.50, sum(irate(istio_response_bytes_bucket{reporter=\"source\", connection_security_policy!=\"mutual_tls\", destination_service=~\"$service\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{source_workload}}.{{source_workload_namespace}} P50", + "refId": "E", + "step": 2 + }, + { + "expr": "histogram_quantile(0.90, sum(irate(istio_response_bytes_bucket{reporter=\"source\", connection_security_policy!=\"mutual_tls\", destination_service=~\"$service\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{source_workload}}.{{source_workload_namespace}} P90", + "refId": "F", + "step": 2 + }, + { + "expr": "histogram_quantile(0.95, sum(irate(istio_response_bytes_bucket{reporter=\"source\", connection_security_policy!=\"mutual_tls\", destination_service=~\"$service\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{source_workload}}.{{source_workload_namespace}} P95", + "refId": "G", + "step": 2 + }, + { + "expr": "histogram_quantile(0.99, sum(irate(istio_response_bytes_bucket{reporter=\"source\", connection_security_policy!=\"mutual_tls\", destination_service=~\"$service\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{source_workload}}.{{source_workload_namespace}} P99", + "refId": "H", + "step": 2 + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Response Size By Source", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "decbytes", + "label": null, + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 6, + "w": 12, + "x": 0, + "y": 26 + }, + "id": 80, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "round(sum(irate(istio_tcp_received_bytes_total{reporter=\"source\", connection_security_policy=\"mutual_tls\", destination_service=~\"$service\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace), 0.001)", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ source_workload }}.{{ source_workload_namespace}} (🔐mTLS)", + "refId": "A", + "step": 2 + }, + { + "expr": "round(sum(irate(istio_tcp_received_bytes_total{reporter=\"source\", connection_security_policy!=\"mutual_tls\", destination_service=~\"$service\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace), 0.001)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{ source_workload }}.{{ source_workload_namespace}}", + "refId": "B", + "step": 2 + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Bytes Received from Incoming TCP Connection", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "Bps", + "label": null, + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 6, + "w": 12, + "x": 12, + "y": 26 + }, + "id": 82, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "round(sum(irate(istio_tcp_sent_bytes_total{connection_security_policy=\"mutual_tls\", reporter=\"source\", destination_service=~\"$service\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace), 0.001)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{ source_workload }}.{{ source_workload_namespace}} (🔐mTLS)", + "refId": "A", + "step": 2 + }, + { + "expr": "round(sum(irate(istio_tcp_sent_bytes_total{connection_security_policy!=\"mutual_tls\", reporter=\"source\", destination_service=~\"$service\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace), 0.001)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{ source_workload }}.{{ source_workload_namespace}}", + "refId": "B", + "step": 2 + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Bytes Sent to Incoming TCP Connection", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "Bps", + "label": null, + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "content": "
\nSERVICE WORKLOADS\n
", + "gridPos": { + "h": 3, + "w": 24, + "x": 0, + "y": 32 + }, + "id": 69, + "links": [], + "mode": "html", + "title": "", + "transparent": true, + "type": "text" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 0, + "gridPos": { + "h": 6, + "w": 12, + "x": 0, + "y": 35 + }, + "id": 90, + "legend": { + "avg": false, + "current": false, + "hideEmpty": true, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null as zero", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "round(sum(irate(istio_requests_total{connection_security_policy=\"mutual_tls\",destination_service=~\"$service\",reporter=\"destination\",destination_workload=~\"$dstwl\",destination_workload_namespace=~\"$dstns\"}[5m])) by (destination_workload, destination_workload_namespace, response_code), 0.001)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{ destination_workload }}.{{ destination_workload_namespace }} : {{ response_code }} (🔐mTLS)", + "refId": "B", + "step": 2 + }, + { + "expr": "round(sum(irate(istio_requests_total{connection_security_policy!=\"mutual_tls\", destination_service=~\"$service\", reporter=\"destination\", destination_workload=~\"$dstwl\", destination_workload_namespace=~\"$dstns\"}[5m])) by (destination_workload, destination_workload_namespace, response_code), 0.001)", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_workload }}.{{ destination_workload_namespace }} : {{ response_code }}", + "refId": "A", + "step": 2 + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Incoming Requests by Destination And Response Code", + "tooltip": { + "shared": false, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [ + "total" + ] + }, + "yaxes": [ + { + "format": "ops", + "label": null, + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 6, + "w": 12, + "x": 12, + "y": 35 + }, + "id": 91, + "legend": { + "avg": false, + "current": false, + "hideEmpty": true, + "hideZero": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(irate(istio_requests_total{reporter=\"destination\", connection_security_policy=\"mutual_tls\", destination_service=~\"$service\",response_code!~\"5.*\", destination_workload=~\"$dstwl\", destination_workload_namespace=~\"$dstns\"}[5m])) by (destination_workload, destination_workload_namespace) / sum(irate(istio_requests_total{reporter=\"destination\", connection_security_policy=\"mutual_tls\", destination_service=~\"$service\", destination_workload=~\"$dstwl\", destination_workload_namespace=~\"$dstns\"}[5m])) by (destination_workload, destination_workload_namespace)", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_workload }}.{{ destination_workload_namespace }} (🔐mTLS)", + "refId": "A", + "step": 2 + }, + { + "expr": "sum(irate(istio_requests_total{reporter=\"destination\", connection_security_policy!=\"mutual_tls\", destination_service=~\"$service\",response_code!~\"5.*\", destination_workload=~\"$dstwl\", destination_workload_namespace=~\"$dstns\"}[5m])) by (destination_workload, destination_workload_namespace) / sum(irate(istio_requests_total{reporter=\"destination\", connection_security_policy!=\"mutual_tls\", destination_service=~\"$service\", destination_workload=~\"$dstwl\", destination_workload_namespace=~\"$dstns\"}[5m])) by (destination_workload, destination_workload_namespace)", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_workload }}.{{ destination_workload_namespace }}", + "refId": "B", + "step": 2 + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Incoming Success Rate (non-5xx responses) By Source", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "percentunit", + "label": null, + "logBase": 1, + "max": "1.01", + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "description": "", + "fill": 1, + "gridPos": { + "h": 6, + "w": 8, + "x": 0, + "y": 41 + }, + "id": 94, + "legend": { + "alignAsTable": false, + "avg": false, + "current": false, + "hideEmpty": true, + "hideZero": false, + "max": false, + "min": false, + "rightSide": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "(histogram_quantile(0.50, sum(irate(istio_request_duration_milliseconds_bucket{reporter=\"destination\", connection_security_policy=\"mutual_tls\", destination_service=~\"$service\", destination_workload=~\"$dstwl\", destination_workload_namespace=~\"$dstns\"}[1m])) by (destination_workload, destination_workload_namespace, le)) / 1000) or histogram_quantile(0.50, sum(irate(istio_request_duration_seconds_bucket{reporter=\"destination\", connection_security_policy=\"mutual_tls\", destination_service=~\"$service\", destination_workload=~\"$dstwl\", destination_workload_namespace=~\"$dstns\"}[1m])) by (destination_workload, destination_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_workload }}.{{ destination_workload_namespace }} P50 (🔐mTLS)", + "refId": "D", + "step": 2 + }, + { + "expr": "(histogram_quantile(0.90, sum(irate(istio_request_duration_milliseconds_bucket{reporter=\"destination\", connection_security_policy=\"mutual_tls\", destination_service=~\"$service\", destination_workload=~\"$dstwl\", destination_workload_namespace=~\"$dstns\"}[1m])) by (destination_workload, destination_workload_namespace, le)) / 1000) or histogram_quantile(0.90, sum(irate(istio_request_duration_seconds_bucket{reporter=\"destination\", connection_security_policy=\"mutual_tls\", destination_service=~\"$service\", destination_workload=~\"$dstwl\", destination_workload_namespace=~\"$dstns\"}[1m])) by (destination_workload, destination_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_workload }}.{{ destination_workload_namespace }} P90 (🔐mTLS)", + "refId": "A", + "step": 2 + }, + { + "expr": "(histogram_quantile(0.95, sum(irate(istio_request_duration_milliseconds_bucket{reporter=\"destination\", connection_security_policy=\"mutual_tls\", destination_service=~\"$service\", destination_workload=~\"$dstwl\", destination_workload_namespace=~\"$dstns\"}[1m])) by (destination_workload, destination_workload_namespace, le)) / 1000) or histogram_quantile(0.95, sum(irate(istio_request_duration_seconds_bucket{reporter=\"destination\", connection_security_policy=\"mutual_tls\", destination_service=~\"$service\", destination_workload=~\"$dstwl\", destination_workload_namespace=~\"$dstns\"}[1m])) by (destination_workload, destination_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_workload }}.{{ destination_workload_namespace }} P95 (🔐mTLS)", + "refId": "B", + "step": 2 + }, + { + "expr": "(histogram_quantile(0.99, sum(irate(istio_request_duration_milliseconds_bucket{reporter=\"destination\", connection_security_policy=\"mutual_tls\", destination_service=~\"$service\", destination_workload=~\"$dstwl\", destination_workload_namespace=~\"$dstns\"}[1m])) by (destination_workload, destination_workload_namespace, le)) / 1000) or histogram_quantile(0.99, sum(irate(istio_request_duration_seconds_bucket{reporter=\"destination\", connection_security_policy=\"mutual_tls\", destination_service=~\"$service\", destination_workload=~\"$dstwl\", destination_workload_namespace=~\"$dstns\"}[1m])) by (destination_workload, destination_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_workload }}.{{ destination_workload_namespace }} P99 (🔐mTLS)", + "refId": "C", + "step": 2 + }, + { + "expr": "(histogram_quantile(0.50, sum(irate(istio_request_duration_milliseconds_bucket{reporter=\"destination\", connection_security_policy!=\"mutual_tls\", destination_service=~\"$service\", destination_workload=~\"$dstwl\", destination_workload_namespace=~\"$dstns\"}[1m])) by (destination_workload, destination_workload_namespace, le)) / 1000) or histogram_quantile(0.50, sum(irate(istio_request_duration_seconds_bucket{reporter=\"destination\", connection_security_policy!=\"mutual_tls\", destination_service=~\"$service\", destination_workload=~\"$dstwl\", destination_workload_namespace=~\"$dstns\"}[1m])) by (destination_workload, destination_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_workload }}.{{ destination_workload_namespace }} P50", + "refId": "E", + "step": 2 + }, + { + "expr": "(histogram_quantile(0.90, sum(irate(istio_request_duration_milliseconds_bucket{reporter=\"destination\", connection_security_policy!=\"mutual_tls\", destination_service=~\"$service\", destination_workload=~\"$dstwl\", destination_workload_namespace=~\"$dstns\"}[1m])) by (destination_workload, destination_workload_namespace, le)) / 1000) or histogram_quantile(0.90, sum(irate(istio_request_duration_seconds_bucket{reporter=\"destination\", connection_security_policy!=\"mutual_tls\", destination_service=~\"$service\", destination_workload=~\"$dstwl\", destination_workload_namespace=~\"$dstns\"}[1m])) by (destination_workload, destination_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_workload }}.{{ destination_workload_namespace }} P90", + "refId": "F", + "step": 2 + }, + { + "expr": "(histogram_quantile(0.95, sum(irate(istio_request_duration_milliseconds_bucket{reporter=\"destination\", connection_security_policy!=\"mutual_tls\", destination_service=~\"$service\", destination_workload=~\"$dstwl\", destination_workload_namespace=~\"$dstns\"}[1m])) by (destination_workload, destination_workload_namespace, le)) / 1000) or histogram_quantile(0.95, sum(irate(istio_request_duration_seconds_bucket{reporter=\"destination\", connection_security_policy!=\"mutual_tls\", destination_service=~\"$service\", destination_workload=~\"$dstwl\", destination_workload_namespace=~\"$dstns\"}[1m])) by (destination_workload, destination_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_workload }}.{{ destination_workload_namespace }} P95", + "refId": "G", + "step": 2 + }, + { + "expr": "(histogram_quantile(0.99, sum(irate(istio_request_duration_milliseconds_bucket{reporter=\"destination\", connection_security_policy!=\"mutual_tls\", destination_service=~\"$service\", destination_workload=~\"$dstwl\", destination_workload_namespace=~\"$dstns\"}[1m])) by (destination_workload, destination_workload_namespace, le)) / 1000) or histogram_quantile(0.99, sum(irate(istio_request_duration_seconds_bucket{reporter=\"destination\", connection_security_policy!=\"mutual_tls\", destination_service=~\"$service\", destination_workload=~\"$dstwl\", destination_workload_namespace=~\"$dstns\"}[1m])) by (destination_workload, destination_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_workload }}.{{ destination_workload_namespace }} P99", + "refId": "H", + "step": 2 + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Incoming Request Duration by Source", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "s", + "label": null, + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 6, + "w": 8, + "x": 8, + "y": 41 + }, + "id": 95, + "legend": { + "alignAsTable": false, + "avg": false, + "current": false, + "hideEmpty": true, + "max": false, + "min": false, + "rightSide": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "histogram_quantile(0.50, sum(irate(istio_request_bytes_bucket{reporter=\"destination\", connection_security_policy=\"mutual_tls\", destination_service=~\"$service\", destination_workload=~\"$dstwl\", destination_workload_namespace=~\"$dstns\"}[1m])) by (destination_workload, destination_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_workload }}.{{ destination_workload_namespace }} P50 (🔐mTLS)", + "refId": "D", + "step": 2 + }, + { + "expr": "histogram_quantile(0.90, sum(irate(istio_request_bytes_bucket{reporter=\"destination\", connection_security_policy=\"mutual_tls\", destination_service=~\"$service\", destination_workload=~\"$dstwl\", destination_workload_namespace=~\"$dstns\"}[1m])) by (destination_workload, destination_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_workload }}.{{ destination_workload_namespace }} P90 (🔐mTLS)", + "refId": "A", + "step": 2 + }, + { + "expr": "histogram_quantile(0.95, sum(irate(istio_request_bytes_bucket{reporter=\"destination\", connection_security_policy=\"mutual_tls\", destination_service=~\"$service\", destination_workload=~\"$dstwl\", destination_workload_namespace=~\"$dstns\"}[1m])) by (destination_workload, destination_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_workload }}.{{ destination_workload_namespace }} P95 (🔐mTLS)", + "refId": "B", + "step": 2 + }, + { + "expr": "histogram_quantile(0.99, sum(irate(istio_request_bytes_bucket{reporter=\"destination\", connection_security_policy=\"mutual_tls\", destination_service=~\"$service\", destination_workload=~\"$dstwl\", destination_workload_namespace=~\"$dstns\"}[1m])) by (destination_workload, destination_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_workload }}.{{ destination_workload_namespace }} P99 (🔐mTLS)", + "refId": "C", + "step": 2 + }, + { + "expr": "histogram_quantile(0.50, sum(irate(istio_request_bytes_bucket{reporter=\"destination\", connection_security_policy!=\"mutual_tls\", destination_service=~\"$service\", destination_workload=~\"$dstwl\", destination_workload_namespace=~\"$dstns\"}[1m])) by (destination_workload, destination_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_workload }}.{{ destination_workload_namespace }} P50", + "refId": "E", + "step": 2 + }, + { + "expr": "histogram_quantile(0.90, sum(irate(istio_request_bytes_bucket{reporter=\"destination\", connection_security_policy!=\"mutual_tls\", destination_service=~\"$service\", destination_workload=~\"$dstwl\", destination_workload_namespace=~\"$dstns\"}[1m])) by (destination_workload, destination_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_workload }}.{{ destination_workload_namespace }} P90", + "refId": "F", + "step": 2 + }, + { + "expr": "histogram_quantile(0.95, sum(irate(istio_request_bytes_bucket{reporter=\"destination\", connection_security_policy!=\"mutual_tls\", destination_service=~\"$service\", destination_workload=~\"$dstwl\", destination_workload_namespace=~\"$dstns\"}[1m])) by (destination_workload, destination_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_workload }}.{{ destination_workload_namespace }} P95", + "refId": "G", + "step": 2 + }, + { + "expr": "histogram_quantile(0.99, sum(irate(istio_request_bytes_bucket{reporter=\"destination\", connection_security_policy!=\"mutual_tls\", destination_service=~\"$service\", destination_workload=~\"$dstwl\", destination_workload_namespace=~\"$dstns\"}[1m])) by (destination_workload, destination_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_workload }}.{{ destination_workload_namespace }} P99", + "refId": "H", + "step": 2 + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Incoming Request Size By Source", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "decbytes", + "label": null, + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 6, + "w": 8, + "x": 16, + "y": 41 + }, + "id": 96, + "legend": { + "alignAsTable": false, + "avg": false, + "current": false, + "hideEmpty": true, + "max": false, + "min": false, + "rightSide": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "histogram_quantile(0.50, sum(irate(istio_response_bytes_bucket{reporter=\"destination\", connection_security_policy=\"mutual_tls\", destination_service=~\"$service\", destination_workload=~\"$dstwl\", destination_workload_namespace=~\"$dstns\"}[1m])) by (destination_workload, destination_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_workload }}.{{ destination_workload_namespace }} P50 (🔐mTLS)", + "refId": "D", + "step": 2 + }, + { + "expr": "histogram_quantile(0.90, sum(irate(istio_response_bytes_bucket{reporter=\"destination\", connection_security_policy=\"mutual_tls\", destination_service=~\"$service\", destination_workload=~\"$dstwl\", destination_workload_namespace=~\"$dstns\"}[1m])) by (destination_workload, destination_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_workload }}.{{ destination_workload_namespace }} P90 (🔐mTLS)", + "refId": "A", + "step": 2 + }, + { + "expr": "histogram_quantile(0.95, sum(irate(istio_response_bytes_bucket{reporter=\"destination\", connection_security_policy=\"mutual_tls\", destination_service=~\"$service\", destination_workload=~\"$dstwl\", destination_workload_namespace=~\"$dstns\"}[1m])) by (destination_workload, destination_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_workload }}.{{ destination_workload_namespace }} P95 (🔐mTLS)", + "refId": "B", + "step": 2 + }, + { + "expr": "histogram_quantile(0.99, sum(irate(istio_response_bytes_bucket{reporter=\"destination\", connection_security_policy=\"mutual_tls\", destination_service=~\"$service\", destination_workload=~\"$dstwl\", destination_workload_namespace=~\"$dstns\"}[1m])) by (destination_workload, destination_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_workload }}.{{ destination_workload_namespace }} P99 (🔐mTLS)", + "refId": "C", + "step": 2 + }, + { + "expr": "histogram_quantile(0.50, sum(irate(istio_response_bytes_bucket{reporter=\"destination\", connection_security_policy!=\"mutual_tls\", destination_service=~\"$service\", destination_workload=~\"$dstwl\", destination_workload_namespace=~\"$dstns\"}[1m])) by (destination_workload, destination_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_workload }}.{{ destination_workload_namespace }} P50", + "refId": "E", + "step": 2 + }, + { + "expr": "histogram_quantile(0.90, sum(irate(istio_response_bytes_bucket{reporter=\"destination\", connection_security_policy!=\"mutual_tls\", destination_service=~\"$service\", destination_workload=~\"$dstwl\", destination_workload_namespace=~\"$dstns\"}[1m])) by (destination_workload, destination_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_workload }}.{{ destination_workload_namespace }} P90", + "refId": "F", + "step": 2 + }, + { + "expr": "histogram_quantile(0.95, sum(irate(istio_response_bytes_bucket{reporter=\"destination\", connection_security_policy!=\"mutual_tls\", destination_service=~\"$service\", destination_workload=~\"$dstwl\", destination_workload_namespace=~\"$dstns\"}[1m])) by (destination_workload, destination_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_workload }}.{{ destination_workload_namespace }} P95", + "refId": "G", + "step": 2 + }, + { + "expr": "histogram_quantile(0.99, sum(irate(istio_response_bytes_bucket{reporter=\"destination\", connection_security_policy!=\"mutual_tls\", destination_service=~\"$service\", destination_workload=~\"$dstwl\", destination_workload_namespace=~\"$dstns\"}[1m])) by (destination_workload, destination_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_workload }}.{{ destination_workload_namespace }} P99", + "refId": "H", + "step": 2 + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Response Size By Source", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "decbytes", + "label": null, + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 6, + "w": 12, + "x": 0, + "y": 47 + }, + "id": 92, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "round(sum(irate(istio_tcp_received_bytes_total{reporter=\"source\", connection_security_policy=\"mutual_tls\", destination_service=~\"$service\", destination_workload=~\"$dstwl\", destination_workload_namespace=~\"$dstns\"}[1m])) by (destination_workload, destination_workload_namespace), 0.001)", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_workload }}.{{ destination_workload_namespace}} (🔐mTLS)", + "refId": "A", + "step": 2 + }, + { + "expr": "round(sum(irate(istio_tcp_received_bytes_total{reporter=\"source\", connection_security_policy!=\"mutual_tls\", destination_service=~\"$service\", destination_workload=~\"$dstwl\", destination_workload_namespace=~\"$dstns\"}[1m])) by (destination_workload, destination_workload_namespace), 0.001)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{ destination_workload }}.{{ destination_workload_namespace}}", + "refId": "B", + "step": 2 + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Bytes Received from Incoming TCP Connection", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "Bps", + "label": null, + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 6, + "w": 12, + "x": 12, + "y": 47 + }, + "id": 93, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "round(sum(irate(istio_tcp_sent_bytes_total{connection_security_policy=\"mutual_tls\", reporter=\"source\", destination_service=~\"$service\", destination_workload=~\"$dstwl\", destination_workload_namespace=~\"$dstns\"}[1m])) by (destination_workload, destination_workload_namespace), 0.001)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{ destination_workload }}.{{destination_workload_namespace }} (🔐mTLS)", + "refId": "A", + "step": 2 + }, + { + "expr": "round(sum(irate(istio_tcp_sent_bytes_total{connection_security_policy!=\"mutual_tls\", reporter=\"source\", destination_service=~\"$service\", destination_workload=~\"$dstwl\", destination_workload_namespace=~\"$dstns\"}[1m])) by (destination_workload, destination_workload_namespace), 0.001)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{ destination_workload }}.{{destination_workload_namespace }}", + "refId": "B", + "step": 2 + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Bytes Sent to Incoming TCP Connection", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "Bps", + "label": null, + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + } + ], + "refresh": "10s", + "schemaVersion": 16, + "style": "dark", + "tags": [], + "templating": { + "list": [ + { + "allValue": null, + "datasource": "Prometheus", + "hide": 0, + "includeAll": false, + "label": "Service", + "multi": false, + "name": "service", + "options": [], + "query": "label_values(destination_service)", + "refresh": 1, + "regex": "", + "sort": 0, + "tagValuesQuery": "", + "tags": [], + "tagsQuery": "", + "type": "query", + "useTags": false + }, + { + "allValue": null, + "current": { + "text": "All", + "value": "$__all" + }, + "datasource": "Prometheus", + "hide": 0, + "includeAll": true, + "label": "Client Workload Namespace", + "multi": true, + "name": "srcns", + "options": [], + "query": "query_result( sum(istio_requests_total{reporter=\"destination\", destination_service=\"$service\"}) by (source_workload_namespace) or sum(istio_tcp_sent_bytes_total{reporter=\"destination\", destination_service=~\"$service\"}) by (source_workload_namespace))", + "refresh": 1, + "regex": "/.*namespace=\"([^\"]*).*/", + "sort": 2, + "tagValuesQuery": "", + "tags": [], + "tagsQuery": "", + "type": "query", + "useTags": false + }, + { + "allValue": null, + "current": { + "text": "All", + "value": "$__all" + }, + "datasource": "Prometheus", + "hide": 0, + "includeAll": true, + "label": "Client Workload", + "multi": true, + "name": "srcwl", + "options": [], + "query": "query_result( sum(istio_requests_total{reporter=\"destination\", destination_service=~\"$service\", source_workload_namespace=~\"$srcns\"}) by (source_workload) or sum(istio_tcp_sent_bytes_total{reporter=\"destination\", destination_service=~\"$service\", source_workload_namespace=~\"$srcns\"}) by (source_workload))", + "refresh": 1, + "regex": "/.*workload=\"([^\"]*).*/", + "sort": 3, + "tagValuesQuery": "", + "tags": [], + "tagsQuery": "", + "type": "query", + "useTags": false + }, + { + "allValue": null, + "current": { + "text": "All", + "value": "$__all" + }, + "datasource": "Prometheus", + "hide": 0, + "includeAll": true, + "label": "Service Workload Namespace", + "multi": true, + "name": "dstns", + "options": [], + "query": "query_result( sum(istio_requests_total{reporter=\"destination\", destination_service=\"$service\"}) by (destination_workload_namespace) or sum(istio_tcp_sent_bytes_total{reporter=\"destination\", destination_service=~\"$service\"}) by (destination_workload_namespace))", + "refresh": 1, + "regex": "/.*namespace=\"([^\"]*).*/", + "sort": 2, + "tagValuesQuery": "", + "tags": [], + "tagsQuery": "", + "type": "query", + "useTags": false + }, + { + "allValue": null, + "current": { + "text": "All", + "value": "$__all" + }, + "datasource": "Prometheus", + "hide": 0, + "includeAll": true, + "label": "Service Workload", + "multi": true, + "name": "dstwl", + "options": [], + "query": "query_result( sum(istio_requests_total{reporter=\"destination\", destination_service=~\"$service\", destination_workload_namespace=~\"$dstns\"}) by (destination_workload) or sum(istio_tcp_sent_bytes_total{reporter=\"destination\", destination_service=~\"$service\", destination_workload_namespace=~\"$dstns\"}) by (destination_workload))", + "refresh": 1, + "regex": "/.*workload=\"([^\"]*).*/", + "sort": 3, + "tagValuesQuery": "", + "tags": [], + "tagsQuery": "", + "type": "query", + "useTags": false + } + ] + }, + "time": { + "from": "now-5m", + "to": "now" + }, + "timepicker": { + "refresh_intervals": [ + "5s", + "10s", + "30s", + "1m", + "5m", + "15m", + "30m", + "1h", + "2h", + "1d" + ], + "time_options": [ + "5m", + "15m", + "1h", + "6h", + "12h", + "24h", + "2d", + "7d", + "30d" + ] + }, + "timezone": "", + "title": "Istio Service Dashboard", + "uid": "LJ_uJAvmk", + "version": 1 +} diff --git a/istio-1.3.5/install/kubernetes/helm/istio/charts/grafana/dashboards/istio-workload-dashboard.json b/istio-1.3.5/install/kubernetes/helm/istio/charts/grafana/dashboards/istio-workload-dashboard.json new file mode 100644 index 0000000..62ad1b5 --- /dev/null +++ b/istio-1.3.5/install/kubernetes/helm/istio/charts/grafana/dashboards/istio-workload-dashboard.json @@ -0,0 +1,2303 @@ +{ + "__inputs": [ + { + "name": "DS_PROMETHEUS", + "label": "Prometheus", + "description": "", + "type": "datasource", + "pluginId": "prometheus", + "pluginName": "Prometheus" + } + ], + "__requires": [ + { + "type": "grafana", + "id": "grafana", + "name": "Grafana", + "version": "5.0.4" + }, + { + "type": "panel", + "id": "graph", + "name": "Graph", + "version": "5.0.0" + }, + { + "type": "datasource", + "id": "prometheus", + "name": "Prometheus", + "version": "5.0.0" + }, + { + "type": "panel", + "id": "singlestat", + "name": "Singlestat", + "version": "5.0.0" + }, + { + "type": "panel", + "id": "text", + "name": "Text", + "version": "5.0.0" + } + ], + "annotations": { + "list": [ + { + "builtIn": 1, + "datasource": "-- Grafana --", + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations & Alerts", + "type": "dashboard" + } + ] + }, + "editable": false, + "gnetId": null, + "graphTooltip": 0, + "id": null, + "iteration": 1531345461465, + "links": [], + "panels": [ + { + "content": "
\nWORKLOAD: $workload.$namespace\n
", + "gridPos": { + "h": 3, + "w": 24, + "x": 0, + "y": 0 + }, + "id": 89, + "links": [], + "mode": "html", + "title": "", + "transparent": true, + "type": "text" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "datasource": "Prometheus", + "format": "ops", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "gridPos": { + "h": 4, + "w": 8, + "x": 0, + "y": 3 + }, + "id": 12, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": true, + "lineColor": "rgb(31, 120, 193)", + "show": true + }, + "tableColumn": "", + "targets": [ + { + "expr": "round(sum(irate(istio_requests_total{reporter=\"destination\",destination_workload_namespace=~\"$namespace\",destination_workload=~\"$workload\"}[5m])), 0.001)", + "format": "time_series", + "intervalFactor": 1, + "refId": "A", + "step": 4 + } + ], + "thresholds": "", + "title": "Incoming Request Volume", + "transparent": false, + "type": "singlestat", + "valueFontSize": "80%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "current" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "rgba(50, 172, 45, 0.97)", + "rgba(237, 129, 40, 0.89)", + "rgba(245, 54, 54, 0.9)" + ], + "datasource": "Prometheus", + "decimals": null, + "format": "percentunit", + "gauge": { + "maxValue": 100, + "minValue": 80, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": false + }, + "gridPos": { + "h": 4, + "w": 8, + "x": 8, + "y": 3 + }, + "id": 14, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": true, + "lineColor": "rgb(31, 120, 193)", + "show": true + }, + "tableColumn": "", + "targets": [ + { + "expr": "sum(irate(istio_requests_total{reporter=\"destination\",destination_workload_namespace=~\"$namespace\",destination_workload=~\"$workload\",response_code!~\"5.*\"}[5m])) / sum(irate(istio_requests_total{reporter=\"destination\",destination_workload_namespace=~\"$namespace\",destination_workload=~\"$workload\"}[5m]))", + "format": "time_series", + "intervalFactor": 1, + "refId": "B" + } + ], + "thresholds": "95, 99, 99.5", + "title": "Incoming Success Rate (non-5xx responses)", + "transparent": false, + "type": "singlestat", + "valueFontSize": "80%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "avg" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 4, + "w": 8, + "x": 16, + "y": 3 + }, + "id": 87, + "legend": { + "alignAsTable": false, + "avg": false, + "current": false, + "hideEmpty": false, + "hideZero": false, + "max": false, + "min": false, + "rightSide": true, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "(histogram_quantile(0.50, sum(irate(istio_request_duration_milliseconds_bucket{reporter=\"destination\",destination_workload=~\"$workload\", destination_workload_namespace=~\"$namespace\"}[1m])) by (le)) / 1000) or histogram_quantile(0.50, sum(irate(istio_request_duration_seconds_bucket{reporter=\"destination\",destination_workload=~\"$workload\", destination_workload_namespace=~\"$namespace\"}[1m])) by (le))", + "format": "time_series", + "interval": "", + "intervalFactor": 1, + "legendFormat": "P50", + "refId": "A" + }, + { + "expr": "(histogram_quantile(0.50, sum(irate(istio_request_duration_milliseconds_bucket{reporter=\"destination\",destination_workload=~\"$workload\", destination_workload_namespace=~\"$namespace\"}[1m])) by (le)) / 1000) or histogram_quantile(0.90, sum(irate(istio_request_duration_seconds_bucket{reporter=\"destination\",destination_workload=~\"$workload\", destination_workload_namespace=~\"$namespace\"}[1m])) by (le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "P90", + "refId": "B" + }, + { + "expr": "(histogram_quantile(0.50, sum(irate(istio_request_duration_milliseconds_bucket{reporter=\"destination\",destination_workload=~\"$workload\", destination_workload_namespace=~\"$namespace\"}[1m])) by (le)) / 1000) or histogram_quantile(0.99, sum(irate(istio_request_duration_seconds_bucket{reporter=\"destination\",destination_workload=~\"$workload\", destination_workload_namespace=~\"$namespace\"}[1m])) by (le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "P99", + "refId": "C" + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Request Duration", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "s", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ] + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "#299c46", + "rgba(237, 129, 40, 0.89)", + "#d44a3a" + ], + "datasource": "Prometheus", + "format": "Bps", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "gridPos": { + "h": 4, + "w": 12, + "x": 0, + "y": 7 + }, + "id": 84, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": true, + "lineColor": "rgb(31, 120, 193)", + "show": true + }, + "tableColumn": "", + "targets": [ + { + "expr": "sum(irate(istio_tcp_sent_bytes_total{reporter=\"destination\", destination_workload_namespace=~\"$namespace\", destination_workload=~\"$workload\"}[1m])) + sum(irate(istio_tcp_received_bytes_total{reporter=\"destination\", destination_workload_namespace=~\"$namespace\", destination_workload=~\"$workload\"}[1m]))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "", + "refId": "A" + } + ], + "thresholds": "", + "title": "TCP Server Traffic", + "transparent": false, + "type": "singlestat", + "valueFontSize": "80%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "avg" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "#299c46", + "rgba(237, 129, 40, 0.89)", + "#d44a3a" + ], + "datasource": "Prometheus", + "format": "Bps", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "gridPos": { + "h": 4, + "w": 12, + "x": 12, + "y": 7 + }, + "id": 85, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": true, + "lineColor": "rgb(31, 120, 193)", + "show": true + }, + "tableColumn": "", + "targets": [ + { + "expr": "sum(irate(istio_tcp_sent_bytes_total{reporter=\"source\", source_workload_namespace=~\"$namespace\", source_workload=~\"$workload\"}[1m])) + sum(irate(istio_tcp_received_bytes_total{reporter=\"source\", source_workload_namespace=~\"$namespace\", source_workload=~\"$workload\"}[1m]))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "", + "refId": "A" + } + ], + "thresholds": "", + "title": "TCP Client Traffic", + "transparent": false, + "type": "singlestat", + "valueFontSize": "80%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "avg" + }, + { + "content": "
\nINBOUND WORKLOADS\n
", + "gridPos": { + "h": 3, + "w": 24, + "x": 0, + "y": 11 + }, + "id": 45, + "links": [], + "mode": "html", + "title": "", + "transparent": true, + "type": "text" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 0, + "gridPos": { + "h": 6, + "w": 12, + "x": 0, + "y": 14 + }, + "id": 25, + "legend": { + "avg": false, + "current": false, + "hideEmpty": true, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null as zero", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "round(sum(irate(istio_requests_total{connection_security_policy=\"mutual_tls\", destination_workload_namespace=~\"$namespace\", destination_workload=~\"$workload\", reporter=\"destination\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[5m])) by (source_workload, source_workload_namespace, response_code), 0.001)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{ source_workload }}.{{ source_workload_namespace }} : {{ response_code }} (🔐mTLS)", + "refId": "B", + "step": 2 + }, + { + "expr": "round(sum(irate(istio_requests_total{connection_security_policy!=\"mutual_tls\", destination_workload_namespace=~\"$namespace\", destination_workload=~\"$workload\", reporter=\"destination\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[5m])) by (source_workload, source_workload_namespace, response_code), 0.001)", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ source_workload }}.{{ source_workload_namespace }} : {{ response_code }}", + "refId": "A", + "step": 2 + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Incoming Requests by Source And Response Code", + "tooltip": { + "shared": false, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [ + "total" + ] + }, + "yaxes": [ + { + "format": "ops", + "label": null, + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ] + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 6, + "w": 12, + "x": 12, + "y": 14 + }, + "id": 26, + "legend": { + "avg": false, + "current": false, + "hideEmpty": true, + "hideZero": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(irate(istio_requests_total{reporter=\"destination\", connection_security_policy=\"mutual_tls\", destination_workload_namespace=~\"$namespace\", destination_workload=~\"$workload\",response_code!~\"5.*\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[5m])) by (source_workload, source_workload_namespace) / sum(irate(istio_requests_total{reporter=\"destination\", connection_security_policy=\"mutual_tls\", destination_workload_namespace=~\"$namespace\", destination_workload=~\"$workload\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[5m])) by (source_workload, source_workload_namespace)", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ source_workload }}.{{ source_workload_namespace }} (🔐mTLS)", + "refId": "A", + "step": 2 + }, + { + "expr": "sum(irate(istio_requests_total{reporter=\"destination\", connection_security_policy!=\"mutual_tls\", destination_workload_namespace=~\"$namespace\", destination_workload=~\"$workload\",response_code!~\"5.*\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[5m])) by (source_workload, source_workload_namespace) / sum(irate(istio_requests_total{reporter=\"destination\", connection_security_policy!=\"mutual_tls\", destination_workload_namespace=~\"$namespace\", destination_workload=~\"$workload\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[5m])) by (source_workload, source_workload_namespace)", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ source_workload }}.{{ source_workload_namespace }}", + "refId": "B", + "step": 2 + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Incoming Success Rate (non-5xx responses) By Source", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "percentunit", + "label": null, + "logBase": 1, + "max": "1.01", + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ] + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "description": "", + "fill": 1, + "gridPos": { + "h": 6, + "w": 8, + "x": 0, + "y": 20 + }, + "id": 27, + "legend": { + "alignAsTable": false, + "avg": false, + "current": false, + "hideEmpty": true, + "hideZero": false, + "max": false, + "min": false, + "rightSide": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "(histogram_quantile(0.50, sum(irate(istio_request_duration_milliseconds_bucket{reporter=\"destination\", connection_security_policy=\"mutual_tls\", destination_workload=~\"$workload\", destination_workload_namespace=~\"$namespace\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le)) / 1000) or histogram_quantile(0.50, sum(irate(istio_request_duration_seconds_bucket{reporter=\"destination\", connection_security_policy=\"mutual_tls\", destination_workload=~\"$workload\", destination_workload_namespace=~\"$namespace\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{source_workload}}.{{source_workload_namespace}} P50 (🔐mTLS)", + "refId": "D", + "step": 2 + }, + { + "expr": "(histogram_quantile(0.90, sum(irate(istio_request_duration_milliseconds_bucket{reporter=\"destination\", connection_security_policy=\"mutual_tls\", destination_workload=~\"$workload\", destination_workload_namespace=~\"$namespace\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le)) / 1000) or histogram_quantile(0.90, sum(irate(istio_request_duration_seconds_bucket{reporter=\"destination\", connection_security_policy=\"mutual_tls\", destination_workload=~\"$workload\", destination_workload_namespace=~\"$namespace\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{source_workload}}.{{source_workload_namespace}} P90 (🔐mTLS)", + "refId": "A", + "step": 2 + }, + { + "expr": "(histogram_quantile(0.95, sum(irate(istio_request_duration_milliseconds_bucket{reporter=\"destination\", connection_security_policy=\"mutual_tls\", destination_workload=~\"$workload\", destination_workload_namespace=~\"$namespace\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le)) / 1000) or histogram_quantile(0.95, sum(irate(istio_request_duration_seconds_bucket{reporter=\"destination\", connection_security_policy=\"mutual_tls\", destination_workload=~\"$workload\", destination_workload_namespace=~\"$namespace\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{source_workload}}.{{source_workload_namespace}} P95 (🔐mTLS)", + "refId": "B", + "step": 2 + }, + { + "expr": "(histogram_quantile(0.99, sum(irate(istio_request_duration_milliseconds_bucket{reporter=\"destination\", connection_security_policy=\"mutual_tls\", destination_workload=~\"$workload\", destination_workload_namespace=~\"$namespace\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le)) / 1000) or histogram_quantile(0.99, sum(irate(istio_request_duration_seconds_bucket{reporter=\"destination\", connection_security_policy=\"mutual_tls\", destination_workload=~\"$workload\", destination_workload_namespace=~\"$namespace\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{source_workload}}.{{source_workload_namespace}} P99 (🔐mTLS)", + "refId": "C", + "step": 2 + }, + { + "expr": "(histogram_quantile(0.50, sum(irate(istio_request_duration_milliseconds_bucket{reporter=\"destination\", connection_security_policy!=\"mutual_tls\", destination_workload=~\"$workload\", destination_workload_namespace=~\"$namespace\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le)) / 1000) or histogram_quantile(0.50, sum(irate(istio_request_duration_seconds_bucket{reporter=\"destination\", connection_security_policy!=\"mutual_tls\", destination_workload=~\"$workload\", destination_workload_namespace=~\"$namespace\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{source_workload}}.{{source_workload_namespace}} P50", + "refId": "E", + "step": 2 + }, + { + "expr": "(histogram_quantile(0.90, sum(irate(istio_request_duration_milliseconds_bucket{reporter=\"destination\", connection_security_policy!=\"mutual_tls\", destination_workload=~\"$workload\", destination_workload_namespace=~\"$namespace\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le)) / 1000) or histogram_quantile(0.90, sum(irate(istio_request_duration_seconds_bucket{reporter=\"destination\", connection_security_policy!=\"mutual_tls\", destination_workload=~\"$workload\", destination_workload_namespace=~\"$namespace\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{source_workload}}.{{source_workload_namespace}} P90", + "refId": "F", + "step": 2 + }, + { + "expr": "(histogram_quantile(0.95, sum(irate(istio_request_duration_milliseconds_bucket{reporter=\"destination\", connection_security_policy!=\"mutual_tls\", destination_workload=~\"$workload\", destination_workload_namespace=~\"$namespace\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le)) / 1000) or histogram_quantile(0.95, sum(irate(istio_request_duration_seconds_bucket{reporter=\"destination\", connection_security_policy!=\"mutual_tls\", destination_workload=~\"$workload\", destination_workload_namespace=~\"$namespace\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{source_workload}}.{{source_workload_namespace}} P95", + "refId": "G", + "step": 2 + }, + { + "expr": "(histogram_quantile(0.99, sum(irate(istio_request_duration_milliseconds_bucket{reporter=\"destination\", connection_security_policy!=\"mutual_tls\", destination_workload=~\"$workload\", destination_workload_namespace=~\"$namespace\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le)) / 1000) or histogram_quantile(0.99, sum(irate(istio_request_duration_seconds_bucket{reporter=\"destination\", connection_security_policy!=\"mutual_tls\", destination_workload=~\"$workload\", destination_workload_namespace=~\"$namespace\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{source_workload}}.{{source_workload_namespace}} P99", + "refId": "H", + "step": 2 + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Incoming Request Duration by Source", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "s", + "label": null, + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ] + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 6, + "w": 8, + "x": 8, + "y": 20 + }, + "id": 28, + "legend": { + "alignAsTable": false, + "avg": false, + "current": false, + "hideEmpty": true, + "max": false, + "min": false, + "rightSide": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "histogram_quantile(0.50, sum(irate(istio_request_bytes_bucket{reporter=\"destination\", connection_security_policy=\"mutual_tls\", destination_workload=~\"$workload\", destination_workload_namespace=~\"$namespace\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{source_workload}}.{{source_workload_namespace}} P50 (🔐mTLS)", + "refId": "D", + "step": 2 + }, + { + "expr": "histogram_quantile(0.90, sum(irate(istio_request_bytes_bucket{reporter=\"destination\", connection_security_policy=\"mutual_tls\", destination_workload=~\"$workload\", destination_workload_namespace=~\"$namespace\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{source_workload}}.{{source_workload_namespace}} P90 (🔐mTLS)", + "refId": "A", + "step": 2 + }, + { + "expr": "histogram_quantile(0.95, sum(irate(istio_request_bytes_bucket{reporter=\"destination\", connection_security_policy=\"mutual_tls\", destination_workload=~\"$workload\", destination_workload_namespace=~\"$namespace\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{source_workload}}.{{source_workload_namespace}} P95 (🔐mTLS)", + "refId": "B", + "step": 2 + }, + { + "expr": "histogram_quantile(0.99, sum(irate(istio_request_bytes_bucket{reporter=\"destination\", connection_security_policy=\"mutual_tls\", destination_workload=~\"$workload\", destination_workload_namespace=~\"$namespace\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{source_workload}}.{{source_workload_namespace}} P99 (🔐mTLS)", + "refId": "C", + "step": 2 + }, + { + "expr": "histogram_quantile(0.50, sum(irate(istio_request_bytes_bucket{reporter=\"destination\", connection_security_policy!=\"mutual_tls\", destination_workload=~\"$workload\", destination_workload_namespace=~\"$namespace\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{source_workload}}.{{source_workload_namespace}} P50", + "refId": "E", + "step": 2 + }, + { + "expr": "histogram_quantile(0.90, sum(irate(istio_request_bytes_bucket{reporter=\"destination\", connection_security_policy!=\"mutual_tls\", destination_workload=~\"$workload\", destination_workload_namespace=~\"$namespace\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{source_workload}}.{{source_workload_namespace}} P90", + "refId": "F", + "step": 2 + }, + { + "expr": "histogram_quantile(0.95, sum(irate(istio_request_bytes_bucket{reporter=\"destination\", connection_security_policy!=\"mutual_tls\", destination_workload=~\"$workload\", destination_workload_namespace=~\"$namespace\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{source_workload}}.{{source_workload_namespace}} P95", + "refId": "G", + "step": 2 + }, + { + "expr": "histogram_quantile(0.99, sum(irate(istio_request_bytes_bucket{reporter=\"destination\", connection_security_policy!=\"mutual_tls\", destination_workload=~\"$workload\", destination_workload_namespace=~\"$namespace\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{source_workload}}.{{source_workload_namespace}} P99", + "refId": "H", + "step": 2 + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Incoming Request Size By Source", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "decbytes", + "label": null, + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ] + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 6, + "w": 8, + "x": 16, + "y": 20 + }, + "id": 68, + "legend": { + "alignAsTable": false, + "avg": false, + "current": false, + "hideEmpty": true, + "max": false, + "min": false, + "rightSide": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "histogram_quantile(0.50, sum(irate(istio_response_bytes_bucket{reporter=\"destination\", connection_security_policy=\"mutual_tls\", destination_workload=~\"$workload\", destination_workload_namespace=~\"$namespace\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{source_workload}}.{{source_workload_namespace}} P50 (🔐mTLS)", + "refId": "D", + "step": 2 + }, + { + "expr": "histogram_quantile(0.90, sum(irate(istio_response_bytes_bucket{reporter=\"destination\", connection_security_policy=\"mutual_tls\", destination_workload=~\"$workload\", destination_workload_namespace=~\"$namespace\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{source_workload}}.{{source_workload_namespace}} P90 (🔐mTLS)", + "refId": "A", + "step": 2 + }, + { + "expr": "histogram_quantile(0.95, sum(irate(istio_response_bytes_bucket{reporter=\"destination\", connection_security_policy=\"mutual_tls\", destination_workload=~\"$workload\", destination_workload_namespace=~\"$namespace\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{source_workload}}.{{source_workload_namespace}} P95 (🔐mTLS)", + "refId": "B", + "step": 2 + }, + { + "expr": "histogram_quantile(0.99, sum(irate(istio_response_bytes_bucket{reporter=\"destination\", connection_security_policy=\"mutual_tls\", destination_workload=~\"$workload\", destination_workload_namespace=~\"$namespace\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{source_workload}}.{{source_workload_namespace}} P99 (🔐mTLS)", + "refId": "C", + "step": 2 + }, + { + "expr": "histogram_quantile(0.50, sum(irate(istio_response_bytes_bucket{reporter=\"destination\", connection_security_policy!=\"mutual_tls\", destination_workload=~\"$workload\", destination_workload_namespace=~\"$namespace\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{source_workload}}.{{source_workload_namespace}} P50", + "refId": "E", + "step": 2 + }, + { + "expr": "histogram_quantile(0.90, sum(irate(istio_response_bytes_bucket{reporter=\"destination\", connection_security_policy!=\"mutual_tls\", destination_workload=~\"$workload\", destination_workload_namespace=~\"$namespace\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{source_workload}}.{{source_workload_namespace}} P90", + "refId": "F", + "step": 2 + }, + { + "expr": "histogram_quantile(0.95, sum(irate(istio_response_bytes_bucket{reporter=\"destination\", connection_security_policy!=\"mutual_tls\", destination_workload=~\"$workload\", destination_workload_namespace=~\"$namespace\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{source_workload}}.{{source_workload_namespace}} P95", + "refId": "G", + "step": 2 + }, + { + "expr": "histogram_quantile(0.99, sum(irate(istio_response_bytes_bucket{reporter=\"destination\", connection_security_policy!=\"mutual_tls\", destination_workload=~\"$workload\", destination_workload_namespace=~\"$namespace\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{source_workload}}.{{source_workload_namespace}} P99", + "refId": "H", + "step": 2 + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Response Size By Source", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "decbytes", + "label": null, + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ] + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 6, + "w": 12, + "x": 0, + "y": 26 + }, + "id": 80, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "round(sum(irate(istio_tcp_received_bytes_total{reporter=\"destination\", connection_security_policy=\"mutual_tls\", destination_workload_namespace=~\"$namespace\", destination_workload=~\"$workload\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace), 0.001)", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ source_workload }}.{{ source_workload_namespace}} (🔐mTLS)", + "refId": "A", + "step": 2 + }, + { + "expr": "round(sum(irate(istio_tcp_received_bytes_total{reporter=\"destination\", connection_security_policy!=\"mutual_tls\", destination_workload_namespace=~\"$namespace\", destination_workload=~\"$workload\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace), 0.001)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{ source_workload }}.{{ source_workload_namespace}}", + "refId": "B", + "step": 2 + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Bytes Received from Incoming TCP Connection", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "Bps", + "label": null, + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ] + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 6, + "w": 12, + "x": 12, + "y": 26 + }, + "id": 82, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "round(sum(irate(istio_tcp_sent_bytes_total{connection_security_policy=\"mutual_tls\", reporter=\"destination\", destination_workload_namespace=~\"$namespace\", destination_workload=~\"$workload\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace), 0.001)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{ source_workload }}.{{ source_workload_namespace}} (🔐mTLS)", + "refId": "A", + "step": 2 + }, + { + "expr": "round(sum(irate(istio_tcp_sent_bytes_total{connection_security_policy!=\"mutual_tls\", reporter=\"destination\", destination_workload_namespace=~\"$namespace\", destination_workload=~\"$workload\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace), 0.001)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{ source_workload }}.{{ source_workload_namespace}}", + "refId": "B", + "step": 2 + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Bytes Sent to Incoming TCP Connection", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "Bps", + "label": null, + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ] + }, + { + "content": "
\nOUTBOUND SERVICES\n
", + "gridPos": { + "h": 3, + "w": 24, + "x": 0, + "y": 32 + }, + "id": 69, + "links": [], + "mode": "html", + "title": "", + "transparent": true, + "type": "text" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 0, + "gridPos": { + "h": 6, + "w": 12, + "x": 0, + "y": 35 + }, + "id": 70, + "legend": { + "avg": false, + "current": false, + "hideEmpty": true, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null as zero", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "round(sum(irate(istio_requests_total{connection_security_policy=\"mutual_tls\", source_workload_namespace=~\"$namespace\", source_workload=~\"$workload\", reporter=\"source\", destination_service=~\"$dstsvc\"}[5m])) by (destination_service, response_code), 0.001)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{ destination_service }} : {{ response_code }} (🔐mTLS)", + "refId": "B", + "step": 2 + }, + { + "expr": "round(sum(irate(istio_requests_total{connection_security_policy!=\"mutual_tls\", source_workload_namespace=~\"$namespace\", source_workload=~\"$workload\", reporter=\"source\", destination_service=~\"$dstsvc\"}[5m])) by (destination_service, response_code), 0.001)", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_service }} : {{ response_code }}", + "refId": "A", + "step": 2 + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Outgoing Requests by Destination And Response Code", + "tooltip": { + "shared": false, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [ + "total" + ] + }, + "yaxes": [ + { + "format": "ops", + "label": null, + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ] + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 6, + "w": 12, + "x": 12, + "y": 35 + }, + "id": 71, + "legend": { + "avg": false, + "current": false, + "hideEmpty": true, + "hideZero": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(irate(istio_requests_total{reporter=\"source\", connection_security_policy=\"mutual_tls\", source_workload_namespace=~\"$namespace\", source_workload=~\"$workload\",response_code!~\"5.*\", destination_service=~\"$dstsvc\"}[5m])) by (destination_service) / sum(irate(istio_requests_total{reporter=\"source\", connection_security_policy=\"mutual_tls\", source_workload_namespace=~\"$namespace\", source_workload=~\"$workload\", destination_service=~\"$dstsvc\"}[5m])) by (destination_service)", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_service }} (🔐mTLS)", + "refId": "A", + "step": 2 + }, + { + "expr": "sum(irate(istio_requests_total{reporter=\"source\", connection_security_policy!=\"mutual_tls\", source_workload_namespace=~\"$namespace\", source_workload=~\"$workload\",response_code!~\"5.*\", destination_service=~\"$dstsvc\"}[5m])) by (destination_service) / sum(irate(istio_requests_total{reporter=\"source\", connection_security_policy!=\"mutual_tls\", source_workload_namespace=~\"$namespace\", source_workload=~\"$workload\", destination_service=~\"$dstsvc\"}[5m])) by (destination_service)", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{destination_service }}", + "refId": "B", + "step": 2 + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Outgoing Success Rate (non-5xx responses) By Destination", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "percentunit", + "label": null, + "logBase": 1, + "max": "1.01", + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ] + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "description": "", + "fill": 1, + "gridPos": { + "h": 6, + "w": 8, + "x": 0, + "y": 41 + }, + "id": 72, + "legend": { + "alignAsTable": false, + "avg": false, + "current": false, + "hideEmpty": true, + "hideZero": false, + "max": false, + "min": false, + "rightSide": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "(histogram_quantile(0.50, sum(irate(istio_request_duration_milliseconds_bucket{reporter=\"source\", connection_security_policy=\"mutual_tls\", source_workload=~\"$workload\", source_workload_namespace=~\"$namespace\", destination_service=~\"$dstsvc\"}[1m])) by (destination_service, le)) / 1000) or histogram_quantile(0.50, sum(irate(istio_request_duration_seconds_bucket{reporter=\"source\", connection_security_policy=\"mutual_tls\", source_workload=~\"$workload\", source_workload_namespace=~\"$namespace\", destination_service=~\"$dstsvc\"}[1m])) by (destination_service, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_service }} P50 (🔐mTLS)", + "refId": "D", + "step": 2 + }, + { + "expr": "(histogram_quantile(0.90, sum(irate(istio_request_duration_milliseconds_bucket{reporter=\"source\", connection_security_policy=\"mutual_tls\", source_workload=~\"$workload\", source_workload_namespace=~\"$namespace\", destination_service=~\"$dstsvc\"}[1m])) by (destination_service, le)) / 1000) or histogram_quantile(0.90, sum(irate(istio_request_duration_seconds_bucket{reporter=\"source\", connection_security_policy=\"mutual_tls\", source_workload=~\"$workload\", source_workload_namespace=~\"$namespace\", destination_service=~\"$dstsvc\"}[1m])) by (destination_service, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_service }} P90 (🔐mTLS)", + "refId": "A", + "step": 2 + }, + { + "expr": "(histogram_quantile(0.95, sum(irate(istio_request_duration_milliseconds_bucket{reporter=\"source\", connection_security_policy=\"mutual_tls\", source_workload=~\"$workload\", source_workload_namespace=~\"$namespace\", destination_service=~\"$dstsvc\"}[1m])) by (destination_service, le)) / 1000) or histogram_quantile(0.95, sum(irate(istio_request_duration_seconds_bucket{reporter=\"source\", connection_security_policy=\"mutual_tls\", source_workload=~\"$workload\", source_workload_namespace=~\"$namespace\", destination_service=~\"$dstsvc\"}[1m])) by (destination_service, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_service }} P95 (🔐mTLS)", + "refId": "B", + "step": 2 + }, + { + "expr": "(histogram_quantile(0.99, sum(irate(istio_request_duration_milliseconds_bucket{reporter=\"source\", connection_security_policy=\"mutual_tls\", source_workload=~\"$workload\", source_workload_namespace=~\"$namespace\", destination_service=~\"$dstsvc\"}[1m])) by (destination_service, le)) / 1000) or histogram_quantile(0.99, sum(irate(istio_request_duration_seconds_bucket{reporter=\"source\", connection_security_policy=\"mutual_tls\", source_workload=~\"$workload\", source_workload_namespace=~\"$namespace\", destination_service=~\"$dstsvc\"}[1m])) by (destination_service, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_service }} P99 (🔐mTLS)", + "refId": "C", + "step": 2 + }, + { + "expr": "(histogram_quantile(0.50, sum(irate(istio_request_duration_milliseconds_bucket{reporter=\"source\", connection_security_policy!=\"mutual_tls\", source_workload=~\"$workload\", source_workload_namespace=~\"$namespace\", destination_service=~\"$dstsvc\"}[1m])) by (destination_service, le)) / 1000) or histogram_quantile(0.50, sum(irate(istio_request_duration_seconds_bucket{reporter=\"source\", connection_security_policy!=\"mutual_tls\", source_workload=~\"$workload\", source_workload_namespace=~\"$namespace\", destination_service=~\"$dstsvc\"}[1m])) by (destination_service, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_service }} P50", + "refId": "E", + "step": 2 + }, + { + "expr": "(histogram_quantile(0.90, sum(irate(istio_request_duration_milliseconds_bucket{reporter=\"source\", connection_security_policy!=\"mutual_tls\", source_workload=~\"$workload\", source_workload_namespace=~\"$namespace\", destination_service=~\"$dstsvc\"}[1m])) by (destination_service, le)) / 1000) or histogram_quantile(0.90, sum(irate(istio_request_duration_seconds_bucket{reporter=\"source\", connection_security_policy!=\"mutual_tls\", source_workload=~\"$workload\", source_workload_namespace=~\"$namespace\", destination_service=~\"$dstsvc\"}[1m])) by (destination_service, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_service }} P90", + "refId": "F", + "step": 2 + }, + { + "expr": "(histogram_quantile(0.95, sum(irate(istio_request_duration_milliseconds_bucket{reporter=\"source\", connection_security_policy!=\"mutual_tls\", source_workload=~\"$workload\", source_workload_namespace=~\"$namespace\", destination_service=~\"$dstsvc\"}[1m])) by (destination_service, le)) / 1000) or histogram_quantile(0.95, sum(irate(istio_request_duration_seconds_bucket{reporter=\"source\", connection_security_policy!=\"mutual_tls\", source_workload=~\"$workload\", source_workload_namespace=~\"$namespace\", destination_service=~\"$dstsvc\"}[1m])) by (destination_service, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_service }} P95", + "refId": "G", + "step": 2 + }, + { + "expr": "(histogram_quantile(0.99, sum(irate(istio_request_duration_milliseconds_bucket{reporter=\"source\", connection_security_policy!=\"mutual_tls\", source_workload=~\"$workload\", source_workload_namespace=~\"$namespace\", destination_service=~\"$dstsvc\"}[1m])) by (destination_service, le)) / 1000) or histogram_quantile(0.99, sum(irate(istio_request_duration_seconds_bucket{reporter=\"source\", connection_security_policy!=\"mutual_tls\", source_workload=~\"$workload\", source_workload_namespace=~\"$namespace\", destination_service=~\"$dstsvc\"}[1m])) by (destination_service, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_service }} P99", + "refId": "H", + "step": 2 + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Outgoing Request Duration by Destination", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "s", + "label": null, + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ] + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 6, + "w": 8, + "x": 8, + "y": 41 + }, + "id": 73, + "legend": { + "alignAsTable": false, + "avg": false, + "current": false, + "hideEmpty": true, + "max": false, + "min": false, + "rightSide": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "histogram_quantile(0.50, sum(irate(istio_request_bytes_bucket{reporter=\"source\", connection_security_policy=\"mutual_tls\", source_workload=~\"$workload\", source_workload_namespace=~\"$namespace\", destination_service=~\"$dstsvc\"}[1m])) by (destination_service, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_service }} P50 (🔐mTLS)", + "refId": "D", + "step": 2 + }, + { + "expr": "histogram_quantile(0.90, sum(irate(istio_request_bytes_bucket{reporter=\"source\", connection_security_policy=\"mutual_tls\", source_workload=~\"$workload\", source_workload_namespace=~\"$namespace\", destination_service=~\"$dstsvc\"}[1m])) by (destination_service, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_service }} P90 (🔐mTLS)", + "refId": "A", + "step": 2 + }, + { + "expr": "histogram_quantile(0.95, sum(irate(istio_request_bytes_bucket{reporter=\"source\", connection_security_policy=\"mutual_tls\", source_workload=~\"$workload\", source_workload_namespace=~\"$namespace\", destination_service=~\"$dstsvc\"}[1m])) by (destination_service, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_service }} P95 (🔐mTLS)", + "refId": "B", + "step": 2 + }, + { + "expr": "histogram_quantile(0.99, sum(irate(istio_request_bytes_bucket{reporter=\"source\", connection_security_policy=\"mutual_tls\", source_workload=~\"$workload\", source_workload_namespace=~\"$namespace\", destination_service=~\"$dstsvc\"}[1m])) by (destination_service, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_service }} P99 (🔐mTLS)", + "refId": "C", + "step": 2 + }, + { + "expr": "histogram_quantile(0.50, sum(irate(istio_request_bytes_bucket{reporter=\"source\", connection_security_policy!=\"mutual_tls\", source_workload=~\"$workload\", source_workload_namespace=~\"$namespace\", destination_service=~\"$dstsvc\"}[1m])) by (destination_service, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_service }} P50", + "refId": "E", + "step": 2 + }, + { + "expr": "histogram_quantile(0.90, sum(irate(istio_request_bytes_bucket{reporter=\"source\", connection_security_policy!=\"mutual_tls\", source_workload=~\"$workload\", source_workload_namespace=~\"$namespace\", destination_service=~\"$dstsvc\"}[1m])) by (destination_service, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_service }} P90", + "refId": "F", + "step": 2 + }, + { + "expr": "histogram_quantile(0.95, sum(irate(istio_request_bytes_bucket{reporter=\"source\", connection_security_policy!=\"mutual_tls\", source_workload=~\"$workload\", source_workload_namespace=~\"$namespace\", destination_service=~\"$dstsvc\"}[1m])) by (destination_service, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_service }} P95", + "refId": "G", + "step": 2 + }, + { + "expr": "histogram_quantile(0.99, sum(irate(istio_request_bytes_bucket{reporter=\"source\", connection_security_policy!=\"mutual_tls\", source_workload=~\"$workload\", source_workload_namespace=~\"$namespace\", destination_service=~\"$dstsvc\"}[1m])) by (destination_service, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_service }} P99", + "refId": "H", + "step": 2 + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Outgoing Request Size By Destination", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "decbytes", + "label": null, + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ] + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 6, + "w": 8, + "x": 16, + "y": 41 + }, + "id": 74, + "legend": { + "alignAsTable": false, + "avg": false, + "current": false, + "hideEmpty": true, + "max": false, + "min": false, + "rightSide": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "histogram_quantile(0.50, sum(irate(istio_response_bytes_bucket{reporter=\"source\", connection_security_policy=\"mutual_tls\", source_workload=~\"$workload\", source_workload_namespace=~\"$namespace\", destination_service=~\"$dstsvc\"}[1m])) by (destination_service, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_service }} P50 (🔐mTLS)", + "refId": "D", + "step": 2 + }, + { + "expr": "histogram_quantile(0.90, sum(irate(istio_response_bytes_bucket{reporter=\"source\", connection_security_policy=\"mutual_tls\", source_workload=~\"$workload\", source_workload_namespace=~\"$namespace\", destination_service=~\"$dstsvc\"}[1m])) by (destination_service, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_service }} P90 (🔐mTLS)", + "refId": "A", + "step": 2 + }, + { + "expr": "histogram_quantile(0.95, sum(irate(istio_response_bytes_bucket{reporter=\"source\", connection_security_policy=\"mutual_tls\", source_workload=~\"$workload\", source_workload_namespace=~\"$namespace\", destination_service=~\"$dstsvc\"}[1m])) by (destination_service, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_service }} P95 (🔐mTLS)", + "refId": "B", + "step": 2 + }, + { + "expr": "histogram_quantile(0.99, sum(irate(istio_response_bytes_bucket{reporter=\"source\", connection_security_policy=\"mutual_tls\", source_workload=~\"$workload\", source_workload_namespace=~\"$namespace\", destination_service=~\"$dstsvc\"}[1m])) by (destination_service, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_service }} P99 (🔐mTLS)", + "refId": "C", + "step": 2 + }, + { + "expr": "histogram_quantile(0.50, sum(irate(istio_response_bytes_bucket{reporter=\"source\", connection_security_policy!=\"mutual_tls\", source_workload=~\"$workload\", source_workload_namespace=~\"$namespace\", destination_service=~\"$dstsvc\"}[1m])) by (destination_service, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_service }} P50", + "refId": "E", + "step": 2 + }, + { + "expr": "histogram_quantile(0.90, sum(irate(istio_response_bytes_bucket{reporter=\"source\", connection_security_policy!=\"mutual_tls\", source_workload=~\"$workload\", source_workload_namespace=~\"$namespace\", destination_service=~\"$dstsvc\"}[1m])) by (destination_service, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_service }} P90", + "refId": "F", + "step": 2 + }, + { + "expr": "histogram_quantile(0.95, sum(irate(istio_response_bytes_bucket{reporter=\"source\", connection_security_policy!=\"mutual_tls\", source_workload=~\"$workload\", source_workload_namespace=~\"$namespace\", destination_service=~\"$dstsvc\"}[1m])) by (destination_service, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_service }} P95", + "refId": "G", + "step": 2 + }, + { + "expr": "histogram_quantile(0.99, sum(irate(istio_response_bytes_bucket{reporter=\"source\", connection_security_policy!=\"mutual_tls\", source_workload=~\"$workload\", source_workload_namespace=~\"$namespace\", destination_service=~\"$dstsvc\"}[1m])) by (destination_service, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_service }} P99", + "refId": "H", + "step": 2 + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Response Size By Destination", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "decbytes", + "label": null, + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ] + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 6, + "w": 12, + "x": 0, + "y": 47 + }, + "id": 76, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "round(sum(irate(istio_tcp_sent_bytes_total{connection_security_policy=\"mutual_tls\", reporter=\"source\", source_workload_namespace=~\"$namespace\", source_workload=~\"$workload\", destination_service=~\"$dstsvc\"}[1m])) by (destination_service), 0.001)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{ destination_service }} (🔐mTLS)", + "refId": "A", + "step": 2 + }, + { + "expr": "round(sum(irate(istio_tcp_sent_bytes_total{connection_security_policy!=\"mutual_tls\", reporter=\"source\", source_workload_namespace=~\"$namespace\", source_workload=~\"$workload\", destination_service=~\"$dstsvc\"}[1m])) by (destination_service), 0.001)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{ destination_service }}", + "refId": "B", + "step": 2 + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Bytes Sent on Outgoing TCP Connection", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "Bps", + "label": null, + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ] + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 6, + "w": 12, + "x": 12, + "y": 47 + }, + "id": 78, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "round(sum(irate(istio_tcp_received_bytes_total{reporter=\"source\", connection_security_policy=\"mutual_tls\", source_workload_namespace=~\"$namespace\", source_workload=~\"$workload\", destination_service=~\"$dstsvc\"}[1m])) by (destination_service), 0.001)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{ destination_service }} (🔐mTLS)", + "refId": "A", + "step": 2 + }, + { + "expr": "round(sum(irate(istio_tcp_received_bytes_total{reporter=\"source\", connection_security_policy!=\"mutual_tls\", source_workload_namespace=~\"$namespace\", source_workload=~\"$workload\", destination_service=~\"$dstsvc\"}[1m])) by (destination_service), 0.001)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{ destination_service }}", + "refId": "B", + "step": 2 + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Bytes Received from Outgoing TCP Connection", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "Bps", + "label": null, + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ] + } + ], + "refresh": "10s", + "schemaVersion": 16, + "style": "dark", + "tags": [], + "templating": { + "list": [ + { + "allValue": null, + "current": {}, + "datasource": "Prometheus", + "hide": 0, + "includeAll": false, + "label": "Namespace", + "multi": false, + "name": "namespace", + "options": [], + "query": "query_result(sum(istio_requests_total) by (destination_workload_namespace) or sum(istio_tcp_sent_bytes_total) by (destination_workload_namespace))", + "refresh": 1, + "regex": "/.*_namespace=\"([^\"]*).*/", + "sort": 0, + "tagValuesQuery": "", + "tags": [], + "tagsQuery": "", + "type": "query", + "useTags": false + }, + { + "allValue": null, + "current": {}, + "datasource": "Prometheus", + "hide": 0, + "includeAll": false, + "label": "Workload", + "multi": false, + "name": "workload", + "options": [], + "query": "query_result((sum(istio_requests_total{destination_workload_namespace=~\"$namespace\"}) by (destination_workload) or sum(istio_requests_total{source_workload_namespace=~\"$namespace\"}) by (source_workload)) or (sum(istio_tcp_sent_bytes_total{destination_workload_namespace=~\"$namespace\"}) by (destination_workload) or sum(istio_tcp_sent_bytes_total{source_workload_namespace=~\"$namespace\"}) by (source_workload)))", + "refresh": 1, + "regex": "/.*workload=\"([^\"]*).*/", + "sort": 1, + "tagValuesQuery": "", + "tags": [], + "tagsQuery": "", + "type": "query", + "useTags": false + }, + { + "allValue": null, + "current": {}, + "datasource": "Prometheus", + "hide": 0, + "includeAll": true, + "label": "Inbound Workload Namespace", + "multi": true, + "name": "srcns", + "options": [], + "query": "query_result( sum(istio_requests_total{reporter=\"destination\", destination_workload=\"$workload\", destination_workload_namespace=~\"$namespace\"}) by (source_workload_namespace) or sum(istio_tcp_sent_bytes_total{reporter=\"destination\", destination_workload=\"$workload\", destination_workload_namespace=~\"$namespace\"}) by (source_workload_namespace))", + "refresh": 1, + "regex": "/.*namespace=\"([^\"]*).*/", + "sort": 2, + "tagValuesQuery": "", + "tags": [], + "tagsQuery": "", + "type": "query", + "useTags": false + }, + { + "allValue": null, + "current": {}, + "datasource": "Prometheus", + "hide": 0, + "includeAll": true, + "label": "Inbound Workload", + "multi": true, + "name": "srcwl", + "options": [], + "query": "query_result( sum(istio_requests_total{reporter=\"destination\", destination_workload=\"$workload\", destination_workload_namespace=~\"$namespace\", source_workload_namespace=~\"$srcns\"}) by (source_workload) or sum(istio_tcp_sent_bytes_total{reporter=\"destination\", destination_workload=\"$workload\", destination_workload_namespace=~\"$namespace\", source_workload_namespace=~\"$srcns\"}) by (source_workload))", + "refresh": 1, + "regex": "/.*workload=\"([^\"]*).*/", + "sort": 3, + "tagValuesQuery": "", + "tags": [], + "tagsQuery": "", + "type": "query", + "useTags": false + }, + { + "allValue": null, + "current": {}, + "datasource": "Prometheus", + "hide": 0, + "includeAll": true, + "label": "Destination Service", + "multi": true, + "name": "dstsvc", + "options": [], + "query": "query_result( sum(istio_requests_total{reporter=\"source\", source_workload=~\"$workload\", source_workload_namespace=~\"$namespace\"}) by (destination_service) or sum(istio_tcp_sent_bytes_total{reporter=\"source\", source_workload=~\"$workload\", source_workload_namespace=~\"$namespace\"}) by (destination_service))", + "refresh": 1, + "regex": "/.*destination_service=\"([^\"]*).*/", + "sort": 4, + "tagValuesQuery": "", + "tags": [], + "tagsQuery": "", + "type": "query", + "useTags": false + } + ] + }, + "time": { + "from": "now-5m", + "to": "now" + }, + "timepicker": { + "refresh_intervals": [ + "5s", + "10s", + "30s", + "1m", + "5m", + "15m", + "30m", + "1h", + "2h", + "1d" + ], + "time_options": [ + "5m", + "15m", + "1h", + "6h", + "12h", + "24h", + "2d", + "7d", + "30d" + ] + }, + "timezone": "", + "title": "Istio Workload Dashboard", + "uid": "UbsSZTDik", + "version": 1 +} diff --git a/istio-1.3.5/install/kubernetes/helm/istio/charts/grafana/dashboards/mixer-dashboard.json b/istio-1.3.5/install/kubernetes/helm/istio/charts/grafana/dashboards/mixer-dashboard.json new file mode 100644 index 0000000..b074d13 --- /dev/null +++ b/istio-1.3.5/install/kubernetes/helm/istio/charts/grafana/dashboards/mixer-dashboard.json @@ -0,0 +1,1808 @@ +{ + "__inputs": [ + { + "name": "DS_PROMETHEUS", + "label": "Prometheus", + "description": "", + "type": "datasource", + "pluginId": "prometheus", + "pluginName": "Prometheus" + } + ], + "__requires": [ + { + "type": "grafana", + "id": "grafana", + "name": "Grafana", + "version": "5.2.3" + }, + { + "type": "panel", + "id": "graph", + "name": "Graph", + "version": "5.0.0" + }, + { + "type": "datasource", + "id": "prometheus", + "name": "Prometheus", + "version": "5.0.0" + }, + { + "type": "panel", + "id": "text", + "name": "Text", + "version": "5.0.0" + } + ], + "annotations": { + "list": [ + { + "builtIn": 1, + "datasource": "-- Grafana --", + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "limit": 100, + "name": "Annotations & Alerts", + "showIn": 0, + "type": "dashboard" + } + ] + }, + "editable": false, + "gnetId": null, + "graphTooltip": 1, + "id": null, + "iteration": 1543881232533, + "links": [], + "panels": [ + { + "content": "

Deployed Versions

", + "gridPos": { + "h": 3, + "w": 24, + "x": 0, + "y": 0 + }, + "height": "40", + "id": 62, + "links": [], + "mode": "html", + "title": "", + "transparent": true, + "type": "text" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 5, + "w": 24, + "x": 0, + "y": 3 + }, + "id": 64, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(istio_build{component=\"mixer\"}) by (tag)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{ tag }}", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Mixer Versions", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "content": "

Resource Usage

", + "gridPos": { + "h": 3, + "w": 24, + "x": 0, + "y": 8 + }, + "height": "40", + "id": 29, + "links": [], + "mode": "html", + "title": "", + "transparent": true, + "type": "text" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 7, + "w": 6, + "x": 0, + "y": 11 + }, + "id": 5, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(process_virtual_memory_bytes{job=~\"istio-telemetry|istio-policy\"}) by (job)", + "format": "time_series", + "instant": false, + "intervalFactor": 2, + "legendFormat": "Virtual Memory ({{ job }})", + "refId": "I" + }, + { + "expr": "sum(process_resident_memory_bytes{job=~\"istio-telemetry|istio-policy\"}) by (job)", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "Resident Memory ({{ job }})", + "refId": "H" + }, + { + "expr": "sum(go_memstats_heap_sys_bytes{job=~\"istio-telemetry|istio-policy\"}) by (job)", + "format": "time_series", + "hide": true, + "intervalFactor": 2, + "legendFormat": "heap sys ({{ job }})", + "refId": "A" + }, + { + "expr": "sum(go_memstats_heap_alloc_bytes{job=~\"istio-telemetry|istio-policy\"}) by (job)", + "format": "time_series", + "hide": true, + "intervalFactor": 2, + "legendFormat": "heap alloc ({{ job }})", + "refId": "D" + }, + { + "expr": "sum(go_memstats_alloc_bytes{job=~\"istio-telemetry|istio-policy\"}) by (job)", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "Alloc ({{ job }})", + "refId": "F" + }, + { + "expr": "sum(go_memstats_heap_inuse_bytes{job=~\"istio-telemetry|istio-policy\"}) by (job)", + "format": "time_series", + "hide": false, + "intervalFactor": 2, + "legendFormat": "Heap in-use ({{ job }})", + "refId": "E" + }, + { + "expr": "sum(go_memstats_stack_inuse_bytes{job=~\"istio-telemetry|istio-policy\"}) by (job)", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "Stack in-use ({{ job }})", + "refId": "G" + }, + { + "expr": "sum(label_replace(container_memory_usage_bytes{job=\"kubernetes-cadvisor\", container_name=~\"mixer|istio-proxy\", pod_name=~\"istio-telemetry-.*|istio-policy-.*\"}, \"service\", \"$1\" , \"pod_name\", \"(istio-telemetry|istio-policy)-.*\")) by (service)", + "format": "time_series", + "hide": false, + "intervalFactor": 2, + "legendFormat": "{{ service }} total (k8s)", + "refId": "C" + }, + { + "expr": "sum(label_replace(container_memory_usage_bytes{job=\"kubernetes-cadvisor\", container_name=~\"mixer|istio-proxy\", pod_name=~\"istio-telemetry-.*|istio-policy-.*\"}, \"service\", \"$1\" , \"pod_name\", \"(istio-telemetry|istio-policy)-.*\")) by (container_name, service)", + "format": "time_series", + "hide": false, + "intervalFactor": 2, + "legendFormat": "{{ service }} - {{ container_name }} (k8s)", + "refId": "B" + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Memory", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "bytes", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 7, + "w": 6, + "x": 6, + "y": 11 + }, + "id": 6, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "label_replace(sum(rate(container_cpu_usage_seconds_total{job=\"kubernetes-cadvisor\",container_name=~\"mixer|istio-proxy\", pod_name=~\"istio-telemetry-.*|istio-policy-.*\"}[1m])) by (pod_name), \"service\", \"$1\" , \"pod_name\", \"(istio-telemetry|istio-policy)-.*\")", + "format": "time_series", + "hide": false, + "intervalFactor": 2, + "legendFormat": "{{ service }} total (k8s)", + "refId": "A" + }, + { + "expr": "label_replace(sum(rate(container_cpu_usage_seconds_total{job=\"kubernetes-cadvisor\",container_name=~\"mixer|istio-proxy\", pod_name=~\"istio-telemetry-.*|istio-policy-.*\"}[1m])) by (container_name, pod_name), \"service\", \"$1\" , \"pod_name\", \"(istio-telemetry|istio-policy)-.*\")", + "format": "time_series", + "hide": false, + "intervalFactor": 2, + "legendFormat": "{{ service }} - {{ container_name }} (k8s)", + "refId": "B" + }, + { + "expr": "sum(irate(process_cpu_seconds_total{job=~\"istio-telemetry|istio-policy\"}[1m])) by (job)", + "format": "time_series", + "hide": false, + "intervalFactor": 2, + "legendFormat": "{{ job }} (self-reported)", + "refId": "C" + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "CPU", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 7, + "w": 6, + "x": 12, + "y": 11 + }, + "id": 7, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(process_open_fds{job=~\"istio-telemetry|istio-policy\"}) by (job)", + "format": "time_series", + "hide": true, + "instant": false, + "interval": "", + "intervalFactor": 2, + "legendFormat": "Open FDs ({{ job }})", + "refId": "A" + }, + { + "expr": "sum(label_replace(container_fs_usage_bytes{job=\"kubernetes-cadvisor\", container_name=~\"mixer|istio-proxy\", pod_name=~\"istio-telemetry-.*|istio-policy-.*\"}, \"service\", \"$1\" , \"pod_name\", \"(istio-telemetry|istio-policy)-.*\")) by (container_name, service)", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "{{ service }} - {{ container_name }}", + "refId": "B" + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Disk", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "bytes", + "label": "", + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "decimals": null, + "format": "none", + "label": "", + "logBase": 1024, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 7, + "w": 6, + "x": 18, + "y": 11 + }, + "id": 4, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": false, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(go_goroutines{job=~\"istio-telemetry|istio-policy\"}) by (job)", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "Number of Goroutines ({{ job }})", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Goroutines", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": "", + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "content": "

Mixer Overview

", + "gridPos": { + "h": 3, + "w": 24, + "x": 0, + "y": 18 + }, + "height": "40px", + "id": 30, + "links": [], + "mode": "html", + "title": "", + "transparent": true, + "type": "text" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 6, + "w": 6, + "x": 0, + "y": 21 + }, + "id": 9, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(rate(grpc_io_server_completed_rpcs[1m]))", + "format": "time_series", + "hide": false, + "intervalFactor": 2, + "legendFormat": "mixer (Total)", + "refId": "B" + }, + { + "expr": "sum(rate(grpc_io_server_completed_rpcs[1m])) by (grpc_server_method)", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "mixer ({{ grpc_server_method }})", + "refId": "C" + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Incoming Requests", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "ops", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 6, + "w": 6, + "x": 6, + "y": 21 + }, + "id": 8, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [ + { + "alias": "{}", + "yaxis": 1 + } + ], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "histogram_quantile(0.5, sum(rate(grpc_io_server_server_latency_bucket{}[1m])) by (grpc_server_method, le))", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "{{ grpc_server_method }} 0.5", + "refId": "B" + }, + { + "expr": "histogram_quantile(0.9, sum(rate(grpc_io_server_server_latency_bucket{}[1m])) by (grpc_server_method, le))", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "{{ grpc_server_method }} 0.9", + "refId": "C" + }, + { + "expr": "histogram_quantile(0.99, sum(rate(grpc_io_server_server_latency_bucket{}[1m])) by (grpc_server_method, le))", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "{{ grpc_server_method }} 0.99", + "refId": "D" + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Response Durations", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "ms", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 6, + "w": 6, + "x": 12, + "y": 21 + }, + "id": 11, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(rate(grpc_server_handled_total{grpc_code=~\"Unknown|Unimplemented|Internal|DataLoss\"}[1m])) by (grpc_method)", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "Mixer {{ grpc_method }}", + "refId": "B" + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Server Error Rate (5xx responses)", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 6, + "w": 6, + "x": 18, + "y": 21 + }, + "id": 12, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(irate(grpc_server_handled_total{grpc_code!=\"OK\",grpc_service=~\".*Mixer\"}[1m])) by (grpc_method)", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "Mixer {{ grpc_method }}", + "refId": "B" + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Non-successes (4xxs)", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "content": "

Adapters and Config

", + "gridPos": { + "h": 3, + "w": 24, + "x": 0, + "y": 27 + }, + "id": 28, + "links": [], + "mode": "html", + "title": "", + "transparent": true, + "type": "text" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 7, + "w": 12, + "x": 0, + "y": 30 + }, + "id": 13, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(irate(mixer_runtime_dispatches_total{adapter=~\"$adapter\"}[1m])) by (adapter)", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "{{ adapter }}", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Adapter Dispatch Count", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 7, + "w": 12, + "x": 12, + "y": 30 + }, + "id": 14, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "histogram_quantile(0.5, sum(irate(mixer_runtime_dispatch_duration_seconds_bucket{adapter=~\"$adapter\"}[1m])) by (adapter, le))", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "{{ adapter }} - p50", + "refId": "A" + }, + { + "expr": "histogram_quantile(0.9, sum(irate(mixer_runtime_dispatch_duration_seconds_bucket{adapter=~\"$adapter\"}[1m])) by (adapter, le))", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "{{ adapter }} - p90 ", + "refId": "B" + }, + { + "expr": "histogram_quantile(0.99, sum(irate(mixer_runtime_dispatch_duration_seconds_bucket{adapter=~\"$adapter\"}[1m])) by (adapter, le))", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "{{ adapter }} - p99", + "refId": "C" + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Adapter Dispatch Duration", + "tooltip": { + "shared": true, + "sort": 1, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "s", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 7, + "w": 6, + "x": 0, + "y": 37 + }, + "id": 60, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "scalar(topk(1, max(mixer_config_rule_config_count) by (configID)))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Rules", + "refId": "A" + }, + { + "expr": "scalar(topk(1, max(mixer_config_rule_config_error_count) by (configID)))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Config Errors", + "refId": "B" + }, + { + "expr": "scalar(topk(1, max(mixer_config_rule_config_match_error_count) by (configID)))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Match Errors", + "refId": "C" + }, + { + "expr": "scalar(topk(1, max(mixer_config_unsatisfied_action_handler_count) by (configID)))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Unsatisfied Actions", + "refId": "D" + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Rules", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 7, + "w": 6, + "x": 6, + "y": 37 + }, + "id": 56, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "scalar(topk(1, max(mixer_config_instance_config_count) by (configID)))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Instances", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Instances in Latest Config", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 7, + "w": 6, + "x": 12, + "y": 37 + }, + "id": 54, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "scalar(topk(1, max(mixer_config_handler_config_count) by (configID)))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Handlers", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Handlers in Latest Config", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 7, + "w": 6, + "x": 18, + "y": 37 + }, + "id": 58, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "scalar(topk(1, max(mixer_config_attribute_count) by (configID)))", + "format": "time_series", + "instant": false, + "intervalFactor": 1, + "legendFormat": "Attributes", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Attributes in Latest Config", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "content": "

Individual Adapters

", + "gridPos": { + "h": 3, + "w": 24, + "x": 0, + "y": 44 + }, + "id": 23, + "links": [], + "mode": "html", + "title": "", + "transparent": true, + "type": "text" + }, + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 47 + }, + "id": 46, + "panels": [], + "repeat": "adapter", + "title": "$adapter Adapter", + "type": "row" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 7, + "w": 12, + "x": 0, + "y": 48 + }, + "id": 17, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "label_replace(irate(mixer_runtime_dispatches_total{adapter=~\"$adapter\"}[1m]),\"handler\", \"$1 ($3)\", \"handler\", \"(.*)\\\\.(.*)\\\\.(.*)\")", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "{{ handler }} (error: {{ error }})", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Dispatch Count By Handler", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 7, + "w": 12, + "x": 12, + "y": 48 + }, + "id": 18, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "label_replace(histogram_quantile(0.5, sum(rate(mixer_runtime_dispatch_duration_seconds_bucket{adapter=~\"$adapter\"}[1m])) by (handler, error, le)), \"handler_short\", \"$1 ($3)\", \"handler\", \"(.*)\\\\.(.*)\\\\.(.*)\")", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "p50 - {{ handler_short }} (error: {{ error }})", + "refId": "A" + }, + { + "expr": "label_replace(histogram_quantile(0.9, sum(irate(mixer_runtime_dispatch_duration_seconds_bucket{adapter=~\"$adapter\"}[1m])) by (handler, error, le)), \"handler_short\", \"$1 ($3)\", \"handler\", \"(.*)\\\\.(.*)\\\\.(.*)\")", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "p90 - {{ handler_short }} (error: {{ error }})", + "refId": "D" + }, + { + "expr": "label_replace(histogram_quantile(0.99, sum(irate(mixer_runtime_dispatch_duration_seconds_bucket{adapter=~\"$adapter\"}[1m])) by (handler, error, le)), \"handler_short\", \"$1 ($3)\", \"handler\", \"(.*)\\\\.(.*)\\\\.(.*)\")", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "p99 - {{ handler_short }} (error: {{ error }})", + "refId": "E" + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Dispatch Duration By Handler", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "s", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + } + ], + "refresh": "5s", + "schemaVersion": 16, + "style": "dark", + "tags": [], + "templating": { + "list": [ + { + "allValue": null, + "current": {}, + "datasource": "Prometheus", + "hide": 0, + "includeAll": true, + "label": "Adapter", + "multi": true, + "name": "adapter", + "options": [], + "query": "label_values(adapter)", + "refresh": 2, + "regex": "", + "sort": 1, + "tagValuesQuery": "", + "tags": [], + "tagsQuery": "", + "type": "query", + "useTags": false + } + ] + }, + "time": { + "from": "now-5m", + "to": "now" + }, + "timepicker": { + "refresh_intervals": [ + "5s", + "10s", + "30s", + "1m", + "5m", + "15m", + "30m", + "1h", + "2h", + "1d" + ], + "time_options": [ + "5m", + "15m", + "1h", + "6h", + "12h", + "24h", + "2d", + "7d", + "30d" + ] + }, + "timezone": "", + "title": "Istio Mixer Dashboard", + "version": 4 +} diff --git a/istio-1.3.5/install/kubernetes/helm/istio/charts/grafana/dashboards/pilot-dashboard.json b/istio-1.3.5/install/kubernetes/helm/istio/charts/grafana/dashboards/pilot-dashboard.json new file mode 100644 index 0000000..b8ef6d2 --- /dev/null +++ b/istio-1.3.5/install/kubernetes/helm/istio/charts/grafana/dashboards/pilot-dashboard.json @@ -0,0 +1,1591 @@ +{ + "annotations": { + "list": [ + { + "builtIn": 1, + "datasource": "-- Grafana --", + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations & Alerts", + "type": "dashboard" + } + ] + }, + "editable": false, + "gnetId": null, + "graphTooltip": 1, + "id": 11, + "links": [], + "panels": [ + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 0 + }, + "id": 60, + "panels": [], + "title": "Deployed Versions", + "type": "row" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 5, + "w": 24, + "x": 0, + "y": 1 + }, + "id": 56, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(istio_build{component=\"pilot\"}) by (tag)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{ tag }}", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Pilot Versions", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 6 + }, + "id": 62, + "panels": [], + "title": "Resource Usage", + "type": "row" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 7, + "w": 6, + "x": 0, + "y": 7 + }, + "id": 5, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "process_virtual_memory_bytes{job=\"pilot\"}", + "format": "time_series", + "instant": false, + "intervalFactor": 2, + "legendFormat": "Virtual Memory", + "refId": "I", + "step": 2 + }, + { + "expr": "process_resident_memory_bytes{job=\"pilot\"}", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "Resident Memory", + "refId": "H", + "step": 2 + }, + { + "expr": "go_memstats_heap_sys_bytes{job=\"pilot\"}", + "format": "time_series", + "hide": true, + "intervalFactor": 2, + "legendFormat": "heap sys", + "refId": "A" + }, + { + "expr": "go_memstats_heap_alloc_bytes{job=\"pilot\"}", + "format": "time_series", + "hide": true, + "intervalFactor": 2, + "legendFormat": "heap alloc", + "refId": "D" + }, + { + "expr": "go_memstats_alloc_bytes{job=\"pilot\"}", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "Alloc", + "refId": "F", + "step": 2 + }, + { + "expr": "go_memstats_heap_inuse_bytes{job=\"pilot\"}", + "format": "time_series", + "hide": false, + "intervalFactor": 2, + "legendFormat": "Heap in-use", + "refId": "E", + "step": 2 + }, + { + "expr": "go_memstats_stack_inuse_bytes{job=\"pilot\"}", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "Stack in-use", + "refId": "G", + "step": 2 + }, + { + "expr": "container_memory_usage_bytes{job=\"kubernetes-cadvisor\", container_name=~\"discovery\", pod_name=~\"istio-pilot-.*\"}", + "format": "time_series", + "hide": false, + "intervalFactor": 2, + "legendFormat": "Discovery (container)", + "refId": "B", + "step": 2 + }, + { + "expr": "container_memory_usage_bytes{job=\"kubernetes-cadvisor\", container_name=~\"istio-proxy\", pod_name=~\"istio-pilot-.*\"}", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Sidecar (container)", + "refId": "C" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Memory", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "bytes", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 7, + "w": 6, + "x": 6, + "y": 7 + }, + "id": 6, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(irate(container_cpu_usage_seconds_total{job=\"kubernetes-cadvisor\",container_name=\"discovery\", pod_name=~\"istio-pilot-.*\"}[1m]))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Discovery (container)", + "refId": "A" + }, + { + "expr": "irate(process_cpu_seconds_total{job=\"pilot\"}[1m])", + "format": "time_series", + "hide": false, + "intervalFactor": 2, + "legendFormat": "Discovery (process)", + "refId": "C", + "step": 2 + }, + { + "expr": "sum(irate(container_cpu_usage_seconds_total{job=\"kubernetes-cadvisor\",container_name=\"istio-proxy\", pod_name=~\"istio-pilot-.*\"}[1m]))", + "format": "time_series", + "hide": false, + "intervalFactor": 2, + "legendFormat": "Sidecar (container)", + "refId": "B", + "step": 2 + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "CPU", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 7, + "w": 6, + "x": 12, + "y": 7 + }, + "id": 7, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "container_fs_usage_bytes{job=\"kubernetes-cadvisor\", container_name=\"discovery\", pod_name=~\"istio-pilot-.*\"}", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "Discovery", + "refId": "B", + "step": 2 + }, + { + "expr": "container_fs_usage_bytes{job=\"kubernetes-cadvisor\", container_name=\"istio-proxy\", pod_name=~\"istio-pilot-.*\"}", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Sidecar", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Disk", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "bytes", + "label": "", + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "decimals": null, + "format": "none", + "label": "", + "logBase": 1024, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 7, + "w": 6, + "x": 18, + "y": 7 + }, + "id": 4, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": false, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "go_goroutines{job=\"pilot\"}", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "Number of Goroutines", + "refId": "A", + "step": 2 + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Goroutines", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": "", + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 14 + }, + "id": 58, + "panels": [], + "title": "Pilot Push Information", + "type": "row" + }, + { + "aliasColors": {}, + "bars": true, + "dashLength": 10, + "dashes": false, + "description": "Shows the rate of pilot pushes", + "fill": 1, + "gridPos": { + "h": 8, + "w": 8, + "x": 0, + "y": 15 + }, + "id": 622, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": false, + "linewidth": 1, + "links": [], + "nullPointMode": "null as zero", + "paceLength": 10, + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": true, + "steppedLine": false, + "targets": [ + { + "expr": "sum(irate(pilot_xds_pushes{type=\"cds\"}[1m]))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Cluster", + "refId": "C" + }, + { + "expr": "sum(irate(pilot_xds_pushes{type=\"eds\"}[1m]))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Endpoints", + "refId": "D" + }, + { + "expr": "sum(irate(pilot_xds_pushes{type=\"lds\"}[1m]))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Listeners", + "refId": "A" + }, + { + "expr": "sum(irate(pilot_xds_pushes{type=\"rds\"}[1m]))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Routes", + "refId": "E" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Pilot Pushes", + "tooltip": { + "shared": false, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [ + "total" + ] + }, + "yaxes": [ + { + "format": "ops", + "label": null, + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "description": "Captures a variety of pilot errors", + "fill": 1, + "gridPos": { + "h": 8, + "w": 8, + "x": 8, + "y": 15 + }, + "id": 67, + "legend": { + "avg": false, + "current": false, + "hideEmpty": true, + "hideZero": true, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(pilot_xds_cds_reject{job=\"pilot\"}) or (absent(pilot_xds_cds_reject{job=\"pilot\"}) - 1)", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "Rejected CDS Configs", + "refId": "C" + }, + { + "expr": "sum(pilot_xds_eds_reject{job=\"pilot\"}) or (absent(pilot_xds_eds_reject{job=\"pilot\"}) - 1)", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "Rejected EDS Configs", + "refId": "D" + }, + { + "expr": "sum(pilot_xds_rds_reject{job=\"pilot\"}) or (absent(pilot_xds_rds_reject{job=\"pilot\"}) - 1)", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "Rejected RDS Configs", + "refId": "A" + }, + { + "expr": "sum(pilot_xds_lds_reject{job=\"pilot\"}) or (absent(pilot_xds_lds_reject{job=\"pilot\"}) - 1)", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "Rejected LDS Configs", + "refId": "B" + }, + { + "expr": "sum(rate(pilot_xds_write_timeout{job=\"pilot\"}[1m]))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Write Timeouts", + "refId": "F" + }, + { + "expr": "sum(rate(pilot_total_xds_internal_errors{job=\"pilot\"}[1m]))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "Internal Errors", + "refId": "H" + }, + { + "expr": "sum(rate(pilot_total_xds_rejects{job=\"pilot\"}[1m]))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "Config Rejection Rate", + "refId": "E" + }, + { + "expr": "sum(rate(pilot_xds_push_context_errors{job=\"pilot\"}[1m]))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "Push Context Errors", + "refId": "K" + }, + { + "expr": "sum(rate(pilot_xds_pushes{type!~\"lds|cds|rds|eds\"}[1m])) by (type)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Push Errors ({{ type }})", + "refId": "L" + }, + { + "expr": "sum(rate(pilot_xds_push_errors{job=\"pilot\"}[1m])) by (type)", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "Push Errors ({{ type }})", + "refId": "I" + }, + { + "expr": "sum(rate(pilot_xds_push_timeout{job=\"pilot\"}[1m]))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Push Timeouts", + "refId": "G" + }, + { + "expr": "sum(rate(pilot_xds_push_timeout_failures{job=\"pilot\"}[1m]))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Push Timeouts Failures", + "refId": "J" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Pilot Errors", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "description": "Shows the total time it takes to push a config update to a proxy", + "fill": 1, + "gridPos": { + "h": 8, + "w": 8, + "x": 16, + "y": 15 + }, + "id": 624, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "histogram_quantile(0.5, sum(rate(pilot_proxy_convergence_time_bucket[1m])) by (le))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "p50 ", + "refId": "A" + }, + { + "expr": "histogram_quantile(0.9, sum(rate(pilot_proxy_convergence_time_bucket[1m])) by (le))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "p90", + "refId": "B" + }, + { + "expr": "histogram_quantile(0.99, sum(rate(pilot_proxy_convergence_time_bucket[1m])) by (le))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "p99", + "refId": "C" + }, + { + "expr": "histogram_quantile(0.999, sum(rate(pilot_proxy_convergence_time_bucket[1m])) by (le))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "p99.9", + "refId": "D" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Proxy Push Time", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "s", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 8, + "w": 8, + "x": 0, + "y": 23 + }, + "id": 45, + "legend": { + "avg": false, + "current": false, + "hideEmpty": true, + "hideZero": true, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null as zero", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "pilot_conflict_inbound_listener{job=\"pilot\"}", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "Inbound Listeners", + "refId": "B" + }, + { + "expr": "pilot_conflict_outbound_listener_http_over_current_tcp{job=\"pilot\"}", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "Outbound Listeners (http over current tcp)", + "refId": "A" + }, + { + "expr": "pilot_conflict_outbound_listener_tcp_over_current_tcp{job=\"pilot\"}", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "Outbound Listeners (tcp over current tcp)", + "refId": "C" + }, + { + "expr": "pilot_conflict_outbound_listener_tcp_over_current_http{job=\"pilot\"}", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "Outbound Listeners (tcp over current http)", + "refId": "D" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Conflicts", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 8, + "w": 8, + "x": 8, + "y": 23 + }, + "id": 47, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "pilot_virt_services{job=\"pilot\"}", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Virtual Services", + "refId": "A" + }, + { + "expr": "pilot_services{job=\"pilot\"}", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Services", + "refId": "B" + }, + { + "expr": "pilot_xds{job=\"pilot\"}", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Connected Endpoints", + "refId": "E" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "ADS Monitoring", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "columns": [], + "datasource": "Prometheus", + "description": "Clusters in this table do not have any endpoints known to pilot. This could be from referencing subsets that do not have any instances, or pods marked as NotReady", + "fontSize": "100%", + "gridPos": { + "h": 8, + "w": 8, + "x": 16, + "y": 23 + }, + "id": 51, + "links": [], + "pageSize": null, + "scroll": true, + "showHeader": true, + "sort": { + "col": null, + "desc": false + }, + "styles": [ + { + "alias": "Time", + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "pattern": "Time", + "type": "date" + }, + { + "alias": "Clusters", + "colorMode": null, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "decimals": 2, + "pattern": "/.*/", + "thresholds": [], + "type": "number", + "unit": "short" + } + ], + "targets": [ + { + "expr": "sum(pilot_xds_eds_instances{job=\"pilot\", cluster=~\".+\\\\|.+\"}) by (cluster) < 1", + "format": "time_series", + "hide": false, + "instant": true, + "intervalFactor": 1, + "legendFormat": "{{cluster}}", + "refId": "B" + } + ], + "timeFrom": null, + "timeShift": null, + "title": "Clusters with no known endpoints", + "transform": "timeseries_aggregations", + "type": "table" + }, + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 31 + }, + "id": 64, + "panels": [], + "title": "Envoy Information", + "type": "row" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "description": "Shows details about Envoy proxies in the mesh", + "fill": 1, + "gridPos": { + "h": 8, + "w": 8, + "x": 0, + "y": 32 + }, + "id": 40, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(irate(envoy_cluster_upstream_cx_total{cluster_name=\"xds-grpc\"}[1m]))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "XDS Connections", + "refId": "C" + }, + { + "expr": "sum(irate(envoy_cluster_upstream_cx_connect_fail{cluster_name=\"xds-grpc\"}[1m]))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "XDS Connection Failures", + "refId": "A" + }, + { + "expr": "sum(increase(envoy_server_hot_restart_epoch[1m]))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Envoy Restarts", + "refId": "B" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Envoy Details", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "ops", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "ops", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 8, + "w": 8, + "x": 8, + "y": 32 + }, + "id": 41, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(envoy_cluster_upstream_cx_active{cluster_name=\"xds-grpc\"})", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "XDS Active Connections", + "refId": "C", + "step": 2 + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "XDS Active Connections", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "description": "Shows the size of XDS requests and responses", + "fill": 1, + "gridPos": { + "h": 8, + "w": 8, + "x": 16, + "y": 32 + }, + "id": 42, + "legend": { + "avg": false, + "current": false, + "hideEmpty": false, + "hideZero": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "max(rate(envoy_cluster_upstream_cx_rx_bytes_total{cluster_name=\"xds-grpc\"}[1m]))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "XDS Response Bytes Max", + "refId": "D" + }, + { + "expr": "quantile(0.5, rate(envoy_cluster_upstream_cx_rx_bytes_total{cluster_name=\"xds-grpc\"}[1m]))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "XDS Response Bytes Average", + "refId": "B" + }, + { + "expr": "max(rate(envoy_cluster_upstream_cx_tx_bytes_total{cluster_name=\"xds-grpc\"}[1m]))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "XDS Request Bytes Max", + "refId": "A" + }, + { + "expr": "quantile(.5, rate(envoy_cluster_upstream_cx_tx_bytes_total{cluster_name=\"xds-grpc\"}[1m]))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "XDS Request Bytes Average", + "refId": "C" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "XDS Requests Size", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "Bps", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "ops", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + } + ], + "refresh": "5s", + "schemaVersion": 18, + "style": "dark", + "tags": [], + "templating": { + "list": [] + }, + "time": { + "from": "now-5m", + "to": "now" + }, + "timepicker": { + "refresh_intervals": [ + "5s", + "10s", + "30s", + "1m", + "5m", + "15m", + "30m", + "1h", + "2h", + "1d" + ], + "time_options": [ + "5m", + "15m", + "1h", + "6h", + "12h", + "24h", + "2d", + "7d", + "30d" + ] + }, + "timezone": "browser", + "title": "Istio Pilot Dashboard", + "uid": "3--MLVZZk", + "version": 11 +} \ No newline at end of file diff --git a/istio-1.3.5/install/kubernetes/helm/istio/charts/grafana/templates/_helpers.tpl b/istio-1.3.5/install/kubernetes/helm/istio/charts/grafana/templates/_helpers.tpl new file mode 100644 index 0000000..9d4c592 --- /dev/null +++ b/istio-1.3.5/install/kubernetes/helm/istio/charts/grafana/templates/_helpers.tpl @@ -0,0 +1,32 @@ +{{/* vim: set filetype=mustache: */}} +{{/* +Expand the name of the chart. +*/}} +{{- define "grafana.name" -}} +{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" -}} +{{- end -}} + +{{/* +Create a default fully qualified app name. +We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). +If release name contains chart name it will be used as a full name. +*/}} +{{- define "grafana.fullname" -}} +{{- if .Values.fullnameOverride -}} +{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" -}} +{{- else -}} +{{- $name := default .Chart.Name .Values.nameOverride -}} +{{- if contains $name .Release.Name -}} +{{- .Release.Name | trunc 63 | trimSuffix "-" -}} +{{- else -}} +{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" -}} +{{- end -}} +{{- end -}} +{{- end -}} + +{{/* +Create chart name and version as used by the chart label. +*/}} +{{- define "grafana.chart" -}} +{{- .Chart.Name | trunc 63 | trimSuffix "-" -}} +{{- end -}} diff --git a/istio-1.3.5/install/kubernetes/helm/istio/charts/grafana/templates/configmap-custom-resources.yaml b/istio-1.3.5/install/kubernetes/helm/istio/charts/grafana/templates/configmap-custom-resources.yaml new file mode 100644 index 0000000..b89bc07 --- /dev/null +++ b/istio-1.3.5/install/kubernetes/helm/istio/charts/grafana/templates/configmap-custom-resources.yaml @@ -0,0 +1,16 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: istio-grafana-custom-resources + namespace: {{ .Release.Namespace }} + labels: + app: {{ template "grafana.name" . }} + chart: {{ template "grafana.chart" . }} + heritage: {{ .Release.Service }} + release: {{ .Release.Name }} + istio: grafana +data: + custom-resources.yaml: |- + {{- include "grafana-default.yaml.tpl" . | indent 4}} + run.sh: |- + {{- include "install-custom-resources.sh.tpl" . | indent 4}} diff --git a/istio-1.3.5/install/kubernetes/helm/istio/charts/grafana/templates/configmap-dashboards.yaml b/istio-1.3.5/install/kubernetes/helm/istio/charts/grafana/templates/configmap-dashboards.yaml new file mode 100644 index 0000000..dd1ab0d --- /dev/null +++ b/istio-1.3.5/install/kubernetes/helm/istio/charts/grafana/templates/configmap-dashboards.yaml @@ -0,0 +1,18 @@ +{{- $files := .Files }} +{{- range $path, $bytes := .Files.Glob "dashboards/*.json" }} +{{- $filename := trimSuffix (ext $path) (base $path) }} +apiVersion: v1 +kind: ConfigMap +metadata: + name: istio-grafana-configuration-dashboards-{{ $filename }} + namespace: {{ $.Release.Namespace }} + labels: + app: {{ template "grafana.name" $ }} + chart: {{ template "grafana.chart" $ }} + heritage: {{ $.Release.Service }} + release: {{ $.Release.Name }} + istio: grafana +data: + {{ base $path }}: '{{ $files.Get $path }}' +--- +{{- end }} diff --git a/istio-1.3.5/install/kubernetes/helm/istio/charts/grafana/templates/configmap.yaml b/istio-1.3.5/install/kubernetes/helm/istio/charts/grafana/templates/configmap.yaml new file mode 100644 index 0000000..c86efe1 --- /dev/null +++ b/istio-1.3.5/install/kubernetes/helm/istio/charts/grafana/templates/configmap.yaml @@ -0,0 +1,25 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: istio-grafana + namespace: {{ .Release.Namespace }} + labels: + app: {{ template "grafana.name" . }} + chart: {{ template "grafana.chart" . }} + heritage: {{ .Release.Service }} + release: {{ .Release.Name }} + istio: grafana +data: +{{- if .Values.datasources }} + {{- range $key, $value := .Values.datasources }} + {{ $key }}: | +{{ toYaml $value | indent 4 }} + {{- end -}} +{{- end -}} + +{{- if .Values.dashboardProviders }} + {{- range $key, $value := .Values.dashboardProviders }} + {{ $key }}: | +{{ toYaml $value | indent 4 }} + {{- end -}} +{{- end -}} diff --git a/istio-1.3.5/install/kubernetes/helm/istio/charts/grafana/templates/create-custom-resources-job.yaml b/istio-1.3.5/install/kubernetes/helm/istio/charts/grafana/templates/create-custom-resources-job.yaml new file mode 100644 index 0000000..8f179d5 --- /dev/null +++ b/istio-1.3.5/install/kubernetes/helm/istio/charts/grafana/templates/create-custom-resources-job.yaml @@ -0,0 +1,101 @@ +apiVersion: v1 +kind: ServiceAccount +{{- if .Values.global.imagePullSecrets }} +imagePullSecrets: +{{- range .Values.global.imagePullSecrets }} + - name: {{ . }} +{{- end }} +{{- end }} +metadata: + name: istio-grafana-post-install-account + namespace: {{ .Release.Namespace }} + labels: + app: {{ template "grafana.name" . }} + chart: {{ template "grafana.chart" . }} + heritage: {{ .Release.Service }} + release: {{ .Release.Name }} +{{- if .Values.global.imagePullSecrets }} +imagePullSecrets: +{{- range .Values.global.imagePullSecrets }} + - name: {{ . }} +{{- end }} +{{- end }} +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: istio-grafana-post-install-{{ .Release.Namespace }} + labels: + app: {{ template "grafana.name" . }} + chart: {{ template "grafana.chart" . }} + heritage: {{ .Release.Service }} + release: {{ .Release.Name }} +rules: +- apiGroups: ["authentication.istio.io"] # needed to create default authn policy + resources: ["*"] + verbs: ["*"] +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: istio-grafana-post-install-role-binding-{{ .Release.Namespace }} + labels: + app: {{ template "grafana.name" . }} + chart: {{ template "grafana.chart" . }} + heritage: {{ .Release.Service }} + release: {{ .Release.Name }} +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: istio-grafana-post-install-{{ .Release.Namespace }} +subjects: + - kind: ServiceAccount + name: istio-grafana-post-install-account + namespace: {{ .Release.Namespace }} +--- +apiVersion: batch/v1 +kind: Job +metadata: + name: istio-grafana-post-install-{{ .Values.global.tag | printf "%v" | trunc 32 }} + namespace: {{ .Release.Namespace }} + annotations: + "helm.sh/hook": post-install + "helm.sh/hook-delete-policy": hook-succeeded + labels: + app: {{ template "grafana.name" . }} + chart: {{ template "grafana.chart" . }} + heritage: {{ .Release.Service }} + release: {{ .Release.Name }} +spec: + template: + metadata: + name: istio-grafana-post-install + labels: + app: istio-grafana + chart: {{ template "grafana.chart" . }} + heritage: {{ .Release.Service }} + release: {{ .Release.Name }} + spec: + serviceAccountName: istio-grafana-post-install-account + containers: + - name: kubectl + image: "{{ .Values.global.hub }}/kubectl:{{ .Values.global.tag }}" + command: [ "/bin/bash", "/tmp/grafana/run.sh", "/tmp/grafana/custom-resources.yaml" ] + volumeMounts: + - mountPath: "/tmp/grafana" + name: tmp-configmap-grafana + volumes: + - name: tmp-configmap-grafana + configMap: + name: istio-grafana-custom-resources + restartPolicy: OnFailure + affinity: + {{- include "nodeaffinity" . | indent 6 }} + {{- include "podAntiAffinity" . | indent 6 }} + {{- if .Values.tolerations }} + tolerations: +{{ toYaml .Values.tolerations | indent 6 }} + {{- else if .Values.global.defaultTolerations }} + tolerations: +{{ toYaml .Values.global.defaultTolerations | indent 6 }} + {{- end }} diff --git a/istio-1.3.5/install/kubernetes/helm/istio/charts/grafana/templates/deployment.yaml b/istio-1.3.5/install/kubernetes/helm/istio/charts/grafana/templates/deployment.yaml new file mode 100644 index 0000000..ba3037e --- /dev/null +++ b/istio-1.3.5/install/kubernetes/helm/istio/charts/grafana/templates/deployment.yaml @@ -0,0 +1,138 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: grafana + namespace: {{ .Release.Namespace }} + labels: + app: {{ template "grafana.name" . }} + chart: {{ template "grafana.chart" . }} + heritage: {{ .Release.Service }} + release: {{ .Release.Name }} +spec: + replicas: {{ .Values.replicaCount }} + selector: + matchLabels: + app: grafana + template: + metadata: + labels: + app: grafana + chart: {{ template "grafana.chart" . }} + heritage: {{ .Release.Service }} + release: {{ .Release.Name }} + annotations: + sidecar.istio.io/inject: "false" + prometheus.io/scrape: "true" + spec: + securityContext: + runAsUser: 472 + fsGroup: 472 +{{- if .Values.global.priorityClassName }} + priorityClassName: "{{ .Values.global.priorityClassName }}" +{{- end }} +{{- if .Values.global.imagePullSecrets }} + imagePullSecrets: +{{- range .Values.global.imagePullSecrets }} + - name: {{ . }} +{{- end }} +{{- end }} + containers: + - name: {{ .Chart.Name }} + image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}" + imagePullPolicy: {{ .Values.global.imagePullPolicy }} + ports: + - containerPort: 3000 + readinessProbe: + httpGet: + path: /api/health + port: 3000 + env: + - name: GRAFANA_PORT + value: "3000" +{{- if .Values.security.enabled }} + - name: GF_SECURITY_ADMIN_USER + valueFrom: + secretKeyRef: + name: {{ .Values.security.secretName }} + key: {{ .Values.security.usernameKey }} + - name: GF_SECURITY_ADMIN_PASSWORD + valueFrom: + secretKeyRef: + name: {{ .Values.security.secretName }} + key: {{ .Values.security.passphraseKey }} + - name: GF_AUTH_BASIC_ENABLED + value: "true" + - name: GF_AUTH_ANONYMOUS_ENABLED + value: "false" + - name: GF_AUTH_DISABLE_LOGIN_FORM + value: "false" +{{- else }} + - name: GF_AUTH_BASIC_ENABLED + value: "false" + - name: GF_AUTH_ANONYMOUS_ENABLED + value: "true" + - name: GF_AUTH_ANONYMOUS_ORG_ROLE + value: Admin +{{- end }} + - name: GF_PATHS_DATA + value: /data/grafana + {{- range $key, $value := $.Values.env }} + - name: {{ $key }} + value: {{ $value | quote }} + {{- end }} + {{- range $key, $secret := $.Values.envSecrets }} + - name: {{ $key }} + valueFrom: + secretKeyRef: + name: {{ $secret }} + key: {{ $key | quote }} + {{- end }} + resources: +{{- if .Values.resources }} +{{ toYaml .Values.resources | indent 12 }} +{{- else }} +{{ toYaml .Values.global.defaultResources | indent 12 }} +{{- end }} + volumeMounts: + - name: data + mountPath: /data/grafana + {{- range $path, $bytes := .Files.Glob "dashboards/*.json" }} + {{- $filename := trimSuffix (ext $path) (base $path) }} + - name: dashboards-istio-{{ $filename }} + mountPath: "/var/lib/grafana/dashboards/istio/{{ base $path }}" + subPath: {{ base $path }} + readOnly: true + {{- end }} + - name: config + mountPath: "/etc/grafana/provisioning/datasources/datasources.yaml" + subPath: datasources.yaml + - name: config + mountPath: "/etc/grafana/provisioning/dashboards/dashboardproviders.yaml" + subPath: dashboardproviders.yaml + affinity: + {{- include "nodeaffinity" . | indent 6 }} + {{- include "podAntiAffinity" . | indent 6 }} + {{- if .Values.tolerations }} + tolerations: +{{ toYaml .Values.tolerations | indent 6 }} + {{- else if .Values.global.defaultTolerations }} + tolerations: +{{ toYaml .Values.global.defaultTolerations | indent 6 }} + {{- end }} + volumes: + - name: config + configMap: + name: istio-grafana + - name: data +{{- if .Values.persist }} + persistentVolumeClaim: + claimName: istio-grafana-pvc +{{- else }} + emptyDir: {} +{{- end }} +{{- range $path, $bytes := .Files.Glob "dashboards/*.json" }} +{{- $filename := trimSuffix (ext $path) (base $path) }} + - name: dashboards-istio-{{ $filename }} + configMap: + name: istio-grafana-configuration-dashboards-{{ $filename }} +{{- end }} diff --git a/istio-1.3.5/install/kubernetes/helm/istio/charts/grafana/templates/grafana-ports-mtls.yaml b/istio-1.3.5/install/kubernetes/helm/istio/charts/grafana/templates/grafana-ports-mtls.yaml new file mode 100644 index 0000000..b9a3926 --- /dev/null +++ b/istio-1.3.5/install/kubernetes/helm/istio/charts/grafana/templates/grafana-ports-mtls.yaml @@ -0,0 +1,17 @@ +{{ define "grafana-default.yaml.tpl" }} +apiVersion: authentication.istio.io/v1alpha1 +kind: Policy +metadata: + name: grafana-ports-mtls-disabled + namespace: {{ .Release.Namespace }} + labels: + app: {{ template "grafana.name" . }} + chart: {{ template "grafana.chart" . }} + heritage: {{ .Release.Service }} + release: {{ .Release.Name }} +spec: + targets: + - name: grafana + ports: + - number: {{ .Values.service.externalPort }} +{{- end }} diff --git a/istio-1.3.5/install/kubernetes/helm/istio/charts/grafana/templates/ingress.yaml b/istio-1.3.5/install/kubernetes/helm/istio/charts/grafana/templates/ingress.yaml new file mode 100644 index 0000000..0ebe71f --- /dev/null +++ b/istio-1.3.5/install/kubernetes/helm/istio/charts/grafana/templates/ingress.yaml @@ -0,0 +1,40 @@ +{{- if .Values.ingress.enabled -}} +apiVersion: extensions/v1beta1 +kind: Ingress +metadata: + name: grafana + namespace: {{ .Release.Namespace }} + labels: + app: {{ template "grafana.name" . }} + chart: {{ template "grafana.chart" . }} + heritage: {{ .Release.Service }} + release: {{ .Release.Name }} + annotations: + {{- range $key, $value := .Values.ingress.annotations }} + {{ $key }}: {{ $value | quote }} + {{- end }} +spec: + rules: +{{- if .Values.ingress.hosts }} + {{- range $host := .Values.ingress.hosts }} + - host: {{ $host }} + http: + paths: + - path: {{ if $.Values.contextPath }} {{ $.Values.contextPath }} {{ else }} / {{ end }} + backend: + serviceName: grafana + servicePort: 3000 + {{- end -}} +{{- else }} + - http: + paths: + - path: {{ if .Values.contextPath }} {{ .Values.contextPath }} {{ else }} / {{ end }} + backend: + serviceName: grafana + servicePort: 3000 +{{- end }} + {{- if .Values.ingress.tls }} + tls: +{{ toYaml .Values.ingress.tls | indent 4 }} + {{- end -}} +{{- end -}} diff --git a/istio-1.3.5/install/kubernetes/helm/istio/charts/grafana/templates/pvc.yaml b/istio-1.3.5/install/kubernetes/helm/istio/charts/grafana/templates/pvc.yaml new file mode 100644 index 0000000..e376a13 --- /dev/null +++ b/istio-1.3.5/install/kubernetes/helm/istio/charts/grafana/templates/pvc.yaml @@ -0,0 +1,19 @@ +{{- if .Values.persist }} +kind: PersistentVolumeClaim +apiVersion: v1 +metadata: + name: istio-grafana-pvc + namespace: {{ .Release.Namespace }} + labels: + app: {{ template "grafana.name" . }} + chart: {{ template "grafana.chart" . }} + heritage: {{ .Release.Service }} + release: {{ .Release.Name }} +spec: + storageClassName: {{ .Values.storageClassName }} + accessModes: + - {{ .Values.accessMode }} + resources: + requests: + storage: 5Gi +{{- end }} diff --git a/istio-1.3.5/install/kubernetes/helm/istio/charts/grafana/templates/service.yaml b/istio-1.3.5/install/kubernetes/helm/istio/charts/grafana/templates/service.yaml new file mode 100644 index 0000000..1dfd82c --- /dev/null +++ b/istio-1.3.5/install/kubernetes/helm/istio/charts/grafana/templates/service.yaml @@ -0,0 +1,32 @@ +apiVersion: v1 +kind: Service +metadata: + name: grafana + namespace: {{ .Release.Namespace }} + annotations: + {{- range $key, $val := .Values.service.annotations }} + {{ $key }}: {{ $val | quote }} + {{- end }} + labels: + app: {{ template "grafana.name" . }} + chart: {{ template "grafana.chart" . }} + heritage: {{ .Release.Service }} + release: {{ .Release.Name }} +spec: + type: {{ .Values.service.type }} + ports: + - port: {{ .Values.service.externalPort }} + targetPort: 3000 + protocol: TCP + name: {{ .Values.service.name }} + selector: + app: grafana +{{- if .Values.service.loadBalancerIP }} + loadBalancerIP: "{{ .Values.service.loadBalancerIP }}" +{{- end }} + {{if .Values.service.loadBalancerSourceRanges}} + loadBalancerSourceRanges: + {{range $rangeList := .Values.service.loadBalancerSourceRanges}} + - {{ $rangeList }} + {{end}} + {{end}} \ No newline at end of file diff --git a/istio-1.3.5/install/kubernetes/helm/istio/charts/grafana/templates/tests/test-grafana-connection.yaml b/istio-1.3.5/install/kubernetes/helm/istio/charts/grafana/templates/tests/test-grafana-connection.yaml new file mode 100644 index 0000000..e9268c4 --- /dev/null +++ b/istio-1.3.5/install/kubernetes/helm/istio/charts/grafana/templates/tests/test-grafana-connection.yaml @@ -0,0 +1,37 @@ +{{- if .Values.global.enableHelmTest }} +apiVersion: v1 +kind: Pod +metadata: + name: {{ template "grafana.fullname" . }}-test + namespace: {{ .Release.Namespace }} + labels: + app: grafana-test + chart: {{ template "grafana.chart" . }} + release: {{ .Release.Name }} + heritage: {{ .Release.Service }} + istio: grafana + annotations: + sidecar.istio.io/inject: "false" + helm.sh/hook: test-success +spec: +{{- if .Values.global.priorityClassName }} + priorityClassName: "{{ .Values.global.priorityClassName }}" +{{- end }} + containers: + - name: "{{ template "grafana.fullname" . }}-test" + image: pstauffer/curl:v1.0.3 + imagePullPolicy: "{{ .Values.global.imagePullPolicy }}" + command: ['curl'] + args: ['http://grafana:{{ .Values.grafana.service.externalPort }}'] + restartPolicy: Never + affinity: + {{- include "nodeaffinity" . | indent 4 }} + {{- include "podAntiAffinity" . | indent 4 }} + {{- if .Values.tolerations }} + tolerations: +{{ toYaml .Values.tolerations | indent 2 }} + {{- else if .Values.global.defaultTolerations }} + tolerations: +{{ toYaml .Values.global.defaultTolerations | indent 2 }} + {{- end }} +{{- end }} diff --git a/istio-1.3.5/install/kubernetes/helm/istio/charts/grafana/values.yaml b/istio-1.3.5/install/kubernetes/helm/istio/charts/grafana/values.yaml new file mode 100644 index 0000000..d6c192a --- /dev/null +++ b/istio-1.3.5/install/kubernetes/helm/istio/charts/grafana/values.yaml @@ -0,0 +1,117 @@ +# +# addon grafana configuration +# +enabled: false +replicaCount: 1 +image: + repository: grafana/grafana + tag: 6.1.6 +ingress: + enabled: false + ## Used to create an Ingress record. + hosts: + - grafana.local + annotations: + # kubernetes.io/ingress.class: nginx + # kubernetes.io/tls-acme: "true" + tls: + # Secrets must be manually created in the namespace. + # - secretName: grafana-tls + # hosts: + # - grafana.local +persist: false +storageClassName: "" +accessMode: ReadWriteMany +security: + enabled: false + secretName: grafana + usernameKey: username + passphraseKey: passphrase +nodeSelector: {} +tolerations: [] + +env: {} + # Define additional environment variables for configuring grafana. + # @see https://grafana.com/docs/installation/configuration/#using-environment-variables + # Format: env_variable_name: value + # For example: + # GF_SMTP_ENABLED: true + # GF_SMTP_HOST: email-smtp.eu-west-1.amazonaws.com:2587 + # GF_SMTP_FROM_ADDRESS: alerts@mydomain.com + # GF_SMTP_FROM_NAME: Grafana + +envSecrets: {} + # The key name and ENV name must match in the secrets file. + # @see https://grafana.com/docs/installation/configuration/#using-environment-variables + # For example: + # --- + # apiVersion: v1 + # kind: Secret + # metadata: + # name: grafana-secrets + # namespace: istio-system + # data: + # GF_SMTP_USER: bXl1c2Vy + # GF_SMTP_PASSWORD: bXlwYXNzd29yZA== + # type: Opaque + # --- + # env_variable_key_name: secretsName + # --- + # GF_SMTP_USER: grafana-secrets + # GF_SMTP_PASSWORD: grafana-secrets + +# Specify the pod anti-affinity that allows you to constrain which nodes +# your pod is eligible to be scheduled based on labels on pods that are +# already running on the node rather than based on labels on nodes. +# There are currently two types of anti-affinity: +# "requiredDuringSchedulingIgnoredDuringExecution" +# "preferredDuringSchedulingIgnoredDuringExecution" +# which denote "hard" vs. "soft" requirements, you can define your values +# in "podAntiAffinityLabelSelector" and "podAntiAffinityTermLabelSelector" +# correspondingly. +# For example: +# podAntiAffinityLabelSelector: +# - key: security +# operator: In +# values: S1,S2 +# topologyKey: "kubernetes.io/hostname" +# This pod anti-affinity rule says that the pod requires not to be scheduled +# onto a node if that node is already running a pod with label having key +# "security" and value "S1". +podAntiAffinityLabelSelector: [] +podAntiAffinityTermLabelSelector: [] + +contextPath: /grafana +service: + annotations: {} + name: http + type: ClusterIP + externalPort: 3000 + loadBalancerIP: + loadBalancerSourceRanges: + +datasources: + datasources.yaml: + apiVersion: 1 + datasources: + - name: Prometheus + type: prometheus + orgId: 1 + url: http://prometheus:9090 + access: proxy + isDefault: true + jsonData: + timeInterval: 5s + editable: true + +dashboardProviders: + dashboardproviders.yaml: + apiVersion: 1 + providers: + - name: 'istio' + orgId: 1 + folder: 'istio' + type: file + disableDeletion: false + options: + path: /var/lib/grafana/dashboards/istio diff --git a/istio-1.3.5/install/kubernetes/helm/istio/charts/istiocoredns/Chart.yaml b/istio-1.3.5/install/kubernetes/helm/istio/charts/istiocoredns/Chart.yaml new file mode 100644 index 0000000..9e2bf08 --- /dev/null +++ b/istio-1.3.5/install/kubernetes/helm/istio/charts/istiocoredns/Chart.yaml @@ -0,0 +1,6 @@ +apiVersion: v1 +description: Istio CoreDNS provides DNS resolution for services in multicluster setups. +name: istiocoredns +version: 1.3.5 +appVersion: 0.1 +tillerVersion: ">=2.7.2" diff --git a/istio-1.3.5/install/kubernetes/helm/istio/charts/istiocoredns/templates/_helpers.tpl b/istio-1.3.5/install/kubernetes/helm/istio/charts/istiocoredns/templates/_helpers.tpl new file mode 100644 index 0000000..e7add11 --- /dev/null +++ b/istio-1.3.5/install/kubernetes/helm/istio/charts/istiocoredns/templates/_helpers.tpl @@ -0,0 +1,32 @@ +{{/* vim: set filetype=mustache: */}} +{{/* +Expand the name of the chart. +*/}} +{{- define "istiocoredns.name" -}} +{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" -}} +{{- end -}} + +{{/* +Create a default fully qualified app name. +We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). +If release name contains chart name it will be used as a full name. +*/}} +{{- define "istiocoredns.fullname" -}} +{{- if .Values.fullnameOverride -}} +{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" -}} +{{- else -}} +{{- $name := default .Chart.Name .Values.nameOverride -}} +{{- if contains $name .Release.Name -}} +{{- .Release.Name | trunc 63 | trimSuffix "-" -}} +{{- else -}} +{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" -}} +{{- end -}} +{{- end -}} +{{- end -}} + +{{/* +Create chart name and version as used by the chart label. +*/}} +{{- define "istiocoredns.chart" -}} +{{- .Chart.Name | trunc 63 | trimSuffix "-" -}} +{{- end -}} diff --git a/istio-1.3.5/install/kubernetes/helm/istio/charts/istiocoredns/templates/clusterrole.yaml b/istio-1.3.5/install/kubernetes/helm/istio/charts/istiocoredns/templates/clusterrole.yaml new file mode 100644 index 0000000..4242a32 --- /dev/null +++ b/istio-1.3.5/install/kubernetes/helm/istio/charts/istiocoredns/templates/clusterrole.yaml @@ -0,0 +1,13 @@ +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: istiocoredns + labels: + app: {{ template "istiocoredns.name" . }} + chart: {{ template "istiocoredns.chart" . }} + heritage: {{ .Release.Service }} + release: {{ .Release.Name }} +rules: +- apiGroups: ["networking.istio.io"] + resources: ["*"] + verbs: ["get", "watch", "list"] diff --git a/istio-1.3.5/install/kubernetes/helm/istio/charts/istiocoredns/templates/clusterrolebinding.yaml b/istio-1.3.5/install/kubernetes/helm/istio/charts/istiocoredns/templates/clusterrolebinding.yaml new file mode 100644 index 0000000..bafd0ca --- /dev/null +++ b/istio-1.3.5/install/kubernetes/helm/istio/charts/istiocoredns/templates/clusterrolebinding.yaml @@ -0,0 +1,17 @@ +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: istio-istiocoredns-role-binding-{{ .Release.Namespace }} + labels: + app: {{ template "istiocoredns.name" . }} + chart: {{ template "istiocoredns.chart" . }} + heritage: {{ .Release.Service }} + release: {{ .Release.Name }} +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: istiocoredns +subjects: +- kind: ServiceAccount + name: istiocoredns-service-account + namespace: {{ .Release.Namespace }} diff --git a/istio-1.3.5/install/kubernetes/helm/istio/charts/istiocoredns/templates/configmap.yaml b/istio-1.3.5/install/kubernetes/helm/istio/charts/istiocoredns/templates/configmap.yaml new file mode 100644 index 0000000..50d166f --- /dev/null +++ b/istio-1.3.5/install/kubernetes/helm/istio/charts/istiocoredns/templates/configmap.yaml @@ -0,0 +1,24 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: coredns + namespace: {{ .Release.Namespace }} + labels: + app: {{ template "istiocoredns.name" . }} + chart: {{ template "istiocoredns.chart" . }} + heritage: {{ .Release.Service }} + release: {{ .Release.Name }} +data: + Corefile: | + .:53 { + errors + health + proxy global 127.0.0.1:8053 { + protocol grpc insecure + } + prometheus :9153 + proxy . /etc/resolv.conf + cache 30 + reload + } +--- diff --git a/istio-1.3.5/install/kubernetes/helm/istio/charts/istiocoredns/templates/deployment.yaml b/istio-1.3.5/install/kubernetes/helm/istio/charts/istiocoredns/templates/deployment.yaml new file mode 100644 index 0000000..4cd5f00 --- /dev/null +++ b/istio-1.3.5/install/kubernetes/helm/istio/charts/istiocoredns/templates/deployment.yaml @@ -0,0 +1,100 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: istiocoredns + namespace: {{ .Release.Namespace }} + labels: + app: {{ template "istiocoredns.name" . }} + chart: {{ template "istiocoredns.chart" . }} + heritage: {{ .Release.Service }} + release: {{ .Release.Name }} +spec: + replicas: {{ .Values.replicaCount }} + selector: + matchLabels: + app: istiocoredns + strategy: + rollingUpdate: + maxSurge: {{ .Values.rollingMaxSurge }} + maxUnavailable: {{ .Values.rollingMaxUnavailable }} + template: + metadata: + name: istiocoredns + labels: + app: istiocoredns + chart: {{ template "istiocoredns.chart" . }} + heritage: {{ .Release.Service }} + release: {{ .Release.Name }} + annotations: + sidecar.istio.io/inject: "false" + spec: + serviceAccountName: istiocoredns-service-account +{{- if .Values.global.priorityClassName }} + priorityClassName: "{{ .Values.global.priorityClassName }}" +{{- end }} + containers: + - name: coredns + image: {{ .Values.coreDNSImage }} + imagePullPolicy: {{ .Values.global.imagePullPolicy }} + args: [ "-conf", "/etc/coredns/Corefile" ] + volumeMounts: + - name: config-volume + mountPath: /etc/coredns + ports: + - containerPort: 53 + name: dns + protocol: UDP + - containerPort: 53 + name: dns-tcp + protocol: TCP + - containerPort: 9153 + name: metrics + protocol: TCP + livenessProbe: + httpGet: + path: /health + port: 8080 + scheme: HTTP + initialDelaySeconds: 60 + timeoutSeconds: 5 + successThreshold: 1 + failureThreshold: 5 + resources: +{{- if .Values.resources }} +{{ toYaml .Values.resources | indent 10 }} +{{- else }} +{{ toYaml .Values.global.defaultResources | indent 10 }} +{{- end }} + - name: istio-coredns-plugin + command: + - /usr/local/bin/plugin + image: {{ .Values.coreDNSPluginImage }} + imagePullPolicy: {{ .Values.global.imagePullPolicy }} + ports: + - containerPort: 8053 + name: dns-grpc + protocol: TCP + resources: +{{- if .Values.resources }} +{{ toYaml .Values.resources | indent 10 }} +{{- else }} +{{ toYaml .Values.global.defaultResources | indent 10 }} +{{- end }} + dnsPolicy: Default + volumes: + - name: config-volume + configMap: + name: coredns + items: + - key: Corefile + path: Corefile + affinity: + {{- include "nodeaffinity" . | indent 6 }} + {{- include "podAntiAffinity" . | indent 6 }} + {{- if .Values.tolerations }} + tolerations: +{{ toYaml .Values.tolerations | indent 6 }} + {{- else if .Values.global.defaultTolerations }} + tolerations: +{{ toYaml .Values.global.defaultTolerations | indent 6 }} + {{- end }} diff --git a/istio-1.3.5/install/kubernetes/helm/istio/charts/istiocoredns/templates/service.yaml b/istio-1.3.5/install/kubernetes/helm/istio/charts/istiocoredns/templates/service.yaml new file mode 100644 index 0000000..a631101 --- /dev/null +++ b/istio-1.3.5/install/kubernetes/helm/istio/charts/istiocoredns/templates/service.yaml @@ -0,0 +1,20 @@ +apiVersion: v1 +kind: Service +metadata: + name: istiocoredns + namespace: {{ .Release.Namespace }} + labels: + app: {{ template "istiocoredns.name" . }} + chart: {{ template "istiocoredns.chart" . }} + heritage: {{ .Release.Service }} + release: {{ .Release.Name }} +spec: + selector: + app: istiocoredns + ports: + - name: dns + port: 53 + protocol: UDP + - name: dns-tcp + port: 53 + protocol: TCP diff --git a/istio-1.3.5/install/kubernetes/helm/istio/charts/istiocoredns/templates/serviceaccount.yaml b/istio-1.3.5/install/kubernetes/helm/istio/charts/istiocoredns/templates/serviceaccount.yaml new file mode 100644 index 0000000..e2627cf --- /dev/null +++ b/istio-1.3.5/install/kubernetes/helm/istio/charts/istiocoredns/templates/serviceaccount.yaml @@ -0,0 +1,16 @@ +apiVersion: v1 +kind: ServiceAccount +{{- if .Values.global.imagePullSecrets }} +imagePullSecrets: +{{- range .Values.global.imagePullSecrets }} + - name: {{ . }} +{{- end }} +{{- end }} +metadata: + name: istiocoredns-service-account + namespace: {{ .Release.Namespace }} + labels: + app: {{ template "istiocoredns.name" . }} + chart: {{ template "istiocoredns.chart" . }} + heritage: {{ .Release.Service }} + release: {{ .Release.Name }} diff --git a/istio-1.3.5/install/kubernetes/helm/istio/charts/istiocoredns/values.yaml b/istio-1.3.5/install/kubernetes/helm/istio/charts/istiocoredns/values.yaml new file mode 100644 index 0000000..4724df7 --- /dev/null +++ b/istio-1.3.5/install/kubernetes/helm/istio/charts/istiocoredns/values.yaml @@ -0,0 +1,35 @@ +# +# addon istiocoredns tracing configuration +# +enabled: false +replicaCount: 1 +rollingMaxSurge: 100% +rollingMaxUnavailable: 25% +coreDNSImage: coredns/coredns:1.1.2 +# Source code for the plugin can be found at +# https://github.com/istio-ecosystem/istio-coredns-plugin +# The plugin listens for DNS requests from coredns server at 127.0.0.1:8053 +coreDNSPluginImage: istio/coredns-plugin:0.2-istio-1.1 +nodeSelector: {} +tolerations: [] + +# Specify the pod anti-affinity that allows you to constrain which nodes +# your pod is eligible to be scheduled based on labels on pods that are +# already running on the node rather than based on labels on nodes. +# There are currently two types of anti-affinity: +# "requiredDuringSchedulingIgnoredDuringExecution" +# "preferredDuringSchedulingIgnoredDuringExecution" +# which denote "hard" vs. "soft" requirements, you can define your values +# in "podAntiAffinityLabelSelector" and "podAntiAffinityTermLabelSelector" +# correspondingly. +# For example: +# podAntiAffinityLabelSelector: +# - key: security +# operator: In +# values: S1,S2 +# topologyKey: "kubernetes.io/hostname" +# This pod anti-affinity rule says that the pod requires not to be scheduled +# onto a node if that node is already running a pod with label having key +# "security" and value "S1". +podAntiAffinityLabelSelector: [] +podAntiAffinityTermLabelSelector: [] diff --git a/istio-1.3.5/install/kubernetes/helm/istio/charts/kiali/Chart.yaml b/istio-1.3.5/install/kubernetes/helm/istio/charts/kiali/Chart.yaml new file mode 100644 index 0000000..3002a91 --- /dev/null +++ b/istio-1.3.5/install/kubernetes/helm/istio/charts/kiali/Chart.yaml @@ -0,0 +1,6 @@ +apiVersion: v1 +description: Kiali is an open source project for service mesh observability, refer to https://www.kiali.io for details. +name: kiali +version: 1.3.5 +appVersion: 1.3.5 +tillerVersion: ">=2.7.2" diff --git a/istio-1.3.5/install/kubernetes/helm/istio/charts/kiali/templates/_helpers.tpl b/istio-1.3.5/install/kubernetes/helm/istio/charts/kiali/templates/_helpers.tpl new file mode 100644 index 0000000..6b00957 --- /dev/null +++ b/istio-1.3.5/install/kubernetes/helm/istio/charts/kiali/templates/_helpers.tpl @@ -0,0 +1,32 @@ +{{/* vim: set filetype=mustache: */}} +{{/* +Expand the name of the chart. +*/}} +{{- define "kiali.name" -}} +{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" -}} +{{- end -}} + +{{/* +Create a default fully qualified app name. +We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). +If release name contains chart name it will be used as a full name. +*/}} +{{- define "kiali.fullname" -}} +{{- if .Values.fullnameOverride -}} +{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" -}} +{{- else -}} +{{- $name := default .Chart.Name .Values.nameOverride -}} +{{- if contains $name .Release.Name -}} +{{- .Release.Name | trunc 63 | trimSuffix "-" -}} +{{- else -}} +{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" -}} +{{- end -}} +{{- end -}} +{{- end -}} + +{{/* +Create chart name and version as used by the chart label. +*/}} +{{- define "kiali.chart" -}} +{{- .Chart.Name | trunc 63 | trimSuffix "-" -}} +{{- end -}} diff --git a/istio-1.3.5/install/kubernetes/helm/istio/charts/kiali/templates/clusterrole.yaml b/istio-1.3.5/install/kubernetes/helm/istio/charts/kiali/templates/clusterrole.yaml new file mode 100644 index 0000000..d9091a0 --- /dev/null +++ b/istio-1.3.5/install/kubernetes/helm/istio/charts/kiali/templates/clusterrole.yaml @@ -0,0 +1,267 @@ +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: kiali + labels: + app: {{ template "kiali.name" . }} + chart: {{ template "kiali.chart" . }} + heritage: {{ .Release.Service }} + release: {{ .Release.Name }} +rules: +- apiGroups: [""] + resources: + - configmaps + - endpoints + - namespaces + - nodes + - pods + - pods/log + - replicationcontrollers + - services + verbs: + - get + - list + - watch +- apiGroups: ["extensions", "apps"] + resources: + - deployments + - replicasets + - statefulsets + verbs: + - get + - list + - watch +- apiGroups: ["autoscaling"] + resources: + - horizontalpodautoscalers + verbs: + - get + - list + - watch +- apiGroups: ["batch"] + resources: + - cronjobs + - jobs + verbs: + - get + - list + - watch +- apiGroups: ["config.istio.io"] + resources: + - adapters + - apikeys + - bypasses + - authorizations + - checknothings + - circonuses + - cloudwatches + - deniers + - dogstatsds + - edges + - fluentds + - handlers + - instances + - kubernetesenvs + - kuberneteses + - listcheckers + - listentries + - logentries + - memquotas + - metrics + - noops + - opas + - prometheuses + - quotas + - quotaspecbindings + - quotaspecs + - rbacs + - redisquotas + - reportnothings + - rules + - signalfxs + - solarwindses + - stackdrivers + - statsds + - stdios + - templates + - tracespans + - zipkins + verbs: + - create + - delete + - get + - list + - patch + - watch +- apiGroups: ["networking.istio.io"] + resources: + - destinationrules + - gateways + - serviceentries + - sidecars + - virtualservices + verbs: + - create + - delete + - get + - list + - patch + - watch +- apiGroups: ["authentication.istio.io"] + resources: + - meshpolicies + - policies + verbs: + - create + - delete + - get + - list + - patch + - watch +- apiGroups: ["rbac.istio.io"] + resources: + - clusterrbacconfigs + - rbacconfigs + - servicerolebindings + - serviceroles + verbs: + - create + - delete + - get + - list + - patch + - watch +- apiGroups: ["monitoring.kiali.io"] + resources: + - monitoringdashboards + verbs: + - get + - list +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: kiali-viewer + labels: + app: {{ template "kiali.name" . }} + chart: {{ template "kiali.chart" . }} + heritage: {{ .Release.Service }} + release: {{ .Release.Name }} +rules: +- apiGroups: [""] + resources: + - configmaps + - endpoints + - namespaces + - nodes + - pods + - pods/log + - replicationcontrollers + - services + verbs: + - get + - list + - watch +- apiGroups: ["extensions", "apps"] + resources: + - deployments + - replicasets + - statefulsets + verbs: + - get + - list + - watch +- apiGroups: ["autoscaling"] + resources: + - horizontalpodautoscalers + verbs: + - get + - list + - watch +- apiGroups: ["batch"] + resources: + - cronjobs + - jobs + verbs: + - get + - list + - watch +- apiGroups: ["config.istio.io"] + resources: + - adapters + - apikeys + - bypasses + - authorizations + - checknothings + - circonuses + - cloudwatches + - deniers + - dogstatsds + - edges + - fluentds + - handlers + - instances + - kubernetesenvs + - kuberneteses + - listcheckers + - listentries + - logentries + - memquotas + - metrics + - noops + - opas + - prometheuses + - quotas + - quotaspecbindings + - quotaspecs + - rbacs + - redisquotas + - reportnothings + - rules + - signalfxs + - solarwindses + - stackdrivers + - statsds + - stdios + - templates + - tracespans + - zipkins + verbs: + - get + - list + - watch +- apiGroups: ["networking.istio.io"] + resources: + - destinationrules + - gateways + - serviceentries + - sidecars + - virtualservices + verbs: + - get + - list + - watch +- apiGroups: ["authentication.istio.io"] + resources: + - meshpolicies + - policies + verbs: + - get + - list + - watch +- apiGroups: ["rbac.istio.io"] + resources: + - clusterrbacconfigs + - rbacconfigs + - servicerolebindings + - serviceroles + verbs: + - get + - list + - watch +- apiGroups: ["monitoring.kiali.io"] + resources: + - monitoringdashboards + verbs: + - get + - list diff --git a/istio-1.3.5/install/kubernetes/helm/istio/charts/kiali/templates/clusterrolebinding.yaml b/istio-1.3.5/install/kubernetes/helm/istio/charts/kiali/templates/clusterrolebinding.yaml new file mode 100644 index 0000000..8817967 --- /dev/null +++ b/istio-1.3.5/install/kubernetes/helm/istio/charts/kiali/templates/clusterrolebinding.yaml @@ -0,0 +1,37 @@ +{{- if not .Values.dashboard.viewOnlyMode }} +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: istio-kiali-admin-role-binding-{{ .Release.Namespace }} + labels: + app: {{ template "kiali.name" . }} + chart: {{ template "kiali.chart" . }} + heritage: {{ .Release.Service }} + release: {{ .Release.Name }} +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: kiali +subjects: +- kind: ServiceAccount + name: kiali-service-account + namespace: {{ .Release.Namespace }} +{{- else }} +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: istio-kiali-viewer-role-binding-{{ .Release.Namespace }} + labels: + app: {{ template "kiali.name" . }} + chart: {{ template "kiali.chart" . }} + heritage: {{ .Release.Service }} + release: {{ .Release.Name }} +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: kiali-viewer +subjects: +- kind: ServiceAccount + name: kiali-service-account + namespace: {{ .Release.Namespace }} +{{- end }} diff --git a/istio-1.3.5/install/kubernetes/helm/istio/charts/kiali/templates/configmap.yaml b/istio-1.3.5/install/kubernetes/helm/istio/charts/kiali/templates/configmap.yaml new file mode 100644 index 0000000..cd63a90 --- /dev/null +++ b/istio-1.3.5/install/kubernetes/helm/istio/charts/kiali/templates/configmap.yaml @@ -0,0 +1,32 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: kiali + namespace: {{ .Release.Namespace }} + labels: + app: {{ template "kiali.name" . }} + chart: {{ template "kiali.chart" . }} + heritage: {{ .Release.Service }} + release: {{ .Release.Name }} +data: + config.yaml: | + istio_namespace: {{ .Release.Namespace }} + auth: + strategy: {{ .Values.dashboard.auth.strategy }} + server: + port: 20001 +{{- if .Values.contextPath }} + web_root: {{ .Values.contextPath }} +{{- end }} + external_services: + tracing: + url: {{ .Values.dashboard.jaegerURL }} + grafana: + url: {{ .Values.dashboard.grafanaURL }} + prometheus: + url: {{ .Values.prometheusAddr }} +{{- if .Values.security.enabled }} + identity: + cert_file: {{ .Values.security.cert_file }} + private_key_file: {{ .Values.security.private_key_file }} +{{- end}} diff --git a/istio-1.3.5/install/kubernetes/helm/istio/charts/kiali/templates/demosecret.yaml b/istio-1.3.5/install/kubernetes/helm/istio/charts/kiali/templates/demosecret.yaml new file mode 100644 index 0000000..ad44298 --- /dev/null +++ b/istio-1.3.5/install/kubernetes/helm/istio/charts/kiali/templates/demosecret.yaml @@ -0,0 +1,16 @@ +{{- if .Values.createDemoSecret }} +apiVersion: v1 +kind: Secret +metadata: + name: {{ .Values.dashboard.secretName }} + namespace: {{ .Release.Namespace }} + labels: + app: {{ template "kiali.name" . }} + chart: {{ template "kiali.chart" . }} + heritage: {{ .Release.Service }} + release: {{ .Release.Name }} +type: Opaque +data: + username: YWRtaW4= # admin + passphrase: YWRtaW4= # admin +{{- end }} diff --git a/istio-1.3.5/install/kubernetes/helm/istio/charts/kiali/templates/deployment.yaml b/istio-1.3.5/install/kubernetes/helm/istio/charts/kiali/templates/deployment.yaml new file mode 100644 index 0000000..9389f58 --- /dev/null +++ b/istio-1.3.5/install/kubernetes/helm/istio/charts/kiali/templates/deployment.yaml @@ -0,0 +1,100 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: kiali + namespace: {{ .Release.Namespace }} + labels: + app: {{ template "kiali.name" . }} + chart: {{ template "kiali.chart" . }} + heritage: {{ .Release.Service }} + release: {{ .Release.Name }} +spec: + replicas: {{ .Values.replicaCount }} + selector: + matchLabels: + app: kiali + template: + metadata: + name: kiali + labels: + app: kiali + chart: {{ template "kiali.chart" . }} + heritage: {{ .Release.Service }} + release: {{ .Release.Name }} + annotations: + sidecar.istio.io/inject: "false" + scheduler.alpha.kubernetes.io/critical-pod: "" + prometheus.io/scrape: "true" + prometheus.io/port: "9090" + kiali.io/runtimes: go,kiali + spec: + serviceAccountName: kiali-service-account +{{- if .Values.global.priorityClassName }} + priorityClassName: "{{ .Values.global.priorityClassName }}" +{{- end }} + containers: + - image: "{{ .Values.hub }}/{{ .Values.image }}:{{ .Values.tag }}" + imagePullPolicy: {{ .Values.global.imagePullPolicy }} + name: kiali + command: + - "/opt/kiali/kiali" + - "-config" + - "/kiali-configuration/config.yaml" + - "-v" + - "3" + readinessProbe: + httpGet: + path: {{ .Values.contextPath }}/healthz + port: 20001 + scheme: {{ if .Values.security.enabled }} 'HTTPS' {{ else }} 'HTTP' {{ end }} + initialDelaySeconds: 5 + periodSeconds: 30 + livenessProbe: + httpGet: + path: {{ .Values.contextPath }}/healthz + port: 20001 + scheme: {{ if .Values.security.enabled }} 'HTTPS' {{ else }} 'HTTP' {{ end }} + initialDelaySeconds: 5 + periodSeconds: 30 + env: + - name: ACTIVE_NAMESPACE + valueFrom: + fieldRef: + fieldPath: metadata.namespace + volumeMounts: + - name: kiali-configuration + mountPath: "/kiali-configuration" + - name: kiali-cert + mountPath: "/kiali-cert" + - name: kiali-secret + mountPath: "/kiali-secret" + resources: +{{- if .Values.resources }} +{{ toYaml .Values.resources | indent 10 }} +{{- else }} +{{ toYaml .Values.global.defaultResources | indent 10 }} +{{- end }} + volumes: + - name: kiali-configuration + configMap: + name: kiali + - name: kiali-cert + secret: + secretName: istio.kiali-service-account +{{- if not .Values.security.enabled }} + optional: true +{{- end }} + - name: kiali-secret + secret: + secretName: {{ .Values.dashboard.secretName }} + optional: true + affinity: + {{- include "nodeaffinity" . | indent 6 }} + {{- include "podAntiAffinity" . | indent 6 }} + {{- if .Values.tolerations }} + tolerations: +{{ toYaml .Values.tolerations | indent 6 }} + {{- else if .Values.global.defaultTolerations }} + tolerations: +{{ toYaml .Values.global.defaultTolerations | indent 6 }} + {{- end }} diff --git a/istio-1.3.5/install/kubernetes/helm/istio/charts/kiali/templates/ingress.yaml b/istio-1.3.5/install/kubernetes/helm/istio/charts/kiali/templates/ingress.yaml new file mode 100644 index 0000000..2e2a0de --- /dev/null +++ b/istio-1.3.5/install/kubernetes/helm/istio/charts/kiali/templates/ingress.yaml @@ -0,0 +1,40 @@ +{{- if .Values.ingress.enabled -}} +apiVersion: extensions/v1beta1 +kind: Ingress +metadata: + name: kiali + namespace: {{ .Release.Namespace }} + labels: + app: {{ template "kiali.name" . }} + chart: {{ template "kiali.chart" . }} + heritage: {{ .Release.Service }} + release: {{ .Release.Name }} + annotations: + {{- range $key, $value := .Values.ingress.annotations }} + {{ $key }}: {{ $value | quote }} + {{- end }} +spec: + rules: +{{- if .Values.ingress.hosts }} + {{- range $host := .Values.ingress.hosts }} + - host: {{ $host }} + http: + paths: + - path: {{ if $.Values.contextPath }} {{ $.Values.contextPath }} {{ else }} / {{ end }} + backend: + serviceName: kiali + servicePort: 20001 + {{- end -}} +{{- else }} + - http: + paths: + - path: {{ if .Values.contextPath }} {{ .Values.contextPath }} {{ else }} / {{ end }} + backend: + serviceName: kiali + servicePort: 20001 +{{- end }} + {{- if .Values.ingress.tls }} + tls: +{{ toYaml .Values.ingress.tls | indent 4 }} + {{- end -}} +{{- end -}} diff --git a/istio-1.3.5/install/kubernetes/helm/istio/charts/kiali/templates/service.yaml b/istio-1.3.5/install/kubernetes/helm/istio/charts/kiali/templates/service.yaml new file mode 100644 index 0000000..1aa79bf --- /dev/null +++ b/istio-1.3.5/install/kubernetes/helm/istio/charts/kiali/templates/service.yaml @@ -0,0 +1,17 @@ +apiVersion: v1 +kind: Service +metadata: + name: kiali + namespace: {{ .Release.Namespace }} + labels: + app: {{ template "kiali.name" . }} + chart: {{ template "kiali.chart" . }} + heritage: {{ .Release.Service }} + release: {{ .Release.Name }} +spec: + ports: + - name: http-kiali + protocol: TCP + port: 20001 + selector: + app: kiali diff --git a/istio-1.3.5/install/kubernetes/helm/istio/charts/kiali/templates/serviceaccount.yaml b/istio-1.3.5/install/kubernetes/helm/istio/charts/kiali/templates/serviceaccount.yaml new file mode 100644 index 0000000..2ae38a1 --- /dev/null +++ b/istio-1.3.5/install/kubernetes/helm/istio/charts/kiali/templates/serviceaccount.yaml @@ -0,0 +1,16 @@ +apiVersion: v1 +kind: ServiceAccount +{{- if .Values.global.imagePullSecrets }} +imagePullSecrets: +{{- range .Values.global.imagePullSecrets }} + - name: {{ . }} +{{- end }} +{{- end }} +metadata: + name: kiali-service-account + namespace: {{ .Release.Namespace }} + labels: + app: {{ template "kiali.name" . }} + chart: {{ template "kiali.chart" . }} + heritage: {{ .Release.Service }} + release: {{ .Release.Name }} diff --git a/istio-1.3.5/install/kubernetes/helm/istio/charts/kiali/templates/tests/test-kiali-connection.yaml b/istio-1.3.5/install/kubernetes/helm/istio/charts/kiali/templates/tests/test-kiali-connection.yaml new file mode 100644 index 0000000..d798f7f --- /dev/null +++ b/istio-1.3.5/install/kubernetes/helm/istio/charts/kiali/templates/tests/test-kiali-connection.yaml @@ -0,0 +1,37 @@ +{{- if .Values.global.enableHelmTest }} +apiVersion: v1 +kind: Pod +metadata: + name: {{ template "kiali.fullname" . }}-test + namespace: {{ .Release.Namespace }} + labels: + app: kiali-test + chart: {{ template "kiali.chart" . }} + release: {{ .Release.Name }} + heritage: {{ .Release.Service }} + istio: kiali + annotations: + sidecar.istio.io/inject: "false" + helm.sh/hook: test-success +spec: +{{- if .Values.global.priorityClassName }} + priorityClassName: "{{ .Values.global.priorityClassName }}" +{{- end }} + containers: + - name: "{{ template "kiali.fullname" . }}-test" + image: pstauffer/curl:v1.0.3 + imagePullPolicy: "{{ .Values.global.imagePullPolicy }}" + command: ['curl'] + args: ['http://kiali:20001'] + restartPolicy: Never + affinity: + {{- include "nodeaffinity" . | indent 4 }} + {{- include "podAntiAffinity" . | indent 4 }} + {{- if .Values.tolerations }} + tolerations: +{{ toYaml .Values.tolerations | indent 2 }} + {{- else if .Values.global.defaultTolerations }} + tolerations: +{{ toYaml .Values.global.defaultTolerations | indent 2 }} + {{- end }} +{{- end }} diff --git a/istio-1.3.5/install/kubernetes/helm/istio/charts/kiali/values.yaml b/istio-1.3.5/install/kubernetes/helm/istio/charts/kiali/values.yaml new file mode 100644 index 0000000..bb536f1 --- /dev/null +++ b/istio-1.3.5/install/kubernetes/helm/istio/charts/kiali/values.yaml @@ -0,0 +1,63 @@ +# +# addon kiali +# +enabled: false # Note that if using the demo or demo-auth yaml when installing via Helm, this default will be `true`. +replicaCount: 1 +hub: quay.io/kiali +image: kiali +tag: v1.4 +contextPath: /kiali # The root context path to access the Kiali UI. +nodeSelector: {} +tolerations: [] + +# Specify the pod anti-affinity that allows you to constrain which nodes +# your pod is eligible to be scheduled based on labels on pods that are +# already running on the node rather than based on labels on nodes. +# There are currently two types of anti-affinity: +# "requiredDuringSchedulingIgnoredDuringExecution" +# "preferredDuringSchedulingIgnoredDuringExecution" +# which denote "hard" vs. "soft" requirements, you can define your values +# in "podAntiAffinityLabelSelector" and "podAntiAffinityTermLabelSelector" +# correspondingly. +# For example: +# podAntiAffinityLabelSelector: +# - key: security +# operator: In +# values: S1,S2 +# topologyKey: "kubernetes.io/hostname" +# This pod anti-affinity rule says that the pod requires not to be scheduled +# onto a node if that node is already running a pod with label having key +# "security" and value "S1". +podAntiAffinityLabelSelector: [] +podAntiAffinityTermLabelSelector: [] + +ingress: + enabled: false + ## Used to create an Ingress record. + hosts: + - kiali.local + annotations: + # kubernetes.io/ingress.class: nginx + # kubernetes.io/tls-acme: "true" + tls: + # Secrets must be manually created in the namespace. + # - secretName: kiali-tls + # hosts: + # - kiali.local + +dashboard: + auth: + strategy: login # Can be anonymous, login, or openshift + secretName: kiali # You must create a secret with this name - one is not provided out-of-box. + viewOnlyMode: false # Bind the service account to a role with only read access + grafanaURL: # If you have Grafana installed and it is accessible to client browsers, then set this to its external URL. Kiali will redirect users to this URL when Grafana metrics are to be shown. + jaegerURL: # If you have Jaeger installed and it is accessible to client browsers, then set this property to its external URL. Kiali will redirect users to this URL when Jaeger tracing is to be shown. +prometheusAddr: http://prometheus:9090 + +# When true, a secret will be created with a default username and password. Useful for demos. +createDemoSecret: false + +security: + enabled: false + cert_file: /kiali-cert/cert-chain.pem + private_key_file: /kiali-cert/key.pem diff --git a/istio-1.3.5/install/kubernetes/helm/istio/charts/mixer/Chart.yaml b/istio-1.3.5/install/kubernetes/helm/istio/charts/mixer/Chart.yaml new file mode 100644 index 0000000..e7eb21a --- /dev/null +++ b/istio-1.3.5/install/kubernetes/helm/istio/charts/mixer/Chart.yaml @@ -0,0 +1,13 @@ +apiVersion: v1 +name: mixer +version: 1.3.5 +appVersion: 1.3.5 +tillerVersion: ">=2.7.2" +description: Helm chart for mixer deployment +keywords: + - istio + - mixer +sources: + - http://github.com/istio/istio +engine: gotpl +icon: https://istio.io/favicons/android-192x192.png diff --git a/istio-1.3.5/install/kubernetes/helm/istio/charts/mixer/templates/_helpers.tpl b/istio-1.3.5/install/kubernetes/helm/istio/charts/mixer/templates/_helpers.tpl new file mode 100644 index 0000000..dac6da0 --- /dev/null +++ b/istio-1.3.5/install/kubernetes/helm/istio/charts/mixer/templates/_helpers.tpl @@ -0,0 +1,32 @@ +{{/* vim: set filetype=mustache: */}} +{{/* +Expand the name of the chart. +*/}} +{{- define "mixer.name" -}} +{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" -}} +{{- end -}} + +{{/* +Create a default fully qualified app name. +We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). +If release name contains chart name it will be used as a full name. +*/}} +{{- define "mixer.fullname" -}} +{{- if .Values.fullnameOverride -}} +{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" -}} +{{- else -}} +{{- $name := default .Chart.Name .Values.nameOverride -}} +{{- if contains $name .Release.Name -}} +{{- .Release.Name | trunc 63 | trimSuffix "-" -}} +{{- else -}} +{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" -}} +{{- end -}} +{{- end -}} +{{- end -}} + +{{/* +Create chart name and version as used by the chart label. +*/}} +{{- define "mixer.chart" -}} +{{- .Chart.Name | trunc 63 | trimSuffix "-" -}} +{{- end -}} diff --git a/istio-1.3.5/install/kubernetes/helm/istio/charts/mixer/templates/autoscale.yaml b/istio-1.3.5/install/kubernetes/helm/istio/charts/mixer/templates/autoscale.yaml new file mode 100644 index 0000000..377b47d --- /dev/null +++ b/istio-1.3.5/install/kubernetes/helm/istio/charts/mixer/templates/autoscale.yaml @@ -0,0 +1,29 @@ +{{- range $key, $spec := .Values }} +{{- if or (eq $key "policy") (eq $key "telemetry") }} +{{- if and $spec.enabled $spec.autoscaleEnabled $spec.autoscaleMin $spec.autoscaleMax }} +apiVersion: autoscaling/v2beta1 +kind: HorizontalPodAutoscaler +metadata: + name: istio-{{ $key }} + namespace: {{ $.Release.Namespace }} + labels: + app: {{ template "mixer.name" $ }} + chart: {{ template "mixer.chart" $ }} + heritage: {{ $.Release.Service }} + release: {{ $.Release.Name }} +spec: + maxReplicas: {{ $spec.autoscaleMax }} + minReplicas: {{ $spec.autoscaleMin }} + scaleTargetRef: + apiVersion: apps/v1 + kind: Deployment + name: istio-{{ $key }} + metrics: + - type: Resource + resource: + name: cpu + targetAverageUtilization: {{ $spec.cpu.targetAverageUtilization }} +--- +{{- end }} +{{- end }} +{{- end }} diff --git a/istio-1.3.5/install/kubernetes/helm/istio/charts/mixer/templates/clusterrole.yaml b/istio-1.3.5/install/kubernetes/helm/istio/charts/mixer/templates/clusterrole.yaml new file mode 100644 index 0000000..3d7438f --- /dev/null +++ b/istio-1.3.5/install/kubernetes/helm/istio/charts/mixer/templates/clusterrole.yaml @@ -0,0 +1,24 @@ +{{- if or (.Values.policy.enabled) (.Values.telemetry.enabled) }} +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: istio-mixer-{{ .Release.Namespace }} + labels: + app: {{ template "mixer.name" . }} + chart: {{ template "mixer.chart" . }} + heritage: {{ .Release.Service }} + release: {{ .Release.Name }} +rules: +- apiGroups: ["config.istio.io"] # istio CRD watcher + resources: ["*"] + verbs: ["create", "get", "list", "watch", "patch"] +- apiGroups: ["apiextensions.k8s.io"] + resources: ["customresourcedefinitions"] + verbs: ["get", "list", "watch"] +- apiGroups: [""] + resources: ["configmaps", "endpoints", "pods", "services", "namespaces", "secrets", "replicationcontrollers"] + verbs: ["get", "list", "watch"] +- apiGroups: ["extensions", "apps"] + resources: ["replicasets"] + verbs: ["get", "list", "watch"] +{{- end }} diff --git a/istio-1.3.5/install/kubernetes/helm/istio/charts/mixer/templates/clusterrolebinding.yaml b/istio-1.3.5/install/kubernetes/helm/istio/charts/mixer/templates/clusterrolebinding.yaml new file mode 100644 index 0000000..773e68b --- /dev/null +++ b/istio-1.3.5/install/kubernetes/helm/istio/charts/mixer/templates/clusterrolebinding.yaml @@ -0,0 +1,19 @@ +{{- if or (.Values.policy.enabled) (.Values.telemetry.enabled) }} +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: istio-mixer-admin-role-binding-{{ .Release.Namespace }} + labels: + app: {{ template "mixer.name" . }} + chart: {{ template "mixer.chart" . }} + heritage: {{ .Release.Service }} + release: {{ .Release.Name }} +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: istio-mixer-{{ .Release.Namespace }} +subjects: + - kind: ServiceAccount + name: istio-mixer-service-account + namespace: {{ .Release.Namespace }} +{{- end }} diff --git a/istio-1.3.5/install/kubernetes/helm/istio/charts/mixer/templates/config.yaml b/istio-1.3.5/install/kubernetes/helm/istio/charts/mixer/templates/config.yaml new file mode 100644 index 0000000..43b2c5c --- /dev/null +++ b/istio-1.3.5/install/kubernetes/helm/istio/charts/mixer/templates/config.yaml @@ -0,0 +1,1088 @@ +{{- if or (.Values.policy.enabled) (.Values.telemetry.enabled) }} +apiVersion: "config.istio.io/v1alpha2" +kind: attributemanifest +metadata: + name: istioproxy + namespace: {{ .Release.Namespace }} + labels: + app: {{ template "mixer.name" . }} + chart: {{ template "mixer.chart" . }} + heritage: {{ .Release.Service }} + release: {{ .Release.Name }} +spec: + attributes: + origin.ip: + valueType: IP_ADDRESS + origin.uid: + valueType: STRING + origin.user: + valueType: STRING + request.headers: + valueType: STRING_MAP + request.id: + valueType: STRING + request.host: + valueType: STRING + request.method: + valueType: STRING + request.path: + valueType: STRING + request.url_path: + valueType: STRING + request.query_params: + valueType: STRING_MAP + request.reason: + valueType: STRING + request.referer: + valueType: STRING + request.scheme: + valueType: STRING + request.total_size: + valueType: INT64 + request.size: + valueType: INT64 + request.time: + valueType: TIMESTAMP + request.useragent: + valueType: STRING + response.code: + valueType: INT64 + response.duration: + valueType: DURATION + response.headers: + valueType: STRING_MAP + response.total_size: + valueType: INT64 + response.size: + valueType: INT64 + response.time: + valueType: TIMESTAMP + response.grpc_status: + valueType: STRING + response.grpc_message: + valueType: STRING + source.uid: + valueType: STRING + source.user: # DEPRECATED + valueType: STRING + source.principal: + valueType: STRING + destination.uid: + valueType: STRING + destination.principal: + valueType: STRING + destination.port: + valueType: INT64 + connection.event: + valueType: STRING + connection.id: + valueType: STRING + connection.received.bytes: + valueType: INT64 + connection.received.bytes_total: + valueType: INT64 + connection.sent.bytes: + valueType: INT64 + connection.sent.bytes_total: + valueType: INT64 + connection.duration: + valueType: DURATION + connection.mtls: + valueType: BOOL + connection.requested_server_name: + valueType: STRING + context.protocol: + valueType: STRING + context.proxy_error_code: + valueType: STRING + context.timestamp: + valueType: TIMESTAMP + context.time: + valueType: TIMESTAMP + # Deprecated, kept for compatibility + context.reporter.local: + valueType: BOOL + context.reporter.kind: + valueType: STRING + context.reporter.uid: + valueType: STRING + api.service: + valueType: STRING + api.version: + valueType: STRING + api.operation: + valueType: STRING + api.protocol: + valueType: STRING + request.auth.principal: + valueType: STRING + request.auth.audiences: + valueType: STRING + request.auth.presenter: + valueType: STRING + request.auth.claims: + valueType: STRING_MAP + request.auth.raw_claims: + valueType: STRING + request.api_key: + valueType: STRING + rbac.permissive.response_code: + valueType: STRING + rbac.permissive.effective_policy_id: + valueType: STRING + check.error_code: + valueType: INT64 + check.error_message: + valueType: STRING + check.cache_hit: + valueType: BOOL + quota.cache_hit: + valueType: BOOL + context.proxy_version: + valueType: STRING + +--- +apiVersion: "config.istio.io/v1alpha2" +kind: attributemanifest +metadata: + name: kubernetes + namespace: {{ .Release.Namespace }} + labels: + app: {{ template "mixer.name" . }} + chart: {{ template "mixer.chart" . }} + heritage: {{ .Release.Service }} + release: {{ .Release.Name }} +spec: + attributes: + source.ip: + valueType: IP_ADDRESS + source.labels: + valueType: STRING_MAP + source.metadata: + valueType: STRING_MAP + source.name: + valueType: STRING + source.namespace: + valueType: STRING + source.owner: + valueType: STRING + source.serviceAccount: + valueType: STRING + source.services: + valueType: STRING + source.workload.uid: + valueType: STRING + source.workload.name: + valueType: STRING + source.workload.namespace: + valueType: STRING + destination.ip: + valueType: IP_ADDRESS + destination.labels: + valueType: STRING_MAP + destination.metadata: + valueType: STRING_MAP + destination.owner: + valueType: STRING + destination.name: + valueType: STRING + destination.container.name: + valueType: STRING + destination.namespace: + valueType: STRING + destination.service.uid: + valueType: STRING + destination.service.name: + valueType: STRING + destination.service.namespace: + valueType: STRING + destination.service.host: + valueType: STRING + destination.serviceAccount: + valueType: STRING + destination.workload.uid: + valueType: STRING + destination.workload.name: + valueType: STRING + destination.workload.namespace: + valueType: STRING +--- +{{- if and .Values.adapters.stdio.enabled .Values.telemetry.enabled }} +apiVersion: "config.istio.io/v1alpha2" +kind: handler +metadata: + name: stdio + namespace: {{ .Release.Namespace }} + labels: + app: {{ template "mixer.name" . }} + chart: {{ template "mixer.chart" . }} + heritage: {{ .Release.Service }} + release: {{ .Release.Name }} +spec: + compiledAdapter: stdio + params: + outputAsJson: {{ .Values.adapters.stdio.outputAsJson }} +--- +apiVersion: "config.istio.io/v1alpha2" +kind: instance +metadata: + name: accesslog + namespace: {{ .Release.Namespace }} + labels: + app: {{ template "mixer.name" . }} + chart: {{ template "mixer.chart" . }} + heritage: {{ .Release.Service }} + release: {{ .Release.Name }} +spec: + compiledTemplate: logentry + params: + severity: '"Info"' + timestamp: request.time + variables: + sourceIp: source.ip | ip("0.0.0.0") + sourceApp: source.labels["app"] | "" + sourcePrincipal: source.principal | "" + sourceName: source.name | "" + sourceWorkload: source.workload.name | "" + sourceNamespace: source.namespace | "" + sourceOwner: source.owner | "" + destinationApp: destination.labels["app"] | "" + destinationIp: destination.ip | ip("0.0.0.0") + destinationServiceHost: destination.service.host | request.host | "" + destinationWorkload: destination.workload.name | "" + destinationName: destination.name | "" + destinationNamespace: destination.namespace | "" + destinationOwner: destination.owner | "" + destinationPrincipal: destination.principal | "" + apiClaims: request.auth.raw_claims | "" + apiKey: request.api_key | request.headers["x-api-key"] | "" + protocol: request.scheme | context.protocol | "http" + method: request.method | "" + url: request.path | "" + responseCode: response.code | 0 + responseFlags: context.proxy_error_code | "" + responseSize: response.size | 0 + permissiveResponseCode: rbac.permissive.response_code | "none" + permissiveResponsePolicyID: rbac.permissive.effective_policy_id | "none" + requestSize: request.size | 0 + requestId: request.headers["x-request-id"] | "" + clientTraceId: request.headers["x-client-trace-id"] | "" + latency: response.duration | "0ms" + connection_security_policy: conditional((context.reporter.kind | "inbound") == "outbound", "unknown", conditional(connection.mtls | false, "mutual_tls", "none")) + requestedServerName: connection.requested_server_name | "" + userAgent: request.useragent | "" + responseTimestamp: response.time + receivedBytes: request.total_size | 0 + sentBytes: response.total_size | 0 + referer: request.referer | "" + httpAuthority: request.headers[":authority"] | request.host | "" + xForwardedFor: request.headers["x-forwarded-for"] | "0.0.0.0" + reporter: conditional((context.reporter.kind | "inbound") == "outbound", "source", "destination") + grpcStatus: response.grpc_status | "" + grpcMessage: response.grpc_message | "" + monitored_resource_type: '"global"' +--- +apiVersion: "config.istio.io/v1alpha2" +kind: instance +metadata: + name: tcpaccesslog + namespace: {{ .Release.Namespace }} + labels: + app: {{ template "mixer.name" . }} + chart: {{ template "mixer.chart" . }} + heritage: {{ .Release.Service }} + release: {{ .Release.Name }} +spec: + compiledTemplate: logentry + params: + severity: '"Info"' + timestamp: context.time | timestamp("2017-01-01T00:00:00Z") + variables: + connectionEvent: connection.event | "" + sourceIp: source.ip | ip("0.0.0.0") + sourceApp: source.labels["app"] | "" + sourcePrincipal: source.principal | "" + sourceName: source.name | "" + sourceWorkload: source.workload.name | "" + sourceNamespace: source.namespace | "" + sourceOwner: source.owner | "" + destinationApp: destination.labels["app"] | "" + destinationIp: destination.ip | ip("0.0.0.0") + destinationServiceHost: destination.service.host | "" + destinationWorkload: destination.workload.name | "" + destinationName: destination.name | "" + destinationNamespace: destination.namespace | "" + destinationOwner: destination.owner | "" + destinationPrincipal: destination.principal | "" + protocol: context.protocol | "tcp" + connectionDuration: connection.duration | "0ms" + connection_security_policy: conditional((context.reporter.kind | "inbound") == "outbound", "unknown", conditional(connection.mtls | false, "mutual_tls", "none")) + requestedServerName: connection.requested_server_name | "" + receivedBytes: connection.received.bytes | 0 + sentBytes: connection.sent.bytes | 0 + totalReceivedBytes: connection.received.bytes_total | 0 + totalSentBytes: connection.sent.bytes_total | 0 + reporter: conditional((context.reporter.kind | "inbound") == "outbound", "source", "destination") + responseFlags: context.proxy_error_code | "" + monitored_resource_type: '"global"' +--- +apiVersion: "config.istio.io/v1alpha2" +kind: rule +metadata: + name: stdio + namespace: {{ .Release.Namespace }} + labels: + app: {{ template "mixer.name" . }} + chart: {{ template "mixer.chart" . }} + heritage: {{ .Release.Service }} + release: {{ .Release.Name }} +spec: + match: context.protocol == "http" || context.protocol == "grpc" + actions: + - handler: stdio + instances: + - accesslog +--- +apiVersion: "config.istio.io/v1alpha2" +kind: rule +metadata: + name: stdiotcp + namespace: {{ .Release.Namespace }} + labels: + app: {{ template "mixer.name" . }} + chart: {{ template "mixer.chart" . }} + heritage: {{ .Release.Service }} + release: {{ .Release.Name }} +spec: + match: context.protocol == "tcp" + actions: + - handler: stdio + instances: + - tcpaccesslog +{{- end }} +--- +{{- if and .Values.adapters.prometheus.enabled .Values.telemetry.enabled }} +apiVersion: "config.istio.io/v1alpha2" +kind: instance +metadata: + name: requestcount + namespace: {{ .Release.Namespace }} + labels: + app: {{ template "mixer.name" . }} + chart: {{ template "mixer.chart" . }} + heritage: {{ .Release.Service }} + release: {{ .Release.Name }} +spec: + compiledTemplate: metric + params: + value: "1" + dimensions: + reporter: conditional((context.reporter.kind | "inbound") == "outbound", "source", "destination") + source_workload: source.workload.name | "unknown" + source_workload_namespace: source.workload.namespace | "unknown" + source_principal: source.principal | "unknown" + source_app: source.labels["app"] | "unknown" + source_version: source.labels["version"] | "unknown" + destination_workload: destination.workload.name | "unknown" + destination_workload_namespace: destination.workload.namespace | "unknown" + destination_principal: destination.principal | "unknown" + destination_app: destination.labels["app"] | "unknown" + destination_version: destination.labels["version"] | "unknown" + destination_service: destination.service.host | request.host | "unknown" + destination_service_name: destination.service.name | "unknown" + destination_service_namespace: destination.service.namespace | "unknown" + request_protocol: api.protocol | context.protocol | "unknown" + response_code: response.code | 200 + response_flags: context.proxy_error_code | "-" + permissive_response_code: rbac.permissive.response_code | "none" + permissive_response_policyid: rbac.permissive.effective_policy_id | "none" + connection_security_policy: conditional((context.reporter.kind | "inbound") == "outbound", "unknown", conditional(connection.mtls | false, "mutual_tls", "none")) + monitored_resource_type: '"UNSPECIFIED"' +--- +apiVersion: "config.istio.io/v1alpha2" +kind: instance +metadata: + name: requestduration + namespace: {{ .Release.Namespace }} + labels: + app: {{ template "mixer.name" . }} + chart: {{ template "mixer.chart" . }} + heritage: {{ .Release.Service }} + release: {{ .Release.Name }} +spec: + compiledTemplate: metric + params: + value: response.duration | "0ms" + dimensions: + reporter: conditional((context.reporter.kind | "inbound") == "outbound", "source", "destination") + source_workload: source.workload.name | "unknown" + source_workload_namespace: source.workload.namespace | "unknown" + source_principal: source.principal | "unknown" + source_app: source.labels["app"] | "unknown" + source_version: source.labels["version"] | "unknown" + destination_workload: destination.workload.name | "unknown" + destination_workload_namespace: destination.workload.namespace | "unknown" + destination_principal: destination.principal | "unknown" + destination_app: destination.labels["app"] | "unknown" + destination_version: destination.labels["version"] | "unknown" + destination_service: destination.service.host | request.host | "unknown" + destination_service_name: destination.service.name | "unknown" + destination_service_namespace: destination.service.namespace | "unknown" + request_protocol: api.protocol | context.protocol | "unknown" + response_code: response.code | 200 + response_flags: context.proxy_error_code | "-" + permissive_response_code: rbac.permissive.response_code | "none" + permissive_response_policyid: rbac.permissive.effective_policy_id | "none" + connection_security_policy: conditional((context.reporter.kind | "inbound") == "outbound", "unknown", conditional(connection.mtls | false, "mutual_tls", "none")) + monitored_resource_type: '"UNSPECIFIED"' +--- +apiVersion: "config.istio.io/v1alpha2" +kind: instance +metadata: + name: requestsize + namespace: {{ .Release.Namespace }} + labels: + app: {{ template "mixer.name" . }} + chart: {{ template "mixer.chart" . }} + heritage: {{ .Release.Service }} + release: {{ .Release.Name }} +spec: + compiledTemplate: metric + params: + value: request.size | 0 + dimensions: + reporter: conditional((context.reporter.kind | "inbound") == "outbound", "source", "destination") + source_workload: source.workload.name | "unknown" + source_workload_namespace: source.workload.namespace | "unknown" + source_principal: source.principal | "unknown" + source_app: source.labels["app"] | "unknown" + source_version: source.labels["version"] | "unknown" + destination_workload: destination.workload.name | "unknown" + destination_workload_namespace: destination.workload.namespace | "unknown" + destination_principal: destination.principal | "unknown" + destination_app: destination.labels["app"] | "unknown" + destination_version: destination.labels["version"] | "unknown" + destination_service: destination.service.host | request.host | "unknown" + destination_service_name: destination.service.name | "unknown" + destination_service_namespace: destination.service.namespace | "unknown" + request_protocol: api.protocol | context.protocol | "unknown" + response_code: response.code | 200 + response_flags: context.proxy_error_code | "-" + permissive_response_code: rbac.permissive.response_code | "none" + permissive_response_policyid: rbac.permissive.effective_policy_id | "none" + connection_security_policy: conditional((context.reporter.kind | "inbound") == "outbound", "unknown", conditional(connection.mtls | false, "mutual_tls", "none")) + monitored_resource_type: '"UNSPECIFIED"' +--- +apiVersion: "config.istio.io/v1alpha2" +kind: instance +metadata: + name: responsesize + namespace: {{ .Release.Namespace }} + labels: + app: {{ template "mixer.name" . }} + chart: {{ template "mixer.chart" . }} + heritage: {{ .Release.Service }} + release: {{ .Release.Name }} +spec: + compiledTemplate: metric + params: + value: response.size | 0 + dimensions: + reporter: conditional((context.reporter.kind | "inbound") == "outbound", "source", "destination") + source_workload: source.workload.name | "unknown" + source_workload_namespace: source.workload.namespace | "unknown" + source_principal: source.principal | "unknown" + source_app: source.labels["app"] | "unknown" + source_version: source.labels["version"] | "unknown" + destination_workload: destination.workload.name | "unknown" + destination_workload_namespace: destination.workload.namespace | "unknown" + destination_principal: destination.principal | "unknown" + destination_app: destination.labels["app"] | "unknown" + destination_version: destination.labels["version"] | "unknown" + destination_service: destination.service.host | request.host | "unknown" + destination_service_name: destination.service.name | "unknown" + destination_service_namespace: destination.service.namespace | "unknown" + request_protocol: api.protocol | context.protocol | "unknown" + response_code: response.code | 200 + response_flags: context.proxy_error_code | "-" + permissive_response_code: rbac.permissive.response_code | "none" + permissive_response_policyid: rbac.permissive.effective_policy_id | "none" + connection_security_policy: conditional((context.reporter.kind | "inbound") == "outbound", "unknown", conditional(connection.mtls | false, "mutual_tls", "none")) + monitored_resource_type: '"UNSPECIFIED"' +--- +apiVersion: "config.istio.io/v1alpha2" +kind: instance +metadata: + name: tcpbytesent + namespace: {{ .Release.Namespace }} + labels: + app: {{ template "mixer.name" . }} + chart: {{ template "mixer.chart" . }} + heritage: {{ .Release.Service }} + release: {{ .Release.Name }} +spec: + compiledTemplate: metric + params: + value: connection.sent.bytes | 0 + dimensions: + reporter: conditional((context.reporter.kind | "inbound") == "outbound", "source", "destination") + source_workload: source.workload.name | "unknown" + source_workload_namespace: source.workload.namespace | "unknown" + source_principal: source.principal | "unknown" + source_app: source.labels["app"] | "unknown" + source_version: source.labels["version"] | "unknown" + destination_workload: destination.workload.name | "unknown" + destination_workload_namespace: destination.workload.namespace | "unknown" + destination_principal: destination.principal | "unknown" + destination_app: destination.labels["app"] | "unknown" + destination_version: destination.labels["version"] | "unknown" + destination_service: destination.service.host | "unknown" + destination_service_name: destination.service.name | "unknown" + destination_service_namespace: destination.service.namespace | "unknown" + connection_security_policy: conditional((context.reporter.kind | "inbound") == "outbound", "unknown", conditional(connection.mtls | false, "mutual_tls", "none")) + response_flags: context.proxy_error_code | "-" + monitored_resource_type: '"UNSPECIFIED"' +--- +apiVersion: "config.istio.io/v1alpha2" +kind: instance +metadata: + name: tcpbytereceived + namespace: {{ .Release.Namespace }} + labels: + app: {{ template "mixer.name" . }} + chart: {{ template "mixer.chart" . }} + heritage: {{ .Release.Service }} + release: {{ .Release.Name }} +spec: + compiledTemplate: metric + params: + value: connection.received.bytes | 0 + dimensions: + reporter: conditional((context.reporter.kind | "inbound") == "outbound", "source", "destination") + source_workload: source.workload.name | "unknown" + source_workload_namespace: source.workload.namespace | "unknown" + source_principal: source.principal | "unknown" + source_app: source.labels["app"] | "unknown" + source_version: source.labels["version"] | "unknown" + destination_workload: destination.workload.name | "unknown" + destination_workload_namespace: destination.workload.namespace | "unknown" + destination_principal: destination.principal | "unknown" + destination_app: destination.labels["app"] | "unknown" + destination_version: destination.labels["version"] | "unknown" + destination_service: destination.service.host | "unknown" + destination_service_name: destination.service.name | "unknown" + destination_service_namespace: destination.service.namespace | "unknown" + connection_security_policy: conditional((context.reporter.kind | "inbound") == "outbound", "unknown", conditional(connection.mtls | false, "mutual_tls", "none")) + response_flags: context.proxy_error_code | "-" + monitored_resource_type: '"UNSPECIFIED"' +--- +apiVersion: "config.istio.io/v1alpha2" +kind: instance +metadata: + name: tcpconnectionsopened + namespace: {{ .Release.Namespace }} + labels: + app: {{ template "mixer.name" . }} + chart: {{ template "mixer.chart" . }} + heritage: {{ .Release.Service }} + release: {{ .Release.Name }} +spec: + compiledTemplate: metric + params: + value: "1" + dimensions: + reporter: conditional((context.reporter.kind | "inbound") == "outbound", "source", "destination") + source_workload: source.workload.name | "unknown" + source_workload_namespace: source.workload.namespace | "unknown" + source_principal: source.principal | "unknown" + source_app: source.labels["app"] | "unknown" + source_version: source.labels["version"] | "unknown" + destination_workload: destination.workload.name | "unknown" + destination_workload_namespace: destination.workload.namespace | "unknown" + destination_principal: destination.principal | "unknown" + destination_app: destination.labels["app"] | "unknown" + destination_version: destination.labels["version"] | "unknown" + destination_service: destination.service.host | "unknown" + destination_service_name: destination.service.name | "unknown" + destination_service_namespace: destination.service.namespace | "unknown" + connection_security_policy: conditional((context.reporter.kind | "inbound") == "outbound", "unknown", conditional(connection.mtls | false, "mutual_tls", "none")) + response_flags: context.proxy_error_code | "-" + monitored_resource_type: '"UNSPECIFIED"' +--- +apiVersion: "config.istio.io/v1alpha2" +kind: instance +metadata: + name: tcpconnectionsclosed + namespace: {{ .Release.Namespace }} + labels: + app: {{ template "mixer.name" . }} + chart: {{ template "mixer.chart" . }} + heritage: {{ .Release.Service }} + release: {{ .Release.Name }} +spec: + compiledTemplate: metric + params: + value: "1" + dimensions: + reporter: conditional((context.reporter.kind | "inbound") == "outbound", "source", "destination") + source_workload: source.workload.name | "unknown" + source_workload_namespace: source.workload.namespace | "unknown" + source_principal: source.principal | "unknown" + source_app: source.labels["app"] | "unknown" + source_version: source.labels["version"] | "unknown" + destination_workload: destination.workload.name | "unknown" + destination_workload_namespace: destination.workload.namespace | "unknown" + destination_principal: destination.principal | "unknown" + destination_app: destination.labels["app"] | "unknown" + destination_version: destination.labels["version"] | "unknown" + destination_service: destination.service.host | "unknown" + destination_service_name: destination.service.name | "unknown" + destination_service_namespace: destination.service.namespace | "unknown" + connection_security_policy: conditional((context.reporter.kind | "inbound") == "outbound", "unknown", conditional(connection.mtls | false, "mutual_tls", "none")) + response_flags: context.proxy_error_code | "-" + monitored_resource_type: '"UNSPECIFIED"' +--- +apiVersion: "config.istio.io/v1alpha2" +kind: handler +metadata: + name: prometheus + namespace: {{ .Release.Namespace }} + labels: + app: {{ template "mixer.name" . }} + chart: {{ template "mixer.chart" . }} + heritage: {{ .Release.Service }} + release: {{ .Release.Name }} +spec: + compiledAdapter: prometheus + params: + metricsExpirationPolicy: + metricsExpiryDuration: "{{ .Values.adapters.prometheus.metricsExpiryDuration }}" + metrics: + - name: requests_total + instance_name: requestcount.instance.{{ .Release.Namespace }} + kind: COUNTER + label_names: + - reporter + - source_app + - source_principal + - source_workload + - source_workload_namespace + - source_version + - destination_app + - destination_principal + - destination_workload + - destination_workload_namespace + - destination_version + - destination_service + - destination_service_name + - destination_service_namespace + - request_protocol + - response_code + - response_flags + - permissive_response_code + - permissive_response_policyid + - connection_security_policy + - name: request_duration_seconds + instance_name: requestduration.instance.{{ .Release.Namespace }} + kind: DISTRIBUTION + label_names: + - reporter + - source_app + - source_principal + - source_workload + - source_workload_namespace + - source_version + - destination_app + - destination_principal + - destination_workload + - destination_workload_namespace + - destination_version + - destination_service + - destination_service_name + - destination_service_namespace + - request_protocol + - response_code + - response_flags + - permissive_response_code + - permissive_response_policyid + - connection_security_policy + buckets: + explicit_buckets: + bounds: [0.005, 0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 1, 2.5, 5, 10] + - name: request_bytes + instance_name: requestsize.instance.{{ .Release.Namespace }} + kind: DISTRIBUTION + label_names: + - reporter + - source_app + - source_principal + - source_workload + - source_workload_namespace + - source_version + - destination_app + - destination_principal + - destination_workload + - destination_workload_namespace + - destination_version + - destination_service + - destination_service_name + - destination_service_namespace + - request_protocol + - response_code + - response_flags + - permissive_response_code + - permissive_response_policyid + - connection_security_policy + buckets: + exponentialBuckets: + numFiniteBuckets: 8 + scale: 1 + growthFactor: 10 + - name: response_bytes + instance_name: responsesize.instance.{{ .Release.Namespace }} + kind: DISTRIBUTION + label_names: + - reporter + - source_app + - source_principal + - source_workload + - source_workload_namespace + - source_version + - destination_app + - destination_principal + - destination_workload + - destination_workload_namespace + - destination_version + - destination_service + - destination_service_name + - destination_service_namespace + - request_protocol + - response_code + - response_flags + - permissive_response_code + - permissive_response_policyid + - connection_security_policy + buckets: + exponentialBuckets: + numFiniteBuckets: 8 + scale: 1 + growthFactor: 10 + - name: tcp_sent_bytes_total + instance_name: tcpbytesent.instance.{{ .Release.Namespace }} + kind: COUNTER + label_names: + - reporter + - source_app + - source_principal + - source_workload + - source_workload_namespace + - source_version + - destination_app + - destination_principal + - destination_workload + - destination_workload_namespace + - destination_version + - destination_service + - destination_service_name + - destination_service_namespace + - connection_security_policy + - response_flags + - name: tcp_received_bytes_total + instance_name: tcpbytereceived.instance.{{ .Release.Namespace }} + kind: COUNTER + label_names: + - reporter + - source_app + - source_principal + - source_workload + - source_workload_namespace + - source_version + - destination_app + - destination_principal + - destination_workload + - destination_workload_namespace + - destination_version + - destination_service + - destination_service_name + - destination_service_namespace + - connection_security_policy + - response_flags + - name: tcp_connections_opened_total + instance_name: tcpconnectionsopened.instance.{{ .Release.Namespace }} + kind: COUNTER + label_names: + - reporter + - source_app + - source_principal + - source_workload + - source_workload_namespace + - source_version + - destination_app + - destination_principal + - destination_workload + - destination_workload_namespace + - destination_version + - destination_service + - destination_service_name + - destination_service_namespace + - connection_security_policy + - response_flags + - name: tcp_connections_closed_total + instance_name: tcpconnectionsclosed.instance.{{ .Release.Namespace }} + kind: COUNTER + label_names: + - reporter + - source_app + - source_principal + - source_workload + - source_workload_namespace + - source_version + - destination_app + - destination_principal + - destination_workload + - destination_workload_namespace + - destination_version + - destination_service + - destination_service_name + - destination_service_namespace + - connection_security_policy + - response_flags +--- +apiVersion: "config.istio.io/v1alpha2" +kind: rule +metadata: + name: promhttp + namespace: {{ .Release.Namespace }} + labels: + app: {{ template "mixer.name" . }} + chart: {{ template "mixer.chart" . }} + heritage: {{ .Release.Service }} + release: {{ .Release.Name }} +spec: + match: (context.protocol == "http" || context.protocol == "grpc") && (match((request.useragent | "-"), "kube-probe*") == false) && (match((request.useragent | "-"), "Prometheus*") == false) + actions: + - handler: prometheus + instances: + - requestcount + - requestduration + - requestsize + - responsesize +--- +apiVersion: "config.istio.io/v1alpha2" +kind: rule +metadata: + name: promtcp + namespace: {{ .Release.Namespace }} + labels: + app: {{ template "mixer.name" . }} + chart: {{ template "mixer.chart" . }} + heritage: {{ .Release.Service }} + release: {{ .Release.Name }} +spec: + match: context.protocol == "tcp" + actions: + - handler: prometheus + instances: + - tcpbytesent + - tcpbytereceived +--- +apiVersion: "config.istio.io/v1alpha2" +kind: rule +metadata: + name: promtcpconnectionopen + namespace: {{ .Release.Namespace }} + labels: + app: {{ template "mixer.name" . }} + chart: {{ template "mixer.chart" . }} + heritage: {{ .Release.Service }} + release: {{ .Release.Name }} +spec: + match: context.protocol == "tcp" && ((connection.event | "na") == "open") + actions: + - handler: prometheus + instances: + - tcpconnectionsopened +--- +apiVersion: "config.istio.io/v1alpha2" +kind: rule +metadata: + name: promtcpconnectionclosed + namespace: {{ .Release.Namespace }} + labels: + app: {{ template "mixer.name" . }} + chart: {{ template "mixer.chart" . }} + heritage: {{ .Release.Service }} + release: {{ .Release.Name }} +spec: + match: context.protocol == "tcp" && ((connection.event | "na") == "close") + actions: + - handler: prometheus + instances: + - tcpconnectionsclosed +{{- end }} +--- +{{- if and .Values.adapters.kubernetesenv.enabled (or .Values.policy.enabled .Values.telemetry.enabled) }} +apiVersion: "config.istio.io/v1alpha2" +kind: handler +metadata: + name: kubernetesenv + namespace: {{ .Release.Namespace }} + labels: + app: {{ template "mixer.name" . }} + chart: {{ template "mixer.chart" . }} + heritage: {{ .Release.Service }} + release: {{ .Release.Name }} +spec: + compiledAdapter: kubernetesenv + params: + # when running from mixer root, use the following config after adding a + # symbolic link to a kubernetes config file via: + # + # $ ln -s ~/.kube/config mixer/adapter/kubernetes/kubeconfig + # + # kubeconfig_path: "mixer/adapter/kubernetes/kubeconfig" + +--- +apiVersion: "config.istio.io/v1alpha2" +kind: rule +metadata: + name: kubeattrgenrulerule + namespace: {{ .Release.Namespace }} + labels: + app: {{ template "mixer.name" . }} + chart: {{ template "mixer.chart" . }} + heritage: {{ .Release.Service }} + release: {{ .Release.Name }} +spec: + actions: + - handler: kubernetesenv + instances: + - attributes +--- +apiVersion: "config.istio.io/v1alpha2" +kind: rule +metadata: + name: tcpkubeattrgenrulerule + namespace: {{ .Release.Namespace }} + labels: + app: {{ template "mixer.name" . }} + chart: {{ template "mixer.chart" . }} + heritage: {{ .Release.Service }} + release: {{ .Release.Name }} +spec: + match: context.protocol == "tcp" + actions: + - handler: kubernetesenv + instances: + - attributes +--- +apiVersion: "config.istio.io/v1alpha2" +kind: instance +metadata: + name: attributes + namespace: {{ .Release.Namespace }} + labels: + app: {{ template "mixer.name" . }} + chart: {{ template "mixer.chart" . }} + heritage: {{ .Release.Service }} + release: {{ .Release.Name }} +spec: + compiledTemplate: kubernetes + params: + # Pass the required attribute data to the adapter + source_uid: source.uid | "" + source_ip: source.ip | ip("0.0.0.0") # default to unspecified ip addr + destination_uid: destination.uid | "" + destination_port: destination.port | 0 + attributeBindings: + # Fill the new attributes from the adapter produced output. + # $out refers to an instance of OutputTemplate message + source.ip: $out.source_pod_ip | ip("0.0.0.0") + source.uid: $out.source_pod_uid | "unknown" + source.labels: $out.source_labels | emptyStringMap() + source.name: $out.source_pod_name | "unknown" + source.namespace: $out.source_namespace | "default" + source.owner: $out.source_owner | "unknown" + source.serviceAccount: $out.source_service_account_name | "unknown" + source.workload.uid: $out.source_workload_uid | "unknown" + source.workload.name: $out.source_workload_name | "unknown" + source.workload.namespace: $out.source_workload_namespace | "unknown" + destination.ip: $out.destination_pod_ip | ip("0.0.0.0") + destination.uid: $out.destination_pod_uid | "unknown" + destination.labels: $out.destination_labels | emptyStringMap() + destination.name: $out.destination_pod_name | "unknown" + destination.container.name: $out.destination_container_name | "unknown" + destination.namespace: $out.destination_namespace | "default" + destination.owner: $out.destination_owner | "unknown" + destination.serviceAccount: $out.destination_service_account_name | "unknown" + destination.workload.uid: $out.destination_workload_uid | "unknown" + destination.workload.name: $out.destination_workload_name | "unknown" + destination.workload.namespace: $out.destination_workload_namespace | "unknown" +{{- end }} +--- +{{- if .Values.policy.enabled }} +# Configuration needed by Mixer. +# Mixer cluster is delivered via CDS +# Specify mixer cluster settings +apiVersion: networking.istio.io/v1alpha3 +kind: DestinationRule +metadata: + name: istio-policy + namespace: {{ .Release.Namespace }} + labels: + app: {{ template "mixer.name" . }} + chart: {{ template "mixer.chart" . }} + heritage: {{ .Release.Service }} + release: {{ .Release.Name }} +spec: + host: istio-policy.{{ .Release.Namespace }}.svc.{{ .Values.global.proxy.clusterDomain }} + {{- if .Values.global.defaultConfigVisibilitySettings }} + exportTo: + - '*' + {{- end }} + trafficPolicy: + {{- if .Values.global.controlPlaneSecurityEnabled }} + portLevelSettings: + - port: + number: 15004 + tls: + mode: ISTIO_MUTUAL + {{- end}} + connectionPool: + http: + http2MaxRequests: 10000 + maxRequestsPerConnection: 10000 +{{- end }} +--- +{{- if .Values.telemetry.enabled }} +apiVersion: networking.istio.io/v1alpha3 +kind: DestinationRule +metadata: + name: istio-telemetry + namespace: {{ .Release.Namespace }} + labels: + app: {{ template "mixer.name" . }} + chart: {{ template "mixer.chart" . }} + heritage: {{ .Release.Service }} + release: {{ .Release.Name }} +spec: + host: istio-telemetry.{{ .Release.Namespace }}.svc.{{ .Values.global.proxy.clusterDomain }} + {{- if .Values.global.defaultConfigVisibilitySettings }} + exportTo: + - '*' + {{- end }} + trafficPolicy: + {{- if .Values.global.controlPlaneSecurityEnabled }} + portLevelSettings: + - port: + number: 15004 + tls: + mode: ISTIO_MUTUAL + {{- end}} + connectionPool: + http: + http2MaxRequests: 10000 + maxRequestsPerConnection: 10000 +{{- end }} +--- +{{- end }} diff --git a/istio-1.3.5/install/kubernetes/helm/istio/charts/mixer/templates/deployment.yaml b/istio-1.3.5/install/kubernetes/helm/istio/charts/mixer/templates/deployment.yaml new file mode 100644 index 0000000..2b32b1e --- /dev/null +++ b/istio-1.3.5/install/kubernetes/helm/istio/charts/mixer/templates/deployment.yaml @@ -0,0 +1,418 @@ +{{- define "policy_container" }} + spec: + serviceAccountName: istio-mixer-service-account +{{- if $.Values.global.priorityClassName }} + priorityClassName: "{{ $.Values.global.priorityClassName }}" +{{- end }} + volumes: + - name: istio-certs + secret: + secretName: istio.istio-mixer-service-account + optional: true + {{- if $.Values.global.sds.enabled }} + - hostPath: + path: /var/run/sds + name: sds-uds-path + - name: istio-token + projected: + sources: + - serviceAccountToken: + audience: {{ $.Values.global.sds.token.aud }} + expirationSeconds: 43200 + path: istio-token + {{- end }} + - name: uds-socket + emptyDir: {} + - name: policy-adapter-secret + secret: + secretName: policy-adapter-secret + optional: true + affinity: + {{- include "nodeaffinity" . | indent 6 }} + {{- include "podAntiAffinity" . | indent 6 }} + {{- if .Values.tolerations }} + tolerations: +{{ toYaml .Values.tolerations | indent 6 }} + {{- else if .Values.global.defaultTolerations }} + tolerations: +{{ toYaml .Values.global.defaultTolerations | indent 6 }} + {{- end }} + containers: + - name: mixer +{{- if contains "/" .Values.image }} + image: "{{ .Values.image }}" +{{- else }} + image: "{{ $.Values.global.hub }}/{{ $.Values.image }}:{{ $.Values.global.tag }}" +{{- end }} + imagePullPolicy: {{ $.Values.global.imagePullPolicy }} + ports: + - containerPort: {{ .Values.global.monitoringPort }} + - containerPort: 42422 + args: + - --monitoringPort={{ .Values.global.monitoringPort }} + - --address + - unix:///sock/mixer.socket +{{- if $.Values.global.logging.level }} + - --log_output_level={{ $.Values.global.logging.level }} +{{- end}} +{{- if $.Values.global.useMCP }} + {{- if $.Values.global.controlPlaneSecurityEnabled}} + - --configStoreURL=mcps://istio-galley.{{ $.Release.Namespace }}.svc:9901 + {{- else }} + - --configStoreURL=mcp://istio-galley.{{ $.Release.Namespace }}.svc:9901 + {{- end }} +{{- else }} + - --configStoreURL=k8s:// +{{- end }} + - --configDefaultNamespace={{ $.Release.Namespace }} + {{- if $.Values.adapters.useAdapterCRDs }} + - --useAdapterCRDs=true + {{- else }} + - --useAdapterCRDs=false + {{- end }} + - --useTemplateCRDs=false + {{- if $.Values.global.tracer.zipkin.address }} + - --trace_zipkin_url=http://{{- $.Values.global.tracer.zipkin.address }}/api/v1/spans + {{- else }} + - --trace_zipkin_url=http://zipkin.{{ $.Release.Namespace }}:9411/api/v1/spans + {{- end }} + {{- if .Values.env }} + env: + {{- range $key, $val := .Values.env }} + - name: {{ $key }} + value: "{{ $val }}" + {{- end }} + {{- end }} + resources: +{{- if .Values.policy.resources }} +{{ toYaml .Values.policy.resources | indent 10 }} +{{- else if .Values.resources }} +{{ toYaml .Values.resources | indent 10 }} +{{- else }} +{{ toYaml .Values.global.defaultResources | indent 10 }} +{{- end }} + volumeMounts: +{{- if $.Values.global.useMCP }} + - name: istio-certs + mountPath: /etc/certs + readOnly: true +{{- end }} + - name: uds-socket + mountPath: /sock + livenessProbe: + httpGet: + path: /version + port: {{ .Values.global.monitoringPort }} + initialDelaySeconds: 5 + periodSeconds: 5 + - name: istio-proxy +{{- if contains "/" $.Values.global.proxy.image }} + image: "{{ $.Values.global.proxy.image }}" +{{- else }} + image: "{{ $.Values.global.hub }}/{{ $.Values.global.proxy.image }}:{{ $.Values.global.tag }}" +{{- end }} + imagePullPolicy: {{ $.Values.global.imagePullPolicy }} + ports: + - containerPort: 9091 + - containerPort: 15004 + - containerPort: 15090 + protocol: TCP + name: http-envoy-prom + args: + - proxy + - --domain + - $(POD_NAMESPACE).svc.{{ $.Values.global.proxy.clusterDomain }} + - --serviceCluster + - istio-policy + - --templateFile + - /etc/istio/proxy/envoy_policy.yaml.tmpl + {{- if $.Values.global.controlPlaneSecurityEnabled }} + - --controlPlaneAuthPolicy + - MUTUAL_TLS + {{- else }} + - --controlPlaneAuthPolicy + - NONE + {{- end }} + {{- if $.Values.global.trustDomain }} + - --trust-domain={{ $.Values.global.trustDomain }} + {{- end }} + env: + - name: POD_NAME + valueFrom: + fieldRef: + apiVersion: v1 + fieldPath: metadata.name + - name: POD_NAMESPACE + valueFrom: + fieldRef: + apiVersion: v1 + fieldPath: metadata.namespace + - name: INSTANCE_IP + valueFrom: + fieldRef: + apiVersion: v1 + fieldPath: status.podIP + - name: SDS_ENABLED + value: "{{ $.Values.global.sds.enabled }}" + resources: +{{- if $.Values.global.proxy.resources }} +{{ toYaml $.Values.global.proxy.resources | indent 10 }} +{{- else }} +{{ toYaml .Values.global.defaultResources | indent 10 }} +{{- end }} + volumeMounts: + - name: istio-certs + mountPath: /etc/certs + readOnly: true + {{- if $.Values.global.sds.enabled }} + - name: sds-uds-path + mountPath: /var/run/sds + readOnly: true + - name: istio-token + mountPath: /var/run/secrets/tokens + {{- end }} + - name: uds-socket + mountPath: /sock + - name: policy-adapter-secret + mountPath: /var/run/secrets/istio.io/policy/adapter + readOnly: true +{{- end }} + +{{- define "telemetry_container" }} + spec: + serviceAccountName: istio-mixer-service-account +{{- if $.Values.global.priorityClassName }} + priorityClassName: "{{ $.Values.global.priorityClassName }}" +{{- end }} + volumes: + - name: istio-certs + secret: + secretName: istio.istio-mixer-service-account + optional: true + {{- if $.Values.global.sds.enabled }} + - hostPath: + path: /var/run/sds + name: sds-uds-path + - name: istio-token + projected: + sources: + - serviceAccountToken: + audience: {{ $.Values.global.sds.token.aud }} + expirationSeconds: 43200 + path: istio-token + {{- end }} + - name: uds-socket + emptyDir: {} + - name: telemetry-adapter-secret + secret: + secretName: telemetry-adapter-secret + optional: true + affinity: + {{- include "nodeaffinity" . | indent 6 }} + {{- include "podAntiAffinity" . | indent 6 }} + {{- if .Values.tolerations }} + tolerations: +{{ toYaml .Values.tolerations | indent 6 }} + {{- else if .Values.global.defaultTolerations }} + tolerations: +{{ toYaml .Values.global.defaultTolerations | indent 6 }} + {{- end }} + containers: + - name: mixer +{{- if contains "/" .Values.image }} + image: "{{ .Values.image }}" +{{- else }} + image: "{{ $.Values.global.hub }}/{{ $.Values.image }}:{{ $.Values.global.tag }}" +{{- end }} + imagePullPolicy: {{ $.Values.global.imagePullPolicy }} + ports: + - containerPort: {{ .Values.global.monitoringPort }} + - containerPort: 42422 + args: + - --monitoringPort={{ .Values.global.monitoringPort }} + - --address + - unix:///sock/mixer.socket +{{- if $.Values.global.logging.level }} + - --log_output_level={{ $.Values.global.logging.level }} +{{- end}} +{{- if $.Values.global.useMCP }} + {{- if $.Values.global.controlPlaneSecurityEnabled}} + - --configStoreURL=mcps://istio-galley.{{ $.Release.Namespace }}.svc:9901 + - --certFile=/etc/certs/cert-chain.pem + - --keyFile=/etc/certs/key.pem + - --caCertFile=/etc/certs/root-cert.pem + {{- else }} + - --configStoreURL=mcp://istio-galley.{{ $.Release.Namespace }}.svc:9901 + {{- end }} +{{- else }} + - --configStoreURL=k8s:// +{{- end }} + - --configDefaultNamespace={{ $.Release.Namespace }} + {{- if $.Values.adapters.useAdapterCRDs }} + - --useAdapterCRDs=true + {{- else }} + - --useAdapterCRDs=false + {{- end }} + {{- if $.Values.global.tracer.zipkin.address }} + - --trace_zipkin_url=http://{{- $.Values.global.tracer.zipkin.address }}/api/v1/spans + {{- else }} + - --trace_zipkin_url=http://zipkin.{{ $.Release.Namespace }}:9411/api/v1/spans + {{- end }} + - --averageLatencyThreshold + - {{ $.Values.telemetry.loadshedding.latencyThreshold }} + - --loadsheddingMode + - {{ $.Values.telemetry.loadshedding.mode }} + {{- if .Values.env }} + env: + {{- range $key, $val := .Values.env }} + - name: {{ $key }} + value: "{{ $val }}" + {{- end }} + {{- end }} + resources: +{{- if .Values.telemetry.resources }} +{{ toYaml .Values.telemetry.resources | indent 10 }} +{{- else if .Values.resources }} +{{ toYaml .Values.resources | indent 10 }} +{{- else }} +{{ toYaml .Values.global.defaultResources | indent 10 }} +{{- end }} + volumeMounts: +{{- if $.Values.global.useMCP }} + - name: istio-certs + mountPath: /etc/certs + readOnly: true +{{- end }} + - name: telemetry-adapter-secret + mountPath: /var/run/secrets/istio.io/telemetry/adapter + readOnly: true + - name: uds-socket + mountPath: /sock + livenessProbe: + httpGet: + path: /version + port: {{ .Values.global.monitoringPort }} + initialDelaySeconds: 5 + periodSeconds: 5 + - name: istio-proxy +{{- if contains "/" $.Values.global.proxy.image }} + image: "{{ $.Values.global.proxy.image }}" +{{- else }} + image: "{{ $.Values.global.hub }}/{{ $.Values.global.proxy.image }}:{{ $.Values.global.tag }}" +{{- end }} + imagePullPolicy: {{ $.Values.global.imagePullPolicy }} + ports: + - containerPort: 9091 + - containerPort: 15004 + - containerPort: 15090 + protocol: TCP + name: http-envoy-prom + args: + - proxy + - --domain + - $(POD_NAMESPACE).svc.{{ .Values.global.proxy.clusterDomain }} + - --serviceCluster + - istio-telemetry + - --templateFile + - /etc/istio/proxy/envoy_telemetry.yaml.tmpl + {{- if $.Values.global.controlPlaneSecurityEnabled }} + - --controlPlaneAuthPolicy + - MUTUAL_TLS + {{- else }} + - --controlPlaneAuthPolicy + - NONE + {{- end }} + env: + - name: POD_NAME + valueFrom: + fieldRef: + apiVersion: v1 + fieldPath: metadata.name + - name: POD_NAMESPACE + valueFrom: + fieldRef: + apiVersion: v1 + fieldPath: metadata.namespace + - name: INSTANCE_IP + valueFrom: + fieldRef: + apiVersion: v1 + fieldPath: status.podIP + - name: SDS_ENABLED + value: "{{ $.Values.global.sds.enabled }}" + resources: +{{- if $.Values.global.proxy.resources }} +{{ toYaml $.Values.global.proxy.resources | indent 10 }} +{{- else }} +{{ toYaml .Values.global.defaultResources | indent 10 }} +{{- end }} + volumeMounts: + - name: istio-certs + mountPath: /etc/certs + readOnly: true + {{- if $.Values.global.sds.enabled }} + - name: sds-uds-path + mountPath: /var/run/sds + readOnly: true + - name: istio-token + mountPath: /var/run/secrets/tokens + {{- end }} + - name: uds-socket + mountPath: /sock +{{- end }} + + +{{- range $key, $spec := .Values }} +{{- if or (eq $key "policy") (eq $key "telemetry") }} +{{- if $spec.enabled }} +apiVersion: apps/v1 +kind: Deployment +metadata: + name: istio-{{ $key }} + namespace: {{ $.Release.Namespace }} + labels: + app: istio-mixer + chart: {{ template "mixer.chart" $ }} + heritage: {{ $.Release.Service }} + release: {{ $.Release.Name }} + istio: mixer +spec: +{{- if not $spec.autoscaleEnabled }} +{{- if $spec.replicaCount }} + replicas: {{ $spec.replicaCount }} +{{- else }} + replicas: 1 +{{- end }} +{{- end }} + strategy: + rollingUpdate: + maxSurge: {{ $spec.rollingMaxSurge }} + maxUnavailable: {{ $spec.rollingMaxUnavailable }} + selector: + matchLabels: + istio: mixer + istio-mixer-type: {{ $key }} + template: + metadata: + labels: + app: {{ $key }} + chart: {{ template "mixer.chart" $ }} + heritage: {{ $.Release.Service }} + release: {{ $.Release.Name }} + istio: mixer + istio-mixer-type: {{ $key }} + annotations: + sidecar.istio.io/inject: "false" +{{- with $.Values.podAnnotations }} +{{ toYaml . | indent 8 }} +{{- end }} +{{- if eq $key "policy"}} +{{- template "policy_container" $ }} +{{- else }} +{{- template "telemetry_container" $ }} +{{- end }} + +--- +{{- end }} +{{- end }} +{{- end }} {{/* range */}} diff --git a/istio-1.3.5/install/kubernetes/helm/istio/charts/mixer/templates/poddisruptionbudget.yaml b/istio-1.3.5/install/kubernetes/helm/istio/charts/mixer/templates/poddisruptionbudget.yaml new file mode 100644 index 0000000..a6bfe86 --- /dev/null +++ b/istio-1.3.5/install/kubernetes/helm/istio/charts/mixer/templates/poddisruptionbudget.yaml @@ -0,0 +1,32 @@ +{{- range $key, $spec := .Values }} +{{- if or (eq $key "policy") (eq $key "telemetry") }} +{{- if $spec.enabled }} +{{- if $.Values.global.defaultPodDisruptionBudget.enabled }} +apiVersion: policy/v1beta1 +kind: PodDisruptionBudget +metadata: + name: istio-{{ $key }} + namespace: {{ $.Release.Namespace }} + labels: + app: {{ $key }} + chart: {{ template "mixer.chart" $ }} + heritage: {{ $.Release.Service }} + release: {{ $.Release.Name }} + version: {{ $.Chart.Version }} + istio: mixer + istio-mixer-type: {{ $key }} +spec: +{{- if $.Values.global.defaultPodDisruptionBudget.enabled }} +{{ include "podDisruptionBudget.spec" $.Values.global.defaultPodDisruptionBudget }} +{{- end }} + selector: + matchLabels: + app: {{ $key }} + release: {{ $.Release.Name }} + istio: mixer + istio-mixer-type: {{ $key }} +--- +{{- end }} +{{- end }} +{{- end }} +{{- end }} diff --git a/istio-1.3.5/install/kubernetes/helm/istio/charts/mixer/templates/service.yaml b/istio-1.3.5/install/kubernetes/helm/istio/charts/mixer/templates/service.yaml new file mode 100644 index 0000000..79cc4a5 --- /dev/null +++ b/istio-1.3.5/install/kubernetes/helm/istio/charts/mixer/templates/service.yaml @@ -0,0 +1,39 @@ +{{- range $key, $spec := .Values }} +{{- if or (eq $key "policy") (eq $key "telemetry") }} +{{- if $spec.enabled }} +apiVersion: v1 +kind: Service +metadata: + name: istio-{{ $key }} + namespace: {{ $.Release.Namespace }} + annotations: + networking.istio.io/exportTo: "*" + labels: + app: {{ template "mixer.name" $ }} + chart: {{ template "mixer.chart" $ }} + heritage: {{ $.Release.Service }} + release: {{ $.Release.Name }} + istio: mixer +spec: + ports: + - name: grpc-mixer + port: 9091 + - name: grpc-mixer-mtls + port: 15004 + - name: http-monitoring + port: {{ $.Values.global.monitoringPort }} +{{- if eq $key "telemetry" }} + - name: prometheus + port: 42422 +{{- if $spec.sessionAffinityEnabled }} + sessionAffinity: ClientIP +{{- end }} +{{- end }} + selector: + istio: mixer + istio-mixer-type: {{ $key }} +--- +{{- end }} +{{- end }} +{{- end }} + diff --git a/istio-1.3.5/install/kubernetes/helm/istio/charts/mixer/templates/serviceaccount.yaml b/istio-1.3.5/install/kubernetes/helm/istio/charts/mixer/templates/serviceaccount.yaml new file mode 100644 index 0000000..9d3da7d --- /dev/null +++ b/istio-1.3.5/install/kubernetes/helm/istio/charts/mixer/templates/serviceaccount.yaml @@ -0,0 +1,18 @@ +{{- if or (.Values.policy.enabled) (.Values.telemetry.enabled) }} +apiVersion: v1 +kind: ServiceAccount +{{- if .Values.global.imagePullSecrets }} +imagePullSecrets: +{{- range .Values.global.imagePullSecrets }} + - name: {{ . }} +{{- end }} +{{- end }} +metadata: + name: istio-mixer-service-account + namespace: {{ .Release.Namespace }} + labels: + app: {{ template "mixer.name" . }} + chart: {{ template "mixer.chart" . }} + heritage: {{ .Release.Service }} + release: {{ .Release.Name }} +{{- end }} diff --git a/istio-1.3.5/install/kubernetes/helm/istio/charts/mixer/values.yaml b/istio-1.3.5/install/kubernetes/helm/istio/charts/mixer/values.yaml new file mode 100644 index 0000000..4d94523 --- /dev/null +++ b/istio-1.3.5/install/kubernetes/helm/istio/charts/mixer/values.yaml @@ -0,0 +1,99 @@ +# +# mixer configuration +# +image: mixer + +env: + GODEBUG: gctrace=1 + # max procs should be ceil(cpu limit + 1) + GOMAXPROCS: "6" + +policy: + # if policy is enabled, global.disablePolicyChecks has affect. + enabled: false + replicaCount: 1 + autoscaleEnabled: true + autoscaleMin: 1 + autoscaleMax: 5 + cpu: + targetAverageUtilization: 80 + rollingMaxSurge: 100% + rollingMaxUnavailable: 25% + +telemetry: + enabled: true + replicaCount: 1 + autoscaleEnabled: true + autoscaleMin: 1 + autoscaleMax: 5 + cpu: + targetAverageUtilization: 80 + rollingMaxSurge: 100% + rollingMaxUnavailable: 25% + sessionAffinityEnabled: false + + # mixer load shedding configuration. + # When mixer detects that it is overloaded, it starts rejecting grpc requests. + loadshedding: + # disabled, logonly or enforce + mode: enforce + # based on measurements 100ms p50 translates to p99 of under 1s. This is ok for telemetry which is inherently async. + latencyThreshold: 100ms + resources: + requests: + cpu: 1000m + memory: 1G + limits: + # It is best to do horizontal scaling of mixer using moderate cpu allocation. + # We have experimentally found that these values work well. + cpu: 4800m + memory: 4G + + # Set reportBatchMaxEntries to 0 to use the default batching behavior (i.e., every 100 requests). + # A positive value indicates the number of requests that are batched before telemetry data + # is sent to the mixer server + reportBatchMaxEntries: 100 + + # Set reportBatchMaxTime to 0 to use the default batching behavior (i.e., every 1 second). + # A positive time value indicates the maximum wait time since the last request will telemetry data + # be batched before being sent to the mixer server + reportBatchMaxTime: 1s + +podAnnotations: {} +nodeSelector: {} +tolerations: [] + +# Specify the pod anti-affinity that allows you to constrain which nodes +# your pod is eligible to be scheduled based on labels on pods that are +# already running on the node rather than based on labels on nodes. +# There are currently two types of anti-affinity: +# "requiredDuringSchedulingIgnoredDuringExecution" +# "preferredDuringSchedulingIgnoredDuringExecution" +# which denote "hard" vs. "soft" requirements, you can define your values +# in "podAntiAffinityLabelSelector" and "podAntiAffinityTermLabelSelector" +# correspondingly. +# For example: +# podAntiAffinityLabelSelector: +# - key: security +# operator: In +# values: S1,S2 +# topologyKey: "kubernetes.io/hostname" +# This pod anti-affinity rule says that the pod requires not to be scheduled +# onto a node if that node is already running a pod with label having key +# "security" and value "S1". +podAntiAffinityLabelSelector: [] +podAntiAffinityTermLabelSelector: [] + +adapters: + kubernetesenv: + enabled: true + + # stdio is a debug adapter in istio-telemetry, it is not recommended for production use. + stdio: + enabled: false + outputAsJson: true + prometheus: + enabled: true + metricsExpiryDuration: 10m + # Setting this to false sets the useAdapterCRDs mixer startup argument to false + useAdapterCRDs: false diff --git a/istio-1.3.5/install/kubernetes/helm/istio/charts/nodeagent/Chart.yaml b/istio-1.3.5/install/kubernetes/helm/istio/charts/nodeagent/Chart.yaml new file mode 100644 index 0000000..efc9f1a --- /dev/null +++ b/istio-1.3.5/install/kubernetes/helm/istio/charts/nodeagent/Chart.yaml @@ -0,0 +1,13 @@ +apiVersion: v1 +name: nodeagent +version: 1.3.5 +appVersion: 1.3.5 +tillerVersion: ">=2.7.2" +description: Helm chart for nodeagent deployment +keywords: + - istio + - nodeagent +sources: + - http://github.com/istio/istio +engine: gotpl +icon: https://istio.io/favicons/android-192x192.png diff --git a/istio-1.3.5/install/kubernetes/helm/istio/charts/nodeagent/templates/_helpers.tpl b/istio-1.3.5/install/kubernetes/helm/istio/charts/nodeagent/templates/_helpers.tpl new file mode 100644 index 0000000..fda6043 --- /dev/null +++ b/istio-1.3.5/install/kubernetes/helm/istio/charts/nodeagent/templates/_helpers.tpl @@ -0,0 +1,32 @@ +{{/* vim: set filetype=mustache: */}} +{{/* +Expand the name of the chart. +*/}} +{{- define "nodeagent.name" -}} +{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" -}} +{{- end -}} + +{{/* +Create a default fully qualified app name. +We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). +If release name contains chart name it will be used as a full name. +*/}} +{{- define "nodeagent.fullname" -}} +{{- if .Values.fullnameOverride -}} +{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" -}} +{{- else -}} +{{- $name := default .Chart.Name .Values.nameOverride -}} +{{- if contains $name .Release.Name -}} +{{- .Release.Name | trunc 63 | trimSuffix "-" -}} +{{- else -}} +{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" -}} +{{- end -}} +{{- end -}} +{{- end -}} + +{{/* +Create chart name and version as used by the chart label. +*/}} +{{- define "nodeagent.chart" -}} +{{- .Chart.Name | trunc 63 | trimSuffix "-" -}} +{{- end -}} diff --git a/istio-1.3.5/install/kubernetes/helm/istio/charts/nodeagent/templates/clusterrole.yaml b/istio-1.3.5/install/kubernetes/helm/istio/charts/nodeagent/templates/clusterrole.yaml new file mode 100644 index 0000000..9127b05 --- /dev/null +++ b/istio-1.3.5/install/kubernetes/helm/istio/charts/nodeagent/templates/clusterrole.yaml @@ -0,0 +1,13 @@ +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: istio-nodeagent-{{ .Release.Namespace }} + labels: + app: {{ template "nodeagent.name" . }} + chart: {{ template "nodeagent.chart" . }} + heritage: {{ .Release.Service }} + release: {{ .Release.Name }} +rules: +- apiGroups: [""] + resources: ["configmaps"] + verbs: ["get"] \ No newline at end of file diff --git a/istio-1.3.5/install/kubernetes/helm/istio/charts/nodeagent/templates/clusterrolebinding.yaml b/istio-1.3.5/install/kubernetes/helm/istio/charts/nodeagent/templates/clusterrolebinding.yaml new file mode 100644 index 0000000..963757e --- /dev/null +++ b/istio-1.3.5/install/kubernetes/helm/istio/charts/nodeagent/templates/clusterrolebinding.yaml @@ -0,0 +1,17 @@ +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: istio-nodeagent-{{ .Release.Namespace }} + labels: + app: {{ template "nodeagent.name" . }} + chart: {{ template "nodeagent.chart" . }} + heritage: {{ .Release.Service }} + release: {{ .Release.Name }} +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: istio-nodeagent-{{ .Release.Namespace }} +subjects: + - kind: ServiceAccount + name: istio-nodeagent-service-account + namespace: {{ .Release.Namespace }} \ No newline at end of file diff --git a/istio-1.3.5/install/kubernetes/helm/istio/charts/nodeagent/templates/daemonset.yaml b/istio-1.3.5/install/kubernetes/helm/istio/charts/nodeagent/templates/daemonset.yaml new file mode 100644 index 0000000..00935f9 --- /dev/null +++ b/istio-1.3.5/install/kubernetes/helm/istio/charts/nodeagent/templates/daemonset.yaml @@ -0,0 +1,70 @@ +apiVersion: apps/v1 +kind: DaemonSet +metadata: + name: istio-nodeagent + namespace: {{ .Release.Namespace }} + labels: + app: {{ template "nodeagent.name" . }} + chart: {{ template "nodeagent.chart" . }} + release: {{ .Release.Name }} + heritage: {{ .Release.Service }} + istio: nodeagent +spec: + selector: + matchLabels: + istio: nodeagent + template: + metadata: + labels: + app: {{ template "nodeagent.name" . }} + chart: {{ template "nodeagent.chart" . }} + release: {{ .Release.Name }} + heritage: {{ .Release.Service }} + istio: nodeagent + annotations: + sidecar.istio.io/inject: "false" + spec: + serviceAccountName: istio-nodeagent-service-account +{{- if .Values.global.priorityClassName }} + priorityClassName: "{{ .Values.global.priorityClassName }}" +{{- end }} + containers: + - name: nodeagent +{{- if contains "/" .Values.image }} + image: "{{ .Values.image }}" +{{- else }} + image: "{{ .Values.global.hub }}/{{ .Values.image }}:{{ .Values.global.tag }}" +{{- end }} + imagePullPolicy: {{ .Values.global.imagePullPolicy }} + volumeMounts: + - mountPath: /var/run/sds + name: sdsudspath + env: + {{- if .Values.env }} + {{- range $key, $val := .Values.env }} + - name: {{ $key }} + value: "{{ $val }}" + {{- end }} + {{- end }} + - name: "TRUST_DOMAIN" + value: "{{ .Values.global.trustDomain }}" + - name: NAMESPACE + valueFrom: + fieldRef: + fieldPath: metadata.namespace + volumes: + - name: sdsudspath + hostPath: + path: /var/run/sds + affinity: + {{- include "nodeaffinity" . | indent 6 }} + {{- include "podAntiAffinity" . | indent 6 }} + {{- if .Values.tolerations }} + tolerations: +{{ toYaml .Values.tolerations | indent 6 }} + {{- else if .Values.global.defaultTolerations }} + tolerations: +{{ toYaml .Values.global.defaultTolerations | indent 6 }} + {{- end }} + updateStrategy: + type: RollingUpdate \ No newline at end of file diff --git a/istio-1.3.5/install/kubernetes/helm/istio/charts/nodeagent/templates/serviceaccount.yaml b/istio-1.3.5/install/kubernetes/helm/istio/charts/nodeagent/templates/serviceaccount.yaml new file mode 100644 index 0000000..b52f852 --- /dev/null +++ b/istio-1.3.5/install/kubernetes/helm/istio/charts/nodeagent/templates/serviceaccount.yaml @@ -0,0 +1,16 @@ +apiVersion: v1 +kind: ServiceAccount +{{- if .Values.global.imagePullSecrets }} +imagePullSecrets: +{{- range .Values.global.imagePullSecrets }} + - name: {{ . }} +{{- end }} +{{- end }} +metadata: + name: istio-nodeagent-service-account + namespace: {{ .Release.Namespace }} + labels: + app: {{ template "nodeagent.name" . }} + chart: {{ template "nodeagent.chart" . }} + heritage: {{ .Release.Service }} + release: {{ .Release.Name }} \ No newline at end of file diff --git a/istio-1.3.5/install/kubernetes/helm/istio/charts/nodeagent/values.yaml b/istio-1.3.5/install/kubernetes/helm/istio/charts/nodeagent/values.yaml new file mode 100644 index 0000000..76c5503 --- /dev/null +++ b/istio-1.3.5/install/kubernetes/helm/istio/charts/nodeagent/values.yaml @@ -0,0 +1,35 @@ +# +# nodeagent configuration +# +enabled: false +image: node-agent-k8s +env: + # name of authentication provider. + CA_PROVIDER: "" + # CA endpoint. + CA_ADDR: "" + # names of authentication provider's plugins. + PLUGINS: "" +nodeSelector: {} +tolerations: [] + +# Specify the pod anti-affinity that allows you to constrain which nodes +# your pod is eligible to be scheduled based on labels on pods that are +# already running on the node rather than based on labels on nodes. +# There are currently two types of anti-affinity: +# "requiredDuringSchedulingIgnoredDuringExecution" +# "preferredDuringSchedulingIgnoredDuringExecution" +# which denote "hard" vs. "soft" requirements, you can define your values +# in "podAntiAffinityLabelSelector" and "podAntiAffinityTermLabelSelector" +# correspondingly. +# For example: +# podAntiAffinityLabelSelector: +# - key: security +# operator: In +# values: S1,S2 +# topologyKey: "kubernetes.io/hostname" +# This pod anti-affinity rule says that the pod requires not to be scheduled +# onto a node if that node is already running a pod with label having key +# "security" and value "S1". +podAntiAffinityLabelSelector: [] +podAntiAffinityTermLabelSelector: [] diff --git a/istio-1.3.5/install/kubernetes/helm/istio/charts/pilot/Chart.yaml b/istio-1.3.5/install/kubernetes/helm/istio/charts/pilot/Chart.yaml new file mode 100644 index 0000000..a827694 --- /dev/null +++ b/istio-1.3.5/install/kubernetes/helm/istio/charts/pilot/Chart.yaml @@ -0,0 +1,13 @@ +apiVersion: v1 +name: pilot +version: 1.3.5 +appVersion: 1.3.5 +tillerVersion: ">=2.7.2" +description: Helm chart for pilot deployment +keywords: + - istio + - pilot +sources: + - http://github.com/istio/istio +engine: gotpl +icon: https://istio.io/favicons/android-192x192.png diff --git a/istio-1.3.5/install/kubernetes/helm/istio/charts/pilot/templates/_helpers.tpl b/istio-1.3.5/install/kubernetes/helm/istio/charts/pilot/templates/_helpers.tpl new file mode 100644 index 0000000..c812c37 --- /dev/null +++ b/istio-1.3.5/install/kubernetes/helm/istio/charts/pilot/templates/_helpers.tpl @@ -0,0 +1,32 @@ +{{/* vim: set filetype=mustache: */}} +{{/* +Expand the name of the chart. +*/}} +{{- define "pilot.name" -}} +{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" -}} +{{- end -}} + +{{/* +Create a default fully qualified app name. +We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). +If release name contains chart name it will be used as a full name. +*/}} +{{- define "pilot.fullname" -}} +{{- if .Values.fullnameOverride -}} +{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" -}} +{{- else -}} +{{- $name := default .Chart.Name .Values.nameOverride -}} +{{- if contains $name .Release.Name -}} +{{- .Release.Name | trunc 63 | trimSuffix "-" -}} +{{- else -}} +{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" -}} +{{- end -}} +{{- end -}} +{{- end -}} + +{{/* +Create chart name and version as used by the chart label. +*/}} +{{- define "pilot.chart" -}} +{{- .Chart.Name | trunc 63 | trimSuffix "-" -}} +{{- end -}} diff --git a/istio-1.3.5/install/kubernetes/helm/istio/charts/pilot/templates/autoscale.yaml b/istio-1.3.5/install/kubernetes/helm/istio/charts/pilot/templates/autoscale.yaml new file mode 100644 index 0000000..1a99451 --- /dev/null +++ b/istio-1.3.5/install/kubernetes/helm/istio/charts/pilot/templates/autoscale.yaml @@ -0,0 +1,25 @@ +{{- if and .Values.autoscaleEnabled .Values.autoscaleMin .Values.autoscaleMax }} +apiVersion: autoscaling/v2beta1 +kind: HorizontalPodAutoscaler +metadata: + name: istio-pilot + namespace: {{ .Release.Namespace }} + labels: + app: {{ template "pilot.name" . }} + chart: {{ template "pilot.chart" . }} + heritage: {{ .Release.Service }} + release: {{ .Release.Name }} +spec: + maxReplicas: {{ .Values.autoscaleMax }} + minReplicas: {{ .Values.autoscaleMin }} + scaleTargetRef: + apiVersion: apps/v1 + kind: Deployment + name: istio-pilot + metrics: + - type: Resource + resource: + name: cpu + targetAverageUtilization: {{ .Values.cpu.targetAverageUtilization }} +--- +{{- end }} diff --git a/istio-1.3.5/install/kubernetes/helm/istio/charts/pilot/templates/clusterrole.yaml b/istio-1.3.5/install/kubernetes/helm/istio/charts/pilot/templates/clusterrole.yaml new file mode 100644 index 0000000..0435c3e --- /dev/null +++ b/istio-1.3.5/install/kubernetes/helm/istio/charts/pilot/templates/clusterrole.yaml @@ -0,0 +1,34 @@ +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: istio-pilot-{{ .Release.Namespace }} + labels: + app: {{ template "pilot.name" . }} + chart: {{ template "pilot.chart" . }} + heritage: {{ .Release.Service }} + release: {{ .Release.Name }} +rules: +- apiGroups: ["config.istio.io"] + resources: ["*"] + verbs: ["*"] +- apiGroups: ["rbac.istio.io"] + resources: ["*"] + verbs: ["get", "watch", "list"] +- apiGroups: ["networking.istio.io"] + resources: ["*"] + verbs: ["*"] +- apiGroups: ["authentication.istio.io"] + resources: ["*"] + verbs: ["*"] +- apiGroups: ["apiextensions.k8s.io"] + resources: ["customresourcedefinitions"] + verbs: ["*"] +- apiGroups: ["extensions"] + resources: ["ingresses", "ingresses/status"] + verbs: ["*"] +- apiGroups: [""] + resources: ["configmaps"] + verbs: ["create", "get", "list", "watch", "update"] +- apiGroups: [""] + resources: ["endpoints", "pods", "services", "namespaces", "nodes", "secrets"] + verbs: ["get", "list", "watch"] diff --git a/istio-1.3.5/install/kubernetes/helm/istio/charts/pilot/templates/clusterrolebinding.yaml b/istio-1.3.5/install/kubernetes/helm/istio/charts/pilot/templates/clusterrolebinding.yaml new file mode 100644 index 0000000..ef9281c --- /dev/null +++ b/istio-1.3.5/install/kubernetes/helm/istio/charts/pilot/templates/clusterrolebinding.yaml @@ -0,0 +1,17 @@ +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: istio-pilot-{{ .Release.Namespace }} + labels: + app: {{ template "pilot.name" . }} + chart: {{ template "pilot.chart" . }} + heritage: {{ .Release.Service }} + release: {{ .Release.Name }} +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: istio-pilot-{{ .Release.Namespace }} +subjects: + - kind: ServiceAccount + name: istio-pilot-service-account + namespace: {{ .Release.Namespace }} diff --git a/istio-1.3.5/install/kubernetes/helm/istio/charts/pilot/templates/deployment.yaml b/istio-1.3.5/install/kubernetes/helm/istio/charts/pilot/templates/deployment.yaml new file mode 100644 index 0000000..e43ea7d --- /dev/null +++ b/istio-1.3.5/install/kubernetes/helm/istio/charts/pilot/templates/deployment.yaml @@ -0,0 +1,223 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: istio-pilot + namespace: {{ .Release.Namespace }} + # TODO: default template doesn't have this, which one is right ? + labels: + app: {{ template "pilot.name" . }} + chart: {{ template "pilot.chart" . }} + heritage: {{ .Release.Service }} + release: {{ .Release.Name }} + istio: pilot + annotations: + checksum/config-volume: {{ template "istio.configmap.checksum" . }} +spec: +{{- if not .Values.autoscaleEnabled }} +{{- if .Values.replicaCount }} + replicas: {{ .Values.replicaCount }} +{{- else }} + replicas: 1 +{{- end }} +{{- end }} + strategy: + rollingUpdate: + maxSurge: {{ .Values.rollingMaxSurge }} + maxUnavailable: {{ .Values.rollingMaxUnavailable }} + selector: + matchLabels: + istio: pilot + template: + metadata: + labels: + app: {{ template "pilot.name" . }} + chart: {{ template "pilot.chart" . }} + heritage: {{ .Release.Service }} + release: {{ .Release.Name }} + istio: pilot + annotations: + sidecar.istio.io/inject: "false" + spec: + serviceAccountName: istio-pilot-service-account +{{- if .Values.global.priorityClassName }} + priorityClassName: "{{ .Values.global.priorityClassName }}" +{{- end }} + containers: + - name: discovery +{{- if contains "/" .Values.image }} + image: "{{ .Values.image }}" +{{- else }} + image: "{{ .Values.global.hub }}/{{ .Values.image }}:{{ .Values.global.tag }}" +{{- end }} + imagePullPolicy: {{ .Values.global.imagePullPolicy }} + args: + - "discovery" + - --monitoringAddr=:{{ .Values.global.monitoringPort }} +{{- if $.Values.global.logging.level }} + - --log_output_level={{ $.Values.global.logging.level }} +{{- end}} + - --domain + - {{ .Values.global.proxy.clusterDomain }} +{{- if .Values.global.oneNamespace }} + - "-a" + - {{ .Release.Namespace }} +{{- end }} +{{- if and $.Values.global.controlPlaneSecurityEnabled (not .Values.sidecar)}} + - --secureGrpcAddr + - ":15011" +{{- else }} + - --secureGrpcAddr + - "" +{{- end }} +{{- if .Values.global.trustDomain }} + - --trust-domain={{ .Values.global.trustDomain }} +{{- end }} + - --keepaliveMaxServerConnectionAge + - "{{ .Values.keepaliveMaxServerConnectionAge }}" + ports: + - containerPort: 8080 + - containerPort: 15010 +{{- if not .Values.sidecar }} + - containerPort: 15011 +{{- end }} + readinessProbe: + httpGet: + path: /ready + port: 8080 + initialDelaySeconds: 5 + periodSeconds: 30 + timeoutSeconds: 5 + env: + - name: POD_NAME + valueFrom: + fieldRef: + apiVersion: v1 + fieldPath: metadata.name + - name: POD_NAMESPACE + valueFrom: + fieldRef: + apiVersion: v1 + fieldPath: metadata.namespace + {{- if .Values.env }} + {{- range $key, $val := .Values.env }} + - name: {{ $key }} + value: "{{ $val }}" + {{- end }} + {{- end }} +{{- if .Values.traceSampling }} + - name: PILOT_TRACE_SAMPLING + value: "{{ .Values.traceSampling }}" +{{- end }} + - name: PILOT_ENABLE_PROTOCOL_SNIFFING_FOR_OUTBOUND + value: "{{ .Values.enableProtocolSniffingForOutbound }}" + - name: PILOT_ENABLE_PROTOCOL_SNIFFING_FOR_INBOUND + value: "{{ .Values.enableProtocolSniffingForInbound }}" + resources: +{{- if .Values.resources }} +{{ toYaml .Values.resources | indent 12 }} +{{- else }} +{{ toYaml .Values.global.defaultResources | indent 12 }} +{{- end }} + volumeMounts: + - name: config-volume + mountPath: /etc/istio/config + - name: istio-certs + mountPath: /etc/certs + readOnly: true +{{- if .Values.sidecar }} + - name: istio-proxy +{{- if contains "/" .Values.global.proxy.image }} + image: "{{ .Values.global.proxy.image }}" +{{- else }} + image: "{{ .Values.global.hub }}/{{ .Values.global.proxy.image }}:{{ .Values.global.tag }}" +{{- end }} + imagePullPolicy: {{ .Values.global.imagePullPolicy }} + ports: + - containerPort: 15003 + - containerPort: 15005 + - containerPort: 15007 + - containerPort: 15011 + args: + - proxy + - --domain + - $(POD_NAMESPACE).svc.{{ .Values.global.proxy.clusterDomain }} + - --serviceCluster + - istio-pilot + - --templateFile + - /etc/istio/proxy/envoy_pilot.yaml.tmpl + {{- if $.Values.global.controlPlaneSecurityEnabled}} + - --controlPlaneAuthPolicy + - MUTUAL_TLS + {{- else }} + - --controlPlaneAuthPolicy + - NONE + {{- end }} + {{- if .Values.global.trustDomain }} + - --trust-domain={{ .Values.global.trustDomain }} + {{- end }} + env: + - name: POD_NAME + valueFrom: + fieldRef: + apiVersion: v1 + fieldPath: metadata.name + - name: POD_NAMESPACE + valueFrom: + fieldRef: + apiVersion: v1 + fieldPath: metadata.namespace + - name: INSTANCE_IP + valueFrom: + fieldRef: + apiVersion: v1 + fieldPath: status.podIP + - name: SDS_ENABLED + value: "{{ $.Values.global.sds.enabled }}" + resources: +{{- if .Values.global.proxy.resources }} +{{ toYaml .Values.global.proxy.resources | indent 12 }} +{{- else }} +{{ toYaml .Values.global.defaultResources | indent 12 }} +{{- end }} + volumeMounts: + - name: istio-certs + mountPath: /etc/certs + readOnly: true + {{- if $.Values.global.sds.enabled }} + - name: sds-uds-path + mountPath: /var/run/sds + readOnly: true + - name: istio-token + mountPath: /var/run/secrets/tokens + {{- end }} +{{- end }} + volumes: + {{- if $.Values.global.sds.enabled }} + - hostPath: + path: /var/run/sds + name: sds-uds-path + - name: istio-token + projected: + sources: + - serviceAccountToken: + audience: {{ $.Values.global.sds.token.aud }} + expirationSeconds: 43200 + path: istio-token + {{- end }} + - name: config-volume + configMap: + name: istio + - name: istio-certs + secret: + secretName: istio.istio-pilot-service-account + optional: true + affinity: + {{- include "nodeaffinity" . | indent 6 }} + {{- include "podAntiAffinity" . | indent 6 }} + {{- if .Values.tolerations }} + tolerations: +{{ toYaml .Values.tolerations | indent 6 }} + {{- else if .Values.global.defaultTolerations }} + tolerations: +{{ toYaml .Values.global.defaultTolerations | indent 6 }} + {{- end }} diff --git a/istio-1.3.5/install/kubernetes/helm/istio/charts/pilot/templates/meshexpansion.yaml b/istio-1.3.5/install/kubernetes/helm/istio/charts/pilot/templates/meshexpansion.yaml new file mode 100644 index 0000000..4f3d595 --- /dev/null +++ b/istio-1.3.5/install/kubernetes/helm/istio/charts/pilot/templates/meshexpansion.yaml @@ -0,0 +1,91 @@ +{{- if .Values.global.meshExpansion.enabled }} +{{- if .Values.global.meshExpansion.useILB }} +apiVersion: networking.istio.io/v1alpha3 +kind: VirtualService +metadata: + name: meshexpansion-ilb-vs-pilot + namespace: {{ .Release.Namespace }} + labels: + app: {{ template "pilot.name" . }} + chart: {{ template "pilot.chart" . }} + heritage: {{ .Release.Service }} + release: {{ .Release.Name }} +spec: + hosts: + - istio-pilot.{{ .Release.Namespace }}.svc.{{ .Values.global.proxy.clusterDomain }} + gateways: + - meshexpansion-ilb-gateway + tcp: + - match: + - port: 15011 + route: + - destination: + host: istio-pilot.{{ .Release.Namespace }}.svc.{{ .Values.global.proxy.clusterDomain }} + port: + number: 15011 + - match: + - port: 15010 + route: + - destination: + host: istio-pilot.{{ .Release.Namespace }}.svc.{{ .Values.global.proxy.clusterDomain }} + port: + number: 15010 + - match: + - port: 5353 + route: + - destination: + host: kube-dns.kube-system.svc.{{ .Values.global.proxy.clusterDomain }} + port: + number: 53 +--- +{{- else }} + +apiVersion: networking.istio.io/v1alpha3 +kind: VirtualService +metadata: + name: meshexpansion-vs-pilot + namespace: {{ .Release.Namespace }} + labels: + app: {{ template "pilot.name" . }} + chart: {{ template "pilot.chart" . }} + heritage: {{ .Release.Service }} + release: {{ .Release.Name }} +spec: + hosts: + - istio-pilot.{{ $.Release.Namespace }}.svc.{{ .Values.global.proxy.clusterDomain }} + gateways: + - meshexpansion-gateway + tcp: + - match: + - port: 15011 + route: + - destination: + host: istio-pilot.{{ $.Release.Namespace }}.svc.{{ .Values.global.proxy.clusterDomain }} + port: + number: 15011 +--- +{{- end }} + +{{- if .Values.global.controlPlaneSecurityEnabled }} +apiVersion: networking.istio.io/v1alpha3 +kind: DestinationRule +metadata: + name: meshexpansion-dr-pilot + namespace: {{ .Release.Namespace }} + labels: + app: {{ template "pilot.name" . }} + chart: {{ template "pilot.chart" . }} + heritage: {{ .Release.Service }} + release: {{ .Release.Name }} +spec: + host: istio-pilot.{{ .Release.Namespace }}.svc.{{ .Values.global.proxy.clusterDomain }} + trafficPolicy: + portLevelSettings: + - port: + number: 15011 + tls: + mode: DISABLE +--- +{{- end }} +{{- end }} + diff --git a/istio-1.3.5/install/kubernetes/helm/istio/charts/pilot/templates/poddisruptionbudget.yaml b/istio-1.3.5/install/kubernetes/helm/istio/charts/pilot/templates/poddisruptionbudget.yaml new file mode 100644 index 0000000..fd9e06a --- /dev/null +++ b/istio-1.3.5/install/kubernetes/helm/istio/charts/pilot/templates/poddisruptionbudget.yaml @@ -0,0 +1,22 @@ +{{- if .Values.global.defaultPodDisruptionBudget.enabled }} +apiVersion: policy/v1beta1 +kind: PodDisruptionBudget +metadata: + name: istio-pilot + namespace: {{ .Release.Namespace }} + labels: + app: {{ template "pilot.name" . }} + chart: {{ template "pilot.chart" . }} + heritage: {{ .Release.Service }} + release: {{ .Release.Name }} + istio: pilot +spec: +{{- if .Values.global.defaultPodDisruptionBudget.enabled }} +{{ include "podDisruptionBudget.spec" .Values.global.defaultPodDisruptionBudget }} +{{- end }} + selector: + matchLabels: + app: {{ template "pilot.name" . }} + release: {{ .Release.Name }} + istio: pilot +{{- end }} diff --git a/istio-1.3.5/install/kubernetes/helm/istio/charts/pilot/templates/service.yaml b/istio-1.3.5/install/kubernetes/helm/istio/charts/pilot/templates/service.yaml new file mode 100644 index 0000000..a61d930 --- /dev/null +++ b/istio-1.3.5/install/kubernetes/helm/istio/charts/pilot/templates/service.yaml @@ -0,0 +1,23 @@ +apiVersion: v1 +kind: Service +metadata: + name: istio-pilot + namespace: {{ .Release.Namespace }} + labels: + app: {{ template "pilot.name" . }} + chart: {{ template "pilot.chart" . }} + heritage: {{ .Release.Service }} + release: {{ .Release.Name }} + istio: pilot +spec: + ports: + - port: 15010 + name: grpc-xds # direct + - port: 15011 + name: https-xds # mTLS + - port: 8080 + name: http-legacy-discovery # direct + - port: {{ .Values.global.monitoringPort }} + name: http-monitoring + selector: + istio: pilot diff --git a/istio-1.3.5/install/kubernetes/helm/istio/charts/pilot/templates/serviceaccount.yaml b/istio-1.3.5/install/kubernetes/helm/istio/charts/pilot/templates/serviceaccount.yaml new file mode 100644 index 0000000..7ec2a66 --- /dev/null +++ b/istio-1.3.5/install/kubernetes/helm/istio/charts/pilot/templates/serviceaccount.yaml @@ -0,0 +1,16 @@ +apiVersion: v1 +kind: ServiceAccount +{{- if .Values.global.imagePullSecrets }} +imagePullSecrets: +{{- range .Values.global.imagePullSecrets }} + - name: {{ . }} +{{- end }} +{{- end }} +metadata: + name: istio-pilot-service-account + namespace: {{ .Release.Namespace }} + labels: + app: {{ template "pilot.name" . }} + chart: {{ template "pilot.chart" . }} + heritage: {{ .Release.Service }} + release: {{ .Release.Name }} diff --git a/istio-1.3.5/install/kubernetes/helm/istio/charts/pilot/values.yaml b/istio-1.3.5/install/kubernetes/helm/istio/charts/pilot/values.yaml new file mode 100644 index 0000000..58e2a03 --- /dev/null +++ b/istio-1.3.5/install/kubernetes/helm/istio/charts/pilot/values.yaml @@ -0,0 +1,56 @@ +# +# pilot configuration +# +enabled: true +autoscaleEnabled: true +autoscaleMin: 1 +autoscaleMax: 5 +# specify replicaCount when autoscaleEnabled: false +# replicaCount: 1 +rollingMaxSurge: 100% +rollingMaxUnavailable: 25% +image: pilot +sidecar: true +traceSampling: 1.0 +# if protocol sniffing is enabled for outbound +enableProtocolSniffingForOutbound: true +# if protocol sniffing is enabled for inbound +enableProtocolSniffingForInbound: false +# Resources for a small pilot install +resources: + requests: + cpu: 500m + memory: 2048Mi +env: + PILOT_PUSH_THROTTLE: 100 + GODEBUG: gctrace=1 +cpu: + targetAverageUtilization: 80 +nodeSelector: {} +tolerations: [] + +# Specify the pod anti-affinity that allows you to constrain which nodes +# your pod is eligible to be scheduled based on labels on pods that are +# already running on the node rather than based on labels on nodes. +# There are currently two types of anti-affinity: +# "requiredDuringSchedulingIgnoredDuringExecution" +# "preferredDuringSchedulingIgnoredDuringExecution" +# which denote "hard" vs. "soft" requirements, you can define your values +# in "podAntiAffinityLabelSelector" and "podAntiAffinityTermLabelSelector" +# correspondingly. +# For example: +# podAntiAffinityLabelSelector: +# - key: security +# operator: In +# values: S1,S2 +# topologyKey: "kubernetes.io/hostname" +# This pod anti-affinity rule says that the pod requires not to be scheduled +# onto a node if that node is already running a pod with label having key +# "security" and value "S1". +podAntiAffinityLabelSelector: [] +podAntiAffinityTermLabelSelector: [] + +# The following is used to limit how long a sidecar can be connected +# to a pilot. It balances out load across pilot instances at the cost of +# increasing system churn. +keepaliveMaxServerConnectionAge: 30m diff --git a/istio-1.3.5/install/kubernetes/helm/istio/charts/prometheus/Chart.yaml b/istio-1.3.5/install/kubernetes/helm/istio/charts/prometheus/Chart.yaml new file mode 100644 index 0000000..fef6875 --- /dev/null +++ b/istio-1.3.5/install/kubernetes/helm/istio/charts/prometheus/Chart.yaml @@ -0,0 +1,6 @@ +apiVersion: v1 +description: A Helm chart for Kubernetes +name: prometheus +version: 1.3.5 +appVersion: 2.8.0 +tillerVersion: ">=2.7.2" diff --git a/istio-1.3.5/install/kubernetes/helm/istio/charts/prometheus/templates/_helpers.tpl b/istio-1.3.5/install/kubernetes/helm/istio/charts/prometheus/templates/_helpers.tpl new file mode 100644 index 0000000..0393883 --- /dev/null +++ b/istio-1.3.5/install/kubernetes/helm/istio/charts/prometheus/templates/_helpers.tpl @@ -0,0 +1,32 @@ +{{/* vim: set filetype=mustache: */}} +{{/* +Expand the name of the chart. +*/}} +{{- define "prometheus.name" -}} +{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" -}} +{{- end -}} + +{{/* +Create a default fully qualified app name. +We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). +If release name contains chart name it will be used as a full name. +*/}} +{{- define "prometheus.fullname" -}} +{{- if .Values.fullnameOverride -}} +{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" -}} +{{- else -}} +{{- $name := default .Chart.Name .Values.nameOverride -}} +{{- if contains $name .Release.Name -}} +{{- .Release.Name | trunc 63 | trimSuffix "-" -}} +{{- else -}} +{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" -}} +{{- end -}} +{{- end -}} +{{- end -}} + +{{/* +Create chart name and version as used by the chart label. +*/}} +{{- define "prometheus.chart" -}} +{{- .Chart.Name | trunc 63 | trimSuffix "-" -}} +{{- end -}} diff --git a/istio-1.3.5/install/kubernetes/helm/istio/charts/prometheus/templates/clusterrole.yaml b/istio-1.3.5/install/kubernetes/helm/istio/charts/prometheus/templates/clusterrole.yaml new file mode 100644 index 0000000..06fdfaf --- /dev/null +++ b/istio-1.3.5/install/kubernetes/helm/istio/charts/prometheus/templates/clusterrole.yaml @@ -0,0 +1,24 @@ +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: prometheus-{{ .Release.Namespace }} + labels: + app: prometheus + chart: {{ template "prometheus.chart" . }} + heritage: {{ .Release.Service }} + release: {{ .Release.Name }} +rules: +- apiGroups: [""] + resources: + - nodes + - services + - endpoints + - pods + - nodes/proxy + verbs: ["get", "list", "watch"] +- apiGroups: [""] + resources: + - configmaps + verbs: ["get"] +- nonResourceURLs: ["/metrics"] + verbs: ["get"] diff --git a/istio-1.3.5/install/kubernetes/helm/istio/charts/prometheus/templates/clusterrolebindings.yaml b/istio-1.3.5/install/kubernetes/helm/istio/charts/prometheus/templates/clusterrolebindings.yaml new file mode 100644 index 0000000..295e0df --- /dev/null +++ b/istio-1.3.5/install/kubernetes/helm/istio/charts/prometheus/templates/clusterrolebindings.yaml @@ -0,0 +1,17 @@ +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: prometheus-{{ .Release.Namespace }} + labels: + app: prometheus + chart: {{ template "prometheus.chart" . }} + heritage: {{ .Release.Service }} + release: {{ .Release.Name }} +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: prometheus-{{ .Release.Namespace }} +subjects: +- kind: ServiceAccount + name: prometheus + namespace: {{ .Release.Namespace }} diff --git a/istio-1.3.5/install/kubernetes/helm/istio/charts/prometheus/templates/configmap.yaml b/istio-1.3.5/install/kubernetes/helm/istio/charts/prometheus/templates/configmap.yaml new file mode 100644 index 0000000..1b26fa5 --- /dev/null +++ b/istio-1.3.5/install/kubernetes/helm/istio/charts/prometheus/templates/configmap.yaml @@ -0,0 +1,281 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: prometheus + namespace: {{ .Release.Namespace }} + labels: + app: prometheus + chart: {{ template "prometheus.chart" . }} + heritage: {{ .Release.Service }} + release: {{ .Release.Name }} +data: + prometheus.yml: |- + global: + scrape_interval: {{ .Values.scrapeInterval }} + scrape_configs: + + - job_name: 'istio-mesh' + kubernetes_sd_configs: + - role: endpoints + namespaces: + names: + - {{ .Release.Namespace }} + + relabel_configs: + - source_labels: [__meta_kubernetes_service_name, __meta_kubernetes_endpoint_port_name] + action: keep + regex: istio-telemetry;prometheus + + # Scrape config for envoy stats + - job_name: 'envoy-stats' + metrics_path: /stats/prometheus + kubernetes_sd_configs: + - role: pod + + relabel_configs: + - source_labels: [__meta_kubernetes_pod_container_port_name] + action: keep + regex: '.*-envoy-prom' + - source_labels: [__address__, __meta_kubernetes_pod_annotation_prometheus_io_port] + action: replace + regex: ([^:]+)(?::\d+)?;(\d+) + replacement: $1:15090 + target_label: __address__ + - action: labelmap + regex: __meta_kubernetes_pod_label_(.+) + - source_labels: [__meta_kubernetes_namespace] + action: replace + target_label: namespace + - source_labels: [__meta_kubernetes_pod_name] + action: replace + target_label: pod_name + + - job_name: 'istio-policy' + kubernetes_sd_configs: + - role: endpoints + namespaces: + names: + - {{ .Release.Namespace }} + + + relabel_configs: + - source_labels: [__meta_kubernetes_service_name, __meta_kubernetes_endpoint_port_name] + action: keep + regex: istio-policy;http-monitoring + + - job_name: 'istio-telemetry' + kubernetes_sd_configs: + - role: endpoints + namespaces: + names: + - {{ .Release.Namespace }} + + relabel_configs: + - source_labels: [__meta_kubernetes_service_name, __meta_kubernetes_endpoint_port_name] + action: keep + regex: istio-telemetry;http-monitoring + + - job_name: 'pilot' + kubernetes_sd_configs: + - role: endpoints + namespaces: + names: + - {{ .Release.Namespace }} + + relabel_configs: + - source_labels: [__meta_kubernetes_service_name, __meta_kubernetes_endpoint_port_name] + action: keep + regex: istio-pilot;http-monitoring + + - job_name: 'galley' + kubernetes_sd_configs: + - role: endpoints + namespaces: + names: + - {{ .Release.Namespace }} + + relabel_configs: + - source_labels: [__meta_kubernetes_service_name, __meta_kubernetes_endpoint_port_name] + action: keep + regex: istio-galley;http-monitoring + + - job_name: 'citadel' + kubernetes_sd_configs: + - role: endpoints + namespaces: + names: + - {{ .Release.Namespace }} + + relabel_configs: + - source_labels: [__meta_kubernetes_service_name, __meta_kubernetes_endpoint_port_name] + action: keep + regex: istio-citadel;http-monitoring + + # scrape config for API servers + - job_name: 'kubernetes-apiservers' + kubernetes_sd_configs: + - role: endpoints + namespaces: + names: + - default + scheme: https + tls_config: + ca_file: /var/run/secrets/kubernetes.io/serviceaccount/ca.crt + bearer_token_file: /var/run/secrets/kubernetes.io/serviceaccount/token + relabel_configs: + - source_labels: [__meta_kubernetes_service_name, __meta_kubernetes_endpoint_port_name] + action: keep + regex: kubernetes;https + + # scrape config for nodes (kubelet) + - job_name: 'kubernetes-nodes' + scheme: https + tls_config: + ca_file: /var/run/secrets/kubernetes.io/serviceaccount/ca.crt + bearer_token_file: /var/run/secrets/kubernetes.io/serviceaccount/token + kubernetes_sd_configs: + - role: node + relabel_configs: + - action: labelmap + regex: __meta_kubernetes_node_label_(.+) + - target_label: __address__ + replacement: kubernetes.default.svc:443 + - source_labels: [__meta_kubernetes_node_name] + regex: (.+) + target_label: __metrics_path__ + replacement: /api/v1/nodes/${1}/proxy/metrics + + # Scrape config for Kubelet cAdvisor. + # + # This is required for Kubernetes 1.7.3 and later, where cAdvisor metrics + # (those whose names begin with 'container_') have been removed from the + # Kubelet metrics endpoint. This job scrapes the cAdvisor endpoint to + # retrieve those metrics. + # + # In Kubernetes 1.7.0-1.7.2, these metrics are only exposed on the cAdvisor + # HTTP endpoint; use "replacement: /api/v1/nodes/${1}:4194/proxy/metrics" + # in that case (and ensure cAdvisor's HTTP server hasn't been disabled with + # the --cadvisor-port=0 Kubelet flag). + # + # This job is not necessary and should be removed in Kubernetes 1.6 and + # earlier versions, or it will cause the metrics to be scraped twice. + - job_name: 'kubernetes-cadvisor' + scheme: https + tls_config: + ca_file: /var/run/secrets/kubernetes.io/serviceaccount/ca.crt + bearer_token_file: /var/run/secrets/kubernetes.io/serviceaccount/token + kubernetes_sd_configs: + - role: node + relabel_configs: + - action: labelmap + regex: __meta_kubernetes_node_label_(.+) + - target_label: __address__ + replacement: kubernetes.default.svc:443 + - source_labels: [__meta_kubernetes_node_name] + regex: (.+) + target_label: __metrics_path__ + replacement: /api/v1/nodes/${1}/proxy/metrics/cadvisor + + # scrape config for service endpoints. + - job_name: 'kubernetes-service-endpoints' + kubernetes_sd_configs: + - role: endpoints + relabel_configs: + - source_labels: [__meta_kubernetes_service_annotation_prometheus_io_scrape] + action: keep + regex: true + - source_labels: [__meta_kubernetes_service_annotation_prometheus_io_scheme] + action: replace + target_label: __scheme__ + regex: (https?) + - source_labels: [__meta_kubernetes_service_annotation_prometheus_io_path] + action: replace + target_label: __metrics_path__ + regex: (.+) + - source_labels: [__address__, __meta_kubernetes_service_annotation_prometheus_io_port] + action: replace + target_label: __address__ + regex: ([^:]+)(?::\d+)?;(\d+) + replacement: $1:$2 + - action: labelmap + regex: __meta_kubernetes_service_label_(.+) + - source_labels: [__meta_kubernetes_namespace] + action: replace + target_label: kubernetes_namespace + - source_labels: [__meta_kubernetes_service_name] + action: replace + target_label: kubernetes_name + + - job_name: 'kubernetes-pods' + kubernetes_sd_configs: + - role: pod + relabel_configs: # If first two labels are present, pod should be scraped by the istio-secure job. + - source_labels: [__meta_kubernetes_pod_annotation_prometheus_io_scrape] + action: keep + regex: true + # Keep target if there's no sidecar or if prometheus.io/scheme is explicitly set to "http" + - source_labels: [__meta_kubernetes_pod_annotation_sidecar_istio_io_status, __meta_kubernetes_pod_annotation_prometheus_io_scheme] + action: keep + regex: ((;.*)|(.*;http)) + - source_labels: [__meta_kubernetes_pod_annotation_istio_mtls] + action: drop + regex: (true) + - source_labels: [__meta_kubernetes_pod_annotation_prometheus_io_path] + action: replace + target_label: __metrics_path__ + regex: (.+) + - source_labels: [__address__, __meta_kubernetes_pod_annotation_prometheus_io_port] + action: replace + regex: ([^:]+)(?::\d+)?;(\d+) + replacement: $1:$2 + target_label: __address__ + - action: labelmap + regex: __meta_kubernetes_pod_label_(.+) + - source_labels: [__meta_kubernetes_namespace] + action: replace + target_label: namespace + - source_labels: [__meta_kubernetes_pod_name] + action: replace + target_label: pod_name + + - job_name: 'kubernetes-pods-istio-secure' + scheme: https + tls_config: + ca_file: /etc/istio-certs/root-cert.pem + cert_file: /etc/istio-certs/cert-chain.pem + key_file: /etc/istio-certs/key.pem + insecure_skip_verify: true # prometheus does not support secure naming. + kubernetes_sd_configs: + - role: pod + relabel_configs: + - source_labels: [__meta_kubernetes_pod_annotation_prometheus_io_scrape] + action: keep + regex: true + # sidecar status annotation is added by sidecar injector and + # istio_workload_mtls_ability can be specifically placed on a pod to indicate its ability to receive mtls traffic. + - source_labels: [__meta_kubernetes_pod_annotation_sidecar_istio_io_status, __meta_kubernetes_pod_annotation_istio_mtls] + action: keep + regex: (([^;]+);([^;]*))|(([^;]*);(true)) + - source_labels: [__meta_kubernetes_pod_annotation_prometheus_io_scheme] + action: drop + regex: (http) + - source_labels: [__meta_kubernetes_pod_annotation_prometheus_io_path] + action: replace + target_label: __metrics_path__ + regex: (.+) + - source_labels: [__address__] # Only keep address that is host:port + action: keep # otherwise an extra target with ':443' is added for https scheme + regex: ([^:]+):(\d+) + - source_labels: [__address__, __meta_kubernetes_pod_annotation_prometheus_io_port] + action: replace + regex: ([^:]+)(?::\d+)?;(\d+) + replacement: $1:$2 + target_label: __address__ + - action: labelmap + regex: __meta_kubernetes_pod_label_(.+) + - source_labels: [__meta_kubernetes_namespace] + action: replace + target_label: namespace + - source_labels: [__meta_kubernetes_pod_name] + action: replace + target_label: pod_name \ No newline at end of file diff --git a/istio-1.3.5/install/kubernetes/helm/istio/charts/prometheus/templates/deployment copy.yaml b/istio-1.3.5/install/kubernetes/helm/istio/charts/prometheus/templates/deployment copy.yaml new file mode 100644 index 0000000..9b2a534 --- /dev/null +++ b/istio-1.3.5/install/kubernetes/helm/istio/charts/prometheus/templates/deployment copy.yaml @@ -0,0 +1,101 @@ +# TODO: the original template has service account, roles, etc +apiVersion: apps/v1 +kind: Deployment +metadata: + name: prometheus + namespace: {{ .Release.Namespace }} + labels: + app: prometheus + chart: {{ template "prometheus.chart" . }} + heritage: {{ .Release.Service }} + release: {{ .Release.Name }} +spec: + replicas: {{ .Values.replicaCount }} + selector: + matchLabels: + app: prometheus + template: + metadata: + labels: + app: prometheus + chart: {{ template "prometheus.chart" . }} + heritage: {{ .Release.Service }} + release: {{ .Release.Name }} + annotations: + sidecar.istio.io/inject: "false" + spec: + serviceAccountName: prometheus +{{- if .Values.global.priorityClassName }} + priorityClassName: "{{ .Values.global.priorityClassName }}" +{{- end }} + containers: + - name: sidecar + {{- with .Values.stackdriversidecar }} + image: "{{ .hub }}/{{ .image }}:{{ .tag }}" + args: + - "--stackdriver.project-id={{ .gcp_project }}" + - "--prometheus.wal-directory=/data/wal" + - "--prometheus.api-address={{ .api_address }}" + - "--stackdriver.kubernetes.location={{ .gcp_region }}" + - "--stackdriver.kubernetes.cluster-name={{ .cluster_name }}" + {{- end }} + ports: + - name: sidecar + containerPort: 9091 + volumeMounts: + - name: data-volume + mountPath: /data + - name: prometheus + image: "{{ .Values.hub }}/{{ .Values.image }}:{{ .Values.tag }}" + imagePullPolicy: {{ .Values.global.imagePullPolicy }} + args: + - '--storage.tsdb.retention={{ .Values.retention }}' + - '--config.file=/etc/prometheus/prometheus.yml' + - '--storage.tsdb.path=/data' + ports: + - containerPort: 9090 + name: http + livenessProbe: + httpGet: + path: /-/healthy + port: 9090 + readinessProbe: + httpGet: + path: /-/ready + port: 9090 + resources: +{{- if .Values.resources }} +{{ toYaml .Values.resources | indent 12 }} +{{- else }} +{{ toYaml .Values.global.defaultResources | indent 12 }} +{{- end }} + volumeMounts: + -name: data-volume + mountPath: /data + - name: config-volume + mountPath: /etc/prometheus + - mountPath: /etc/istio-certs + name: istio-certs + volumes: + - name: data-volume + emptyDir: {} + - name: config-volume + configMap: + name: prometheus + - name: istio-certs + secret: + defaultMode: 420 +{{- if not .Values.security.enabled }} + optional: true +{{- end }} + secretName: istio.default + affinity: + {{- include "nodeaffinity" . | indent 6 }} + {{- include "podAntiAffinity" . | indent 6 }} + {{- if .Values.tolerations }} + tolerations: +{{ toYaml .Values.tolerations | indent 6 }} + {{- else if .Values.global.defaultTolerations }} + tolerations: +{{ toYaml .Values.global.defaultTolerations | indent 6 }} + {{- end }} diff --git a/istio-1.3.5/install/kubernetes/helm/istio/charts/prometheus/templates/deployment.yaml b/istio-1.3.5/install/kubernetes/helm/istio/charts/prometheus/templates/deployment.yaml new file mode 100644 index 0000000..64214e0 --- /dev/null +++ b/istio-1.3.5/install/kubernetes/helm/istio/charts/prometheus/templates/deployment.yaml @@ -0,0 +1,80 @@ +# TODO: the original template has service account, roles, etc +apiVersion: apps/v1 +kind: Deployment +metadata: + name: prometheus + namespace: {{ .Release.Namespace }} + labels: + app: prometheus + chart: {{ template "prometheus.chart" . }} + heritage: {{ .Release.Service }} + release: {{ .Release.Name }} +spec: + replicas: {{ .Values.replicaCount }} + selector: + matchLabels: + app: prometheus + template: + metadata: + labels: + app: prometheus + chart: {{ template "prometheus.chart" . }} + heritage: {{ .Release.Service }} + release: {{ .Release.Name }} + annotations: + sidecar.istio.io/inject: "false" + spec: + serviceAccountName: prometheus +{{- if .Values.global.priorityClassName }} + priorityClassName: "{{ .Values.global.priorityClassName }}" +{{- end }} + containers: + - name: prometheus + image: "{{ .Values.hub }}/{{ .Values.image }}:{{ .Values.tag }}" + imagePullPolicy: {{ .Values.global.imagePullPolicy }} + args: + - '--storage.tsdb.retention={{ .Values.retention }}' + - '--config.file=/etc/prometheus/prometheus.yml' + ports: + - containerPort: 9090 + name: http + livenessProbe: + httpGet: + path: /-/healthy + port: 9090 + readinessProbe: + httpGet: + path: /-/ready + port: 9090 + resources: +{{- if .Values.resources }} +{{ toYaml .Values.resources | indent 12 }} +{{- else }} +{{ toYaml .Values.global.defaultResources | indent 12 }} +{{- end }} + volumeMounts: + - name: config-volume + mountPath: /etc/prometheus + - mountPath: /etc/istio-certs + name: istio-certs + volumes: + - name: config-volume + configMap: + name: prometheus + - name: istio-certs + secret: + defaultMode: 420 +{{- if not .Values.security.enabled }} + optional: true +{{- end }} + secretName: istio.default + affinity: + {{- include "nodeaffinity" . | indent 6 }} + {{- include "podAntiAffinity" . | indent 6 }} + {{- if .Values.tolerations }} + tolerations: +{{ toYaml .Values.tolerations | indent 6 }} + {{- else if .Values.global.defaultTolerations }} + tolerations: +{{ toYaml .Values.global.defaultTolerations | indent 6 }} + {{- end }} diff --git a/istio-1.3.5/install/kubernetes/helm/istio/charts/prometheus/templates/ingress.yaml b/istio-1.3.5/install/kubernetes/helm/istio/charts/prometheus/templates/ingress.yaml new file mode 100644 index 0000000..43be655 --- /dev/null +++ b/istio-1.3.5/install/kubernetes/helm/istio/charts/prometheus/templates/ingress.yaml @@ -0,0 +1,40 @@ +{{- if .Values.ingress.enabled -}} +apiVersion: extensions/v1beta1 +kind: Ingress +metadata: + name: prometheus + namespace: {{ .Release.Namespace }} + labels: + app: prometheus + chart: {{ template "prometheus.chart" . }} + heritage: {{ .Release.Service }} + release: {{ .Release.Name }} + annotations: + {{- range $key, $value := .Values.ingress.annotations }} + {{ $key }}: {{ $value | quote }} + {{- end }} +spec: + rules: +{{- if .Values.ingress.hosts }} + {{- range $host := .Values.ingress.hosts }} + - host: {{ $host }} + http: + paths: + - path: {{ if $.Values.contextPath }} {{ $.Values.contextPath }} {{ else }} / {{ end }} + backend: + serviceName: prometheus + servicePort: 9090 + {{- end -}} +{{- else }} + - http: + paths: + - path: {{ if .Values.contextPath }} {{ .Values.contextPath }} {{ else }} / {{ end }} + backend: + serviceName: prometheus + servicePort: 9090 +{{- end }} + {{- if .Values.ingress.tls }} + tls: +{{ toYaml .Values.ingress.tls | indent 4 }} + {{- end -}} +{{- end -}} diff --git a/istio-1.3.5/install/kubernetes/helm/istio/charts/prometheus/templates/service.yaml b/istio-1.3.5/install/kubernetes/helm/istio/charts/prometheus/templates/service.yaml new file mode 100644 index 0000000..d92525d --- /dev/null +++ b/istio-1.3.5/install/kubernetes/helm/istio/charts/prometheus/templates/service.yaml @@ -0,0 +1,45 @@ +apiVersion: v1 +kind: Service +metadata: + name: prometheus + namespace: {{ .Release.Namespace }} + annotations: + prometheus.io/scrape: 'true' + {{- range $key, $val := .Values.service.annotations }} + {{ $key }}: {{ $val | quote }} + {{- end }} + labels: + app: prometheus + chart: {{ template "prometheus.chart" . }} + heritage: {{ .Release.Service }} + release: {{ .Release.Name }} +spec: + selector: + app: prometheus + ports: + - name: http-prometheus + protocol: TCP + port: 9090 + +{{- if .Values.service.nodePort.enabled }} +# Using separate ingress for nodeport, to avoid conflict with pilot e2e test configs. +--- +apiVersion: v1 +kind: Service +metadata: + name: prometheus-nodeport + namespace: {{ .Release.Namespace }} + labels: + app: prometheus + chart: {{ template "prometheus.chart" . }} + heritage: {{ .Release.Service }} + release: {{ .Release.Name }} +spec: + type: NodePort + ports: + - port: 9090 + nodePort: {{ .Values.service.nodePort.port }} + name: http-prometheus + selector: + app: prometheus +{{- end }} diff --git a/istio-1.3.5/install/kubernetes/helm/istio/charts/prometheus/templates/serviceaccount.yaml b/istio-1.3.5/install/kubernetes/helm/istio/charts/prometheus/templates/serviceaccount.yaml new file mode 100644 index 0000000..7c2fab3 --- /dev/null +++ b/istio-1.3.5/install/kubernetes/helm/istio/charts/prometheus/templates/serviceaccount.yaml @@ -0,0 +1,16 @@ +apiVersion: v1 +kind: ServiceAccount +{{- if .Values.global.imagePullSecrets }} +imagePullSecrets: +{{- range .Values.global.imagePullSecrets }} + - name: {{ . }} +{{- end }} +{{- end }} +metadata: + name: prometheus + namespace: {{ .Release.Namespace }} + labels: + app: prometheus + chart: {{ template "prometheus.chart" . }} + heritage: {{ .Release.Service }} + release: {{ .Release.Name }} diff --git a/istio-1.3.5/install/kubernetes/helm/istio/charts/prometheus/templates/tests/test-prometheus-connection.yaml b/istio-1.3.5/install/kubernetes/helm/istio/charts/prometheus/templates/tests/test-prometheus-connection.yaml new file mode 100644 index 0000000..45b025e --- /dev/null +++ b/istio-1.3.5/install/kubernetes/helm/istio/charts/prometheus/templates/tests/test-prometheus-connection.yaml @@ -0,0 +1,36 @@ +{{- if .Values.global.enableHelmTest }} +apiVersion: v1 +kind: Pod +metadata: + name: {{ template "prometheus.fullname" . }}-test + namespace: {{ .Release.Namespace }} + labels: + app: prometheus-test + chart: {{ template "prometheus.chart" . }} + release: {{ .Release.Name }} + heritage: {{ .Release.Service }} + istio: prometheus + annotations: + sidecar.istio.io/inject: "false" + helm.sh/hook: test-success +spec: +{{- if .Values.global.priorityClassName }} + priorityClassName: "{{ .Values.global.priorityClassName }}" +{{- end }} + containers: + - name: "{{ template "prometheus.fullname" . }}-test" + image: pstauffer/curl:v1.0.3 + imagePullPolicy: "{{ .Values.global.imagePullPolicy }}" + command: ['sh', '-c', 'for i in 1 2 3; do curl http://prometheus:9090/-/ready && exit 0 || sleep 15; done; exit 1'] + restartPolicy: Never + affinity: + {{- include "nodeaffinity" . | indent 4 }} + {{- include "podAntiAffinity" . | indent 4 }} + {{- if .Values.tolerations }} + tolerations: +{{ toYaml .Values.tolerations | indent 2 }} + {{- else if .Values.global.defaultTolerations }} + tolerations: +{{ toYaml .Values.global.defaultTolerations | indent 2 }} + {{- end }} +{{- end }} diff --git a/istio-1.3.5/install/kubernetes/helm/istio/charts/prometheus/values.yaml b/istio-1.3.5/install/kubernetes/helm/istio/charts/prometheus/values.yaml new file mode 100644 index 0000000..c16f99a --- /dev/null +++ b/istio-1.3.5/install/kubernetes/helm/istio/charts/prometheus/values.yaml @@ -0,0 +1,60 @@ +# +# addon prometheus configuration +# +enabled: true +replicaCount: 1 +hub: docker.io/prom +image: prometheus +tag: v2.8.0 +retention: 6h +nodeSelector: {} +tolerations: [] + +# Specify the pod anti-affinity that allows you to constrain which nodes +# your pod is eligible to be scheduled based on labels on pods that are +# already running on the node rather than based on labels on nodes. +# There are currently two types of anti-affinity: +# "requiredDuringSchedulingIgnoredDuringExecution" +# "preferredDuringSchedulingIgnoredDuringExecution" +# which denote "hard" vs. "soft" requirements, you can define your values +# in "podAntiAffinityLabelSelector" and "podAntiAffinityTermLabelSelector" +# correspondingly. +# For example: +# podAntiAffinityLabelSelector: +# - key: security +# operator: In +# values: S1,S2 +# topologyKey: "kubernetes.io/hostname" +# This pod anti-affinity rule says that the pod requires not to be scheduled +# onto a node if that node is already running a pod with label having key +# "security" and value "S1". +podAntiAffinityLabelSelector: [] +podAntiAffinityTermLabelSelector: [] + +# Controls the frequency of prometheus scraping +scrapeInterval: 15s + +contextPath: /prometheus + +ingress: + enabled: false + ## Used to create an Ingress record. + hosts: + - prometheus.local + annotations: + # kubernetes.io/ingress.class: nginx + # kubernetes.io/tls-acme: "true" + tls: + # Secrets must be manually created in the namespace. + # - secretName: prometheus-tls + # hosts: + # - prometheus.local + +service: + annotations: {} + nodePort: + enabled: false + port: 32090 + +security: + enabled: true diff --git a/istio-1.3.5/install/kubernetes/helm/istio/charts/security/Chart.yaml b/istio-1.3.5/install/kubernetes/helm/istio/charts/security/Chart.yaml new file mode 100644 index 0000000..8536a9c --- /dev/null +++ b/istio-1.3.5/install/kubernetes/helm/istio/charts/security/Chart.yaml @@ -0,0 +1,13 @@ +apiVersion: v1 +name: security +version: 1.3.5 +appVersion: 1.3.5 +tillerVersion: ">=2.7.2" +description: Helm chart for istio authentication +keywords: + - istio + - security +sources: + - http://github.com/istio/istio +engine: gotpl +icon: https://istio.io/favicons/android-192x192.png diff --git a/istio-1.3.5/install/kubernetes/helm/istio/charts/security/templates/_helpers.tpl b/istio-1.3.5/install/kubernetes/helm/istio/charts/security/templates/_helpers.tpl new file mode 100644 index 0000000..7f36f9d --- /dev/null +++ b/istio-1.3.5/install/kubernetes/helm/istio/charts/security/templates/_helpers.tpl @@ -0,0 +1,32 @@ +{{/* vim: set filetype=mustache: */}} +{{/* +Expand the name of the chart. +*/}} +{{- define "security.name" -}} +{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" -}} +{{- end -}} + +{{/* +Create a default fully qualified app name. +We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). +If release name contains chart name it will be used as a full name. +*/}} +{{- define "security.fullname" -}} +{{- if .Values.fullnameOverride -}} +{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" -}} +{{- else -}} +{{- $name := default .Chart.Name .Values.nameOverride -}} +{{- if contains $name .Release.Name -}} +{{- .Release.Name | trunc 63 | trimSuffix "-" -}} +{{- else -}} +{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" -}} +{{- end -}} +{{- end -}} +{{- end -}} + +{{/* +Create chart name and version as used by the chart label. +*/}} +{{- define "security.chart" -}} +{{- .Chart.Name | trunc 63 | trimSuffix "-" -}} +{{- end -}} diff --git a/istio-1.3.5/install/kubernetes/helm/istio/charts/security/templates/clusterrole.yaml b/istio-1.3.5/install/kubernetes/helm/istio/charts/security/templates/clusterrole.yaml new file mode 100644 index 0000000..75f2dec --- /dev/null +++ b/istio-1.3.5/install/kubernetes/helm/istio/charts/security/templates/clusterrole.yaml @@ -0,0 +1,22 @@ +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: istio-citadel-{{ .Release.Namespace }} + labels: + app: {{ template "security.name" . }} + chart: {{ template "security.chart" . }} + heritage: {{ .Release.Service }} + release: {{ .Release.Name }} +rules: +- apiGroups: [""] + resources: ["configmaps"] + verbs: ["create", "get", "update"] +- apiGroups: [""] + resources: ["secrets"] + verbs: ["create", "get", "watch", "list", "update", "delete"] +- apiGroups: [""] + resources: ["serviceaccounts", "services", "namespaces"] + verbs: ["get", "watch", "list"] +- apiGroups: ["authentication.k8s.io"] + resources: ["tokenreviews"] + verbs: ["create"] diff --git a/istio-1.3.5/install/kubernetes/helm/istio/charts/security/templates/clusterrolebinding.yaml b/istio-1.3.5/install/kubernetes/helm/istio/charts/security/templates/clusterrolebinding.yaml new file mode 100644 index 0000000..0a15799 --- /dev/null +++ b/istio-1.3.5/install/kubernetes/helm/istio/charts/security/templates/clusterrolebinding.yaml @@ -0,0 +1,17 @@ +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: istio-citadel-{{ .Release.Namespace }} + labels: + app: {{ template "security.name" . }} + chart: {{ template "security.chart" . }} + heritage: {{ .Release.Service }} + release: {{ .Release.Name }} +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: istio-citadel-{{ .Release.Namespace }} +subjects: + - kind: ServiceAccount + name: istio-citadel-service-account + namespace: {{ .Release.Namespace }} diff --git a/istio-1.3.5/install/kubernetes/helm/istio/charts/security/templates/configmap.yaml b/istio-1.3.5/install/kubernetes/helm/istio/charts/security/templates/configmap.yaml new file mode 100644 index 0000000..14749fd --- /dev/null +++ b/istio-1.3.5/install/kubernetes/helm/istio/charts/security/templates/configmap.yaml @@ -0,0 +1,20 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: istio-security-custom-resources + namespace: {{ .Release.Namespace }} + labels: + app: {{ template "security.name" . }} + chart: {{ template "security.chart" . }} + heritage: {{ .Release.Service }} + release: {{ .Release.Name }} + istio: citadel +data: + custom-resources.yaml: |- + {{- if .Values.global.mtls.enabled }} + {{- include "security-default.yaml.tpl" . | indent 4}} + {{- else }} + {{- include "security-permissive.yaml.tpl" . | indent 4}} + {{- end }} + run.sh: |- + {{- include "install-custom-resources.sh.tpl" . | indent 4}} diff --git a/istio-1.3.5/install/kubernetes/helm/istio/charts/security/templates/create-custom-resources-job.yaml b/istio-1.3.5/install/kubernetes/helm/istio/charts/security/templates/create-custom-resources-job.yaml new file mode 100644 index 0000000..dc0a6c5 --- /dev/null +++ b/istio-1.3.5/install/kubernetes/helm/istio/charts/security/templates/create-custom-resources-job.yaml @@ -0,0 +1,107 @@ +{{- if .Values.createMeshPolicy }} +apiVersion: v1 +kind: ServiceAccount +{{- if .Values.global.imagePullSecrets }} +imagePullSecrets: +{{- range .Values.global.imagePullSecrets }} + - name: {{ . }} +{{- end }} +{{- end }} +metadata: + name: istio-security-post-install-account + namespace: {{ .Release.Namespace }} + labels: + app: {{ template "security.name" . }} + chart: {{ template "security.chart" . }} + heritage: {{ .Release.Service }} + release: {{ .Release.Name }} +--- +apiVersion: rbac.authorization.k8s.io/v1beta1 +kind: ClusterRole +metadata: + name: istio-security-post-install-{{ .Release.Namespace }} + labels: + app: {{ template "security.name" . }} + chart: {{ template "security.chart" . }} + heritage: {{ .Release.Service }} + release: {{ .Release.Name }} +rules: +- apiGroups: ["authentication.istio.io"] # needed to create default authn policy + resources: ["*"] + verbs: ["*"] +- apiGroups: ["networking.istio.io"] # needed to create security destination rules + resources: ["*"] + verbs: ["*"] +- apiGroups: ["admissionregistration.k8s.io"] + resources: ["validatingwebhookconfigurations"] + verbs: ["get"] +- apiGroups: ["extensions", "apps"] + resources: ["deployments", "replicasets"] + verbs: ["get", "list", "watch"] +--- +apiVersion: rbac.authorization.k8s.io/v1beta1 +kind: ClusterRoleBinding +metadata: + name: istio-security-post-install-role-binding-{{ .Release.Namespace }} + labels: + app: {{ template "security.name" . }} + chart: {{ template "security.chart" . }} + heritage: {{ .Release.Service }} + release: {{ .Release.Name }} +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: istio-security-post-install-{{ .Release.Namespace }} +subjects: + - kind: ServiceAccount + name: istio-security-post-install-account + namespace: {{ .Release.Namespace }} +--- +apiVersion: batch/v1 +kind: Job +metadata: + name: istio-security-post-install-{{ .Values.global.tag | printf "%v" | trunc 32 }} + namespace: {{ .Release.Namespace }} + annotations: + "helm.sh/hook": post-install,post-upgrade + "helm.sh/hook-delete-policy": hook-succeeded + labels: + app: {{ template "security.name" . }} + chart: {{ template "security.chart" . }} + heritage: {{ .Release.Service }} + release: {{ .Release.Name }} +spec: + template: + metadata: + name: istio-security-post-install + labels: + app: {{ template "security.name" . }} + chart: {{ template "security.chart" . }} + heritage: {{ .Release.Service }} + release: {{ .Release.Name }} + spec: + serviceAccountName: istio-security-post-install-account + containers: + - name: kubectl + image: "{{ .Values.global.hub }}/kubectl:{{ .Values.global.tag }}" + imagePullPolicy: IfNotPresent + command: [ "/bin/bash", "/tmp/security/run.sh", "/tmp/security/custom-resources.yaml" ] + volumeMounts: + - mountPath: "/tmp/security" + name: tmp-configmap-security + volumes: + - name: tmp-configmap-security + configMap: + name: istio-security-custom-resources + restartPolicy: OnFailure + affinity: + {{- include "nodeaffinity" . | indent 6 }} + {{- include "podAntiAffinity" . | indent 6 }} + {{- if .Values.tolerations }} + tolerations: +{{ toYaml .Values.tolerations | indent 6 }} + {{- else if .Values.global.defaultTolerations }} + tolerations: +{{ toYaml .Values.global.defaultTolerations | indent 6 }} + {{- end }} +{{- end }} diff --git a/istio-1.3.5/install/kubernetes/helm/istio/charts/security/templates/deployment.yaml b/istio-1.3.5/install/kubernetes/helm/istio/charts/security/templates/deployment.yaml new file mode 100644 index 0000000..424bb89 --- /dev/null +++ b/istio-1.3.5/install/kubernetes/helm/istio/charts/security/templates/deployment.yaml @@ -0,0 +1,120 @@ +# istio CA watching all namespaces +apiVersion: apps/v1 +kind: Deployment +metadata: + name: istio-citadel + namespace: {{ .Release.Namespace }} + labels: + app: {{ template "security.name" . }} + chart: {{ template "security.chart" . }} + heritage: {{ .Release.Service }} + release: {{ .Release.Name }} + istio: citadel +spec: + replicas: {{ .Values.replicaCount }} + selector: + matchLabels: + istio: citadel + strategy: + rollingUpdate: + maxSurge: {{ .Values.rollingMaxSurge }} + maxUnavailable: {{ .Values.rollingMaxUnavailable }} + template: + metadata: + labels: + app: {{ template "security.name" . }} + chart: {{ template "security.chart" . }} + heritage: {{ .Release.Service }} + release: {{ .Release.Name }} + istio: citadel + annotations: + sidecar.istio.io/inject: "false" + spec: + serviceAccountName: istio-citadel-service-account +{{- if .Values.global.priorityClassName }} + priorityClassName: "{{ .Values.global.priorityClassName }}" +{{- end }} + containers: + - name: citadel +{{- if contains "/" .Values.image }} + image: "{{ .Values.image }}" +{{- else }} + image: "{{ .Values.global.hub }}/{{ .Values.image }}:{{ .Values.global.tag }}" +{{- end }} + imagePullPolicy: {{ .Values.global.imagePullPolicy }} + args: + {{- if .Values.global.sds.enabled }} + - --sds-enabled=true + {{- end }} + - --append-dns-names=true + - --grpc-port=8060 + - --citadel-storage-namespace={{ .Release.Namespace }} + - --custom-dns-names=istio-pilot-service-account.{{ .Release.Namespace }}:istio-pilot.{{ .Release.Namespace }} + - --monitoring-port={{ .Values.global.monitoringPort }} + {{- if .Values.selfSigned }} + - --self-signed-ca=true + {{- else }} + - --self-signed-ca=false + - --signing-cert=/etc/cacerts/ca-cert.pem + - --signing-key=/etc/cacerts/ca-key.pem + - --root-cert=/etc/cacerts/root-cert.pem + - --cert-chain=/etc/cacerts/cert-chain.pem + {{- end }} + {{- if .Values.global.trustDomain }} + - --trust-domain={{ .Values.global.trustDomain }} + {{- end }} + {{- if .Values.workloadCertTtl }} + - --workload-cert-ttl={{ .Values.workloadCertTtl }} + {{- end }} + {{- if .Values.citadelHealthCheck }} + - --liveness-probe-path=/tmp/ca.liveness # path to the liveness health check status file + - --liveness-probe-interval=60s # interval for health check file update + - --probe-check-interval=15s # interval for health status check + {{- end }} + env: + - name: CITADEL_ENABLE_NAMESPACES_BY_DEFAULT + value: "{{ .Values.enableNamespacesByDefault }}" + {{- if .Values.env }} + {{- range $key, $val := .Values.env }} + - name: {{ $key }} + value: {{ $val | quote }} + {{- end }} + {{- end }} + {{- if .Values.citadelHealthCheck }} + livenessProbe: + exec: + command: + - /usr/local/bin/istio_ca + - probe + - --probe-path=/tmp/ca.liveness # path to the liveness health check status file + - --interval=125s # the maximum time gap allowed between the file mtime and the current sys clock + initialDelaySeconds: 60 + periodSeconds: 60 + {{- end }} + resources: +{{- if .Values.resources }} +{{ toYaml .Values.resources | indent 12 }} +{{- else }} +{{ toYaml .Values.global.defaultResources | indent 12 }} +{{- end }} +{{- if not .Values.selfSigned }} + volumeMounts: + - name: cacerts + mountPath: /etc/cacerts + readOnly: true + volumes: + - name: cacerts + secret: + secretName: cacerts + optional: true +{{- end }} + affinity: + {{- include "nodeaffinity" . | indent 6 }} + {{- include "podAntiAffinity" . | indent 6 }} + {{- if .Values.tolerations }} + tolerations: +{{ toYaml .Values.tolerations | indent 6 }} + {{- else if .Values.global.defaultTolerations }} + tolerations: +{{ toYaml .Values.global.defaultTolerations | indent 6 }} + {{- end }} diff --git a/istio-1.3.5/install/kubernetes/helm/istio/charts/security/templates/enable-mesh-mtls.yaml b/istio-1.3.5/install/kubernetes/helm/istio/charts/security/templates/enable-mesh-mtls.yaml new file mode 100644 index 0000000..75e4a18 --- /dev/null +++ b/istio-1.3.5/install/kubernetes/helm/istio/charts/security/templates/enable-mesh-mtls.yaml @@ -0,0 +1,63 @@ +{{- define "security-default.yaml.tpl" }} +# These policy and destination rules effectively enable mTLS for all services in the mesh. For now, +# they are added to Istio installation yaml for backward compatible. In future, they should be in +# a separated yaml file so that customer can enable mTLS independent from installation. + +# Authentication policy to enable mutual TLS for all services (that have sidecar) in the mesh. +apiVersion: "authentication.istio.io/v1alpha1" +kind: "MeshPolicy" +metadata: + name: "default" + labels: + app: {{ template "security.name" . }} + chart: {{ template "security.chart" . }} + heritage: {{ .Release.Service }} + release: {{ .Release.Name }} +spec: + peers: + - mtls: {} +--- +# Corresponding destination rule to configure client side to use mutual TLS when talking to +# any service (host) in the mesh. +apiVersion: networking.istio.io/v1alpha3 +kind: DestinationRule +metadata: + name: "default" + namespace: {{ .Release.Namespace }} + labels: + app: {{ template "security.name" . }} + chart: {{ template "security.chart" . }} + heritage: {{ .Release.Service }} + release: {{ .Release.Name }} +spec: + host: "*.local" + {{- if .Values.global.defaultConfigVisibilitySettings }} + exportTo: + - '*' + {{- end }} + trafficPolicy: + tls: + mode: ISTIO_MUTUAL +--- +# Destination rule to disable (m)TLS when talking to API server, as API server doesn't have sidecar. +# Customer should add similar destination rules for other services that don't have sidecar. +apiVersion: networking.istio.io/v1alpha3 +kind: DestinationRule +metadata: + name: "api-server" + namespace: {{ .Release.Namespace }} + labels: + app: {{ template "security.name" . }} + chart: {{ template "security.chart" . }} + heritage: {{ .Release.Service }} + release: {{ .Release.Name }} +spec: + host: "kubernetes.default.svc.{{ .Values.global.proxy.clusterDomain }}" + {{- if .Values.global.defaultConfigVisibilitySettings }} + exportTo: + - '*' + {{- end }} + trafficPolicy: + tls: + mode: DISABLE +{{- end }} diff --git a/istio-1.3.5/install/kubernetes/helm/istio/charts/security/templates/enable-mesh-permissive.yaml b/istio-1.3.5/install/kubernetes/helm/istio/charts/security/templates/enable-mesh-permissive.yaml new file mode 100644 index 0000000..a6931b3 --- /dev/null +++ b/istio-1.3.5/install/kubernetes/helm/istio/charts/security/templates/enable-mesh-permissive.yaml @@ -0,0 +1,16 @@ +{{- define "security-permissive.yaml.tpl" }} +# Authentication policy to enable permissive mode for all services (that have sidecar) in the mesh. +apiVersion: "authentication.istio.io/v1alpha1" +kind: "MeshPolicy" +metadata: + name: "default" + labels: + app: {{ template "security.name" . }} + chart: {{ template "security.chart" . }} + heritage: {{ .Release.Service }} + release: {{ .Release.Name }} +spec: + peers: + - mtls: + mode: PERMISSIVE +{{- end }} diff --git a/istio-1.3.5/install/kubernetes/helm/istio/charts/security/templates/meshexpansion.yaml b/istio-1.3.5/install/kubernetes/helm/istio/charts/security/templates/meshexpansion.yaml new file mode 100644 index 0000000..581ce96 --- /dev/null +++ b/istio-1.3.5/install/kubernetes/helm/istio/charts/security/templates/meshexpansion.yaml @@ -0,0 +1,56 @@ +{{- if .Values.global.meshExpansion.enabled }} +{{- if .Values.global.meshExpansion.useILB }} +apiVersion: networking.istio.io/v1alpha3 +kind: VirtualService +metadata: + name: meshexpansion-vs-citadel-ilb + namespace: {{ .Release.Namespace }} + labels: + app: {{ template "security.name" . }} + chart: {{ template "security.chart" . }} + heritage: {{ .Release.Service }} + release: {{ .Release.Name }} + istio: citadel +spec: + hosts: + - istio-citadel.{{ .Release.Namespace }}.svc.{{ .Values.global.proxy.clusterDomain }} + gateways: + - meshexpansion-ilb-gateway + tcp: + - match: + - port: 8060 + route: + - destination: + host: istio-citadel.{{ .Release.Namespace }}.svc.{{ .Values.global.proxy.clusterDomain }} + port: + number: 8060 +--- +{{- else }} + +apiVersion: networking.istio.io/v1alpha3 +kind: VirtualService +metadata: + name: meshexpansion-vs-citadel + namespace: {{ .Release.Namespace }} + labels: + app: {{ template "security.name" . }} + chart: {{ template "security.chart" . }} + heritage: {{ .Release.Service }} + release: {{ .Release.Name }} + istio: citadel +spec: + hosts: + - istio-citadel.{{ .Release.Namespace }}.svc.{{ .Values.global.proxy.clusterDomain }} + gateways: + - meshexpansion-gateway + tcp: + - match: + - port: 8060 + route: + - destination: + host: istio-citadel.{{ .Release.Namespace }}.svc.{{ .Values.global.proxy.clusterDomain }} + port: + number: 8060 +--- +{{- end }} +{{- end }} diff --git a/istio-1.3.5/install/kubernetes/helm/istio/charts/security/templates/service.yaml b/istio-1.3.5/install/kubernetes/helm/istio/charts/security/templates/service.yaml new file mode 100644 index 0000000..efea175 --- /dev/null +++ b/istio-1.3.5/install/kubernetes/helm/istio/charts/security/templates/service.yaml @@ -0,0 +1,23 @@ +apiVersion: v1 +kind: Service +metadata: + # we use the normal name here (e.g. 'prometheus') + # as grafana is configured to use this as a data source + name: istio-citadel + namespace: {{ .Release.Namespace }} + labels: + app: {{ template "security.name" . }} + chart: {{ template "security.chart" . }} + heritage: {{ .Release.Service }} + release: {{ .Release.Name }} + istio: citadel +spec: + ports: + - name: grpc-citadel + port: 8060 + targetPort: 8060 + protocol: TCP + - name: http-monitoring + port: {{ .Values.global.monitoringPort }} + selector: + istio: citadel diff --git a/istio-1.3.5/install/kubernetes/helm/istio/charts/security/templates/serviceaccount.yaml b/istio-1.3.5/install/kubernetes/helm/istio/charts/security/templates/serviceaccount.yaml new file mode 100644 index 0000000..d07d566 --- /dev/null +++ b/istio-1.3.5/install/kubernetes/helm/istio/charts/security/templates/serviceaccount.yaml @@ -0,0 +1,16 @@ +apiVersion: v1 +kind: ServiceAccount +{{- if .Values.global.imagePullSecrets }} +imagePullSecrets: +{{- range .Values.global.imagePullSecrets }} + - name: {{ . }} +{{- end }} +{{- end }} +metadata: + name: istio-citadel-service-account + namespace: {{ .Release.Namespace }} + labels: + app: {{ template "security.name" . }} + chart: {{ template "security.chart" . }} + heritage: {{ .Release.Service }} + release: {{ .Release.Name }} diff --git a/istio-1.3.5/install/kubernetes/helm/istio/charts/security/templates/tests/test-citadel-connection.yaml b/istio-1.3.5/install/kubernetes/helm/istio/charts/security/templates/tests/test-citadel-connection.yaml new file mode 100644 index 0000000..6fc742a --- /dev/null +++ b/istio-1.3.5/install/kubernetes/helm/istio/charts/security/templates/tests/test-citadel-connection.yaml @@ -0,0 +1,36 @@ +{{- if .Values.global.enableHelmTest }} +apiVersion: v1 +kind: Pod +metadata: + name: {{ template "security.fullname" . }}-test + namespace: {{ .Release.Namespace }} + labels: + app: istio-citadel-test + chart: {{ template "security.chart" . }} + release: {{ .Release.Name }} + heritage: {{ .Release.Service }} + istio: citadel + annotations: + sidecar.istio.io/inject: "false" + helm.sh/hook: test-success +spec: +{{- if .Values.global.priorityClassName }} + priorityClassName: "{{ .Values.global.priorityClassName }}" +{{- end }} + containers: + - name: "{{ template "security.fullname" . }}-test" + image: pstauffer/curl:v1.0.3 + imagePullPolicy: "{{ .Values.global.imagePullPolicy }}" + command: ['sh', '-c', 'for i in 1 2 3; do curl http://istio-citadel:{{ .Values.global.monitoringPort }}/version && exit 0 || sleep 15; done; exit 1'] + restartPolicy: Never + affinity: + {{- include "nodeaffinity" . | indent 4 }} + {{- include "podAntiAffinity" . | indent 4 }} + {{- if .Values.tolerations }} + tolerations: +{{ toYaml .Values.tolerations | indent 2 }} + {{- else if .Values.global.defaultTolerations }} + tolerations: +{{ toYaml .Values.global.defaultTolerations | indent 2 }} + {{- end }} +{{- end }} diff --git a/istio-1.3.5/install/kubernetes/helm/istio/charts/security/values.yaml b/istio-1.3.5/install/kubernetes/helm/istio/charts/security/values.yaml new file mode 100644 index 0000000..b99bd29 --- /dev/null +++ b/istio-1.3.5/install/kubernetes/helm/istio/charts/security/values.yaml @@ -0,0 +1,50 @@ +# +# security configuration +# +enabled: true +replicaCount: 1 +rollingMaxSurge: 100% +rollingMaxUnavailable: 25% +image: citadel +selfSigned: true # indicate if self-signed CA is used. +createMeshPolicy: true +nodeSelector: {} +tolerations: [] +# Enable health checking on the Citadel CSR signing API. +# https://istio.io/docs/tasks/security/health-check/ +citadelHealthCheck: false +# 90*24hour = 2160h +workloadCertTtl: 2160h +# Environment variables that configure Citadel. +env: {} + +# Determines Citadel default behavior if the ca.istio.io/env or ca.istio.io/override +# labels are not found on a given namespace. +# +# For example: consider a namespace called "target", which has neither the "ca.istio.io/env" +# nor the "ca.istio.io/override" namespace labels. To decide whether or not to generate secrets +# for service accounts created in this "target" namespace, Citadel will defer to this option. If the value +# of this option is "true" in this case, secrets will be generated for the "target" namespace. +# If the value of this option is "false" Citadel will not generate secrets upon service account creation. +enableNamespacesByDefault: true + +# Specify the pod anti-affinity that allows you to constrain which nodes +# your pod is eligible to be scheduled based on labels on pods that are +# already running on the node rather than based on labels on nodes. +# There are currently two types of anti-affinity: +# "requiredDuringSchedulingIgnoredDuringExecution" +# "preferredDuringSchedulingIgnoredDuringExecution" +# which denote "hard" vs. "soft" requirements, you can define your values +# in "podAntiAffinityLabelSelector" and "podAntiAffinityTermLabelSelector" +# correspondingly. +# For example: +# podAntiAffinityLabelSelector: +# - key: security +# operator: In +# values: S1,S2 +# topologyKey: "kubernetes.io/hostname" +# This pod anti-affinity rule says that the pod requires not to be scheduled +# onto a node if that node is already running a pod with label having key +# "security" and value "S1". +podAntiAffinityLabelSelector: [] +podAntiAffinityTermLabelSelector: [] diff --git a/istio-1.3.5/install/kubernetes/helm/istio/charts/sidecarInjectorWebhook/Chart.yaml b/istio-1.3.5/install/kubernetes/helm/istio/charts/sidecarInjectorWebhook/Chart.yaml new file mode 100644 index 0000000..305aeae --- /dev/null +++ b/istio-1.3.5/install/kubernetes/helm/istio/charts/sidecarInjectorWebhook/Chart.yaml @@ -0,0 +1,13 @@ +apiVersion: v1 +name: sidecarInjectorWebhook +version: 1.3.5 +appVersion: 1.3.5 +tillerVersion: ">=2.7.2" +description: Helm chart for sidecar injector webhook deployment +keywords: + - istio + - sidecarInjectorWebhook +sources: + - http://github.com/istio/istio +engine: gotpl +icon: https://istio.io/favicons/android-192x192.png diff --git a/istio-1.3.5/install/kubernetes/helm/istio/charts/sidecarInjectorWebhook/templates/_helpers.tpl b/istio-1.3.5/install/kubernetes/helm/istio/charts/sidecarInjectorWebhook/templates/_helpers.tpl new file mode 100644 index 0000000..f3b9fb1 --- /dev/null +++ b/istio-1.3.5/install/kubernetes/helm/istio/charts/sidecarInjectorWebhook/templates/_helpers.tpl @@ -0,0 +1,32 @@ +{{/* vim: set filetype=mustache: */}} +{{/* +Expand the name of the chart. +*/}} +{{- define "sidecar-injector.name" -}} +{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" -}} +{{- end -}} + +{{/* +Create a default fully qualified app name. +We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). +If release name contains chart name it will be used as a full name. +*/}} +{{- define "sidecar-injector.fullname" -}} +{{- if .Values.fullnameOverride -}} +{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" -}} +{{- else -}} +{{- $name := default .Chart.Name .Values.nameOverride -}} +{{- if contains $name .Release.Name -}} +{{- .Release.Name | trunc 63 | trimSuffix "-" -}} +{{- else -}} +{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" -}} +{{- end -}} +{{- end -}} +{{- end -}} + +{{/* +Create chart name and version as used by the chart label. +*/}} +{{- define "sidecar-injector.chart" -}} +{{- .Chart.Name | trunc 63 | trimSuffix "-" -}} +{{- end -}} diff --git a/istio-1.3.5/install/kubernetes/helm/istio/charts/sidecarInjectorWebhook/templates/clusterrole.yaml b/istio-1.3.5/install/kubernetes/helm/istio/charts/sidecarInjectorWebhook/templates/clusterrole.yaml new file mode 100644 index 0000000..27f9acb --- /dev/null +++ b/istio-1.3.5/install/kubernetes/helm/istio/charts/sidecarInjectorWebhook/templates/clusterrole.yaml @@ -0,0 +1,17 @@ +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: istio-sidecar-injector-{{ .Release.Namespace }} + labels: + app: {{ template "sidecar-injector.name" . }} + chart: {{ template "sidecar-injector.chart" . }} + heritage: {{ .Release.Service }} + release: {{ .Release.Name }} + istio: sidecar-injector +rules: +- apiGroups: [""] + resources: ["configmaps"] + verbs: ["get", "list", "watch"] +- apiGroups: ["admissionregistration.k8s.io"] + resources: ["mutatingwebhookconfigurations"] + verbs: ["get", "list", "watch", "patch"] diff --git a/istio-1.3.5/install/kubernetes/helm/istio/charts/sidecarInjectorWebhook/templates/clusterrolebinding.yaml b/istio-1.3.5/install/kubernetes/helm/istio/charts/sidecarInjectorWebhook/templates/clusterrolebinding.yaml new file mode 100644 index 0000000..748a932 --- /dev/null +++ b/istio-1.3.5/install/kubernetes/helm/istio/charts/sidecarInjectorWebhook/templates/clusterrolebinding.yaml @@ -0,0 +1,18 @@ +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: istio-sidecar-injector-admin-role-binding-{{ .Release.Namespace }} + labels: + app: {{ template "sidecar-injector.name" . }} + chart: {{ template "sidecar-injector.chart" . }} + heritage: {{ .Release.Service }} + release: {{ .Release.Name }} + istio: sidecar-injector +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: istio-sidecar-injector-{{ .Release.Namespace }} +subjects: + - kind: ServiceAccount + name: istio-sidecar-injector-service-account + namespace: {{ .Release.Namespace }} diff --git a/istio-1.3.5/install/kubernetes/helm/istio/charts/sidecarInjectorWebhook/templates/deployment.yaml b/istio-1.3.5/install/kubernetes/helm/istio/charts/sidecarInjectorWebhook/templates/deployment.yaml new file mode 100644 index 0000000..abbb93d --- /dev/null +++ b/istio-1.3.5/install/kubernetes/helm/istio/charts/sidecarInjectorWebhook/templates/deployment.yaml @@ -0,0 +1,110 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: istio-sidecar-injector + namespace: {{ .Release.Namespace }} + labels: + app: {{ template "sidecar-injector.name" . }} + chart: {{ template "sidecar-injector.chart" . }} + heritage: {{ .Release.Service }} + release: {{ .Release.Name }} + istio: sidecar-injector +spec: + replicas: {{ .Values.replicaCount }} + selector: + matchLabels: + istio: sidecar-injector + strategy: + rollingUpdate: + maxSurge: {{ .Values.rollingMaxSurge }} + maxUnavailable: {{ .Values.rollingMaxUnavailable }} + template: + metadata: + labels: + app: {{ template "sidecar-injector.name" . }} + chart: {{ template "sidecar-injector.chart" . }} + heritage: {{ .Release.Service }} + release: {{ .Release.Name }} + istio: sidecar-injector + annotations: + sidecar.istio.io/inject: "false" + spec: + serviceAccountName: istio-sidecar-injector-service-account +{{- if .Values.global.priorityClassName }} + priorityClassName: "{{ .Values.global.priorityClassName }}" +{{- end }} + containers: + - name: sidecar-injector-webhook +{{- if contains "/" .Values.image }} + image: "{{ .Values.image }}" +{{- else }} + image: "{{ .Values.global.hub }}/{{ .Values.image }}:{{ .Values.global.tag }}" +{{- end }} + imagePullPolicy: {{ .Values.global.imagePullPolicy }} + args: + - --caCertFile=/etc/istio/certs/root-cert.pem + - --tlsCertFile=/etc/istio/certs/cert-chain.pem + - --tlsKeyFile=/etc/istio/certs/key.pem + - --injectConfig=/etc/istio/inject/config + - --meshConfig=/etc/istio/config/mesh + - --healthCheckInterval=2s + - --healthCheckFile=/health + volumeMounts: + - name: config-volume + mountPath: /etc/istio/config + readOnly: true + - name: certs + mountPath: /etc/istio/certs + readOnly: true + - name: inject-config + mountPath: /etc/istio/inject + readOnly: true + livenessProbe: + exec: + command: + - /usr/local/bin/sidecar-injector + - probe + - --probe-path=/health + - --interval=4s + initialDelaySeconds: 4 + periodSeconds: 4 + readinessProbe: + exec: + command: + - /usr/local/bin/sidecar-injector + - probe + - --probe-path=/health + - --interval=4s + initialDelaySeconds: 4 + periodSeconds: 4 + resources: +{{- if .Values.resources }} +{{ toYaml .Values.resources | indent 12 }} +{{- else }} +{{ toYaml .Values.global.defaultResources | indent 12 }} +{{- end }} + volumes: + - name: config-volume + configMap: + name: istio + - name: certs + secret: + secretName: istio.istio-sidecar-injector-service-account + - name: inject-config + configMap: + name: istio-sidecar-injector + items: + - key: config + path: config + - key: values + path: values + affinity: + {{- include "nodeaffinity" . | indent 6 }} + {{- include "podAntiAffinity" . | indent 6 }} + {{- if .Values.tolerations }} + tolerations: +{{ toYaml .Values.tolerations | indent 6 }} + {{- else if .Values.global.defaultTolerations }} + tolerations: +{{ toYaml .Values.global.defaultTolerations | indent 6 }} + {{- end }} diff --git a/istio-1.3.5/install/kubernetes/helm/istio/charts/sidecarInjectorWebhook/templates/mutatingwebhook.yaml b/istio-1.3.5/install/kubernetes/helm/istio/charts/sidecarInjectorWebhook/templates/mutatingwebhook.yaml new file mode 100644 index 0000000..a30dd38 --- /dev/null +++ b/istio-1.3.5/install/kubernetes/helm/istio/charts/sidecarInjectorWebhook/templates/mutatingwebhook.yaml @@ -0,0 +1,39 @@ +apiVersion: admissionregistration.k8s.io/v1beta1 +kind: MutatingWebhookConfiguration +metadata: + name: istio-sidecar-injector + labels: + app: {{ template "sidecar-injector.name" . }} + chart: {{ template "sidecar-injector.chart" . }} + heritage: {{ .Release.Service }} + release: {{ .Release.Name }} +webhooks: + - name: sidecar-injector.istio.io + clientConfig: + service: + name: istio-sidecar-injector + namespace: {{ .Release.Namespace }} + path: "/inject" + caBundle: "" + rules: + - operations: [ "CREATE" ] + apiGroups: [""] + apiVersions: ["v1"] + resources: ["pods"] + failurePolicy: Fail + namespaceSelector: +{{- if .Values.enableNamespacesByDefault }} + matchExpressions: + - key: name + operator: NotIn + values: + - {{ .Release.Namespace }} + - key: istio-injection + operator: NotIn + values: + - disabled +{{- else }} + matchLabels: + istio-injection: enabled +{{- end }} + diff --git a/istio-1.3.5/install/kubernetes/helm/istio/charts/sidecarInjectorWebhook/templates/poddisruptionbudget.yaml b/istio-1.3.5/install/kubernetes/helm/istio/charts/sidecarInjectorWebhook/templates/poddisruptionbudget.yaml new file mode 100644 index 0000000..51fb3fc --- /dev/null +++ b/istio-1.3.5/install/kubernetes/helm/istio/charts/sidecarInjectorWebhook/templates/poddisruptionbudget.yaml @@ -0,0 +1,18 @@ +{{- if .Values.global.defaultPodDisruptionBudget.enabled }} +apiVersion: policy/v1beta1 +kind: PodDisruptionBudget +metadata: + name: istio-sidecar-injector + namespace: {{ .Release.Namespace }} + labels: + app: {{ template "sidecar-injector.name" . }} + release: {{ .Release.Name }} + istio: sidecar-injector +spec: +{{ include "podDisruptionBudget.spec" .Values.global.defaultPodDisruptionBudget }} + selector: + matchLabels: + app: {{ template "sidecar-injector.name" . }} + release: {{ .Release.Name }} + istio: sidecar-injector + {{- end }} \ No newline at end of file diff --git a/istio-1.3.5/install/kubernetes/helm/istio/charts/sidecarInjectorWebhook/templates/service.yaml b/istio-1.3.5/install/kubernetes/helm/istio/charts/sidecarInjectorWebhook/templates/service.yaml new file mode 100644 index 0000000..537e6f9 --- /dev/null +++ b/istio-1.3.5/install/kubernetes/helm/istio/charts/sidecarInjectorWebhook/templates/service.yaml @@ -0,0 +1,19 @@ +apiVersion: v1 +kind: Service +metadata: + name: istio-sidecar-injector + namespace: {{ .Release.Namespace }} + labels: + app: {{ template "sidecar-injector.name" . }} + chart: {{ template "sidecar-injector.chart" . }} + heritage: {{ .Release.Service }} + release: {{ .Release.Name }} + istio: sidecar-injector +spec: + ports: + - port: 443 + name: https-inject + - port: {{ .Values.global.monitoringPort }} + name: http-monitoring + selector: + istio: sidecar-injector diff --git a/istio-1.3.5/install/kubernetes/helm/istio/charts/sidecarInjectorWebhook/templates/serviceaccount.yaml b/istio-1.3.5/install/kubernetes/helm/istio/charts/sidecarInjectorWebhook/templates/serviceaccount.yaml new file mode 100644 index 0000000..d4020b5 --- /dev/null +++ b/istio-1.3.5/install/kubernetes/helm/istio/charts/sidecarInjectorWebhook/templates/serviceaccount.yaml @@ -0,0 +1,17 @@ +apiVersion: v1 +kind: ServiceAccount +{{- if .Values.global.imagePullSecrets }} +imagePullSecrets: +{{- range .Values.global.imagePullSecrets }} + - name: {{ . }} +{{- end }} +{{- end }} +metadata: + name: istio-sidecar-injector-service-account + namespace: {{ .Release.Namespace }} + labels: + app: {{ template "sidecar-injector.name" . }} + chart: {{ template "sidecar-injector.chart" . }} + heritage: {{ .Release.Service }} + release: {{ .Release.Name }} + istio: sidecar-injector diff --git a/istio-1.3.5/install/kubernetes/helm/istio/charts/sidecarInjectorWebhook/values.yaml b/istio-1.3.5/install/kubernetes/helm/istio/charts/sidecarInjectorWebhook/values.yaml new file mode 100644 index 0000000..31980ac --- /dev/null +++ b/istio-1.3.5/install/kubernetes/helm/istio/charts/sidecarInjectorWebhook/values.yaml @@ -0,0 +1,44 @@ +# +# sidecar-injector webhook configuration +# +enabled: true +replicaCount: 1 +rollingMaxSurge: 100% +rollingMaxUnavailable: 25% +image: sidecar_injector +enableNamespacesByDefault: false +nodeSelector: {} +tolerations: [] + +# Specify the pod anti-affinity that allows you to constrain which nodes +# your pod is eligible to be scheduled based on labels on pods that are +# already running on the node rather than based on labels on nodes. +# There are currently two types of anti-affinity: +# "requiredDuringSchedulingIgnoredDuringExecution" +# "preferredDuringSchedulingIgnoredDuringExecution" +# which denote "hard" vs. "soft" requirements, you can define your values +# in "podAntiAffinityLabelSelector" and "podAntiAffinityTermLabelSelector" +# correspondingly. +# For example: +# podAntiAffinityLabelSelector: +# - key: security +# operator: In +# values: S1,S2 +# topologyKey: "kubernetes.io/hostname" +# This pod anti-affinity rule says that the pod requires not to be scheduled +# onto a node if that node is already running a pod with label having key +# "security" and value "S1". +podAntiAffinityLabelSelector: [] +podAntiAffinityTermLabelSelector: [] + +# If true, webhook or istioctl injector will rewrite PodSpec for liveness +# health check to redirect request to sidecar. This makes liveness check work +# even when mTLS is enabled. +rewriteAppHTTPProbe: false + +# You can use the field called alwaysInjectSelector and neverInjectSelector which will always inject the sidecar or +# always skip the injection on pods that match that label selector, regardless of the global policy. +# See https://istio.io/docs/setup/kubernetes/additional-setup/sidecar-injection/#more-control-adding-exceptions +neverInjectSelector: [] + +alwaysInjectSelector: [] \ No newline at end of file diff --git a/istio-1.3.5/install/kubernetes/helm/istio/charts/tracing/Chart.yaml b/istio-1.3.5/install/kubernetes/helm/istio/charts/tracing/Chart.yaml new file mode 100644 index 0000000..68e1751 --- /dev/null +++ b/istio-1.3.5/install/kubernetes/helm/istio/charts/tracing/Chart.yaml @@ -0,0 +1,6 @@ +apiVersion: v1 +description: A Helm chart for Kubernetes +name: tracing +version: 1.3.5 +appVersion: 1.5.1 +tillerVersion: ">=2.7.2" diff --git a/istio-1.3.5/install/kubernetes/helm/istio/charts/tracing/templates/_helpers.tpl b/istio-1.3.5/install/kubernetes/helm/istio/charts/tracing/templates/_helpers.tpl new file mode 100644 index 0000000..e246b59 --- /dev/null +++ b/istio-1.3.5/install/kubernetes/helm/istio/charts/tracing/templates/_helpers.tpl @@ -0,0 +1,32 @@ +{{/* vim: set filetype=mustache: */}} +{{/* +Expand the name of the chart. +*/}} +{{- define "tracing.name" -}} +{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" -}} +{{- end -}} + +{{/* +Create a default fully qualified app name. +We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). +If release name contains chart name it will be used as a full name. +*/}} +{{- define "tracing.fullname" -}} +{{- if .Values.fullnameOverride -}} +{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" -}} +{{- else -}} +{{- $name := default .Chart.Name .Values.nameOverride -}} +{{- if contains $name .Release.Name -}} +{{- .Release.Name | trunc 63 | trimSuffix "-" -}} +{{- else -}} +{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" -}} +{{- end -}} +{{- end -}} +{{- end -}} + +{{/* +Create chart name and version as used by the chart label. +*/}} +{{- define "tracing.chart" -}} +{{- .Chart.Name | trunc 63 | trimSuffix "-" -}} +{{- end -}} diff --git a/istio-1.3.5/install/kubernetes/helm/istio/charts/tracing/templates/deployment-jaeger.yaml b/istio-1.3.5/install/kubernetes/helm/istio/charts/tracing/templates/deployment-jaeger.yaml new file mode 100644 index 0000000..91e6884 --- /dev/null +++ b/istio-1.3.5/install/kubernetes/helm/istio/charts/tracing/templates/deployment-jaeger.yaml @@ -0,0 +1,116 @@ +{{ if eq .Values.provider "jaeger" }} + +apiVersion: apps/v1 +kind: Deployment +metadata: + name: istio-tracing + namespace: {{ .Release.Namespace }} + labels: + app: jaeger + chart: {{ template "tracing.chart" . }} + heritage: {{ .Release.Service }} + release: {{ .Release.Name }} +spec: + selector: + matchLabels: + app: jaeger + template: + metadata: + labels: + app: jaeger + chart: {{ template "tracing.chart" . }} + heritage: {{ .Release.Service }} + release: {{ .Release.Name }} + annotations: + sidecar.istio.io/inject: "false" + prometheus.io/scrape: "true" + prometheus.io/port: "14269" + spec: +{{- if .Values.global.priorityClassName }} + priorityClassName: "{{ .Values.global.priorityClassName }}" +{{- end }} +{{- if .Values.global.imagePullSecrets }} + imagePullSecrets: +{{- range .Values.global.imagePullSecrets }} + - name: {{ . }} +{{- end }} +{{- end }} + containers: + - name: jaeger + image: "{{ .Values.jaeger.hub }}/{{ .Values.jaeger.image }}:{{ .Values.jaeger.tag }}" + imagePullPolicy: {{ .Values.global.imagePullPolicy }} + ports: + - containerPort: 9411 + - containerPort: 16686 + - containerPort: 14250 + - containerPort: 14267 + - containerPort: 14268 + - containerPort: 14269 + - containerPort: 5775 + protocol: UDP + - containerPort: 6831 + protocol: UDP + - containerPort: 6832 + protocol: UDP + env: + - name: POD_NAMESPACE + valueFrom: + fieldRef: + apiVersion: v1 + fieldPath: metadata.namespace + {{- if eq .Values.jaeger.spanStorageType "badger" }} + - name: BADGER_EPHEMERAL + value: "false" + - name: SPAN_STORAGE_TYPE + value: "badger" + - name: BADGER_DIRECTORY_VALUE + value: "/badger/data" + - name: BADGER_DIRECTORY_KEY + value: "/badger/key" + {{- end }} + - name: COLLECTOR_ZIPKIN_HTTP_PORT + value: "9411" + - name: MEMORY_MAX_TRACES + value: "{{ .Values.jaeger.memory.max_traces }}" + - name: QUERY_BASE_PATH + value: {{ if .Values.contextPath }} {{ .Values.contextPath }} {{ else }} /{{ .Values.provider }} {{ end }} + livenessProbe: + httpGet: + path: / + port: 14269 + readinessProbe: + httpGet: + path: / + port: 14269 +{{- if eq .Values.jaeger.spanStorageType "badger" }} + volumeMounts: + - name: data + mountPath: /badger +{{- end }} + resources: +{{- if .Values.jaeger.resources }} +{{ toYaml .Values.jaeger.resources | indent 12 }} +{{- else }} +{{ toYaml .Values.global.defaultResources | indent 12 }} +{{- end }} + affinity: + {{- include "nodeaffinity" . | indent 6 }} + {{- include "podAntiAffinity" . | indent 6 }} + {{- if .Values.tolerations }} + tolerations: +{{ toYaml .Values.tolerations | indent 6 }} + {{- else if .Values.global.defaultTolerations }} + tolerations: +{{ toYaml .Values.global.defaultTolerations | indent 6 }} + {{- end }} +{{- if eq .Values.jaeger.spanStorageType "badger" }} + volumes: + - name: data +{{- if .Values.jaeger.persist }} + persistentVolumeClaim: + claimName: istio-jaeger-pvc +{{- else }} + emptyDir: {} +{{- end }} +{{- end }} +{{ end }} diff --git a/istio-1.3.5/install/kubernetes/helm/istio/charts/tracing/templates/deployment-zipkin.yaml b/istio-1.3.5/install/kubernetes/helm/istio/charts/tracing/templates/deployment-zipkin.yaml new file mode 100644 index 0000000..04dfbb0 --- /dev/null +++ b/istio-1.3.5/install/kubernetes/helm/istio/charts/tracing/templates/deployment-zipkin.yaml @@ -0,0 +1,82 @@ +{{ if eq .Values.provider "zipkin" }} + +apiVersion: apps/v1 +kind: Deployment +metadata: + name: istio-tracing + namespace: {{ .Release.Namespace }} + labels: + app: zipkin + chart: {{ template "tracing.chart" . }} + heritage: {{ .Release.Service }} + release: {{ .Release.Name }} +spec: + selector: + matchLabels: + app: zipkin + template: + metadata: + labels: + app: zipkin + chart: {{ template "tracing.chart" . }} + heritage: {{ .Release.Service }} + release: {{ .Release.Name }} + annotations: + sidecar.istio.io/inject: "false" + scheduler.alpha.kubernetes.io/critical-pod: "" + spec: +{{- if .Values.global.priorityClassName }} + priorityClassName: "{{ .Values.global.priorityClassName }}" +{{- end }} +{{- if .Values.global.imagePullSecrets }} + imagePullSecrets: +{{- range .Values.global.imagePullSecrets }} + - name: {{ . }} +{{- end }} +{{- end }} + containers: + - name: zipkin + image: "{{ .Values.zipkin.hub }}/{{ .Values.zipkin.image }}:{{ .Values.zipkin.tag }}" + imagePullPolicy: {{ .Values.global.imagePullPolicy }} + ports: + - containerPort: {{ .Values.zipkin.queryPort }} + livenessProbe: + initialDelaySeconds: {{ .Values.zipkin.probeStartupDelay }} + tcpSocket: + port: {{ .Values.zipkin.queryPort }} + readinessProbe: + initialDelaySeconds: {{ .Values.zipkin.probeStartupDelay }} + httpGet: + path: /health + port: {{ .Values.zipkin.queryPort }} + resources: +{{- if .Values.zipkin.resources }} +{{ toYaml .Values.zipkin.resources | indent 12 }} +{{- else }} +{{ toYaml .Values.global.defaultResources | indent 12 }} +{{- end }} + env: + - name: POD_NAMESPACE + valueFrom: + fieldRef: + apiVersion: v1 + fieldPath: metadata.namespace + - name: QUERY_PORT + value: "{{ .Values.zipkin.queryPort }}" + - name: JAVA_OPTS + value: "-XX:ConcGCThreads={{ .Values.zipkin.node.cpus }} -XX:ParallelGCThreads={{ .Values.zipkin.node.cpus }} -Djava.util.concurrent.ForkJoinPool.common.parallelism={{ .Values.zipkin.node.cpus }} -Xms{{ .Values.zipkin.javaOptsHeap }}M -Xmx{{ .Values.zipkin.javaOptsHeap }}M -XX:+UseG1GC -server" + - name: STORAGE_METHOD + value: "mem" + - name: ZIPKIN_STORAGE_MEM_MAXSPANS + value: "{{ .Values.zipkin.maxSpans }}" + affinity: + {{- include "nodeaffinity" . | indent 6 }} + {{- include "podAntiAffinity" . | indent 6 }} + {{- if .Values.tolerations }} + tolerations: +{{ toYaml .Values.tolerations | indent 6 }} + {{- else if .Values.global.defaultTolerations }} + tolerations: +{{ toYaml .Values.global.defaultTolerations | indent 6 }} + {{- end }} +{{ end }} diff --git a/istio-1.3.5/install/kubernetes/helm/istio/charts/tracing/templates/ingress.yaml b/istio-1.3.5/install/kubernetes/helm/istio/charts/tracing/templates/ingress.yaml new file mode 100644 index 0000000..72f3621 --- /dev/null +++ b/istio-1.3.5/install/kubernetes/helm/istio/charts/tracing/templates/ingress.yaml @@ -0,0 +1,41 @@ +{{- if .Values.ingress.enabled -}} +apiVersion: extensions/v1beta1 +kind: Ingress +metadata: + name: {{ template "tracing.fullname" . }} + namespace: {{ .Release.Namespace }} + labels: + app: {{ .Values.provider }} + chart: {{ template "tracing.chart" . }} + heritage: {{ .Release.Service }} + release: {{ .Release.Name }} + annotations: + {{- range $key, $value := .Values.ingress.annotations }} + {{ $key }}: {{ $value | quote }} + {{- end }} +spec: + rules: +{{- if .Values.ingress.hosts }} + {{- range $host := .Values.ingress.hosts }} + - host: {{ $host }} + http: + paths: + - path: {{ if $.Values.contextPath }} {{ $.Values.contextPath }} {{ else }} /{{ $.Values.provider }} {{ end }} + backend: + serviceName: tracing + servicePort: 80 + + {{- end -}} +{{- else }} + - http: + paths: + - path: {{ if .Values.contextPath }} {{ .Values.contextPath }} {{ else }} /{{ .Values.provider }} {{ end }} + backend: + serviceName: tracing + servicePort: 80 +{{- end }} + {{- if .Values.ingress.tls }} + tls: +{{ toYaml .Values.ingress.tls | indent 4 }} + {{- end -}} +{{- end -}} diff --git a/istio-1.3.5/install/kubernetes/helm/istio/charts/tracing/templates/pvc.yaml b/istio-1.3.5/install/kubernetes/helm/istio/charts/tracing/templates/pvc.yaml new file mode 100644 index 0000000..6014049 --- /dev/null +++ b/istio-1.3.5/install/kubernetes/helm/istio/charts/tracing/templates/pvc.yaml @@ -0,0 +1,21 @@ +{{- if eq .Values.provider "jaeger" }} +{{- if .Values.jaeger.persist }} +kind: PersistentVolumeClaim +apiVersion: v1 +metadata: + name: istio-jaeger-pvc + namespace: {{ .Release.Namespace }} + labels: + app: jaeger + chart: {{ template "tracing.chart" . }} + heritage: {{ .Release.Service }} + release: {{ .Release.Name }} +spec: + storageClassName: {{ .Values.jaeger.storageClassName }} + accessModes: + - {{ .Values.jaeger.accessMode }} + resources: + requests: + storage: 5Gi +{{- end }} +{{- end }} diff --git a/istio-1.3.5/install/kubernetes/helm/istio/charts/tracing/templates/service-jaeger.yaml b/istio-1.3.5/install/kubernetes/helm/istio/charts/tracing/templates/service-jaeger.yaml new file mode 100644 index 0000000..38c4170 --- /dev/null +++ b/istio-1.3.5/install/kubernetes/helm/istio/charts/tracing/templates/service-jaeger.yaml @@ -0,0 +1,94 @@ +{{ if eq .Values.provider "jaeger" }} + +apiVersion: v1 +kind: List +metadata: + name: jaeger-services + namespace: {{ .Release.Namespace }} + labels: + app: jaeger + chart: {{ template "tracing.chart" . }} + heritage: {{ .Release.Service }} + release: {{ .Release.Name }} +items: +- apiVersion: v1 + kind: Service + metadata: + name: jaeger-query + namespace: {{ .Release.Namespace }} + annotations: + {{- range $key, $val := .Values.service.annotations }} + {{ $key }}: {{ $val | quote }} + {{- end }} + labels: + app: jaeger + jaeger-infra: jaeger-service + chart: {{ template "tracing.chart" . }} + heritage: {{ .Release.Service }} + release: {{ .Release.Name }} + spec: + ports: + - name: query-http + port: 16686 + protocol: TCP + targetPort: 16686 + selector: + app: jaeger +- apiVersion: v1 + kind: Service + metadata: + name: jaeger-collector + namespace: {{ .Release.Namespace }} + labels: + app: jaeger + jaeger-infra: collector-service + chart: {{ template "tracing.chart" . }} + heritage: {{ .Release.Service }} + release: {{ .Release.Name }} + spec: + ports: + - name: jaeger-collector-tchannel + port: 14267 + protocol: TCP + targetPort: 14267 + - name: jaeger-collector-http + port: 14268 + targetPort: 14268 + protocol: TCP + - name: jaeger-collector-grpc + port: 14250 + targetPort: 14250 + protocol: TCP + selector: + app: jaeger + type: ClusterIP +- apiVersion: v1 + kind: Service + metadata: + name: jaeger-agent + namespace: {{ .Release.Namespace }} + labels: + app: jaeger + jaeger-infra: agent-service + chart: {{ template "tracing.chart" . }} + heritage: {{ .Release.Service }} + release: {{ .Release.Name }} + spec: + ports: + - name: agent-zipkin-thrift + port: 5775 + protocol: UDP + targetPort: 5775 + - name: agent-compact + port: 6831 + protocol: UDP + targetPort: 6831 + - name: agent-binary + port: 6832 + protocol: UDP + targetPort: 6832 + clusterIP: None + selector: + app: jaeger +{{ end }} + diff --git a/istio-1.3.5/install/kubernetes/helm/istio/charts/tracing/templates/service.yaml b/istio-1.3.5/install/kubernetes/helm/istio/charts/tracing/templates/service.yaml new file mode 100644 index 0000000..fe94067 --- /dev/null +++ b/istio-1.3.5/install/kubernetes/helm/istio/charts/tracing/templates/service.yaml @@ -0,0 +1,56 @@ +apiVersion: v1 +kind: List +metadata: + name: tracing-services + namespace: {{ .Release.Namespace }} + labels: + app: {{ .Values.provider }} + chart: {{ template "tracing.chart" . }} + heritage: {{ .Release.Service }} + release: {{ .Release.Name }} +items: +- apiVersion: v1 + kind: Service + metadata: + name: zipkin + namespace: {{ .Release.Namespace }} + labels: + app: {{ .Values.provider }} + chart: {{ template "tracing.chart" . }} + heritage: {{ .Release.Service }} + release: {{ .Release.Name }} + spec: + type: {{ .Values.service.type }} + ports: + - port: {{ .Values.service.externalPort }} + targetPort: 9411 + protocol: TCP + name: {{ .Values.service.name }} + selector: + app: {{ .Values.provider }} +- apiVersion: v1 + kind: Service + metadata: + name: tracing + namespace: {{ .Release.Namespace }} + annotations: + {{- range $key, $val := .Values.service.annotations }} + {{ $key }}: {{ $val | quote }} + {{- end }} + labels: + app: {{ .Values.provider }} + chart: {{ template "tracing.chart" . }} + heritage: {{ .Release.Service }} + release: {{ .Release.Name }} + spec: + ports: + - name: http-query + port: 80 + protocol: TCP +{{ if eq .Values.provider "jaeger" }} + targetPort: 16686 +{{ else }} + targetPort: 9411 +{{ end}} + selector: + app: {{ .Values.provider }} diff --git a/istio-1.3.5/install/kubernetes/helm/istio/charts/tracing/templates/tests/test-tracing-connection.yaml b/istio-1.3.5/install/kubernetes/helm/istio/charts/tracing/templates/tests/test-tracing-connection.yaml new file mode 100644 index 0000000..b87f487 --- /dev/null +++ b/istio-1.3.5/install/kubernetes/helm/istio/charts/tracing/templates/tests/test-tracing-connection.yaml @@ -0,0 +1,40 @@ +{{- if .Values.global.enableHelmTest }} +apiVersion: v1 +kind: Pod +metadata: + name: {{ .Release.Name }}-{{ .Values.provider }}-test + namespace: {{ .Release.Namespace }} + labels: + app: {{ .Values.provider }}-test + chart: {{ template "tracing.chart" . }} + release: {{ .Release.Name }} + heritage: {{ .Release.Service }} + annotations: + sidecar.istio.io/inject: "false" + helm.sh/hook: test-success +spec: +{{- if .Values.global.priorityClassName }} + priorityClassName: "{{ .Values.global.priorityClassName }}" +{{- end }} + containers: + - name: "{{ .Values.provider }}-test" + image: pstauffer/curl:v1.0.3 + imagePullPolicy: "{{ .Values.global.imagePullPolicy }}" + command: ['curl'] + {{- if eq .Values.provider "jaeger" }} + args: ['http://tracing:80{{ .Values.jaeger.contextPath}}'] + {{- else }} + args: ['http://tracing:80'] + {{- end }} + restartPolicy: Never + affinity: + {{- include "nodeaffinity" . | indent 4 }} + {{- include "podAntiAffinity" . | indent 4 }} + {{- if .Values.tolerations }} + tolerations: +{{ toYaml .Values.tolerations | indent 2 }} + {{- else if .Values.global.defaultTolerations }} + tolerations: +{{ toYaml .Values.global.defaultTolerations | indent 2 }} + {{- end }} +{{- end }} diff --git a/istio-1.3.5/install/kubernetes/helm/istio/charts/tracing/values.yaml b/istio-1.3.5/install/kubernetes/helm/istio/charts/tracing/values.yaml new file mode 100644 index 0000000..1d5a5f1 --- /dev/null +++ b/istio-1.3.5/install/kubernetes/helm/istio/charts/tracing/values.yaml @@ -0,0 +1,84 @@ +# +# addon jaeger tracing configuration +# +enabled: false + +provider: jaeger +nodeSelector: {} +tolerations: [] + +# Specify the pod anti-affinity that allows you to constrain which nodes +# your pod is eligible to be scheduled based on labels on pods that are +# already running on the node rather than based on labels on nodes. +# There are currently two types of anti-affinity: +# "requiredDuringSchedulingIgnoredDuringExecution" +# "preferredDuringSchedulingIgnoredDuringExecution" +# which denote "hard" vs. "soft" requirements, you can define your values +# in "podAntiAffinityLabelSelector" and "podAntiAffinityTermLabelSelector" +# correspondingly. +# For example: +# podAntiAffinityLabelSelector: +# - key: security +# operator: In +# values: S1,S2 +# topologyKey: "kubernetes.io/hostname" +# This pod anti-affinity rule says that the pod requires not to be scheduled +# onto a node if that node is already running a pod with label having key +# "security" and value "S1". +podAntiAffinityLabelSelector: [] +podAntiAffinityTermLabelSelector: [] + +jaeger: + hub: docker.io/jaegertracing + image: all-in-one + tag: 1.14 + memory: + max_traces: 50000 + # spanStorageType value can be "memory" and "badger" for all-in-one image + spanStorageType: badger + persist: false + storageClassName: "" + accessMode: ReadWriteMany + +zipkin: + hub: docker.io/openzipkin + image: zipkin + tag: 2.14.2 + probeStartupDelay: 200 + queryPort: 9411 + resources: + limits: + cpu: 300m + memory: 900Mi + requests: + cpu: 150m + memory: 900Mi + javaOptsHeap: 700 + # From: https://github.com/openzipkin/zipkin/blob/master/zipkin-server/src/main/resources/zipkin-server-shared.yml#L51 + # Maximum number of spans to keep in memory. When exceeded, oldest traces (and their spans) will be purged. + # A safe estimate is 1K of memory per span (each span with 2 annotations + 1 binary annotation), plus + # 100 MB for a safety buffer. You'll need to verify in your own environment. + maxSpans: 500000 + node: + cpus: 2 + +service: + annotations: {} + name: http + type: ClusterIP + externalPort: 9411 + +ingress: + enabled: false + # Used to create an Ingress record. + hosts: + # - tracing.local + annotations: + # kubernetes.io/ingress.class: nginx + # kubernetes.io/tls-acme: "true" + tls: + # Secrets must be manually created in the namespace. + # - secretName: tracing-tls + # hosts: + # - tracing.local + diff --git a/istio-1.3.5/install/kubernetes/helm/istio/example-values/README.md b/istio-1.3.5/install/kubernetes/helm/istio/example-values/README.md new file mode 100644 index 0000000..74fedcb --- /dev/null +++ b/istio-1.3.5/install/kubernetes/helm/istio/example-values/README.md @@ -0,0 +1,5 @@ +# Example Values + +These files provide various example values for different Istio setups. + +To use them, [read the docs](https://istio.io/docs/setup/kubernetes/helm-install/) and add the flag `--values example-file.yaml`. diff --git a/istio-1.3.5/install/kubernetes/helm/istio/example-values/values-istio-example-sds-vault.yaml b/istio-1.3.5/install/kubernetes/helm/istio/example-values/values-istio-example-sds-vault.yaml new file mode 100644 index 0000000..1016afc --- /dev/null +++ b/istio-1.3.5/install/kubernetes/helm/istio/example-values/values-istio-example-sds-vault.yaml @@ -0,0 +1,26 @@ +global: + controlPlaneSecurityEnabled: false + + mtls: + # Default setting for service-to-service mtls. Can be set explicitly using + # destination rules or service annotations. + enabled: true + + sds: + enabled: true + udsPath: "unix:/var/run/sds/uds_path" + +nodeagent: + enabled: true + image: node-agent-k8s + env: + # The IP address and the port number of a publicly accessible example Vault server. + CA_ADDR: "https://34.83.129.211:8200" + CA_PROVIDER: "VaultCA" + VALID_TOKEN: true + # The IP address and the port number of a publicly accessible example Vault server. + VAULT_ADDR: "https://34.83.129.211:8200" + VAULT_AUTH_PATH: "auth/kubernetes/login" + VAULT_ROLE: "istio-cert" + VAULT_SIGN_CSR_PATH: "istio_ca/sign/istio-pki-role" + VAULT_TLS_ROOT_CERT: '-----BEGIN CERTIFICATE-----\nMIIC3jCCAcagAwIBAgIRAO1S7vuRQmo2He+RtBq3fv8wDQYJKoZIhvcNAQELBQAw\nEDEOMAwGA1UEChMFVmF1bHQwIBcNMTkwNDI3MTY1ODE1WhgPMjExOTA0MDMxNjU4\nMTVaMBAxDjAMBgNVBAoTBVZhdWx0MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB\nCgKCAQEA7/CTbnENEIvFZg9hmVtYnOx3OfMy/GNCuP7sqtAeVVTopAKKkcAAWQck\nrhpBooEGpCugNxXGNCuJh/2nu0AfGFRfdafwSJRoI6yHwQouDm0o4r3h9uL3tu5N\nD+x9j+eejbFsoZVn84CxGkEB6oyeXYHjc6eWh3PFGMtKuOQD4pezvDH0yNCx5waK\nhtPuYtl0ebfdbyh+WQuptO+Q9VSaQNqE3ipZ461y8PduwRRll241W0gQB2iasX03\nD36F2ZrMz3KEVRVKM1yCUDCy2RPJqkXPdnVMWmDGbe8Uw69zr25JltzuRZFT9HL3\nY1RnMTecmSc4ikTUHcMhFX3PYbfR5wIDAQABozEwLzAOBgNVHQ8BAf8EBAMCBaAw\nDAYDVR0TAQH/BAIwADAPBgNVHREECDAGhwQiU4HTMA0GCSqGSIb3DQEBCwUAA4IB\nAQCdLh6olDVQB71LD6srbfAE4EsxLEBbIRnv7Nf1S0KQwgW/QxK8DHBwJBxJkr1N\nzgEPx86f2Fo2UsY9m6rvgP3+iquyMsKi0ooUah3y3LSnONuZcdfSTl/HYd38S6Dp\nVkVOZ7781xxpFVUqQ5voQX1Y1Ipn5qw0FyIcNYWLkNX+iMf1b9kpEIWQNhRC/Yiv\nTS0VA/BzQemGyf2UB6QsuZLH+JFEZnzU859qURnNIITa1Wf4YUtka5Sp1kDnEll3\nwj4IlXKU+Wl1CzxJyn4SSQAXy/Lb08ZKrF/YSzcIISnRX5j+wa8ApOSwwA/B7iaT\nTWz1g+RlV9qHap70eIjPsQvb\n-----END CERTIFICATE-----' \ No newline at end of file diff --git a/istio-1.3.5/install/kubernetes/helm/istio/example-values/values-istio-gateways.yaml b/istio-1.3.5/install/kubernetes/helm/istio/example-values/values-istio-gateways.yaml new file mode 100644 index 0000000..b9930d0 --- /dev/null +++ b/istio-1.3.5/install/kubernetes/helm/istio/example-values/values-istio-gateways.yaml @@ -0,0 +1,135 @@ +# Common settings. +global: + # Omit the istio-sidecar-injector configmap when generate a + # standalone gateway. Gateways may be created in namespaces other + # than `istio-system` and we don't want to re-create the injector + # configmap in those. + omitSidecarInjectorConfigMap: true + + # Istio control plane namespace: This specifies where the Istio control + # plane was installed earlier. Modify this if you installed the control + # plane in a different namespace than istio-system. + istioNamespace: istio-system + + proxy: + # Sets the destination Statsd in envoy (the value of the "--statsdUdpAddress" proxy argument + # would be :). + # Disabled by default. + # The istio-statsd-prom-bridge is deprecated and should not be used moving forward. + envoyStatsd: + # If enabled is set to true, host and port must also be provided. Istio no longer provides a statsd collector. + enabled: false + host: # example: statsd-svc.istio-system + port: # example: 9125 + + +# +# Gateways Configuration +# By default (if enabled) a pair of Ingress and Egress Gateways will be created for the mesh. +# You can add more gateways in addition to the defaults but make sure those are uniquely named +# and that NodePorts are not conflicting. +# Disable specific gateway by setting the `enabled` to false. +# +gateways: + enabled: true + + custom-gateway: + enabled: true + labels: + app: custom-gateway + replicaCount: 1 + autoscaleMin: 1 + autoscaleMax: 5 + resources: {} + # limits: + # cpu: 100m + # memory: 128Mi + #requests: + # cpu: 1800m + # memory: 256Mi + cpu: + targetAverageUtilization: 80 + loadBalancerIP: "" + loadBalancerSourceRanges: {} + externalIPs: [] + serviceAnnotations: {} + podAnnotations: {} + type: LoadBalancer #change to NodePort, ClusterIP or LoadBalancer if need be + #externalTrafficPolicy: Local #change to Local to preserve source IP or Cluster for default behaviour or leave commented out + ports: + ## You can add custom gateway ports + - port: 80 + targetPort: 80 + name: http2 + # nodePort: 31380 + - port: 443 + name: https + # nodePort: 31390 + - port: 31400 + name: tcp + # nodePort: 31400 + # Pilot and Citadel MTLS ports are enabled in gateway - but will only redirect + # to pilot/citadel if global.meshExpansion settings are enabled. + - port: 15011 + targetPort: 15011 + name: tcp-pilot-grpc-tls + - port: 8060 + targetPort: 8060 + name: tcp-citadel-grpc-tls + # Addon ports for kiali are enabled in gateway - but will only redirect if + # the gateway configuration for the various components are enabled. + - port: 15029 + targetPort: 15029 + name: http2-kiali + # Telemetry-related ports are enabled in gateway - but will only redirect if + # the gateway configuration for the various components are enabled. + - port: 15030 + targetPort: 15030 + name: http2-prometheus + - port: 15031 + targetPort: 15031 + name: http2-grafana + - port: 15032 + targetPort: 15032 + name: http2-tracing + secretVolumes: + - name: customgateway-certs + secretName: istio-customgateway-certs + mountPath: /etc/istio/customgateway-certs + - name: customgateway-ca-certs + secretName: istio-customgateway-ca-certs + mountPath: /etc/istio/customgateway-ca-certs + +# all other components are disabled except the gateways +security: + enabled: false + +sidecarInjectorWebhook: + enabled: false + +galley: + enabled: false + +mixer: + policy: + enabled: false + telemetry: + enabled: false + +pilot: + enabled: false + +grafana: + enabled: false + +prometheus: + enabled: false + +tracing: + enabled: false + +kiali: + enabled: false + +certmanager: + enabled: false diff --git a/istio-1.3.5/install/kubernetes/helm/istio/example-values/values-istio-googleca.yaml b/istio-1.3.5/install/kubernetes/helm/istio/example-values/values-istio-googleca.yaml new file mode 100644 index 0000000..0e6d153 --- /dev/null +++ b/istio-1.3.5/install/kubernetes/helm/istio/example-values/values-istio-googleca.yaml @@ -0,0 +1,28 @@ +global: + controlPlaneSecurityEnabled: true + + mtls: + # Default setting for service-to-service mtls. Can be set explicitly using + # destination rules or service annotations. + enabled: true + + sds: + enabled: true + udsPath: "unix:/var/run/sds/uds_path" + # For GoogleCA, the aud field need to be set to the trustDomain, which is also set at the + # installation/configuration time, e.g. by running helm template. + token: + aud: "" + + trustDomain: "" + + useMCP: true + +nodeagent: + enabled: true + image: node-agent-k8s + env: + CA_PROVIDER: "GoogleCA" + CA_ADDR: "meshca.googleapis.com:443" + PLUGINS: "GoogleTokenExchange" + GKE_CLUSTER_URL: "" diff --git a/istio-1.3.5/install/kubernetes/helm/istio/example-values/values-istio-meshexpansion-gateways.yaml b/istio-1.3.5/install/kubernetes/helm/istio/example-values/values-istio-meshexpansion-gateways.yaml new file mode 100644 index 0000000..51a1ded --- /dev/null +++ b/istio-1.3.5/install/kubernetes/helm/istio/example-values/values-istio-meshexpansion-gateways.yaml @@ -0,0 +1,28 @@ +global: + # Provides dns resolution for global services + podDNSSearchNamespaces: + - global + + multiCluster: + enabled: true + + controlPlaneSecurityEnabled: true + meshExpansion: + enabled: true + +# Multicluster with gateways requires a root CA +# Cluster local CAs are bootstrapped with the root CA. +security: + selfSigned: false + +# Provides dns resolution for service entries of form +# name.namespace.global +istiocoredns: + enabled: true + +gateways: + istio-egressgateway: + enabled: true + env: + # Needed to route traffic via egress gateway if desired. + ISTIO_META_REQUESTED_NETWORK_VIEW: "external" diff --git a/istio-1.3.5/install/kubernetes/helm/istio/example-values/values-istio-multicluster-gateways.yaml b/istio-1.3.5/install/kubernetes/helm/istio/example-values/values-istio-multicluster-gateways.yaml new file mode 100644 index 0000000..3524a3d --- /dev/null +++ b/istio-1.3.5/install/kubernetes/helm/istio/example-values/values-istio-multicluster-gateways.yaml @@ -0,0 +1,27 @@ +global: + # Provides dns resolution for global services + podDNSSearchNamespaces: + - global + - "{{ valueOrDefault .DeploymentMeta.Namespace \"default\" }}.global" + + multiCluster: + enabled: true + + controlPlaneSecurityEnabled: true + +# Multicluster with gateways requires a root CA +# Cluster local CAs are bootstrapped with the root CA. +security: + selfSigned: false + +# Provides dns resolution for service entries of form +# name.namespace.global +istiocoredns: + enabled: true + +gateways: + istio-egressgateway: + enabled: true + env: + # Needed to route traffic via egress gateway if desired. + ISTIO_META_REQUESTED_NETWORK_VIEW: "external" diff --git a/istio-1.3.5/install/kubernetes/helm/istio/files/injection-template.yaml b/istio-1.3.5/install/kubernetes/helm/istio/files/injection-template.yaml new file mode 100644 index 0000000..49395a1 --- /dev/null +++ b/istio-1.3.5/install/kubernetes/helm/istio/files/injection-template.yaml @@ -0,0 +1,388 @@ +rewriteAppHTTPProbe: {{ valueOrDefault .Values.sidecarInjectorWebhook.rewriteAppHTTPProbe false }} +{{- if or (not .Values.istio_cni.enabled) .Values.global.proxy.enableCoreDump }} +initContainers: +{{ if ne (annotation .ObjectMeta `sidecar.istio.io/interceptionMode` .ProxyConfig.InterceptionMode) `NONE` }} +{{- if not .Values.istio_cni.enabled }} +- name: istio-init +{{- if contains "/" .Values.global.proxy_init.image }} + image: "{{ .Values.global.proxy_init.image }}" +{{- else }} + image: "{{ .Values.global.hub }}/{{ .Values.global.proxy_init.image }}:{{ .Values.global.tag }}" +{{- end }} + args: + - "-p" + - "15001" + - "-z" + - "15006" + - "-u" + - 1337 + - "-m" + - "{{ annotation .ObjectMeta `sidecar.istio.io/interceptionMode` .ProxyConfig.InterceptionMode }}" + - "-i" + - "{{ annotation .ObjectMeta `traffic.sidecar.istio.io/includeOutboundIPRanges` .Values.global.proxy.includeIPRanges }}" + - "-x" + - "{{ annotation .ObjectMeta `traffic.sidecar.istio.io/excludeOutboundIPRanges` .Values.global.proxy.excludeIPRanges }}" + - "-b" + - "{{ annotation .ObjectMeta `traffic.sidecar.istio.io/includeInboundPorts` `*` }}" + - "-d" + - "{{ excludeInboundPort (annotation .ObjectMeta `status.sidecar.istio.io/port` .Values.global.proxy.statusPort) (annotation .ObjectMeta `traffic.sidecar.istio.io/excludeInboundPorts` .Values.global.proxy.excludeInboundPorts) }}" + {{ if or (isset .ObjectMeta.Annotations `traffic.sidecar.istio.io/excludeOutboundPorts`) (ne .Values.global.proxy.excludeOutboundPorts "") -}} + - "-o" + - "{{ annotation .ObjectMeta `traffic.sidecar.istio.io/excludeOutboundPorts` .Values.global.proxy.excludeOutboundPorts }}" + {{ end -}} + {{ if (isset .ObjectMeta.Annotations `traffic.sidecar.istio.io/kubevirtInterfaces`) -}} + - "-k" + - "{{ index .ObjectMeta.Annotations `traffic.sidecar.istio.io/kubevirtInterfaces` }}" + {{ end -}} + imagePullPolicy: "{{ .Values.global.imagePullPolicy }}" +{{- if .Values.global.proxy.init.resources }} + resources: + {{ toYaml .Values.global.proxy.init.resources | indent 4 }} +{{- else }} + resources: {} +{{- end }} + securityContext: + runAsUser: 0 + runAsNonRoot: false + capabilities: + add: + - NET_ADMIN + {{- if .Values.global.proxy.privileged }} + privileged: true + {{- end }} + restartPolicy: Always +{{- end }} +{{ end -}} +{{- if eq .Values.global.proxy.enableCoreDump true }} +- name: enable-core-dump + args: + - -c + - sysctl -w kernel.core_pattern=/var/lib/istio/core.proxy && ulimit -c unlimited + command: + - /bin/sh + image: {{ $.Values.global.proxy.enableCoreDumpImage }} + imagePullPolicy: IfNotPresent + resources: {} + securityContext: + runAsUser: 0 + runAsNonRoot: false + privileged: true +{{ end }} +{{- end }} +containers: +- name: istio-proxy +{{- if contains "/" (annotation .ObjectMeta `sidecar.istio.io/proxyImage` .Values.global.proxy.image) }} + image: "{{ annotation .ObjectMeta `sidecar.istio.io/proxyImage` .Values.global.proxy.image }}" +{{- else }} + image: "{{ annotation .ObjectMeta `sidecar.istio.io/proxyImage` .Values.global.hub }}/{{ .Values.global.proxy.image }}:{{ .Values.global.tag }}" +{{- end }} + ports: + - containerPort: 15090 + protocol: TCP + name: http-envoy-prom + args: + - proxy + - sidecar + - --domain + - $(POD_NAMESPACE).svc.{{ .Values.global.proxy.clusterDomain }} + - --configPath + - "{{ .ProxyConfig.ConfigPath }}" + - --binaryPath + - "{{ .ProxyConfig.BinaryPath }}" + - --serviceCluster + {{ if ne "" (index .ObjectMeta.Labels "app") -}} + - "{{ index .ObjectMeta.Labels `app` }}.$(POD_NAMESPACE)" + {{ else -}} + - "{{ valueOrDefault .DeploymentMeta.Name `istio-proxy` }}.{{ valueOrDefault .DeploymentMeta.Namespace `default` }}" + {{ end -}} + - --drainDuration + - "{{ formatDuration .ProxyConfig.DrainDuration }}" + - --parentShutdownDuration + - "{{ formatDuration .ProxyConfig.ParentShutdownDuration }}" + - --discoveryAddress + - "{{ annotation .ObjectMeta `sidecar.istio.io/discoveryAddress` .ProxyConfig.DiscoveryAddress }}" +{{- if eq .Values.global.proxy.tracer "lightstep" }} + - --lightstepAddress + - "{{ .ProxyConfig.GetTracing.GetLightstep.GetAddress }}" + - --lightstepAccessToken + - "{{ .ProxyConfig.GetTracing.GetLightstep.GetAccessToken }}" + - --lightstepSecure={{ .ProxyConfig.GetTracing.GetLightstep.GetSecure }} + - --lightstepCacertPath + - "{{ .ProxyConfig.GetTracing.GetLightstep.GetCacertPath }}" +{{- else if eq .Values.global.proxy.tracer "zipkin" }} + - --zipkinAddress + - "{{ .ProxyConfig.GetTracing.GetZipkin.GetAddress }}" +{{- else if eq .Values.global.proxy.tracer "datadog" }} + - --datadogAgentAddress + - "{{ .ProxyConfig.GetTracing.GetDatadog.GetAddress }}" +{{- end }} +{{- if .Values.global.proxy.logLevel }} + - --proxyLogLevel={{ .Values.global.proxy.logLevel }} +{{- end}} +{{- if .Values.global.proxy.componentLogLevel }} + - --proxyComponentLogLevel={{ .Values.global.proxy.componentLogLevel }} +{{- end}} + - --dnsRefreshRate + - {{ .Values.global.proxy.dnsRefreshRate }} + - --connectTimeout + - "{{ formatDuration .ProxyConfig.ConnectTimeout }}" +{{- if .Values.global.proxy.envoyStatsd.enabled }} + - --statsdUdpAddress + - "{{ .ProxyConfig.StatsdUdpAddress }}" +{{- end }} +{{- if .Values.global.proxy.envoyMetricsService.enabled }} + - --envoyMetricsServiceAddress + - "{{ .ProxyConfig.GetEnvoyMetricsService.GetAddress }}" +{{- end }} +{{- if .Values.global.proxy.envoyAccessLogService.enabled }} + - --envoyAccessLogService + - '{{ structToJSON .ProxyConfig.EnvoyAccessLogService }}' +{{- end }} + - --proxyAdminPort + - "{{ .ProxyConfig.ProxyAdminPort }}" + {{ if gt .ProxyConfig.Concurrency 0 -}} + - --concurrency + - "{{ .ProxyConfig.Concurrency }}" + {{ end -}} + - --controlPlaneAuthPolicy + - "{{ annotation .ObjectMeta `sidecar.istio.io/controlPlaneAuthPolicy` .ProxyConfig.ControlPlaneAuthPolicy }}" +{{- if (ne (annotation .ObjectMeta "status.sidecar.istio.io/port" .Values.global.proxy.statusPort) "0") }} + - --statusPort + - "{{ annotation .ObjectMeta `status.sidecar.istio.io/port` .Values.global.proxy.statusPort }}" + - --applicationPorts + - "{{ annotation .ObjectMeta `readiness.status.sidecar.istio.io/applicationPorts` (applicationPorts .Spec.Containers) }}" +{{- end }} +{{- if .Values.global.trustDomain }} + - --trust-domain={{ .Values.global.trustDomain }} +{{- end }} + env: + - name: POD_NAME + valueFrom: + fieldRef: + fieldPath: metadata.name + - name: ISTIO_META_POD_PORTS + value: |- + [ + {{- range $index1, $c := .Spec.Containers }} + {{- range $index2, $p := $c.Ports }} + {{if or (ne $index1 0) (ne $index2 0)}},{{end}}{{ structToJSON $p }} + {{- end}} + {{- end}} + ] + - name: ISTIO_META_CLUSTER_ID + value: "{{ valueOrDefault .Values.global.multicluster.clusterName `Kubernetes` }}" + - name: POD_NAMESPACE + valueFrom: + fieldRef: + fieldPath: metadata.namespace + - name: INSTANCE_IP + valueFrom: + fieldRef: + fieldPath: status.podIP + - name: SERVICE_ACCOUNT + valueFrom: + fieldRef: + fieldPath: spec.serviceAccountName +{{- if eq .Values.global.proxy.tracer "datadog" }} + - name: HOST_IP + valueFrom: + fieldRef: + fieldPath: status.hostIP +{{- if isset .ObjectMeta.Annotations `apm.datadoghq.com/env` }} +{{- range $key, $value := fromJSON (index .ObjectMeta.Annotations `apm.datadoghq.com/env`) }} + - name: {{ $key }} + value: "{{ $value }}" +{{- end }} +{{- end }} +{{- end }} + - name: ISTIO_META_POD_NAME + valueFrom: + fieldRef: + fieldPath: metadata.name + - name: ISTIO_META_CONFIG_NAMESPACE + valueFrom: + fieldRef: + fieldPath: metadata.namespace + - name: SDS_ENABLED + value: {{ $.Values.global.sds.enabled }} + - name: ISTIO_META_INTERCEPTION_MODE + value: "{{ or (index .ObjectMeta.Annotations `sidecar.istio.io/interceptionMode`) .ProxyConfig.InterceptionMode.String }}" + - name: ISTIO_META_INCLUDE_INBOUND_PORTS + value: "{{ annotation .ObjectMeta `traffic.sidecar.istio.io/includeInboundPorts` (applicationPorts .Spec.Containers) }}" + {{- if .Values.global.network }} + - name: ISTIO_META_NETWORK + value: "{{ .Values.global.network }}" + {{- end }} + {{ if .ObjectMeta.Annotations }} + - name: ISTIO_METAJSON_ANNOTATIONS + value: | + {{ toJSON .ObjectMeta.Annotations }} + {{ end }} + {{ if .ObjectMeta.Labels }} + - name: ISTIO_METAJSON_LABELS + value: | + {{ toJSON .ObjectMeta.Labels }} + {{ end }} + {{- if .DeploymentMeta.Name }} + - name: ISTIO_META_WORKLOAD_NAME + value: {{ .DeploymentMeta.Name }} + {{ end }} + {{- if and .TypeMeta.APIVersion .DeploymentMeta.Name }} + - name: ISTIO_META_OWNER + value: kubernetes://api/{{ .TypeMeta.APIVersion }}/namespaces/{{ valueOrDefault .DeploymentMeta.Namespace `default` }}/{{ toLower .TypeMeta.Kind}}s/{{ .DeploymentMeta.Name }} + {{- end}} + {{- if (isset .ObjectMeta.Annotations `sidecar.istio.io/bootstrapOverride`) }} + - name: ISTIO_BOOTSTRAP_OVERRIDE + value: "/etc/istio/custom-bootstrap/custom_bootstrap.json" + {{- end }} + {{- if .Values.global.sds.customTokenDirectory }} + - name: ISTIO_META_SDS_TOKEN_PATH + value: "{{ .Values.global.sds.customTokenDirectory -}}/sdstoken" + {{- end }} + {{- if .Values.global.meshID }} + - name: ISTIO_META_MESH_ID + value: "{{ .Values.global.meshID }}" + {{- else if .Values.global.trustDomain }} + - name: ISTIO_META_MESH_ID + value: "{{ .Values.global.trustDomain }}" + {{- end }} + imagePullPolicy: {{ .Values.global.imagePullPolicy }} + {{ if ne (annotation .ObjectMeta `status.sidecar.istio.io/port` .Values.global.proxy.statusPort) `0` }} + readinessProbe: + httpGet: + path: /healthz/ready + port: {{ annotation .ObjectMeta `status.sidecar.istio.io/port` .Values.global.proxy.statusPort }} + initialDelaySeconds: {{ annotation .ObjectMeta `readiness.status.sidecar.istio.io/initialDelaySeconds` .Values.global.proxy.readinessInitialDelaySeconds }} + periodSeconds: {{ annotation .ObjectMeta `readiness.status.sidecar.istio.io/periodSeconds` .Values.global.proxy.readinessPeriodSeconds }} + failureThreshold: {{ annotation .ObjectMeta `readiness.status.sidecar.istio.io/failureThreshold` .Values.global.proxy.readinessFailureThreshold }} + {{ end -}} + securityContext: + {{- if .Values.global.proxy.privileged }} + privileged: true + {{- end }} + {{- if ne .Values.global.proxy.enableCoreDump true }} + readOnlyRootFilesystem: true + {{- end }} + {{ if eq (annotation .ObjectMeta `sidecar.istio.io/interceptionMode` .ProxyConfig.InterceptionMode) `TPROXY` -}} + capabilities: + add: + - NET_ADMIN + runAsGroup: 1337 + {{ else -}} + {{ if .Values.global.sds.enabled }} + runAsGroup: 1337 + {{- end }} + runAsUser: 1337 + {{- end }} + resources: + {{ if or (isset .ObjectMeta.Annotations `sidecar.istio.io/proxyCPU`) (isset .ObjectMeta.Annotations `sidecar.istio.io/proxyMemory`) -}} + requests: + {{ if (isset .ObjectMeta.Annotations `sidecar.istio.io/proxyCPU`) -}} + cpu: "{{ index .ObjectMeta.Annotations `sidecar.istio.io/proxyCPU` }}" + {{ end}} + {{ if (isset .ObjectMeta.Annotations `sidecar.istio.io/proxyMemory`) -}} + memory: "{{ index .ObjectMeta.Annotations `sidecar.istio.io/proxyMemory` }}" + {{ end }} + {{ else -}} +{{- if .Values.global.proxy.resources }} + {{ toYaml .Values.global.proxy.resources | indent 4 }} +{{- end }} + {{ end -}} + volumeMounts: + {{ if (isset .ObjectMeta.Annotations `sidecar.istio.io/bootstrapOverride`) }} + - mountPath: /etc/istio/custom-bootstrap + name: custom-bootstrap-volume + {{- end }} + - mountPath: /etc/istio/proxy + name: istio-envoy + {{- if .Values.global.sds.enabled }} + - mountPath: /var/run/sds + name: sds-uds-path + readOnly: true + - mountPath: /var/run/secrets/tokens + name: istio-token + {{- if .Values.global.sds.customTokenDirectory }} + - mountPath: "{{ .Values.global.sds.customTokenDirectory -}}" + name: custom-sds-token + readOnly: true + {{- end }} + {{- else }} + - mountPath: /etc/certs/ + name: istio-certs + readOnly: true + {{- end }} + {{- if and (eq .Values.global.proxy.tracer "lightstep") .Values.global.tracer.lightstep.cacertPath }} + - mountPath: {{ directory .ProxyConfig.GetTracing.GetLightstep.GetCacertPath }} + name: lightstep-certs + readOnly: true + {{- end }} + {{- if isset .ObjectMeta.Annotations `sidecar.istio.io/userVolumeMount` }} + {{ range $index, $value := fromJSON (index .ObjectMeta.Annotations `sidecar.istio.io/userVolumeMount`) }} + - name: "{{ $index }}" + {{ toYaml $value | indent 4 }} + {{ end }} + {{- end }} +volumes: +{{- if (isset .ObjectMeta.Annotations `sidecar.istio.io/bootstrapOverride`) }} +- name: custom-bootstrap-volume + configMap: + name: {{ annotation .ObjectMeta `sidecar.istio.io/bootstrapOverride` "" }} +{{- end }} +- emptyDir: + medium: Memory + name: istio-envoy +{{- if .Values.global.sds.enabled }} +- name: sds-uds-path + hostPath: + path: /var/run/sds +- name: istio-token + projected: + sources: + - serviceAccountToken: + path: istio-token + expirationSeconds: 43200 + audience: {{ .Values.global.sds.token.aud }} +{{- if .Values.global.sds.customTokenDirectory }} +- name: custom-sds-token + secret: + secretName: sdstokensecret +{{- end }} +{{- else }} +- name: istio-certs + secret: + optional: true + {{ if eq .Spec.ServiceAccountName "" }} + secretName: istio.default + {{ else -}} + secretName: {{ printf "istio.%s" .Spec.ServiceAccountName }} + {{ end -}} + {{- if isset .ObjectMeta.Annotations `sidecar.istio.io/userVolume` }} + {{range $index, $value := fromJSON (index .ObjectMeta.Annotations `sidecar.istio.io/userVolume`) }} +- name: "{{ $index }}" + {{ toYaml $value | indent 2 }} + {{ end }} + {{ end }} +{{- end }} +{{- if and (eq .Values.global.proxy.tracer "lightstep") .Values.global.tracer.lightstep.cacertPath }} +- name: lightstep-certs + secret: + optional: true + secretName: lightstep.cacert +{{- end }} +{{- if .Values.global.podDNSSearchNamespaces }} +dnsConfig: + searches: + {{- range .Values.global.podDNSSearchNamespaces }} + - {{ render . }} + {{- end }} +{{- end }} +podRedirectAnnot: + sidecar.istio.io/interceptionMode: "{{ annotation .ObjectMeta `sidecar.istio.io/interceptionMode` .ProxyConfig.InterceptionMode }}" + traffic.sidecar.istio.io/includeOutboundIPRanges: "{{ annotation .ObjectMeta `traffic.sidecar.istio.io/includeOutboundIPRanges` .Values.global.proxy.includeIPRanges }}" + traffic.sidecar.istio.io/excludeOutboundIPRanges: "{{ annotation .ObjectMeta `traffic.sidecar.istio.io/excludeOutboundIPRanges` .Values.global.proxy.excludeIPRanges }}" + traffic.sidecar.istio.io/includeInboundPorts: "{{ annotation .ObjectMeta `traffic.sidecar.istio.io/includeInboundPorts` (includeInboundPorts .Spec.Containers) }}" + traffic.sidecar.istio.io/excludeInboundPorts: "{{ excludeInboundPort (annotation .ObjectMeta `status.sidecar.istio.io/port` .Values.global.proxy.statusPort) (annotation .ObjectMeta `traffic.sidecar.istio.io/excludeInboundPorts` .Values.global.proxy.excludeInboundPorts) }}" +{{ if or (isset .ObjectMeta.Annotations `traffic.sidecar.istio.io/excludeOutboundPorts`) (ne .Values.global.proxy.excludeOutboundPorts "") }} + traffic.sidecar.istio.io/excludeOutboundPorts: "{{ annotation .ObjectMeta `traffic.sidecar.istio.io/excludeOutboundPorts` .Values.global.proxy.excludeOutboundPorts }}" +{{- end }} + traffic.sidecar.istio.io/kubevirtInterfaces: "{{ index .ObjectMeta.Annotations `traffic.sidecar.istio.io/kubevirtInterfaces` }}" diff --git a/istio-1.3.5/install/kubernetes/helm/istio/requirements.yaml b/istio-1.3.5/install/kubernetes/helm/istio/requirements.yaml new file mode 100644 index 0000000..9061020 --- /dev/null +++ b/istio-1.3.5/install/kubernetes/helm/istio/requirements.yaml @@ -0,0 +1,40 @@ +dependencies: + - name: sidecarInjectorWebhook + version: 1.3.5 + condition: sidecarInjectorWebhook.enabled + - name: security + version: 1.3.5 + condition: security.enabled + - name: gateways + version: 1.3.5 + condition: gateways.enabled + - name: mixer + version: 1.3.5 + condition: or mixer.policy.enabled mixer.telemetry.enabled + - name: nodeagent + version: 1.3.5 + condition: nodeagent.enabled + - name: pilot + version: 1.3.5 + condition: pilot.enabled + - name: grafana + version: 1.3.5 + condition: grafana.enabled + - name: prometheus + version: 1.3.5 + condition: prometheus.enabled + - name: tracing + version: 1.3.5 + condition: tracing.enabled + - name: galley + version: 1.3.5 + condition: galley.enabled + - name: kiali + version: 1.3.5 + condition: kiali.enabled + - name: istiocoredns + version: 1.3.5 + condition: istiocoredns.enabled + - name: certmanager + version: 1.3.5 + condition: certmanager.enabled diff --git a/istio-1.3.5/install/kubernetes/helm/istio/templates/NOTES.txt b/istio-1.3.5/install/kubernetes/helm/istio/templates/NOTES.txt new file mode 100644 index 0000000..3b32359 --- /dev/null +++ b/istio-1.3.5/install/kubernetes/helm/istio/templates/NOTES.txt @@ -0,0 +1,29 @@ +Thank you for installing {{ .Chart.Name | title }}. + +Your release is named {{ .Release.Name | title }}. + +To get started running application with Istio, execute the following steps: + +{{- if index .Values "sidecarInjectorWebhook" "enabled" }} +1. Label namespace that application object will be deployed to by the following command (take default namespace as an example) + +$ kubectl label namespace default istio-injection=enabled +$ kubectl get namespace -L istio-injection + +2. Deploy your applications + +$ kubectl apply -f .yaml +{{- else }} +1. Download the latest release package to get sidecar injection tool + +$ curl -L https://git.io/getLatestIstio | sh - +$ mv istio-* istio-latest +$ export PATH="$PATH:$PWD/istio-latest/bin" + +2. Deploy your application by manually injecting envoy sidecar with `istioctl kube-inject` + +$ kubectl apply -f <(istioctl kube-inject -f .yaml) +{{- end }} + +For more information on running Istio, visit: +https://istio.io/ diff --git a/istio-1.3.5/install/kubernetes/helm/istio/templates/_affinity.tpl b/istio-1.3.5/install/kubernetes/helm/istio/templates/_affinity.tpl new file mode 100644 index 0000000..7639be4 --- /dev/null +++ b/istio-1.3.5/install/kubernetes/helm/istio/templates/_affinity.tpl @@ -0,0 +1,93 @@ +{{/* affinity - https://kubernetes.io/docs/concepts/configuration/assign-pod-node/ */}} + +{{- define "nodeaffinity" }} + nodeAffinity: + requiredDuringSchedulingIgnoredDuringExecution: + {{- include "nodeAffinityRequiredDuringScheduling" . }} + preferredDuringSchedulingIgnoredDuringExecution: + {{- include "nodeAffinityPreferredDuringScheduling" . }} +{{- end }} + +{{- define "nodeAffinityRequiredDuringScheduling" }} + nodeSelectorTerms: + - matchExpressions: + - key: beta.kubernetes.io/arch + operator: In + values: + {{- range $key, $val := .Values.global.arch }} + {{- if gt ($val | int) 0 }} + - {{ $key | quote }} + {{- end }} + {{- end }} + {{- $nodeSelector := default .Values.global.defaultNodeSelector .Values.nodeSelector -}} + {{- range $key, $val := $nodeSelector }} + - key: {{ $key }} + operator: In + values: + - {{ $val | quote }} + {{- end }} +{{- end }} + +{{- define "nodeAffinityPreferredDuringScheduling" }} + {{- range $key, $val := .Values.global.arch }} + {{- if gt ($val | int) 0 }} + - weight: {{ $val | int }} + preference: + matchExpressions: + - key: beta.kubernetes.io/arch + operator: In + values: + - {{ $key | quote }} + {{- end }} + {{- end }} +{{- end }} + +{{- define "podAntiAffinity" }} +{{- if or .Values.podAntiAffinityLabelSelector .Values.podAntiAffinityTermLabelSelector}} + podAntiAffinity: + {{- if .Values.podAntiAffinityLabelSelector }} + requiredDuringSchedulingIgnoredDuringExecution: + {{- include "podAntiAffinityRequiredDuringScheduling" . }} + {{- end }} + {{- if or .Values.podAntiAffinityTermLabelSelector}} + preferredDuringSchedulingIgnoredDuringExecution: + {{- include "podAntiAffinityPreferredDuringScheduling" . }} + {{- end }} +{{- end }} +{{- end }} + +{{- define "podAntiAffinityRequiredDuringScheduling" }} + {{- range $index, $item := .Values.podAntiAffinityLabelSelector }} + - labelSelector: + matchExpressions: + - key: {{ $item.key }} + operator: {{ $item.operator }} + {{- if $item.values }} + values: + {{- $vals := split "," $item.values }} + {{- range $i, $v := $vals }} + - {{ $v | quote }} + {{- end }} + {{- end }} + topologyKey: {{ $item.topologyKey }} + {{- end }} +{{- end }} + +{{- define "podAntiAffinityPreferredDuringScheduling" }} + {{- range $index, $item := .Values.podAntiAffinityTermLabelSelector }} + - podAffinityTerm: + labelSelector: + matchExpressions: + - key: {{ $item.key }} + operator: {{ $item.operator }} + {{- if $item.values }} + values: + {{- $vals := split "," $item.values }} + {{- range $i, $v := $vals }} + - {{ $v | quote }} + {{- end }} + {{- end }} + topologyKey: {{ $item.topologyKey }} + weight: 100 + {{- end }} +{{- end }} diff --git a/istio-1.3.5/install/kubernetes/helm/istio/templates/_helpers.tpl b/istio-1.3.5/install/kubernetes/helm/istio/templates/_helpers.tpl new file mode 100644 index 0000000..f79bea4 --- /dev/null +++ b/istio-1.3.5/install/kubernetes/helm/istio/templates/_helpers.tpl @@ -0,0 +1,46 @@ +{{/* vim: set filetype=mustache: */}} +{{/* +Expand the name of the chart. +*/}} +{{- define "istio.name" -}} +{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" -}} +{{- end -}} + +{{/* +Create a default fully qualified app name. +We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). +If release name contains chart name it will be used as a full name. +*/}} +{{- define "istio.fullname" -}} +{{- if .Values.fullnameOverride -}} +{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" -}} +{{- else -}} +{{- $name := default .Chart.Name .Values.nameOverride -}} +{{- if contains $name .Release.Name -}} +{{- .Release.Name | trunc 63 | trimSuffix "-" -}} +{{- else -}} +{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" -}} +{{- end -}} +{{- end -}} +{{- end -}} + +{{/* +Create chart name and version as used by the chart label. +*/}} +{{- define "istio.chart" -}} +{{- .Chart.Name | trunc 63 | trimSuffix "-" -}} +{{- end -}} + +{{/* +Create a fully qualified configmap name. +*/}} +{{- define "istio.configmap.fullname" -}} +{{- printf "%s-%s" .Release.Name "istio-mesh-config" | trunc 63 | trimSuffix "-" -}} +{{- end -}} + +{{/* +Configmap checksum. +*/}} +{{- define "istio.configmap.checksum" -}} +{{- print $.Template.BasePath "/configmap.yaml" | sha256sum -}} +{{- end -}} diff --git a/istio-1.3.5/install/kubernetes/helm/istio/templates/_podDisruptionBudget.tpl b/istio-1.3.5/install/kubernetes/helm/istio/templates/_podDisruptionBudget.tpl new file mode 100644 index 0000000..ebb8606 --- /dev/null +++ b/istio-1.3.5/install/kubernetes/helm/istio/templates/_podDisruptionBudget.tpl @@ -0,0 +1,3 @@ +{{- define "podDisruptionBudget.spec" }} + minAvailable: 1 +{{- end }} diff --git a/istio-1.3.5/install/kubernetes/helm/istio/templates/clusterrole.yaml b/istio-1.3.5/install/kubernetes/helm/istio/templates/clusterrole.yaml new file mode 100644 index 0000000..b92c9ef --- /dev/null +++ b/istio-1.3.5/install/kubernetes/helm/istio/templates/clusterrole.yaml @@ -0,0 +1,11 @@ +kind: ClusterRole +apiVersion: rbac.authorization.k8s.io/v1 +metadata: + name: istio-reader +rules: + - apiGroups: [''] + resources: ['nodes', 'pods', 'services', 'endpoints', "replicationcontrollers"] + verbs: ['get', 'watch', 'list'] + - apiGroups: ["extensions", "apps"] + resources: ["replicasets"] + verbs: ["get", "list", "watch"] diff --git a/istio-1.3.5/install/kubernetes/helm/istio/templates/clusterrolebinding.yaml b/istio-1.3.5/install/kubernetes/helm/istio/templates/clusterrolebinding.yaml new file mode 100644 index 0000000..827601b --- /dev/null +++ b/istio-1.3.5/install/kubernetes/helm/istio/templates/clusterrolebinding.yaml @@ -0,0 +1,14 @@ +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: istio-multi + labels: + chart: {{ .Chart.Name }}-{{ .Chart.Version }} +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: istio-reader +subjects: +- kind: ServiceAccount + name: istio-multi + namespace: {{ .Release.Namespace }} diff --git a/istio-1.3.5/install/kubernetes/helm/istio/templates/configmap.yaml b/istio-1.3.5/install/kubernetes/helm/istio/templates/configmap.yaml new file mode 100644 index 0000000..063f2aa --- /dev/null +++ b/istio-1.3.5/install/kubernetes/helm/istio/templates/configmap.yaml @@ -0,0 +1,307 @@ +{{- if or .Values.pilot.enabled .Values.global.istioRemote }} +apiVersion: v1 +kind: ConfigMap +metadata: + name: istio + namespace: {{ .Release.Namespace }} + labels: + app: {{ template "istio.name" . }} + chart: {{ template "istio.chart" . }} + heritage: {{ .Release.Service }} + release: {{ .Release.Name }} +data: + mesh: |- + # Set the following variable to true to disable policy checks by the Mixer. + # Note that metrics will still be reported to the Mixer. + {{- if .Values.mixer.policy.enabled }} + disablePolicyChecks: {{ .Values.global.disablePolicyChecks }} + {{- else }} + disablePolicyChecks: true + {{- end }} + + {{- if .Values.mixer.telemetry.reportBatchMaxEntries }} + # reportBatchMaxEntries is the number of requests that are batched before telemetry data is sent to the mixer server + reportBatchMaxEntries: {{ .Values.mixer.telemetry.reportBatchMaxEntries }} + {{- end }} + + {{- if .Values.mixer.telemetry.reportBatchMaxTime }} + # reportBatchMaxTime is the max waiting time before the telemetry data of a request is sent to the mixer server + reportBatchMaxTime: {{ .Values.mixer.telemetry.reportBatchMaxTime }} + {{- end }} + + {{- if .Values.mixer.telemetry.sessionAffinityEnabled }} + # sidecarToTelemetrySessionAffinity will create a STRICT_DNS type cluster for istio-telemetry. + sidecarToTelemetrySessionAffinity: {{ .Values.mixer.telemetry.sessionAffinityEnabled }} + {{- end }} + + # Set enableTracing to false to disable request tracing. + enableTracing: {{ .Values.global.enableTracing }} + + # Set accessLogFile to empty string to disable access log. + accessLogFile: "{{ .Values.global.proxy.accessLogFile }}" + + # If accessLogEncoding is TEXT, value will be used directly as the log format + # example: "[%START_TIME%] %REQ(:METHOD)% %REQ(X-ENVOY-ORIGINAL-PATH?:PATH)% %PROTOCOL%\n" + # If AccessLogEncoding is JSON, value will be parsed as map[string]string + # example: '{"start_time": "%START_TIME%", "req_method": "%REQ(:METHOD)%"}' + # Leave empty to use default log format + accessLogFormat: {{ .Values.global.proxy.accessLogFormat | quote }} + + # Set accessLogEncoding to JSON or TEXT to configure sidecar access log + accessLogEncoding: '{{ .Values.global.proxy.accessLogEncoding }}' + + enableEnvoyAccessLogService: {{ .Values.global.proxy.envoyAccessLogService.enabled }} + + {{- if .Values.global.istioRemote }} + + {{- if .Values.global.remotePolicyAddress }} + {{- if .Values.global.createRemoteSvcEndpoints }} + mixerCheckServer: istio-policy.{{ .Release.Namespace }}:15004 + {{- else }} + mixerCheckServer: {{ .Values.global.remotePolicyAddress }}:15004 + {{- end }} + {{- end }} + {{- if .Values.global.remoteTelemetryAddress }} + {{- if .Values.global.createRemoteSvcEndpoints }} + mixerReportServer: istio-telemetry.{{ .Release.Namespace }}:15004 + {{- else }} + mixerReportServer: {{ .Values.global.remoteTelemetryAddress }}:15004 + {{- end }} + {{- end }} + + {{- else }} + + {{- if .Values.mixer.policy.enabled }} + {{- if .Values.global.controlPlaneSecurityEnabled }} + mixerCheckServer: istio-policy.{{ .Release.Namespace }}.svc.{{ .Values.global.proxy.clusterDomain }}:15004 + {{- else }} + mixerCheckServer: istio-policy.{{ .Release.Namespace }}.svc.{{ .Values.global.proxy.clusterDomain }}:9091 + {{- end }} + {{- end }} + {{- if .Values.mixer.telemetry.enabled }} + {{- if .Values.global.controlPlaneSecurityEnabled }} + mixerReportServer: istio-telemetry.{{ .Release.Namespace }}.svc.{{ .Values.global.proxy.clusterDomain }}:15004 + {{- else }} + mixerReportServer: istio-telemetry.{{ .Release.Namespace }}.svc.{{ .Values.global.proxy.clusterDomain }}:9091 + {{- end }} + {{- end }} + + {{- end }} + + {{- if or .Values.mixer.policy.enabled (and .Values.global.istioRemote .Values.global.remotePolicyAddress) }} + # policyCheckFailOpen allows traffic in cases when the mixer policy service cannot be reached. + # Default is false which means the traffic is denied when the client is unable to connect to Mixer. + policyCheckFailOpen: {{ .Values.global.policyCheckFailOpen }} + {{- end }} + + {{- if .Values.gateways.enabled }} + # Let Pilot give ingresses the public IP of the Istio ingressgateway + ingressService: istio-ingressgateway + {{- end }} + + # Default connect timeout for dynamic clusters generated by Pilot and returned via XDS + connectTimeout: 10s + + # Automatic protocol detection uses a set of heuristics to + # determine whether the connection is using TLS or not (on the + # server side), as well as the application protocol being used + # (e.g., http vs tcp). These heuristics rely on the client sending + # the first bits of data. For server first protocols like MySQL, + # MongoDB, etc., Envoy will timeout on the protocol detection after + # the specified period, defaulting to non mTLS plain TCP + # traffic. Set this field to tweak the period that Envoy will wait + # for the client to send the first bits of data. (MUST BE >=1ms) + protocolDetectionTimeout: {{ .Values.global.proxy.protocolDetectionTimeout }} + + # DNS refresh rate for Envoy clusters of type STRICT_DNS + dnsRefreshRate: {{ .Values.global.proxy.dnsRefreshRate }} + + # Unix Domain Socket through which envoy communicates with NodeAgent SDS to get + # key/cert for mTLS. Use secret-mount files instead of SDS if set to empty. + sdsUdsPath: {{ .Values.global.sds.udsPath | quote }} + + # The trust domain corresponds to the trust root of a system. + # Refer to https://github.com/spiffe/spiffe/blob/master/standards/SPIFFE-ID.md#21-trust-domain + trustDomain: {{ .Values.global.trustDomain | quote }} + + # Set the default behavior of the sidecar for handling outbound traffic from the application: + # ALLOW_ANY - outbound traffic to unknown destinations will be allowed, in case there are no + # services or ServiceEntries for the destination port + # REGISTRY_ONLY - restrict outbound traffic to services defined in the service registry as well + # as those defined through ServiceEntries + outboundTrafficPolicy: + mode: {{ .Values.global.outboundTrafficPolicy.mode }} + + {{- if .Values.global.localityLbSetting.enabled }} + localityLbSetting: +{{ toYaml .Values.global.localityLbSetting | trim | indent 6 }} + {{- end }} + # The namespace to treat as the administrative root namespace for istio + # configuration. +{{- if .Values.global.configRootNamespace }} + rootNamespace: {{ .Values.global.configRootNamespace }} +{{- else }} + rootNamespace: {{ .Release.Namespace }} +{{- end }} + + {{- if .Values.global.defaultConfigVisibilitySettings }} + defaultServiceExportTo: + {{- range .Values.global.defaultConfigVisibilitySettings }} + - {{ . | quote }} + {{- end }} + defaultVirtualServiceExportTo: + {{- range .Values.global.defaultConfigVisibilitySettings }} + - {{ . | quote }} + {{- end }} + defaultDestinationRuleExportTo: + {{- range .Values.global.defaultConfigVisibilitySettings }} + - {{ . | quote }} + {{- end }} + {{- end }} + + {{- if $.Values.global.useMCP }} + configSources: + - address: istio-galley.{{ $.Release.Namespace }}.svc:9901 + {{- if $.Values.global.controlPlaneSecurityEnabled}} + tlsSettings: + mode: ISTIO_MUTUAL + {{- end }} + {{- end }} + + defaultConfig: + # + # TCP connection timeout between Envoy & the application, and between Envoys. Used for static clusters + # defined in Envoy's configuration file + connectTimeout: 10s + # + ### ADVANCED SETTINGS ############# + # Where should envoy's configuration be stored in the istio-proxy container + configPath: "/etc/istio/proxy" + binaryPath: "/usr/local/bin/envoy" + # The pseudo service name used for Envoy. + serviceCluster: istio-proxy + # These settings that determine how long an old Envoy + # process should be kept alive after an occasional reload. + drainDuration: 45s + parentShutdownDuration: 1m0s + # + # The mode used to redirect inbound connections to Envoy. This setting + # has no effect on outbound traffic: iptables REDIRECT is always used for + # outbound connections. + # If "REDIRECT", use iptables REDIRECT to NAT and redirect to Envoy. + # The "REDIRECT" mode loses source addresses during redirection. + # If "TPROXY", use iptables TPROXY to redirect to Envoy. + # The "TPROXY" mode preserves both the source and destination IP + # addresses and ports, so that they can be used for advanced filtering + # and manipulation. + # The "TPROXY" mode also configures the sidecar to run with the + # CAP_NET_ADMIN capability, which is required to use TPROXY. + #interceptionMode: REDIRECT + # + # Port where Envoy listens (on local host) for admin commands + # You can exec into the istio-proxy container in a pod and + # curl the admin port (curl http://localhost:15000/) to obtain + # diagnostic information from Envoy. See + # https://lyft.github.io/envoy/docs/operations/admin.html + # for more details + proxyAdminPort: 15000 + # + # Set concurrency to a specific number to control the number of Proxy worker threads. + # If set to 0 (default), then start worker thread for each CPU thread/core. + concurrency: {{ .Values.global.proxy.concurrency }} + # + {{- if eq .Values.global.proxy.tracer "lightstep" }} + tracing: + lightstep: + # Address of the LightStep Satellite pool + address: {{ .Values.global.tracer.lightstep.address }} + # Access Token used to communicate with the Satellite pool + accessToken: {{ .Values.global.tracer.lightstep.accessToken }} + # Whether communication with the Satellite pool should be secure + secure: {{ .Values.global.tracer.lightstep.secure }} + # Path to the file containing the cacert to use when verifying TLS + cacertPath: {{ .Values.global.tracer.lightstep.cacertPath }} + {{- else if eq .Values.global.proxy.tracer "zipkin" }} + tracing: + zipkin: + # Address of the Zipkin collector + {{- if .Values.global.tracer.zipkin.address }} + address: {{ .Values.global.tracer.zipkin.address }} + {{- else if .Values.global.remoteZipkinAddress }} + address: {{ .Values.global.remoteZipkinAddress }}:9411 + {{- else }} + address: zipkin.{{ .Release.Namespace }}:9411 + {{- end }} + {{- else if eq .Values.global.proxy.tracer "datadog" }} + tracing: + datadog: + # Address of the Datadog Agent + address: {{ .Values.global.tracer.datadog.address }} + {{- else if eq .Values.global.proxy.tracer "stackdriver" }} + tracing: + stackdriver: {} + {{- end }} + + {{- if .Values.global.proxy.envoyStatsd.enabled }} + # + # Statsd metrics collector converts statsd metrics into Prometheus metrics. + statsdUdpAddress: {{ .Values.global.proxy.envoyStatsd.host }}:{{ .Values.global.proxy.envoyStatsd.port }} + {{- end }} + + {{- if .Values.global.proxy.envoyMetricsService.enabled }} + # + # Envoy's Metrics Service stats sink pushes Envoy metrics to a remote collector via the Metrics Service gRPC API. + envoyMetricsService: + address: {{ .Values.global.proxy.envoyMetricsService.host }}:{{ .Values.global.proxy.envoyMetricsService.port }} + {{- end}} + + {{- if .Values.global.proxy.envoyAccessLogService.enabled }} + # + # Envoy's AccessLog Service pushes access logs to a remote collector via the Access Log Service gRPC API. + envoyAccessLogService: + address: {{ .Values.global.proxy.envoyAccessLogService.host }}:{{ .Values.global.proxy.envoyAccessLogService.port }} + {{- if .Values.global.proxy.envoyAccessLogService.tlsSettings }} + tlsSettings: +{{ toYaml .Values.global.proxy.envoyAccessLogService.tlsSettings | indent 10 }} + {{- end}} + {{- if .Values.global.proxy.envoyAccessLogService.tcpKeepalive }} + tcpKeepalive: +{{ toYaml .Values.global.proxy.envoyAccessLogService.tcpKeepalive | indent 10 }} + {{- end}} + {{- end}} + + {{- $defPilotHostname := printf "istio-pilot.%s" .Release.Namespace }} + {{- $pilotAddress := .Values.global.remotePilotAddress | default $defPilotHostname }} + {{- if .Values.global.controlPlaneSecurityEnabled }} + # + # Mutual TLS authentication between sidecars and istio control plane. + controlPlaneAuthPolicy: MUTUAL_TLS + # + # Address where istio Pilot service is running + {{- if or .Values.global.remotePilotCreateSvcEndpoint .Values.global.createRemoteSvcEndpoints }} + discoveryAddress: {{ $defPilotHostname }}:15011 + {{- else }} + discoveryAddress: {{ $pilotAddress }}:15011 + {{- end }} + {{- else }} + # + # Mutual TLS authentication between sidecars and istio control plane. + controlPlaneAuthPolicy: NONE + # + # Address where istio Pilot service is running + {{- if or .Values.global.remotePilotCreateSvcEndpoint .Values.global.createRemoteSvcEndpoints }} + discoveryAddress: {{ $defPilotHostname }}:15010 + {{- else }} + discoveryAddress: {{ $pilotAddress }}:15010 + {{- end }} + {{- end }} + + # Configuration file for the mesh networks to be used by the Split Horizon EDS. + meshNetworks: |- + {{- if .Values.global.meshNetworks }} + networks: +{{ toYaml .Values.global.meshNetworks | indent 6 }} + {{- else }} + networks: {} + {{- end }} +{{- end }} diff --git a/istio-1.3.5/install/kubernetes/helm/istio/templates/endpoints.yaml b/istio-1.3.5/install/kubernetes/helm/istio/templates/endpoints.yaml new file mode 100644 index 0000000..81b8218 --- /dev/null +++ b/istio-1.3.5/install/kubernetes/helm/istio/templates/endpoints.yaml @@ -0,0 +1,63 @@ +{{- if or .Values.global.remotePilotCreateSvcEndpoint .Values.global.createRemoteSvcEndpoints }} +apiVersion: v1 +kind: Endpoints +metadata: + name: istio-pilot + namespace: {{ .Release.Namespace }} +subsets: +- addresses: + - ip: {{ .Values.global.remotePilotAddress }} + ports: + - port: 15003 + name: http-old-discovery # mTLS or non-mTLS depending on auth setting + - port: 15005 + name: https-discovery # always mTLS + - port: 15007 + name: http-discovery # always plain-text + - port: 15010 + name: grpc-xds # direct + - port: 15011 + name: https-xds # mTLS or non-mTLS depending on auth setting + - port: 8080 + name: http-legacy-discovery # direct + - port: 15014 + name: http-monitoring +{{- end }} +{{- if and .Values.global.remotePolicyAddress .Values.global.createRemoteSvcEndpoints }} +--- +apiVersion: v1 +kind: Endpoints +metadata: + name: istio-policy + namespace: {{ .Release.Namespace }} +subsets: +- addresses: + - ip: {{ .Values.global.remotePolicyAddress }} + ports: + - name: grpc-mixer + port: 9091 + - name: grpc-mixer-mtls + port: 15004 + - name: http-monitoring + port: 15014 +{{- end }} +{{- if and .Values.global.remoteTelemetryAddress .Values.global.createRemoteSvcEndpoints }} +--- +apiVersion: v1 +kind: Endpoints +metadata: + name: istio-telemetry + namespace: {{ .Release.Namespace }} +subsets: +- addresses: + - ip: {{ .Values.global.remoteTelemetryAddress }} + ports: + - name: grpc-mixer + port: 9091 + - name: grpc-mixer-mtls + port: 15004 + - name: http-monitoring + port: 15014 + - name: prometheus + port: 42422 +{{- end }} diff --git a/istio-1.3.5/install/kubernetes/helm/istio/templates/install-custom-resources.sh.tpl b/istio-1.3.5/install/kubernetes/helm/istio/templates/install-custom-resources.sh.tpl new file mode 100644 index 0000000..a5525a1 --- /dev/null +++ b/istio-1.3.5/install/kubernetes/helm/istio/templates/install-custom-resources.sh.tpl @@ -0,0 +1,32 @@ +{{ define "install-custom-resources.sh.tpl" }} +#!/bin/sh + +set -x + +if [ "$#" -ne "1" ]; then + echo "first argument should be path to custom resource yaml" + exit 1 +fi + +pathToResourceYAML=${1} + +kubectl get validatingwebhookconfiguration istio-galley 2>/dev/null +if [ "$?" -eq 0 ]; then + echo "istio-galley validatingwebhookconfiguration found - waiting for istio-galley deployment to be ready" + while true; do + kubectl -n {{ .Release.Namespace }} get deployment istio-galley 2>/dev/null + if [ "$?" -eq 0 ]; then + break + fi + sleep 1 + done + kubectl -n {{ .Release.Namespace }} rollout status deployment istio-galley + if [ "$?" -ne 0 ]; then + echo "istio-galley deployment rollout status check failed" + exit 1 + fi + echo "istio-galley deployment ready for configuration validation" +fi +sleep 5 +kubectl apply -f ${pathToResourceYAML} +{{ end }} diff --git a/istio-1.3.5/install/kubernetes/helm/istio/templates/service.yaml b/istio-1.3.5/install/kubernetes/helm/istio/templates/service.yaml new file mode 100644 index 0000000..732cdef --- /dev/null +++ b/istio-1.3.5/install/kubernetes/helm/istio/templates/service.yaml @@ -0,0 +1,60 @@ +{{- if or .Values.global.remotePilotCreateSvcEndpoint .Values.global.createRemoteSvcEndpoints }} +apiVersion: v1 +kind: Service +metadata: + name: istio-pilot + namespace: {{ .Release.Namespace }} +spec: + ports: + - port: 15003 + name: http-old-discovery # mTLS or non-mTLS depending on auth setting + - port: 15005 + name: https-discovery # always mTLS + - port: 15007 + name: http-discovery # always plain-text + - port: 15010 + name: grpc-xds # direct + - port: 15011 + name: https-xds # mTLS or non-mTLS depending on auth setting + - port: 8080 + name: http-legacy-discovery # direct + - port: 15014 + name: http-monitoring + clusterIP: None +{{- end }} +{{- if and .Values.global.remotePolicyAddress .Values.global.createRemoteSvcEndpoints }} +--- +apiVersion: v1 +kind: Service +metadata: + name: istio-policy + namespace: {{ .Release.Namespace }} +spec: + ports: + - name: grpc-mixer + port: 9091 + - name: grpc-mixer-mtls + port: 15004 + - name: http-monitoring + port: 15014 + clusterIP: None +{{- end }} +{{- if and .Values.global.remoteTelemetryAddress .Values.global.createRemoteSvcEndpoints }} +--- +apiVersion: v1 +kind: Service +metadata: + name: istio-telemetry + namespace: {{ .Release.Namespace }} +spec: + ports: + - name: grpc-mixer + port: 9091 + - name: grpc-mixer-mtls + port: 15004 + - name: http-monitoring + port: 15014 + - name: prometheus + port: 42422 + clusterIP: None +{{- end }} diff --git a/istio-1.3.5/install/kubernetes/helm/istio/templates/serviceaccount.yaml b/istio-1.3.5/install/kubernetes/helm/istio/templates/serviceaccount.yaml new file mode 100644 index 0000000..e52d9eb --- /dev/null +++ b/istio-1.3.5/install/kubernetes/helm/istio/templates/serviceaccount.yaml @@ -0,0 +1,5 @@ +apiVersion: v1 +kind: ServiceAccount +metadata: + name: istio-multi + namespace: {{ .Release.Namespace }} diff --git a/istio-1.3.5/install/kubernetes/helm/istio/templates/sidecar-injector-configmap.yaml b/istio-1.3.5/install/kubernetes/helm/istio/templates/sidecar-injector-configmap.yaml new file mode 100644 index 0000000..135b7fb --- /dev/null +++ b/istio-1.3.5/install/kubernetes/helm/istio/templates/sidecar-injector-configmap.yaml @@ -0,0 +1,25 @@ +{{- if not .Values.global.omitSidecarInjectorConfigMap }} +apiVersion: v1 +kind: ConfigMap +metadata: + name: istio-sidecar-injector + namespace: {{ .Release.Namespace }} + labels: + app: {{ template "istio.name" . }} + chart: {{ template "istio.chart" . }} + heritage: {{ .Release.Service }} + release: {{ .Release.Name }} + istio: sidecar-injector +data: + values: |- + {{ .Values | toJson }} + + config: |- + policy: {{ .Values.global.proxy.autoInject }} + alwaysInjectSelector: +{{ toYaml .Values.sidecarInjectorWebhook.alwaysInjectSelector | trim | indent 6 }} + neverInjectSelector: +{{ toYaml .Values.sidecarInjectorWebhook.neverInjectSelector | trim | indent 6 }} + template: |- +{{ .Files.Get "files/injection-template.yaml" | trim | indent 6 }} +{{- end }} diff --git a/istio-1.3.5/install/kubernetes/helm/istio/values-istio-demo-auth.yaml b/istio-1.3.5/install/kubernetes/helm/istio/values-istio-demo-auth.yaml new file mode 100644 index 0000000..76abed3 --- /dev/null +++ b/istio-1.3.5/install/kubernetes/helm/istio/values-istio-demo-auth.yaml @@ -0,0 +1,87 @@ +# This is used to generate minimal demo mode. It is included from demo and demo-auth values. +# It is shipped with the release, used for bookinfo or quick installation of istio. +# Includes components used in the demo, defaults to alpha3 rules. +# Note: please only put common configuration for the demo profiles here. +global: + proxy: + accessLogFile: "/dev/stdout" + resources: + requests: + cpu: 10m + memory: 40Mi + + disablePolicyChecks: false + +sidecarInjectorWebhook: + enabled: true + # If true, webhook or istioctl injector will rewrite PodSpec for liveness + # health check to redirect request to sidecar. This makes liveness check work + # even when mTLS is enabled. + rewriteAppHTTPProbe: false + +pilot: + autoscaleEnabled: false + traceSampling: 100.0 + resources: + requests: + cpu: 10m + memory: 100Mi + +mixer: + policy: + enabled: true + autoscaleEnabled: false + resources: + requests: + cpu: 10m + memory: 100Mi + + telemetry: + enabled: true + autoscaleEnabled: false + resources: + requests: + cpu: 50m + memory: 100Mi + + adapters: + stdio: + enabled: true + +grafana: + enabled: true + +tracing: + enabled: true + +kiali: + enabled: true + createDemoSecret: true + +gateways: + istio-ingressgateway: + autoscaleEnabled: false + resources: + requests: + cpu: 10m + memory: 40Mi + + istio-egressgateway: + enabled: true + autoscaleEnabled: false + resources: + requests: + cpu: 10m + memory: 40Mi +# This is used to generate istio-auth.yaml for minimal, demo mode with MTLS enabled. +# It is shipped with the release, used for bookinfo or quick installation of istio. +# Includes components used in the demo, defaults to alpha3 rules. + +# @include +global: + controlPlaneSecurityEnabled: true + + mtls: + # Default setting for service-to-service mtls. Can be set explicitly using + # destination rules or service annotations. + enabled: true diff --git a/istio-1.3.5/install/kubernetes/helm/istio/values-istio-demo.yaml b/istio-1.3.5/install/kubernetes/helm/istio/values-istio-demo.yaml new file mode 100644 index 0000000..2a9bf89 --- /dev/null +++ b/istio-1.3.5/install/kubernetes/helm/istio/values-istio-demo.yaml @@ -0,0 +1,88 @@ +# This is used to generate minimal demo mode. It is included from demo and demo-auth values. +# It is shipped with the release, used for bookinfo or quick installation of istio. +# Includes components used in the demo, defaults to alpha3 rules. +# Note: please only put common configuration for the demo profiles here. +global: + proxy: + accessLogFile: "/dev/stdout" + resources: + requests: + cpu: 10m + memory: 40Mi + + disablePolicyChecks: false + +sidecarInjectorWebhook: + enabled: true + # If true, webhook or istioctl injector will rewrite PodSpec for liveness + # health check to redirect request to sidecar. This makes liveness check work + # even when mTLS is enabled. + rewriteAppHTTPProbe: false + +pilot: + autoscaleEnabled: false + traceSampling: 100.0 + resources: + requests: + cpu: 10m + memory: 100Mi + +mixer: + policy: + enabled: true + autoscaleEnabled: false + resources: + requests: + cpu: 10m + memory: 100Mi + + telemetry: + enabled: true + autoscaleEnabled: false + resources: + requests: + cpu: 50m + memory: 100Mi + + adapters: + stdio: + enabled: true + +grafana: + enabled: true + +tracing: + enabled: true + +kiali: + enabled: true + createDemoSecret: true + +gateways: + istio-ingressgateway: + autoscaleEnabled: false + resources: + requests: + cpu: 10m + memory: 40Mi + + istio-egressgateway: + enabled: true + autoscaleEnabled: false + resources: + requests: + cpu: 10m + memory: 40Mi +# This is used to generate istio.yaml for minimal, demo mode. +# It is shipped with the release, used for bookinfo or quick installation of istio. +# Includes components used in the demo, defaults to alpha3 rules. + +# @include +# +global: + controlPlaneSecurityEnabled: false + + mtls: + # Default setting for service-to-service mtls. Can be set explicitly using + # destination rules or service annotations. + enabled: false diff --git a/istio-1.3.5/install/kubernetes/helm/istio/values-istio-minimal.yaml b/istio-1.3.5/install/kubernetes/helm/istio/values-istio-minimal.yaml new file mode 100644 index 0000000..de45fa4 --- /dev/null +++ b/istio-1.3.5/install/kubernetes/helm/istio/values-istio-minimal.yaml @@ -0,0 +1,46 @@ +# +# Minimal Istio Configuration: https://istio.io/docs/setup/kubernetes/additional-setup/config-profiles/ +# +pilot: + enabled: true + sidecar: false + +gateways: + enabled: false + +security: + enabled: false + +sidecarInjectorWebhook: + enabled: false + +galley: + enabled: false + +mixer: + policy: + enabled: false + telemetry: + enabled: false + +prometheus: + enabled: false + + +# Common settings. +global: + + proxy: + # Sets the destination Statsd in envoy (the value of the "--statsdUdpAddress" proxy argument + # would be :). + # Disabled by default. + # The istio-statsd-prom-bridge is deprecated and should not be used moving forward. + envoyStatsd: + # If enabled is set to true, host and port must also be provided. Istio no longer provides a statsd collector. + enabled: false + host: # example: statsd-svc.istio-system + port: # example: 9125 + + useMCP: false + + diff --git a/istio-1.3.5/install/kubernetes/helm/istio/values-istio-remote.yaml b/istio-1.3.5/install/kubernetes/helm/istio/values-istio-remote.yaml new file mode 100644 index 0000000..20fe2ac --- /dev/null +++ b/istio-1.3.5/install/kubernetes/helm/istio/values-istio-remote.yaml @@ -0,0 +1,34 @@ +gateways: + enabled: false + +galley: + enabled: false + +mixer: + policy: + enabled: false + telemetry: + enabled: false + +pilot: + enabled: false + +security: + enabled: true + createMeshPolicy: false + +prometheus: + enabled: false + +global: + istioRemote: true + + enableTracing: false + + # Sets an identifier for the remote network to be used for Split Horizon EDS. The network will be sent + # to the Pilot when connected by the sidecar and will affect the results returned in EDS requests. + # Based on the network identifier Pilot will return all local endpoints + endpoints of gateways to + # other networks. + # + # Must match the names in the meshNetworks section in the Istio local. + network: "" diff --git a/istio-1.3.5/install/kubernetes/helm/istio/values-istio-sds-auth-control-plane-auth-disabled.yaml b/istio-1.3.5/install/kubernetes/helm/istio/values-istio-sds-auth-control-plane-auth-disabled.yaml new file mode 100644 index 0000000..6144aff --- /dev/null +++ b/istio-1.3.5/install/kubernetes/helm/istio/values-istio-sds-auth-control-plane-auth-disabled.yaml @@ -0,0 +1,21 @@ +global: + controlPlaneSecurityEnabled: false + + mtls: + # Default setting for service-to-service mtls. Can be set explicitly using + # destination rules or service annotations. + enabled: true + + sds: + enabled: true + udsPath: "unix:/var/run/sds/uds_path" + token: + aud: "istio-ca" + +nodeagent: + enabled: true + image: node-agent-k8s + env: + CA_PROVIDER: "Citadel" + CA_ADDR: "istio-citadel:8060" + VALID_TOKEN: true diff --git a/istio-1.3.5/install/kubernetes/helm/istio/values-istio-sds-auth.yaml b/istio-1.3.5/install/kubernetes/helm/istio/values-istio-sds-auth.yaml new file mode 100644 index 0000000..d6b8c65 --- /dev/null +++ b/istio-1.3.5/install/kubernetes/helm/istio/values-istio-sds-auth.yaml @@ -0,0 +1,21 @@ +global: + controlPlaneSecurityEnabled: true + + mtls: + # Default setting for service-to-service mtls. Can be set explicitly using + # destination rules or service annotations. + enabled: true + + sds: + enabled: true + udsPath: "unix:/var/run/sds/uds_path" + token: + aud: "istio-ca" + +nodeagent: + enabled: true + image: node-agent-k8s + env: + CA_PROVIDER: "Citadel" + CA_ADDR: "istio-citadel:8060" + VALID_TOKEN: true \ No newline at end of file diff --git a/istio-1.3.5/install/kubernetes/helm/istio/values.yaml b/istio-1.3.5/install/kubernetes/helm/istio/values.yaml new file mode 100644 index 0000000..2f6fb88 --- /dev/null +++ b/istio-1.3.5/install/kubernetes/helm/istio/values.yaml @@ -0,0 +1,564 @@ +# Top level istio values file has the following sections. +# +# global: This file is the authoritative and exhaustive source for the global section. +# +# chart sections: Every subdirectory inside the charts/ directory has a top level +# configuration key in this file. This file overrides the values specified +# by the charts/${chartname}/values.yaml. +# Check the chart level values file for exhaustive list of configuration options. + +# +# Gateways Configuration, refer to the charts/gateways/values.yaml +# for detailed configuration +# +gateways: + enabled: true + +# +# sidecar-injector webhook configuration, refer to the +# charts/sidecarInjectorWebhook/values.yaml for detailed configuration +# +sidecarInjectorWebhook: + enabled: true + +# +# galley configuration, refer to charts/galley/values.yaml +# for detailed configuration +# +galley: + enabled: true + +# +# mixer configuration +# +# @see charts/mixer/values.yaml, it takes precedence +mixer: + policy: + # if policy is enabled the global.disablePolicyChecks has affect. + enabled: true + + telemetry: + enabled: true +# +# pilot configuration +# +# @see charts/pilot/values.yaml +pilot: + enabled: true + +# +# security configuration +# +security: + enabled: true + +# +# nodeagent configuration +# +nodeagent: + enabled: false + +# +# addon grafana configuration +# +grafana: + enabled: false + +# +# addon prometheus configuration +# +prometheus: + enabled: true + +# +# addon jaeger tracing configuration +# +tracing: + enabled: false + +# +# addon kiali tracing configuration +# +kiali: + enabled: false + +# +# addon certmanager configuration +# +certmanager: + enabled: false + +# +# Istio CNI plugin enabled +# This must be enabled to use the CNI plugin in Istio. The CNI plugin is installed separately. +# If true, the privileged initContainer istio-init is not needed to perform the traffic redirect +# settings for the istio-proxy. +# +istio_cni: + enabled: false + +# addon Istio CoreDNS configuration +# +istiocoredns: + enabled: false + +# Common settings used among istio subcharts. +global: + # Default hub for Istio images. + # Releases are published to docker hub under 'istio' project. + # Daily builds from prow are on gcr.io + hub: docker.io/istio + + # Default tag for Istio images. + tag: 1.3.5 + + # Comma-separated minimum per-scope logging level of messages to output, in the form of :,: + # The control plane has different scopes depending on component, but can configure default log level across all components + # If empty, default scope and level will be used as configured in code + logging: + level: "default:info" + + # monitoring port used by mixer, pilot, galley and sidecar injector + monitoringPort: 15014 + + k8sIngress: + enabled: false + # Gateway used for k8s Ingress resources. By default it is + # using 'istio:ingressgateway' that will be installed by setting + # 'gateways.enabled' and 'gateways.istio-ingressgateway.enabled' + # flags to true. + gatewayName: ingressgateway + # enableHttps will add port 443 on the ingress. + # It REQUIRES that the certificates are installed in the + # expected secrets - enabling this option without certificates + # will result in LDS rejection and the ingress will not work. + enableHttps: false + + proxy: + # Configuration for the proxy init container + init: + resources: + limits: + cpu: 100m + memory: 50Mi + requests: + cpu: 10m + memory: 10Mi + image: proxyv2 + + # cluster domain. Default value is "cluster.local". + clusterDomain: "cluster.local" + + # Resources for the sidecar. + resources: + requests: + cpu: 100m + memory: 128Mi + limits: + cpu: 2000m + memory: 1024Mi + + # Controls number of Proxy worker threads. + # If set to 0, then start worker thread for each CPU thread/core. + concurrency: 2 + + # Configures the access log for each sidecar. + # Options: + # "" - disables access log + # "/dev/stdout" - enables access log + accessLogFile: "" + + # Configure how and what fields are displayed in sidecar access log. Setting to + # empty string will result in default log format + accessLogFormat: "" + + # Configure the access log for sidecar to JSON or TEXT. + accessLogEncoding: TEXT + + # Configure envoy gRPC access log service. + envoyAccessLogService: + enabled: false + host: # example: accesslog-service.istio-system + port: # example: 15000 + tlsSettings: + mode: DISABLE # DISABLE, SIMPLE, MUTUAL, ISTIO_MUTUAL + clientCertificate: # example: /etc/istio/als/cert-chain.pem + privateKey: # example: /etc/istio/als/key.pem + caCertificates: # example: /etc/istio/als/root-cert.pem + sni: # example: als.somedomain + subjectAltNames: [] + # - als.somedomain + tcpKeepalive: + probes: 3 + time: 10s + interval: 10s + + # Log level for proxy, applies to gateways and sidecars. If left empty, "warning" is used. + # Expected values are: trace|debug|info|warning|error|critical|off + logLevel: "" + + # Per Component log level for proxy, applies to gateways and sidecars. If a component level is + # not set, then the global "logLevel" will be used. If left empty, "misc:error" is used. + componentLogLevel: "" + + # Configure the DNS refresh rate for Envoy cluster of type STRICT_DNS + # This must be given it terms of seconds. For example, 300s is valid but 5m is invalid. + dnsRefreshRate: 300s + + # Automatic protocol detection uses a set of heuristics to + # determine whether the connection is using TLS or not (on the + # server side), as well as the application protocol being used + # (e.g., http vs tcp). These heuristics rely on the client sending + # the first bits of data. For server first protocols like MySQL, + # MongoDB, etc., Envoy will timeout on the protocol detection after + # the specified period, defaulting to non mTLS plain TCP + # traffic. Set this field to tweak the period that Envoy will wait + # for the client to send the first bits of data. (MUST BE >=1ms) + protocolDetectionTimeout: 100ms + + #If set to true, istio-proxy container will have privileged securityContext + privileged: false + + # If set, newly injected sidecars will have core dumps enabled. + enableCoreDump: false + + # Image used to enable core dumps. This is only used, when "enableCoreDump" is set to true. + enableCoreDumpImage: ubuntu:xenial + + # Default port for Pilot agent health checks. A value of 0 will disable health checking. + statusPort: 15020 + + # The initial delay for readiness probes in seconds. + readinessInitialDelaySeconds: 1 + + # The period between readiness probes. + readinessPeriodSeconds: 2 + + # The number of successive failed probes before indicating readiness failure. + readinessFailureThreshold: 30 + + # istio egress capture whitelist + # https://istio.io/docs/tasks/traffic-management/egress.html#calling-external-services-directly + # example: includeIPRanges: "172.30.0.0/16,172.20.0.0/16" + # would only capture egress traffic on those two IP Ranges, all other outbound traffic would + # be allowed by the sidecar + includeIPRanges: "*" + excludeIPRanges: "" + excludeOutboundPorts: "" + + # pod internal interfaces + kubevirtInterfaces: "" + + # istio ingress capture whitelist + # examples: + # Redirect no inbound traffic to Envoy: --includeInboundPorts="" + # Redirect all inbound traffic to Envoy: --includeInboundPorts="*" + # Redirect only selected ports: --includeInboundPorts="80,8080" + includeInboundPorts: "*" + excludeInboundPorts: "" + + # This controls the 'policy' in the sidecar injector. + autoInject: enabled + + # Sets the destination Statsd in envoy (the value of the "--statsdUdpAddress" proxy argument + # would be :). + # Disabled by default. + # The istio-statsd-prom-bridge is deprecated and should not be used moving forward. + envoyStatsd: + # If enabled is set to true, host and port must also be provided. Istio no longer provides a statsd collector. + enabled: false + host: # example: statsd-svc.istio-system + port: # example: 9125 + + # Sets the Envoy Metrics Service address, used to push Envoy metrics to an external collector + # via the Metrics Service gRPC API. This contains detailed stats information emitted directly + # by Envoy and should not be confused with the the Istio telemetry. The Envoy stats are also + # available to scrape via the Envoy admin port at either /stats or /stats/prometheus. + # + # See https://www.envoyproxy.io/docs/envoy/latest/api-v2/config/metrics/v2/metrics_service.proto + # for details about Envoy's Metrics Service API. + # + # Disabled by default. + envoyMetricsService: + enabled: false + host: # example: metrics-service.istio-system + port: # example: 15000 + + # Specify which tracer to use. One of: zipkin, lightstep, datadog, stackdriver. + # If using stackdriver tracer outside GCP, set env GOOGLE_APPLICATION_CREDENTIALS to the GCP credential file. + tracer: "zipkin" + + proxy_init: + # Base name for the proxy_init container, used to configure iptables. + image: proxy_init + + # imagePullPolicy is applied to istio control plane components. + # local tests require IfNotPresent, to avoid uploading to dockerhub. + # TODO: Switch to Always as default, and override in the local tests. + imagePullPolicy: IfNotPresent + + # controlPlaneSecurityEnabled enabled. Will result in delays starting the pods while secrets are + # propagated, not recommended for tests. + controlPlaneSecurityEnabled: false + + # disablePolicyChecks disables mixer policy checks. + # if mixer.policy.enabled==true then disablePolicyChecks has affect. + # Will set the value with same name in istio config map - pilot needs to be restarted to take effect. + disablePolicyChecks: true + + # policyCheckFailOpen allows traffic in cases when the mixer policy service cannot be reached. + # Default is false which means the traffic is denied when the client is unable to connect to Mixer. + policyCheckFailOpen: false + + # EnableTracing sets the value with same name in istio config map, requires pilot restart to take effect. + enableTracing: true + + # Configuration for each of the supported tracers + tracer: + # Configuration for envoy to send trace data to LightStep. + # Disabled by default. + # address: the : of the satellite pool + # accessToken: required for sending data to the pool + # secure: specifies whether data should be sent with TLS + # cacertPath: the path to the file containing the cacert to use when verifying TLS. If secure is true, this is + # required. If a value is specified then a secret called "lightstep.cacert" must be created in the destination + # namespace with the key matching the base of the provided cacertPath and the value being the cacert itself. + # + lightstep: + address: "" # example: lightstep-satellite:443 + accessToken: "" # example: abcdefg1234567 + secure: true # example: true|false + cacertPath: "" # example: /etc/lightstep/cacert.pem + zipkin: + # Host:Port for reporting trace data in zipkin format. If not specified, will default to + # zipkin service (port 9411) in the same namespace as the other istio components. + address: "" + datadog: + # Host:Port for submitting traces to the Datadog agent. + address: "$(HOST_IP):8126" + + # Default mtls policy. If true, mtls between services will be enabled by default. + mtls: + # Default setting for service-to-service mtls. Can be set explicitly using + # destination rules or service annotations. + enabled: false + + # Lists the secrets you need to use to pull Istio images from a private registry. + imagePullSecrets: [] + # - private-registry-key + + # Specify pod scheduling arch(amd64, ppc64le, s390x) and weight as follows: + # 0 - Never scheduled + # 1 - Least preferred + # 2 - No preference + # 3 - Most preferred + arch: + amd64: 2 + s390x: 2 + ppc64le: 2 + + # Whether to restrict the applications namespace the controller manages; + # If not set, controller watches all namespaces + oneNamespace: false + + # Default node selector to be applied to all deployments so that all pods can be + # constrained to run a particular nodes. Each component can overwrite these default + # values by adding its node selector block in the relevant section below and setting + # the desired values. + defaultNodeSelector: {} + + # Default node tolerations to be applied to all deployments so that all pods can be + # scheduled to a particular nodes with matching taints. Each component can overwrite + # these default values by adding its tolerations block in the relevant section below + # and setting the desired values. + # Configure this field in case that all pods of Istio control plane are expected to + # be scheduled to particular nodes with specified taints. + defaultTolerations: [] + + # Whether to perform server-side validation of configuration. + configValidation: true + + # Custom DNS config for the pod to resolve names of services in other + # clusters. Use this to add additional search domains, and other settings. + # see + # https://kubernetes.io/docs/concepts/services-networking/dns-pod-service/#dns-config + # This does not apply to gateway pods as they typically need a different + # set of DNS settings than the normal application pods (e.g., in + # multicluster scenarios). + # NOTE: If using templates, follow the pattern in the commented example below. + # podDNSSearchNamespaces: + # - global + # - "[[ valueOrDefault .DeploymentMeta.Namespace \"default\" ]].global" + + # If set to true, the pilot and citadel mtls will be exposed on the + # ingress gateway + meshExpansion: + enabled: false + # If set to true, the pilot and citadel mtls and the plaintext pilot ports + # will be exposed on an internal gateway + useILB: false + + multiCluster: + # Set to true to connect two kubernetes clusters via their respective + # ingressgateway services when pods in each cluster cannot directly + # talk to one another. All clusters should be using Istio mTLS and must + # have a shared root CA for this model to work. + enabled: false + + # Should be set to the name of the cluster this installation will run in. This is required for sidecar injection + # to properly label proxies + clusterName: "" + + # A minimal set of requested resources to applied to all deployments so that + # Horizontal Pod Autoscaler will be able to function (if set). + # Each component can overwrite these default values by adding its own resources + # block in the relevant section below and setting the desired resources values. + defaultResources: + requests: + cpu: 10m + # memory: 128Mi + # limits: + # cpu: 100m + # memory: 128Mi + + # enable pod distruption budget for the control plane, which is used to + # ensure Istio control plane components are gradually upgraded or recovered. + defaultPodDisruptionBudget: + enabled: true + # The values aren't mutable due to a current PodDisruptionBudget limitation + # minAvailable: 1 + + # Kubernetes >=v1.11.0 will create two PriorityClass, including system-cluster-critical and + # system-node-critical, it is better to configure this in order to make sure your Istio pods + # will not be killed because of low priority class. + # Refer to https://kubernetes.io/docs/concepts/configuration/pod-priority-preemption/#priorityclass + # for more detail. + priorityClassName: "" + + # Use the Mesh Control Protocol (MCP) for configuring Mixer and + # Pilot. Requires galley (`--set galley.enabled=true`). + useMCP: true + + # The trust domain corresponds to the trust root of a system + # Refer to https://github.com/spiffe/spiffe/blob/master/standards/SPIFFE-ID.md#21-trust-domain + # Indicate the domain used in SPIFFE identity URL + # The default depends on the environment. + # kubernetes: cluster.local + # else: default dns domain + trustDomain: "" + + # Mesh ID means Mesh Identifier. It should be unique within the scope where + # meshes will interact with each other, but it is not required to be + # globally/universally unique. For example, if any of the following are true, + # then two meshes must have different Mesh IDs: + # - Meshes will have their telemetry aggregated in one place + # - Meshes will be federated together + # - Policy will be written referencing one mesh from the other + # + # If an administrator expects that any of these conditions may become true in + # the future, they should ensure their meshes have different Mesh IDs + # assigned. + # + # Within a multicluster mesh, each cluster must be (manually or auto) + # configured to have the same Mesh ID value. If an existing cluster 'joins' a + # multicluster mesh, it will need to be migrated to the new mesh ID. Details + # of migration TBD, and it may be a disruptive operation to change the Mesh + # ID post-install. + # + # If the mesh admin does not specify a value, Istio will use the value of the + # mesh's Trust Domain. The best practice is to select a proper Trust Domain + # value. + meshID: "" + + # Set the default behavior of the sidecar for handling outbound traffic from the application: + # ALLOW_ANY - outbound traffic to unknown destinations will be allowed, in case there are no + # services or ServiceEntries for the destination port + # REGISTRY_ONLY - restrict outbound traffic to services defined in the service registry as well + # as those defined through ServiceEntries + # ALLOW_ANY is the default in 1.1. This means each pod will be able to make outbound requests + # to services outside of the mesh without any ServiceEntry. + # REGISTRY_ONLY was the default in 1.0. If this behavior is desired, set the value below to REGISTRY_ONLY. + outboundTrafficPolicy: + mode: ALLOW_ANY + + # The namespace where globally shared configurations should be present. + # DestinationRules that apply to the entire mesh (e.g., enabling mTLS), + # default Sidecar configs, etc. should be added to this namespace. + # configRootNamespace: istio-config + + # set the default set of namespaces to which services, service entries, virtual services, destination + # rules should be exported to. Currently only one value can be provided in this list. This value + # should be one of the following two options: + # * implies these objects are visible to all namespaces, enabling any sidecar to talk to any other sidecar. + # . implies these objects are visible to only to sidecars in the same namespace, or if imported as a Sidecar.egress.host + # defaultConfigVisibilitySettings: + #- '*' + + sds: + # SDS enabled. IF set to true, mTLS certificates for the sidecars will be + # distributed through the SecretDiscoveryService instead of using K8S secrets to mount the certificates. + enabled: false + udsPath: "" + # The JWT token for SDS and the aud field of such JWT. See RFC 7519, section 4.1.3. + # When a CSR is sent from Citadel Agent to the CA (e.g. Citadel), this aud is to make sure the + # JWT is intended for the CA. + token: + aud: istio-ca + + # Configure the mesh networks to be used by the Split Horizon EDS. + # + # The following example defines two networks with different endpoints association methods. + # For `network1` all endpoints that their IP belongs to the provided CIDR range will be + # mapped to network1. The gateway for this network example is specified by its public IP + # address and port. + # The second network, `network2`, in this example is defined differently with all endpoints + # retrieved through the specified Multi-Cluster registry being mapped to network2. The + # gateway is also defined differently with the name of the gateway service on the remote + # cluster. The public IP for the gateway will be determined from that remote service (only + # LoadBalancer gateway service type is currently supported, for a NodePort type gateway service, + # it still need to be configured manually). + # + # meshNetworks: + # network1: + # endpoints: + # - fromCidr: "192.168.0.1/24" + # gateways: + # - address: 1.1.1.1 + # port: 80 + # network2: + # endpoints: + # - fromRegistry: reg1 + # gateways: + # - registryServiceName: istio-ingressgateway.istio-system.svc.cluster.local + # port: 443 + # + meshNetworks: {} + + # Specifies the global locality load balancing settings. + # Locality-weighted load balancing allows administrators to control the distribution of traffic to + # endpoints based on the localities of where the traffic originates and where it will terminate. + # Either failover or distribute configuration can be set, but not both. If neither are provided + # failover mode will be used. + # + # localityLbSetting: + # enabled: true + # distribute: + # - from: "us-central1/*" + # to: + # "us-central1/*": 80 + # "us-central2/*": 20 + # + # localityLbSetting: + # enabled: true + # failover: + # - from: us-east + # to: eu-west + # - from: us-west + # to: us-east + localityLbSetting: + enabled: true + + # Specifies whether helm test is enabled or not. + # This field is set to false by default, so 'helm template ...' + # will ignore the helm test yaml files when generating the template + enableHelmTest: false diff --git a/istio-1.3.5/install/kubernetes/istio-demo-auth.yaml b/istio-1.3.5/install/kubernetes/istio-demo-auth.yaml new file mode 100644 index 0000000..48199f1 --- /dev/null +++ b/istio-1.3.5/install/kubernetes/istio-demo-auth.yaml @@ -0,0 +1,21075 @@ +apiVersion: v1 +kind: Namespace +metadata: + name: istio-system + labels: + istio-injection: disabled +--- +apiVersion: apiextensions.k8s.io/v1beta1 +kind: CustomResourceDefinition +metadata: + name: virtualservices.networking.istio.io + labels: + app: istio-pilot + chart: istio + heritage: Tiller + release: istio + annotations: + "helm.sh/resource-policy": keep +spec: + group: networking.istio.io + names: + kind: VirtualService + listKind: VirtualServiceList + plural: virtualservices + singular: virtualservice + shortNames: + - vs + categories: + - istio-io + - networking-istio-io + scope: Namespaced + versions: + - name: v1alpha3 + served: true + storage: true + additionalPrinterColumns: + - JSONPath: .spec.gateways + description: The names of gateways and sidecars that should apply these routes + name: Gateways + type: string + - JSONPath: .spec.hosts + description: The destination hosts to which traffic is being sent + name: Hosts + type: string + - JSONPath: .metadata.creationTimestamp + description: |- + CreationTimestamp is a timestamp representing the server time when this object was created. It is not guaranteed to be set in happens-before order across separate operations. Clients may not set this value. It is represented in RFC3339 form and is in UTC. + + Populated by the system. Read-only. Null for lists. More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#metadata + name: Age + type: date +--- +apiVersion: apiextensions.k8s.io/v1beta1 +kind: CustomResourceDefinition +metadata: + name: destinationrules.networking.istio.io + labels: + app: istio-pilot + chart: istio + heritage: Tiller + release: istio + annotations: + "helm.sh/resource-policy": keep +spec: + group: networking.istio.io + names: + kind: DestinationRule + listKind: DestinationRuleList + plural: destinationrules + singular: destinationrule + shortNames: + - dr + categories: + - istio-io + - networking-istio-io + scope: Namespaced + versions: + - name: v1alpha3 + served: true + storage: true + additionalPrinterColumns: + - JSONPath: .spec.host + description: The name of a service from the service registry + name: Host + type: string + - JSONPath: .metadata.creationTimestamp + description: |- + CreationTimestamp is a timestamp representing the server time when this object was created. It is not guaranteed to be set in happens-before order across separate operations. Clients may not set this value. It is represented in RFC3339 form and is in UTC. + + Populated by the system. Read-only. Null for lists. More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#metadata + name: Age + type: date +--- +apiVersion: apiextensions.k8s.io/v1beta1 +kind: CustomResourceDefinition +metadata: + name: serviceentries.networking.istio.io + labels: + app: istio-pilot + chart: istio + heritage: Tiller + release: istio + annotations: + "helm.sh/resource-policy": keep +spec: + group: networking.istio.io + names: + kind: ServiceEntry + listKind: ServiceEntryList + plural: serviceentries + singular: serviceentry + shortNames: + - se + categories: + - istio-io + - networking-istio-io + scope: Namespaced + versions: + - name: v1alpha3 + served: true + storage: true + additionalPrinterColumns: + - JSONPath: .spec.hosts + description: The hosts associated with the ServiceEntry + name: Hosts + type: string + - JSONPath: .spec.location + description: Whether the service is external to the mesh or part of the mesh (MESH_EXTERNAL or MESH_INTERNAL) + name: Location + type: string + - JSONPath: .spec.resolution + description: Service discovery mode for the hosts (NONE, STATIC, or DNS) + name: Resolution + type: string + - JSONPath: .metadata.creationTimestamp + description: |- + CreationTimestamp is a timestamp representing the server time when this object was created. It is not guaranteed to be set in happens-before order across separate operations. Clients may not set this value. It is represented in RFC3339 form and is in UTC. + + Populated by the system. Read-only. Null for lists. More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#metadata + name: Age + type: date +--- +apiVersion: apiextensions.k8s.io/v1beta1 +kind: CustomResourceDefinition +metadata: + name: gateways.networking.istio.io + labels: + app: istio-pilot + chart: istio + heritage: Tiller + release: istio + annotations: + "helm.sh/resource-policy": keep +spec: + group: networking.istio.io + names: + kind: Gateway + plural: gateways + singular: gateway + shortNames: + - gw + categories: + - istio-io + - networking-istio-io + scope: Namespaced + versions: + - name: v1alpha3 + served: true + storage: true +--- +apiVersion: apiextensions.k8s.io/v1beta1 +kind: CustomResourceDefinition +metadata: + name: envoyfilters.networking.istio.io + labels: + app: istio-pilot + chart: istio + heritage: Tiller + release: istio + annotations: + "helm.sh/resource-policy": keep +spec: + group: networking.istio.io + names: + kind: EnvoyFilter + plural: envoyfilters + singular: envoyfilter + categories: + - istio-io + - networking-istio-io + scope: Namespaced + versions: + - name: v1alpha3 + served: true + storage: true +--- +kind: CustomResourceDefinition +apiVersion: apiextensions.k8s.io/v1beta1 +metadata: + name: clusterrbacconfigs.rbac.istio.io + labels: + app: istio-pilot + istio: rbac + heritage: Tiller + release: istio + annotations: + "helm.sh/resource-policy": keep +spec: + group: rbac.istio.io + names: + kind: ClusterRbacConfig + plural: clusterrbacconfigs + singular: clusterrbacconfig + categories: + - istio-io + - rbac-istio-io + scope: Cluster + versions: + - name: v1alpha1 + served: true + storage: true +--- +kind: CustomResourceDefinition +apiVersion: apiextensions.k8s.io/v1beta1 +metadata: + name: policies.authentication.istio.io + labels: + app: istio-citadel + chart: istio + heritage: Tiller + release: istio + annotations: + "helm.sh/resource-policy": keep +spec: + group: authentication.istio.io + names: + kind: Policy + plural: policies + singular: policy + categories: + - istio-io + - authentication-istio-io + scope: Namespaced + versions: + - name: v1alpha1 + served: true + storage: true +--- +kind: CustomResourceDefinition +apiVersion: apiextensions.k8s.io/v1beta1 +metadata: + name: meshpolicies.authentication.istio.io + labels: + app: istio-citadel + chart: istio + heritage: Tiller + release: istio + annotations: + "helm.sh/resource-policy": keep +spec: + group: authentication.istio.io + names: + kind: MeshPolicy + listKind: MeshPolicyList + plural: meshpolicies + singular: meshpolicy + categories: + - istio-io + - authentication-istio-io + scope: Cluster + versions: + - name: v1alpha1 + served: true + storage: true +--- +kind: CustomResourceDefinition +apiVersion: apiextensions.k8s.io/v1beta1 +metadata: + name: httpapispecbindings.config.istio.io + labels: + app: istio-mixer + chart: istio + heritage: Tiller + release: istio + annotations: + "helm.sh/resource-policy": keep +spec: + group: config.istio.io + names: + kind: HTTPAPISpecBinding + plural: httpapispecbindings + singular: httpapispecbinding + categories: + - istio-io + - apim-istio-io + scope: Namespaced + versions: + - name: v1alpha2 + served: true + storage: true +--- +kind: CustomResourceDefinition +apiVersion: apiextensions.k8s.io/v1beta1 +metadata: + name: httpapispecs.config.istio.io + labels: + app: istio-mixer + chart: istio + heritage: Tiller + release: istio + annotations: + "helm.sh/resource-policy": keep +spec: + group: config.istio.io + names: + kind: HTTPAPISpec + plural: httpapispecs + singular: httpapispec + categories: + - istio-io + - apim-istio-io + scope: Namespaced + versions: + - name: v1alpha2 + served: true + storage: true +--- +kind: CustomResourceDefinition +apiVersion: apiextensions.k8s.io/v1beta1 +metadata: + name: quotaspecbindings.config.istio.io + labels: + app: istio-mixer + chart: istio + heritage: Tiller + release: istio + annotations: + "helm.sh/resource-policy": keep +spec: + group: config.istio.io + names: + kind: QuotaSpecBinding + plural: quotaspecbindings + singular: quotaspecbinding + categories: + - istio-io + - apim-istio-io + scope: Namespaced + versions: + - name: v1alpha2 + served: true + storage: true +--- +kind: CustomResourceDefinition +apiVersion: apiextensions.k8s.io/v1beta1 +metadata: + name: quotaspecs.config.istio.io + labels: + app: istio-mixer + chart: istio + heritage: Tiller + release: istio + annotations: + "helm.sh/resource-policy": keep +spec: + group: config.istio.io + names: + kind: QuotaSpec + plural: quotaspecs + singular: quotaspec + categories: + - istio-io + - apim-istio-io + scope: Namespaced + versions: + - name: v1alpha2 + served: true + storage: true +--- +kind: CustomResourceDefinition +apiVersion: apiextensions.k8s.io/v1beta1 +metadata: + name: rules.config.istio.io + labels: + app: mixer + package: istio.io.mixer + istio: core + chart: istio + heritage: Tiller + release: istio + annotations: + "helm.sh/resource-policy": keep +spec: + group: config.istio.io + names: + kind: rule + plural: rules + singular: rule + categories: + - istio-io + - policy-istio-io + scope: Namespaced + versions: + - name: v1alpha2 + served: true + storage: true +--- +kind: CustomResourceDefinition +apiVersion: apiextensions.k8s.io/v1beta1 +metadata: + name: attributemanifests.config.istio.io + labels: + app: mixer + package: istio.io.mixer + istio: core + chart: istio + heritage: Tiller + release: istio + annotations: + "helm.sh/resource-policy": keep +spec: + group: config.istio.io + names: + kind: attributemanifest + plural: attributemanifests + singular: attributemanifest + categories: + - istio-io + - policy-istio-io + scope: Namespaced + versions: + - name: v1alpha2 + served: true + storage: true +--- +kind: CustomResourceDefinition +apiVersion: apiextensions.k8s.io/v1beta1 +metadata: + name: rbacconfigs.rbac.istio.io + labels: + app: mixer + package: istio.io.mixer + istio: rbac + chart: istio + heritage: Tiller + release: istio + annotations: + "helm.sh/resource-policy": keep +spec: + group: rbac.istio.io + names: + kind: RbacConfig + plural: rbacconfigs + singular: rbacconfig + categories: + - istio-io + - rbac-istio-io + scope: Namespaced + versions: + - name: v1alpha1 + served: true + storage: true +--- +kind: CustomResourceDefinition +apiVersion: apiextensions.k8s.io/v1beta1 +metadata: + name: serviceroles.rbac.istio.io + labels: + app: mixer + package: istio.io.mixer + istio: rbac + chart: istio + heritage: Tiller + release: istio + annotations: + "helm.sh/resource-policy": keep +spec: + group: rbac.istio.io + names: + kind: ServiceRole + plural: serviceroles + singular: servicerole + categories: + - istio-io + - rbac-istio-io + scope: Namespaced + versions: + - name: v1alpha1 + served: true + storage: true +--- +kind: CustomResourceDefinition +apiVersion: apiextensions.k8s.io/v1beta1 +metadata: + name: servicerolebindings.rbac.istio.io + labels: + app: mixer + package: istio.io.mixer + istio: rbac + chart: istio + heritage: Tiller + release: istio + annotations: + "helm.sh/resource-policy": keep +spec: + group: rbac.istio.io + names: + kind: ServiceRoleBinding + plural: servicerolebindings + singular: servicerolebinding + categories: + - istio-io + - rbac-istio-io + scope: Namespaced + versions: + - name: v1alpha1 + served: true + storage: true + additionalPrinterColumns: + - JSONPath: .spec.roleRef.name + description: The name of the ServiceRole object being referenced + name: Reference + type: string + - JSONPath: .metadata.creationTimestamp + description: |- + CreationTimestamp is a timestamp representing the server time when this object was created. It is not guaranteed to be set in happens-before order across separate operations. Clients may not set this value. It is represented in RFC3339 form and is in UTC. + + Populated by the system. Read-only. Null for lists. More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#metadata + name: Age + type: date +--- +kind: CustomResourceDefinition +apiVersion: apiextensions.k8s.io/v1beta1 +metadata: + name: adapters.config.istio.io + labels: + app: mixer + package: adapter + istio: mixer-adapter + chart: istio + heritage: Tiller + release: istio + annotations: + "helm.sh/resource-policy": keep +spec: + group: config.istio.io + names: + kind: adapter + plural: adapters + singular: adapter + categories: + - istio-io + - policy-istio-io + scope: Namespaced + versions: + - name: v1alpha2 + served: true + storage: true +--- +kind: CustomResourceDefinition +apiVersion: apiextensions.k8s.io/v1beta1 +metadata: + name: instances.config.istio.io + labels: + app: mixer + package: instance + istio: mixer-instance + chart: istio + heritage: Tiller + release: istio + annotations: + "helm.sh/resource-policy": keep +spec: + group: config.istio.io + names: + kind: instance + plural: instances + singular: instance + categories: + - istio-io + - policy-istio-io + scope: Namespaced + versions: + - name: v1alpha2 + served: true + storage: true +--- +kind: CustomResourceDefinition +apiVersion: apiextensions.k8s.io/v1beta1 +metadata: + name: templates.config.istio.io + labels: + app: mixer + package: template + istio: mixer-template + chart: istio + heritage: Tiller + release: istio + annotations: + "helm.sh/resource-policy": keep +spec: + group: config.istio.io + names: + kind: template + plural: templates + singular: template + categories: + - istio-io + - policy-istio-io + scope: Namespaced + versions: + - name: v1alpha2 + served: true + storage: true +--- +kind: CustomResourceDefinition +apiVersion: apiextensions.k8s.io/v1beta1 +metadata: + name: handlers.config.istio.io + labels: + app: mixer + package: handler + istio: mixer-handler + chart: istio + heritage: Tiller + release: istio + annotations: + "helm.sh/resource-policy": keep +spec: + group: config.istio.io + names: + kind: handler + plural: handlers + singular: handler + categories: + - istio-io + - policy-istio-io + scope: Namespaced + versions: + - name: v1alpha2 + served: true + storage: true +--- +apiVersion: apiextensions.k8s.io/v1beta1 +kind: CustomResourceDefinition +metadata: + name: sidecars.networking.istio.io + labels: + app: istio-pilot + chart: istio + heritage: Tiller + release: istio + annotations: + "helm.sh/resource-policy": keep +spec: + group: networking.istio.io + names: + kind: Sidecar + plural: sidecars + singular: sidecar + categories: + - istio-io + - networking-istio-io + scope: Namespaced + versions: + - name: v1alpha3 + served: true + storage: true +--- +kind: CustomResourceDefinition +apiVersion: apiextensions.k8s.io/v1beta1 +metadata: + name: authorizationpolicies.rbac.istio.io + labels: + app: istio-pilot + istio: rbac + heritage: Tiller + release: istio +spec: + group: rbac.istio.io + names: + kind: AuthorizationPolicy + plural: authorizationpolicies + singular: authorizationpolicy + categories: + - istio-io + - rbac-istio-io + scope: Namespaced + versions: + - name: v1alpha1 + served: true + storage: true +--- +apiVersion: apiextensions.k8s.io/v1beta1 +kind: CustomResourceDefinition +metadata: + name: clusterissuers.certmanager.k8s.io + labels: + app: certmanager + chart: certmanager + heritage: Tiller + release: istio + annotations: + "helm.sh/resource-policy": keep +spec: + group: certmanager.k8s.io + versions: + - name: v1alpha1 + served: true + storage: true + names: + kind: ClusterIssuer + plural: clusterissuers + scope: Cluster +--- +apiVersion: apiextensions.k8s.io/v1beta1 +kind: CustomResourceDefinition +metadata: + name: issuers.certmanager.k8s.io + labels: + app: certmanager + chart: certmanager + heritage: Tiller + release: istio + annotations: + "helm.sh/resource-policy": keep +spec: + group: certmanager.k8s.io + versions: + - name: v1alpha1 + served: true + storage: true + names: + kind: Issuer + plural: issuers + scope: Namespaced +--- +apiVersion: apiextensions.k8s.io/v1beta1 +kind: CustomResourceDefinition +metadata: + name: certificates.certmanager.k8s.io + labels: + app: certmanager + chart: certmanager + heritage: Tiller + release: istio + annotations: + "helm.sh/resource-policy": keep +spec: + additionalPrinterColumns: + - JSONPath: .status.conditions[?(@.type=="Ready")].status + name: Ready + type: string + - JSONPath: .spec.secretName + name: Secret + type: string + - JSONPath: .spec.issuerRef.name + name: Issuer + type: string + priority: 1 + - JSONPath: .status.conditions[?(@.type=="Ready")].message + name: Status + type: string + priority: 1 + - JSONPath: .metadata.creationTimestamp + description: |- + CreationTimestamp is a timestamp representing the server time when this object was created. It is not guaranteed to be set in happens-before order across separate operations. Clients may not set this value. It is represented in RFC3339 form and is in UTC. + + Populated by the system. Read-only. Null for lists. More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#metadata + name: Age + type: date + group: certmanager.k8s.io + versions: + - name: v1alpha1 + served: true + storage: true + scope: Namespaced + names: + kind: Certificate + plural: certificates + shortNames: + - cert + - certs +--- +apiVersion: apiextensions.k8s.io/v1beta1 +kind: CustomResourceDefinition +metadata: + name: orders.certmanager.k8s.io + labels: + app: certmanager + chart: certmanager + heritage: Tiller + release: istio + annotations: + "helm.sh/resource-policy": keep +spec: + additionalPrinterColumns: + - JSONPath: .status.state + name: State + type: string + - JSONPath: .spec.issuerRef.name + name: Issuer + type: string + priority: 1 + - JSONPath: .status.reason + name: Reason + type: string + priority: 1 + - JSONPath: .metadata.creationTimestamp + description: |- + CreationTimestamp is a timestamp representing the server time when this object was created. It is not guaranteed to be set in happens-before order across separate operations. Clients may not set this value. It is represented in RFC3339 form and is in UTC. + + Populated by the system. Read-only. Null for lists. More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#metadata + name: Age + type: date + group: certmanager.k8s.io + versions: + - name: v1alpha1 + served: true + storage: true + names: + kind: Order + plural: orders + scope: Namespaced +--- +apiVersion: apiextensions.k8s.io/v1beta1 +kind: CustomResourceDefinition +metadata: + name: challenges.certmanager.k8s.io + labels: + app: certmanager + chart: certmanager + heritage: Tiller + release: istio + annotations: + "helm.sh/resource-policy": keep +spec: + additionalPrinterColumns: + - JSONPath: .status.state + name: State + type: string + - JSONPath: .spec.dnsName + name: Domain + type: string + - JSONPath: .status.reason + name: Reason + type: string + - JSONPath: .metadata.creationTimestamp + description: |- + CreationTimestamp is a timestamp representing the server time when this object was created. It is not guaranteed to be set in happens-before order across separate operations. Clients may not set this value. It is represented in RFC3339 form and is in UTC. + + Populated by the system. Read-only. Null for lists. More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#metadata + name: Age + type: date + group: certmanager.k8s.io + versions: + - name: v1alpha1 + served: true + storage: true + names: + kind: Challenge + plural: challenges + scope: Namespaced +--- +--- +# Source: istio/charts/kiali/templates/demosecret.yaml + +apiVersion: v1 +kind: Secret +metadata: + name: kiali + namespace: istio-system + labels: + app: kiali + chart: kiali + heritage: Tiller + release: istio +type: Opaque +data: + username: YWRtaW4= # admin + passphrase: YWRtaW4= # admin + +--- +# Source: istio/charts/galley/templates/configmap.yaml +apiVersion: v1 +kind: ConfigMap +metadata: + name: istio-galley-configuration + namespace: istio-system + labels: + app: galley + chart: galley + heritage: Tiller + release: istio + istio: galley +data: + validatingwebhookconfiguration.yaml: |- + apiVersion: admissionregistration.k8s.io/v1beta1 + kind: ValidatingWebhookConfiguration + metadata: + name: istio-galley + labels: + app: galley + chart: galley + heritage: Tiller + release: istio + istio: galley + webhooks: + - name: pilot.validation.istio.io + clientConfig: + service: + name: istio-galley + namespace: istio-system + path: "/admitpilot" + caBundle: "" + rules: + - operations: + - CREATE + - UPDATE + apiGroups: + - config.istio.io + apiVersions: + - v1alpha2 + resources: + - httpapispecs + - httpapispecbindings + - quotaspecs + - quotaspecbindings + - operations: + - CREATE + - UPDATE + apiGroups: + - rbac.istio.io + apiVersions: + - "*" + resources: + - "*" + - operations: + - CREATE + - UPDATE + apiGroups: + - authentication.istio.io + apiVersions: + - "*" + resources: + - "*" + - operations: + - CREATE + - UPDATE + apiGroups: + - networking.istio.io + apiVersions: + - "*" + resources: + - destinationrules + - envoyfilters + - gateways + - serviceentries + - sidecars + - virtualservices + failurePolicy: Fail + sideEffects: None + - name: mixer.validation.istio.io + clientConfig: + service: + name: istio-galley + namespace: istio-system + path: "/admitmixer" + caBundle: "" + rules: + - operations: + - CREATE + - UPDATE + apiGroups: + - config.istio.io + apiVersions: + - v1alpha2 + resources: + - rules + - attributemanifests + - circonuses + - deniers + - fluentds + - kubernetesenvs + - listcheckers + - memquotas + - noops + - opas + - prometheuses + - rbacs + - solarwindses + - stackdrivers + - cloudwatches + - dogstatsds + - statsds + - stdios + - apikeys + - authorizations + - checknothings + # - kuberneteses + - listentries + - logentries + - metrics + - quotas + - reportnothings + - tracespans + - adapters + - handlers + - instances + - templates + - zipkins + failurePolicy: Fail + sideEffects: None + +--- +# Source: istio/charts/grafana/templates/configmap-custom-resources.yaml +apiVersion: v1 +kind: ConfigMap +metadata: + name: istio-grafana-custom-resources + namespace: istio-system + labels: + app: grafana + chart: grafana + heritage: Tiller + release: istio + istio: grafana +data: + custom-resources.yaml: |- + apiVersion: authentication.istio.io/v1alpha1 + kind: Policy + metadata: + name: grafana-ports-mtls-disabled + namespace: istio-system + labels: + app: grafana + chart: grafana + heritage: Tiller + release: istio + spec: + targets: + - name: grafana + ports: + - number: 3000 + run.sh: |- + #!/bin/sh + + set -x + + if [ "$#" -ne "1" ]; then + echo "first argument should be path to custom resource yaml" + exit 1 + fi + + pathToResourceYAML=${1} + + kubectl get validatingwebhookconfiguration istio-galley 2>/dev/null + if [ "$?" -eq 0 ]; then + echo "istio-galley validatingwebhookconfiguration found - waiting for istio-galley deployment to be ready" + while true; do + kubectl -n istio-system get deployment istio-galley 2>/dev/null + if [ "$?" -eq 0 ]; then + break + fi + sleep 1 + done + kubectl -n istio-system rollout status deployment istio-galley + if [ "$?" -ne 0 ]; then + echo "istio-galley deployment rollout status check failed" + exit 1 + fi + echo "istio-galley deployment ready for configuration validation" + fi + sleep 5 + kubectl apply -f ${pathToResourceYAML} + + +--- +# Source: istio/charts/grafana/templates/configmap-dashboards.yaml + +apiVersion: v1 +kind: ConfigMap +metadata: + name: istio-grafana-configuration-dashboards-citadel-dashboard + namespace: istio-system + labels: + app: grafana + chart: grafana + heritage: Tiller + release: istio + istio: grafana +data: + citadel-dashboard.json: '{ + "annotations": { + "list": [ + { + "builtIn": 1, + "datasource": "-- Grafana --", + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations & Alerts", + "type": "dashboard" + } + ] + }, + "description": "", + "editable": true, + "gnetId": null, + "graphTooltip": 0, + "links": [], + "panels": [ + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 0 + }, + "id": 8, + "panels": [], + "title": "Performance", + "type": "row" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "description": "CPU usage across Citadel instances.", + "fill": 1, + "gridPos": { + "h": 6, + "w": 8, + "x": 0, + "y": 1 + }, + "id": 10, + "legend": { + "alignAsTable": false, + "avg": false, + "current": false, + "max": false, + "min": false, + "rightSide": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(rate(container_cpu_usage_seconds_total{job=\"kubernetes-cadvisor\",container_name=~\"citadel\", pod_name=~\"istio-citadel-.*\"}[1m]))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Citadel CPU usage rate", + "refId": "A" + }, + { + "expr": "irate(process_cpu_seconds_total{job=\"citadel\"}[1m])", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Citadel CPU usage irate", + "refId": "C" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "CPU", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": "", + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "description": "Citadel process memory statistics.", + "fill": 1, + "gridPos": { + "h": 6, + "w": 8, + "x": 8, + "y": 1 + }, + "id": 12, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "process_virtual_memory_bytes{job=\"citadel\"}", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Virtual Memory", + "refId": "A" + }, + { + "expr": "process_resident_memory_bytes{job=\"citadel\"}", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Resident Memory", + "refId": "B" + }, + { + "expr": "go_memstats_heap_sys_bytes{job=\"citadel\"}", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Heap Memory Total", + "refId": "C" + }, + { + "expr": "go_memstats_alloc_bytes{job=\"citadel\"}", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Heap Memory Allocated", + "refId": "E" + }, + { + "expr": "go_memstats_heap_inuse_bytes{job=\"citadel\"}", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Heap Inuse", + "refId": "F" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Memory", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "fill": 1, + "gridPos": { + "h": 6, + "w": 8, + "x": 16, + "y": 1 + }, + "id": 14, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "go_goroutines{job=\"citadel\"}", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Goroutines", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Goroutines", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 7 + }, + "id": 28, + "panels": [], + "title": "General", + "type": "row" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "description": "Total number of CSR requests made to Citadel.", + "fill": 1, + "gridPos": { + "h": 5, + "w": 12, + "x": 0, + "y": 8 + }, + "id": 30, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "citadel_server_csr_count{job=\"citadel\"}", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "CSR Request Count", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "CSR Requests", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "description": "The number of certificates issuances that have succeeded.", + "fill": 1, + "gridPos": { + "h": 5, + "w": 12, + "x": 12, + "y": 8 + }, + "id": 32, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "citadel_server_success_cert_issuance_count{job=\"citadel\"}", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Certificates Issued", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Certificates Issued", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 13 + }, + "id": 23, + "panels": [], + "title": "Errors", + "type": "row" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "description": "The number of errors occurred when creating the CSR.", + "fill": 1, + "gridPos": { + "h": 5, + "w": 8, + "x": 0, + "y": 14 + }, + "id": 20, + "legend": { + "alignAsTable": false, + "avg": false, + "current": false, + "max": false, + "min": false, + "rightSide": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "citadel_secret_controller_csr_err_count{job=\"citadel\"}", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "CSR Creation Error Count", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "CSR Creation Errors", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": "", + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "fill": 1, + "gridPos": { + "h": 5, + "w": 8, + "x": 8, + "y": 14 + }, + "id": 24, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "citadel_server_csr_parsing_err_count{job=\"citadel\"}", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "CSR Parse Error Count", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "CSR Parse Errors", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "description": "The number of authentication failures.", + "fill": 1, + "gridPos": { + "h": 5, + "w": 8, + "x": 16, + "y": 14 + }, + "id": 26, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "citadel_server_authentication_failure_count{job=\"citadel\"}", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Authentication Failure Count", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Authentication Failures", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 19 + }, + "id": 4, + "panels": [], + "title": "Secret Controller", + "type": "row" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "description": "The number of certificates created due to service account creation.", + "fill": 1, + "gridPos": { + "h": 5, + "w": 8, + "x": 0, + "y": 20 + }, + "id": 2, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": true, + "targets": [ + { + "expr": "citadel_secret_controller_svc_acc_created_cert_count{job=\"citadel\"}", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "SA Secrets Created", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Service Account Secrets Created (due to SA creation)", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "decimals": null, + "format": "short", + "label": "Certs Created", + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "description": "The number of certificates deleted due to service account deletion.", + "fill": 1, + "gridPos": { + "h": 5, + "w": 8, + "x": 8, + "y": 20 + }, + "id": 16, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": true, + "targets": [ + { + "expr": "citadel_secret_controller_svc_acc_deleted_cert_count{job=\"citadel\"}", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "SA Secrets Deleted", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Service Account Secrets Deleted (due to SA deletion)", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "decimals": null, + "format": "short", + "label": "Certs Created", + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "description": "The number of certificates recreated due to secret deletion (service account still exists).", + "fill": 1, + "gridPos": { + "h": 5, + "w": 8, + "x": 16, + "y": 20 + }, + "id": 6, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": true, + "targets": [ + { + "expr": "citadel_secret_controller_secret_deleted_cert_count{job=\"citadel\"}", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "SA Secrets Recreated", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Service Account Secrets Recreated (due to errant deletion)", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "decimals": null, + "format": "short", + "label": "Certs Created", + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + } + ], + "refresh": "5s", + "schemaVersion": 18, + "style": "dark", + "tags": [], + "templating": { + "list": [] + }, + "time": { + "from": "now-5m", + "to": "now" + }, + "timepicker": { + "refresh_intervals": [ + "5s", + "10s", + "30s", + "1m", + "5m", + "15m", + "30m", + "1h", + "2h", + "1d" + ], + "time_options": [ + "5m", + "15m", + "1h", + "6h", + "12h", + "24h", + "2d", + "7d", + "30d" + ] + }, + "timezone": "", + "title": "Istio Citadel Dashboard", + "uid": "OOyOqb4Wz", + "version": 1 +}' +--- +apiVersion: v1 +kind: ConfigMap +metadata: + name: istio-grafana-configuration-dashboards-galley-dashboard + namespace: istio-system + labels: + app: grafana + chart: grafana + heritage: Tiller + release: istio + istio: grafana +data: + galley-dashboard.json: '{ + "__inputs": [ + { + "name": "DS_PROMETHEUS", + "label": "Prometheus", + "description": "", + "type": "datasource", + "pluginId": "prometheus", + "pluginName": "Prometheus" + } + ], + "annotations": { + "list": [ + { + "builtIn": 1, + "datasource": "-- Grafana --", + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations & Alerts", + "type": "dashboard" + } + ] + }, + "editable": false, + "gnetId": null, + "graphTooltip": 0, + "links": [], + "panels": [ + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 5, + "w": 24, + "x": 0, + "y": 0 + }, + "id": 46, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(istio_build{component=\"galley\"}) by (tag)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{ tag }}", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Galley Versions", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 5 + }, + "id": 40, + "panels": [], + "title": "Resource Usage", + "type": "row" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 8, + "w": 6, + "x": 0, + "y": 6 + }, + "id": 36, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "process_virtual_memory_bytes{job=\"galley\"}", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "Virtual Memory", + "refId": "A" + }, + { + "expr": "process_resident_memory_bytes{job=\"galley\"}", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "Resident Memory", + "refId": "B" + }, + { + "expr": "go_memstats_heap_sys_bytes{job=\"galley\"}", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "heap sys", + "refId": "C" + }, + { + "expr": "go_memstats_heap_alloc_bytes{job=\"galley\"}", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "heap alloc", + "refId": "D" + }, + { + "expr": "go_memstats_alloc_bytes{job=\"galley\"}", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "Alloc", + "refId": "F" + }, + { + "expr": "go_memstats_heap_inuse_bytes{job=\"galley\"}", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "Heap in-use", + "refId": "G" + }, + { + "expr": "go_memstats_stack_inuse_bytes{job=\"galley\"}", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "Stack in-use", + "refId": "H" + }, + { + "expr": "sum(container_memory_usage_bytes{job=\"kubernetes-cadvisor\",container_name=~\"galley\", pod_name=~\"istio-galley-.*\"})", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Total (kis)", + "refId": "E" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Memory", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 8, + "w": 6, + "x": 6, + "y": 6 + }, + "id": 38, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(rate(container_cpu_usage_seconds_total{job=\"kubernetes-cadvisor\",container_name=~\"galley\", pod_name=~\"istio-galley-.*\"}[1m]))", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "Total (k8s)", + "refId": "A" + }, + { + "expr": "sum(rate(container_cpu_usage_seconds_total{job=\"kubernetes-cadvisor\",container_name=~\"galley\", pod_name=~\"istio-galley-.*\"}[1m])) by (container_name)", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "{{ container_name }} (k8s)", + "refId": "B" + }, + { + "expr": "irate(process_cpu_seconds_total{job=\"galley\"}[1m])", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "galley (self-reported)", + "refId": "C" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "CPU", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 8, + "w": 6, + "x": 12, + "y": 6 + }, + "id": 42, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "process_open_fds{job=\"galley\"}", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "Open FDs (galley)", + "refId": "A" + }, + { + "expr": "container_fs_usage_bytes{job=\"kubernetes-cadvisor\",container_name=~\"galley\", pod_name=~\"istio-galley-.*\"}", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "{{ container_name }} ", + "refId": "B" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Disk", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 8, + "w": 6, + "x": 18, + "y": 6 + }, + "id": 44, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "go_goroutines{job=\"galley\"}", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "goroutines_total", + "refId": "A" + }, + { + "expr": "istio_mcp_clients_total{component=\"galley\"}", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "clients_total", + "refId": "B" + }, + { + "expr": "go_goroutines{job=\"galley\"}/sum(istio_mcp_clients_total{component=\"galley\"}) without (component)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "avg_goroutines_per_client", + "refId": "C" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Goroutines", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 14 + }, + "id": 10, + "panels": [], + "title": "Runtime", + "type": "row" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 6, + "w": 8, + "x": 0, + "y": 15 + }, + "id": 2, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(rate(galley_runtime_strategy_on_change_total[1m])) * 60", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Strategy Change Events", + "refId": "A" + }, + { + "expr": "sum(rate(galley_runtime_processor_events_processed_total[1m])) * 60", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Processed Events", + "refId": "B" + }, + { + "expr": "sum(rate(galley_runtime_processor_snapshots_published_total[1m])) * 60", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Snapshot Published", + "refId": "C" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Event Rates", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": "Events/min", + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": "", + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 6, + "w": 8, + "x": 8, + "y": 15 + }, + "id": 4, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(rate(galley_runtime_strategy_timer_max_time_reached_total[1m])) * 60", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Max Time Reached", + "refId": "A" + }, + { + "expr": "sum(rate(galley_runtime_strategy_timer_quiesce_reached_total[1m])) * 60", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Quiesce Reached", + "refId": "B" + }, + { + "expr": "sum(rate(galley_runtime_strategy_timer_resets_total[1m])) * 60", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Timer Resets", + "refId": "C" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Timer Rates", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": "Events/min", + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 6, + "w": 8, + "x": 16, + "y": 15 + }, + "id": 8, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 3, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": true, + "steppedLine": false, + "targets": [ + { + "expr": "histogram_quantile(0.50, sum by (le) (galley_runtime_processor_snapshot_events_total_bucket))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "P50", + "refId": "A" + }, + { + "expr": "histogram_quantile(0.90, sum by (le) (galley_runtime_processor_snapshot_events_total_bucket))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "P90", + "refId": "B" + }, + { + "expr": "histogram_quantile(0.95, sum by (le) (galley_runtime_processor_snapshot_events_total_bucket))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "P95", + "refId": "C" + }, + { + "expr": "histogram_quantile(0.99, sum by (le) (galley_runtime_processor_snapshot_events_total_bucket))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "P99", + "refId": "D" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Events Per Snapshot", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 6, + "w": 8, + "x": 8, + "y": 21 + }, + "id": 6, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum by (typeURL) (galley_runtime_state_type_instances_total)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{ typeURL }}", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "State Type Instances", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": "Count", + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 27 + }, + "id": 34, + "panels": [], + "title": "Validation", + "type": "row" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 6, + "w": 8, + "x": 0, + "y": 28 + }, + "id": 28, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "galley_validation_cert_key_updates{job=\"galley\"}", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Key Updates", + "refId": "A" + }, + { + "expr": "galley_validation_cert_key_update_errors{job=\"galley\"}", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Key Update Errors: {{ error }}", + "refId": "B" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Validation Webhook Certificate", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 6, + "w": 8, + "x": 8, + "y": 28 + }, + "id": 30, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(galley_validation_passed{job=\"galley\"}) by (group, version, resource)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Passed: {{ group }}/{{ version }}/{{resource}}", + "refId": "A" + }, + { + "expr": "sum(galley_validation_failed{job=\"galley\"}) by (group, version, resource, reason)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Failed: {{ group }}/{{ version }}/{{resource}} ({{ reason}})", + "refId": "B" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Resource Validation", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 6, + "w": 8, + "x": 16, + "y": 28 + }, + "id": 32, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(galley_validation_http_error{job=\"galley\"}) by (status)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{ status }}", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Validation HTTP Errors", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 34 + }, + "id": 12, + "panels": [], + "title": "Kubernetes Source", + "type": "row" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 6, + "w": 8, + "x": 0, + "y": 35 + }, + "id": 14, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "rate(galley_source_kube_event_success_total[1m]) * 60", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Success", + "refId": "A" + }, + { + "expr": "rate(galley_source_kube_event_error_total[1m]) * 60", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Error", + "refId": "B" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Source Event Rate", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": "Events/min", + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 6, + "w": 8, + "x": 8, + "y": 35 + }, + "id": 16, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "rate(galley_source_kube_dynamic_converter_success_total[1m]) * 60", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{apiVersion=\"{{apiVersion}}\",group=\"{{group}}\",kind=\"{{kind}}\"}", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Kubernetes Object Conversion Successes", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": "Conversions/min", + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 6, + "w": 8, + "x": 16, + "y": 35 + }, + "id": 24, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "rate(galley_source_kube_dynamic_converter_failure_total[1m]) * 60", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Error", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Kubernetes Object Conversion Failures", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": "Failures/min", + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 41 + }, + "id": 18, + "panels": [], + "title": "Mesh Configuration Protocol", + "type": "row" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 6, + "w": 8, + "x": 0, + "y": 42 + }, + "id": 20, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(istio_mcp_clients_total{component=\"galley\"})", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Clients", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Connected Clients", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 6, + "w": 8, + "x": 8, + "y": 42 + }, + "id": 22, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum by(collection)(irate(istio_mcp_request_acks_total{component=\"galley\"}[1m]) * 60)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Request ACKs", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": "ACKs/min", + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 6, + "w": 8, + "x": 16, + "y": 42 + }, + "id": 26, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "rate(istio_mcp_request_nacks_total{component=\"galley\"}[1m]) * 60", + "format": "time_series", + "intervalFactor": 1, + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Request NACKs", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": "NACKs/min", + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + } + ], + "refresh": "5s", + "schemaVersion": 16, + "style": "dark", + "tags": [], + "templating": { + "list": [] + }, + "time": { + "from": "now-5m", + "to": "now" + }, + "timepicker": { + "refresh_intervals": [ + "5s", + "10s", + "30s", + "1m", + "5m", + "15m", + "30m", + "1h", + "2h", + "1d" + ], + "time_options": [ + "5m", + "15m", + "1h", + "6h", + "12h", + "24h", + "2d", + "7d", + "30d" + ] + }, + "timezone": "", + "title": "Istio Galley Dashboard", + "uid": "TSEY6jLmk", + "version": 1 +} +' +--- +apiVersion: v1 +kind: ConfigMap +metadata: + name: istio-grafana-configuration-dashboards-istio-mesh-dashboard + namespace: istio-system + labels: + app: grafana + chart: grafana + heritage: Tiller + release: istio + istio: grafana +data: + istio-mesh-dashboard.json: '{ + "annotations": { + "list": [ + { + "builtIn": 1, + "datasource": "-- Grafana --", + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations & Alerts", + "type": "dashboard" + } + ] + }, + "editable": false, + "gnetId": null, + "graphTooltip": 0, + "id": null, + "links": [], + "panels": [ + { + "content": "
\n
\n Istio\n
\n
\n Istio is an open platform that provides a uniform way to connect,\n manage, and \n secure microservices.\n
\n Need help? Join the Istio community.\n
\n
", + "gridPos": { + "h": 3, + "w": 24, + "x": 0, + "y": 0 + }, + "height": "50px", + "id": 13, + "links": [], + "mode": "html", + "style": { + "font-size": "18pt" + }, + "title": "", + "transparent": true, + "type": "text" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "datasource": "Prometheus", + "format": "ops", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "gridPos": { + "h": 3, + "w": 6, + "x": 0, + "y": 3 + }, + "id": 20, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": true, + "lineColor": "rgb(31, 120, 193)", + "show": true + }, + "tableColumn": "", + "targets": [ + { + "expr": "round(sum(irate(istio_requests_total{reporter=\"destination\"}[1m])), 0.001)", + "intervalFactor": 1, + "refId": "A", + "step": 4 + } + ], + "thresholds": "", + "title": "Global Request Volume", + "type": "singlestat", + "valueFontSize": "80%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "avg" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "datasource": "Prometheus", + "format": "percentunit", + "gauge": { + "maxValue": 100, + "minValue": 80, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": false + }, + "gridPos": { + "h": 3, + "w": 6, + "x": 6, + "y": 3 + }, + "id": 21, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": true, + "lineColor": "rgb(31, 120, 193)", + "show": true + }, + "tableColumn": "", + "targets": [ + { + "expr": "sum(rate(istio_requests_total{reporter=\"destination\", response_code!~\"5.*\"}[1m])) / sum(rate(istio_requests_total{reporter=\"destination\"}[1m]))", + "format": "time_series", + "intervalFactor": 1, + "refId": "A", + "step": 4 + } + ], + "thresholds": "95, 99, 99.5", + "title": "Global Success Rate (non-5xx responses)", + "type": "singlestat", + "valueFontSize": "80%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "avg" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "datasource": "Prometheus", + "format": "ops", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "gridPos": { + "h": 3, + "w": 6, + "x": 12, + "y": 3 + }, + "id": 22, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": true, + "lineColor": "rgb(31, 120, 193)", + "show": true + }, + "tableColumn": "", + "targets": [ + { + "expr": "sum(irate(istio_requests_total{reporter=\"destination\", response_code=~\"4.*\"}[1m])) ", + "format": "time_series", + "intervalFactor": 1, + "refId": "A", + "step": 4 + } + ], + "thresholds": "", + "title": "4xxs", + "type": "singlestat", + "valueFontSize": "80%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "avg" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "datasource": "Prometheus", + "format": "ops", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "gridPos": { + "h": 3, + "w": 6, + "x": 18, + "y": 3 + }, + "id": 23, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": true, + "lineColor": "rgb(31, 120, 193)", + "show": true + }, + "tableColumn": "", + "targets": [ + { + "expr": "sum(irate(istio_requests_total{reporter=\"destination\", response_code=~\"5.*\"}[1m])) ", + "format": "time_series", + "intervalFactor": 1, + "refId": "A", + "step": 4 + } + ], + "thresholds": "", + "title": "5xxs", + "type": "singlestat", + "valueFontSize": "80%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "avg" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "#299c46", + "rgba(237, 129, 40, 0.89)", + "#d44a3a" + ], + "format": "none", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "gridPos": { + "h": 3, + "w": 6, + "x": 0, + "y": 6 + }, + "id": 113, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": false, + "lineColor": "rgb(31, 120, 193)", + "show": true + }, + "tableColumn": "", + "targets": [ + { + "expr": "sum(galley_istio_networking_virtualservices) / count(up{job=\"galley\"})", + "format": "time_series", + "intervalFactor": 1, + "refId": "A" + } + ], + "thresholds": "", + "timeFrom": null, + "timeShift": null, + "title": "Virtual Services", + "type": "singlestat", + "valueFontSize": "80%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "current" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "#299c46", + "rgba(237, 129, 40, 0.89)", + "#d44a3a" + ], + "format": "none", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "gridPos": { + "h": 3, + "w": 6, + "x": 6, + "y": 6 + }, + "id": 114, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": false, + "lineColor": "rgb(31, 120, 193)", + "show": true + }, + "tableColumn": "", + "targets": [ + { + "expr": "sum(galley_istio_networking_destinationrules) / count(up{job=\"galley\"})", + "format": "time_series", + "intervalFactor": 1, + "refId": "A" + } + ], + "thresholds": "", + "timeFrom": null, + "timeShift": null, + "title": "Destination Rules", + "type": "singlestat", + "valueFontSize": "80%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "current" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "#299c46", + "rgba(237, 129, 40, 0.89)", + "#d44a3a" + ], + "format": "none", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "gridPos": { + "h": 3, + "w": 6, + "x": 12, + "y": 6 + }, + "id": 115, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": false, + "lineColor": "rgb(31, 120, 193)", + "show": true + }, + "tableColumn": "", + "targets": [ + { + "expr": "sum(galley_istio_networking_gateways) / count(up{job=\"galley\"})", + "format": "time_series", + "intervalFactor": 1, + "refId": "A" + } + ], + "thresholds": "", + "timeFrom": null, + "timeShift": null, + "title": "Gateways", + "type": "singlestat", + "valueFontSize": "80%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "current" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "#299c46", + "rgba(237, 129, 40, 0.89)", + "#d44a3a" + ], + "format": "none", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "gridPos": { + "h": 3, + "w": 6, + "x": 18, + "y": 6 + }, + "id": 116, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": false, + "lineColor": "rgb(31, 120, 193)", + "show": true + }, + "tableColumn": "", + "targets": [ + { + "expr": "sum(galley_istio_authentication_meshpolicies) / count(up{job=\"galley\"})", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "refId": "A" + } + ], + "thresholds": "", + "timeFrom": null, + "timeShift": null, + "title": "Authentication Mesh Policies", + "type": "singlestat", + "valueFontSize": "80%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "current" + }, + { + "columns": [], + "datasource": "Prometheus", + "fontSize": "100%", + "gridPos": { + "h": 21, + "w": 24, + "x": 0, + "y": 9 + }, + "hideTimeOverride": false, + "id": 73, + "links": [], + "pageSize": null, + "repeat": null, + "repeatDirection": "v", + "scroll": true, + "showHeader": true, + "sort": { + "col": 4, + "desc": true + }, + "styles": [ + { + "alias": "Workload", + "colorMode": null, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "link": false, + "linkTargetBlank": false, + "linkTooltip": "Workload dashboard", + "linkUrl": "/dashboard/db/istio-workload-dashboard?var-namespace=$__cell_2&var-workload=$__cell_", + "pattern": "destination_workload", + "preserveFormat": false, + "sanitize": false, + "thresholds": [], + "type": "hidden", + "unit": "short" + }, + { + "alias": "", + "colorMode": null, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "pattern": "Time", + "thresholds": [], + "type": "hidden", + "unit": "short" + }, + { + "alias": "Requests", + "colorMode": null, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "pattern": "Value #A", + "thresholds": [], + "type": "number", + "unit": "ops" + }, + { + "alias": "P50 Latency", + "colorMode": null, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "pattern": "Value #B", + "thresholds": [], + "type": "number", + "unit": "s" + }, + { + "alias": "P90 Latency", + "colorMode": null, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "pattern": "Value #D", + "thresholds": [], + "type": "number", + "unit": "s" + }, + { + "alias": "P99 Latency", + "colorMode": null, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "pattern": "Value #E", + "thresholds": [], + "type": "number", + "unit": "s" + }, + { + "alias": "Success Rate", + "colorMode": "cell", + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "pattern": "Value #F", + "thresholds": [ + ".95", + " 1.00" + ], + "type": "number", + "unit": "percentunit" + }, + { + "alias": "Workload", + "colorMode": null, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "link": true, + "linkTooltip": "$__cell dashboard", + "linkUrl": "/dashboard/db/istio-workload-dashboard?var-workload=$__cell_2&var-namespace=$__cell_3", + "pattern": "destination_workload_var", + "thresholds": [], + "type": "number", + "unit": "short" + }, + { + "alias": "Service", + "colorMode": null, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "link": true, + "linkTooltip": "$__cell dashboard", + "linkUrl": "/dashboard/db/istio-service-dashboard?var-service=$__cell", + "pattern": "destination_service", + "thresholds": [], + "type": "string", + "unit": "short" + }, + { + "alias": "", + "colorMode": null, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "pattern": "destination_workload_namespace", + "thresholds": [], + "type": "hidden", + "unit": "short" + } + ], + "targets": [ + { + "expr": "label_join(sum(rate(istio_requests_total{reporter=\"destination\", response_code=\"200\"}[1m])) by (destination_workload, destination_workload_namespace, destination_service), \"destination_workload_var\", \".\", \"destination_workload\", \"destination_workload_namespace\")", + "format": "table", + "hide": false, + "instant": true, + "intervalFactor": 1, + "legendFormat": "{{ destination_workload}}.{{ destination_workload_namespace }}", + "refId": "A" + }, + { + "expr": "label_join((histogram_quantile(0.50, sum(rate(istio_request_duration_milliseconds_bucket{reporter=\"destination\"}[1m])) by (le, destination_workload, destination_workload_namespace)) / 1000) or histogram_quantile(0.50, sum(rate(istio_request_duration_seconds_bucket{reporter=\"destination\"}[1m])) by (le, destination_workload, destination_workload_namespace)), \"destination_workload_var\", \".\", \"destination_workload\", \"destination_workload_namespace\")", + "format": "table", + "hide": false, + "instant": true, + "intervalFactor": 1, + "legendFormat": "{{ destination_workload}}.{{ destination_workload_namespace }}", + "refId": "B" + }, + { + "expr": "label_join((histogram_quantile(0.90, sum(rate(istio_request_duration_milliseconds_bucket{reporter=\"destination\"}[1m])) by (le, destination_workload, destination_workload_namespace)) / 1000) or histogram_quantile(0.90, sum(rate(istio_request_duration_seconds_bucket{reporter=\"destination\"}[1m])) by (le, destination_workload, destination_workload_namespace)), \"destination_workload_var\", \".\", \"destination_workload\", \"destination_workload_namespace\")", + "format": "table", + "hide": false, + "instant": true, + "intervalFactor": 1, + "legendFormat": "{{ destination_workload }}.{{ destination_workload_namespace }}", + "refId": "D" + }, + { + "expr": "label_join((histogram_quantile(0.99, sum(rate(istio_request_duration_milliseconds_bucket{reporter=\"destination\"}[1m])) by (le, destination_workload, destination_workload_namespace)) / 1000) or histogram_quantile(0.99, sum(rate(istio_request_duration_seconds_bucket{reporter=\"destination\"}[1m])) by (le, destination_workload, destination_workload_namespace)), \"destination_workload_var\", \".\", \"destination_workload\", \"destination_workload_namespace\")", + "format": "table", + "hide": false, + "instant": true, + "intervalFactor": 1, + "legendFormat": "{{ destination_workload }}.{{ destination_workload_namespace }}", + "refId": "E" + }, + { + "expr": "label_join((sum(rate(istio_requests_total{reporter=\"destination\", response_code!~\"5.*\"}[1m])) by (destination_workload, destination_workload_namespace) / sum(rate(istio_requests_total{reporter=\"destination\"}[1m])) by (destination_workload, destination_workload_namespace)), \"destination_workload_var\", \".\", \"destination_workload\", \"destination_workload_namespace\")", + "format": "table", + "hide": false, + "instant": true, + "interval": "", + "intervalFactor": 1, + "legendFormat": "{{ destination_workload }}.{{ destination_workload_namespace }}", + "refId": "F" + } + ], + "timeFrom": null, + "title": "HTTP/GRPC Workloads", + "transform": "table", + "type": "table" + }, + { + "columns": [], + "datasource": "Prometheus", + "fontSize": "100%", + "gridPos": { + "h": 18, + "w": 24, + "x": 0, + "y": 30 + }, + "hideTimeOverride": false, + "id": 109, + "links": [], + "pageSize": null, + "repeatDirection": "v", + "scroll": true, + "showHeader": true, + "sort": { + "col": 2, + "desc": true + }, + "styles": [ + { + "alias": "Workload", + "colorMode": null, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "link": false, + "linkTargetBlank": false, + "linkTooltip": "$__cell dashboard", + "linkUrl": "/dashboard/db/istio-tcp-workload-dashboard?var-namespace=$__cell_2&&var-workload=$__cell", + "pattern": "destination_workload", + "preserveFormat": false, + "sanitize": false, + "thresholds": [], + "type": "hidden", + "unit": "short" + }, + { + "alias": "Bytes Sent", + "colorMode": null, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "pattern": "Value #A", + "thresholds": [ + "" + ], + "type": "number", + "unit": "Bps" + }, + { + "alias": "Bytes Received", + "colorMode": null, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "pattern": "Value #C", + "thresholds": [], + "type": "number", + "unit": "Bps" + }, + { + "alias": "", + "colorMode": null, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "pattern": "Time", + "thresholds": [], + "type": "hidden", + "unit": "short" + }, + { + "alias": "Workload", + "colorMode": null, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "link": true, + "linkTooltip": "$__cell dashboard", + "linkUrl": "/dashboard/db/istio-workload-dashboard?var-namespace=$__cell_3&var-workload=$__cell_2", + "pattern": "destination_workload_var", + "thresholds": [], + "type": "string", + "unit": "short" + }, + { + "alias": "", + "colorMode": null, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "pattern": "destination_workload_namespace", + "thresholds": [], + "type": "hidden", + "unit": "short" + }, + { + "alias": "Service", + "colorMode": null, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "link": true, + "linkTooltip": "$__cell dashboard", + "linkUrl": "/dashboard/db/istio-service-dashboard?var-service=$__cell", + "pattern": "destination_service", + "thresholds": [], + "type": "number", + "unit": "short" + } + ], + "targets": [ + { + "expr": "label_join(sum(rate(istio_tcp_received_bytes_total{reporter=\"source\"}[1m])) by (destination_workload, destination_workload_namespace, destination_service), \"destination_workload_var\", \".\", \"destination_workload\", \"destination_workload_namespace\")", + "format": "table", + "hide": false, + "instant": true, + "intervalFactor": 1, + "legendFormat": "{{ destination_workload }}", + "refId": "C" + }, + { + "expr": "label_join(sum(rate(istio_tcp_sent_bytes_total{reporter=\"source\"}[1m])) by (destination_workload, destination_workload_namespace, destination_service), \"destination_workload_var\", \".\", \"destination_workload\", \"destination_workload_namespace\")", + "format": "table", + "hide": false, + "instant": true, + "intervalFactor": 1, + "legendFormat": "{{ destination_workload }}", + "refId": "A" + } + ], + "timeFrom": null, + "title": "TCP Workloads", + "transform": "table", + "type": "table" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 9, + "w": 24, + "x": 0, + "y": 48 + }, + "id": 111, + "legend": { + "alignAsTable": false, + "avg": false, + "current": false, + "max": false, + "min": false, + "rightSide": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(istio_build) by (component, tag)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{ component }}: {{ tag }}", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Istio Components by Version", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + } + ], + "refresh": "5s", + "schemaVersion": 18, + "style": "dark", + "tags": [], + "templating": { + "list": [] + }, + "time": { + "from": "now-5m", + "to": "now" + }, + "timepicker": { + "refresh_intervals": [ + "5s", + "10s", + "30s", + "1m", + "5m", + "15m", + "30m", + "1h", + "2h", + "1d" + ], + "time_options": [ + "5m", + "15m", + "1h", + "6h", + "12h", + "24h", + "2d", + "7d", + "30d" + ] + }, + "timezone": "browser", + "title": "Istio Mesh Dashboard", + "uid": "G8wLrJIZk", + "version": 5 +} +' +--- +apiVersion: v1 +kind: ConfigMap +metadata: + name: istio-grafana-configuration-dashboards-istio-performance-dashboard + namespace: istio-system + labels: + app: grafana + chart: grafana + heritage: Tiller + release: istio + istio: grafana +data: + istio-performance-dashboard.json: '{ + "annotations": { + "list": [ + { + "builtIn": 1, + "datasource": "-- Grafana --", + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations & Alerts", + "type": "dashboard" + } + ] + }, + "editable": false, + "gnetId": null, + "graphTooltip": 0, + "id": 9, + "links": [], + "panels": [ + { + "collapsed": true, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 0 + }, + "id": 21, + "panels": [ + { + "content": "The charts on this dashboard are intended to show Istio main components cost in terms resources utilization under steady load.\n\n- **vCPU/1k rps:** shows vCPU utilization by the main Istio components normalized by 1000 requests/second. When idle or low traffic, this chart will be blank. The curve for istio-proxy refers to the services sidecars only.\n- **vCPU:** vCPU utilization by Istio components, not normalized.\n- **Memory:** memory footprint for the components. Telemetry and policy are normalized by 1k rps, and no data is shown when there is no traffic. For ingress and istio-proxy, the data is per instance.\n- **Bytes transferred/ sec:** shows the number of bytes flowing through each Istio component.\n\n\n", + "gridPos": { + "h": 6, + "w": 24, + "x": 0, + "y": 1 + }, + "id": 19, + "links": [], + "mode": "markdown", + "timeFrom": null, + "timeShift": null, + "title": "Performance Dashboard README", + "transparent": true, + "type": "text" + } + ], + "title": "Performance Dashboard Notes", + "type": "row" + }, + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 1 + }, + "id": 6, + "panels": [], + "title": "vCPU Usage", + "type": "row" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "fill": 1, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 2 + }, + "id": 4, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "(sum(irate(container_cpu_usage_seconds_total{job=\"kubernetes-cadvisor\",pod_name=~\"istio-telemetry-.*\",container_name=~\"mixer|istio-proxy\"}[1m]))/ (round(sum(irate(istio_requests_total[1m])), 0.001)/1000))/ (sum(irate(istio_requests_total{source_workload=\"istio-ingressgateway\"}[1m])) >bool 10)", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "istio-telemetry", + "refId": "A" + }, + { + "expr": "(sum(irate(container_cpu_usage_seconds_total{job=\"kubernetes-cadvisor\",pod_name=~\"istio-ingressgateway-.*\",container_name=\"istio-proxy\"}[1m])) / (round(sum(irate(istio_requests_total{source_workload=\"istio-ingressgateway\", reporter=\"source\"}[1m])), 0.001)/1000))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "istio-ingressgateway", + "refId": "B" + }, + { + "expr": "(sum(irate(container_cpu_usage_seconds_total{job=\"kubernetes-cadvisor\",namespace!=\"istio-system\",container_name=\"istio-proxy\"}[1m]))/ (round(sum(irate(istio_requests_total[1m])), 0.001)/1000))/ (sum(irate(istio_requests_total{source_workload=\"istio-ingressgateway\"}[1m])) >bool 10)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "istio-proxy", + "refId": "C" + }, + { + "expr": "(sum(irate(container_cpu_usage_seconds_total{job=\"kubernetes-cadvisor\",pod_name=~\"istio-policy-.*\",container_name=~\"mixer|istio-proxy\"}[1m]))/ (round(sum(irate(istio_requests_total[1m])), 0.001)/1000))/ (sum(irate(istio_requests_total{source_workload=\"istio-ingressgateway\"}[1m])) >bool 10)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "istio-policy", + "refId": "D" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "vCPU / 1k rps", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "fill": 1, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 2 + }, + "id": 7, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(rate(container_cpu_usage_seconds_total{job=\"kubernetes-cadvisor\",pod_name=~\"istio-telemetry-.*\",container_name=~\"mixer|istio-proxy\"}[1m]))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "istio-telemetry", + "refId": "A" + }, + { + "expr": "sum(rate(container_cpu_usage_seconds_total{job=\"kubernetes-cadvisor\",pod_name=~\"istio-ingressgateway-.*\",container_name=\"istio-proxy\"}[1m]))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "istio-ingressgateway", + "refId": "B" + }, + { + "expr": "sum(rate(container_cpu_usage_seconds_total{job=\"kubernetes-cadvisor\",namespace!=\"istio-system\",container_name=\"istio-proxy\"}[1m]))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "istio-proxy", + "refId": "C" + }, + { + "expr": "sum(rate(container_cpu_usage_seconds_total{job=\"kubernetes-cadvisor\",pod_name=~\"istio-policy-.*\",container_name=~\"mixer|istio-proxy\"}[1m]))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "istio-policy", + "refId": "D" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "vCPU", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 10 + }, + "id": 13, + "panels": [], + "title": "Memory and Data Rates", + "type": "row" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "fill": 1, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 11 + }, + "id": 902, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "(sum(container_memory_usage_bytes{job=\"kubernetes-cadvisor\",pod_name=~\"istio-telemetry-.*\"}) / (sum(irate(istio_requests_total[1m])) / 1000)) / (sum(irate(istio_requests_total{source_workload=\"istio-ingressgateway\"}[1m])) >bool 10)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "istio-telemetry / 1k rps", + "refId": "A" + }, + { + "expr": "sum(container_memory_usage_bytes{job=\"kubernetes-cadvisor\",pod_name=~\"istio-ingressgateway-.*\"}) / count(container_memory_usage_bytes{job=\"kubernetes-cadvisor\",pod_name=~\"istio-ingressgateway-.*\",container_name!=\"POD\"})", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "per istio-ingressgateway", + "refId": "B" + }, + { + "expr": "sum(container_memory_usage_bytes{job=\"kubernetes-cadvisor\",namespace!=\"istio-system\",container_name=\"istio-proxy\"}) / count(container_memory_usage_bytes{job=\"kubernetes-cadvisor\",namespace!=\"istio-system\",container_name=\"istio-proxy\"})", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "per istio proxy", + "refId": "C" + }, + { + "expr": "(sum(container_memory_usage_bytes{job=\"kubernetes-cadvisor\",pod_name=~\"istio-policy-.*\"}) / (sum(irate(istio_requests_total[1m])) / 1000))/ (sum(irate(istio_requests_total{source_workload=\"istio-ingressgateway\"}[1m])) >bool 10)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "istio-policy / 1k rps", + "refId": "D" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Memory Usage", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "bytes", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "fill": 1, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 11 + }, + "id": 11, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(irate(istio_response_bytes_sum{destination_workload=\"istio-telemetry\"}[1m])) + sum(irate(istio_request_bytes_sum{destination_workload=\"istio-telemetry\"}[1m]))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "istio-telemetry", + "refId": "A" + }, + { + "expr": "sum(irate(istio_response_bytes_sum{source_workload=\"istio-ingressgateway\", reporter=\"source\"}[1m]))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "istio-ingressgateway", + "refId": "B" + }, + { + "expr": "sum(irate(istio_response_bytes_sum{source_workload_namespace!=\"istio-system\", reporter=\"source\"}[1m])) + sum(irate(istio_response_bytes_sum{destination_workload_namespace!=\"istio-system\", reporter=\"destination\"}[1m])) + sum(irate(istio_request_bytes_sum{source_workload_namespace!=\"istio-system\", reporter=\"source\"}[1m])) + sum(irate(istio_request_bytes_sum{destination_workload_namespace!=\"istio-system\", reporter=\"destination\"}[1m]))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "istio-proxy", + "refId": "C" + }, + { + "expr": "sum(irate(istio_response_bytes_sum{destination_workload=\"istio-policy\"}[1m])) + sum(irate(istio_request_bytes_sum{destination_workload=\"istio-policy\"}[1m]))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "istio_policy", + "refId": "D" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Bytes transferred / sec", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "Bps", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 19 + }, + "id": 17, + "panels": [], + "title": "Istio Component Versions", + "type": "row" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "fill": 1, + "gridPos": { + "h": 8, + "w": 24, + "x": 0, + "y": 20 + }, + "id": 15, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(istio_build) by (component, tag)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{ component }}: {{ tag }}", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Istio Components by Version", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 31 + }, + "id": 71, + "panels": [], + "title": "Proxy Resource Usage", + "type": "row" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 7, + "w": 6, + "x": 0, + "y": 32 + }, + "id": 72, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(container_memory_usage_bytes{job=\"kubernetes-cadvisor\",container_name=\"istio-proxy\"})", + "format": "time_series", + "hide": false, + "intervalFactor": 2, + "legendFormat": "{{ container_name }} (k8s)", + "refId": "B", + "step": 2 + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Memory", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "bytes", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 7, + "w": 6, + "x": 6, + "y": 32 + }, + "id": 73, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(rate(container_cpu_usage_seconds_total{job=\"kubernetes-cadvisor\",container_name=\"istio-proxy\"}[1m]))", + "format": "time_series", + "hide": false, + "intervalFactor": 2, + "legendFormat": "Total (k8s)", + "refId": "A", + "step": 2 + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "vCPU", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 7, + "w": 6, + "x": 12, + "y": 32 + }, + "id": 702, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(container_fs_usage_bytes{job=\"kubernetes-cadvisor\", container_name=\"istio-proxy\"})", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "{{ container_name }}", + "refId": "B", + "step": 2 + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Disk", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "bytes", + "label": "", + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "decimals": null, + "format": "none", + "label": "", + "logBase": 1024, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 39 + }, + "id": 69, + "panels": [], + "title": "Pilot Resource Usage", + "type": "row" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 7, + "w": 6, + "x": 0, + "y": 40 + }, + "id": 5, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "process_virtual_memory_bytes{job=\"pilot\"}", + "format": "time_series", + "instant": false, + "intervalFactor": 2, + "legendFormat": "Virtual Memory", + "refId": "I", + "step": 2 + }, + { + "expr": "process_resident_memory_bytes{job=\"pilot\"}", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "Resident Memory", + "refId": "H", + "step": 2 + }, + { + "expr": "go_memstats_heap_sys_bytes{job=\"pilot\"}", + "format": "time_series", + "hide": true, + "intervalFactor": 2, + "legendFormat": "heap sys", + "refId": "A" + }, + { + "expr": "go_memstats_heap_alloc_bytes{job=\"pilot\"}", + "format": "time_series", + "hide": true, + "intervalFactor": 2, + "legendFormat": "heap alloc", + "refId": "D" + }, + { + "expr": "go_memstats_alloc_bytes{job=\"pilot\"}", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "Alloc", + "refId": "F", + "step": 2 + }, + { + "expr": "go_memstats_heap_inuse_bytes{job=\"pilot\"}", + "format": "time_series", + "hide": false, + "intervalFactor": 2, + "legendFormat": "Heap in-use", + "refId": "E", + "step": 2 + }, + { + "expr": "go_memstats_stack_inuse_bytes{job=\"pilot\"}", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "Stack in-use", + "refId": "G", + "step": 2 + }, + { + "expr": "sum(container_memory_usage_bytes{job=\"kubernetes-cadvisor\",container_name=~\"discovery|istio-proxy\", pod_name=~\"istio-pilot-.*\"})", + "format": "time_series", + "hide": false, + "intervalFactor": 2, + "legendFormat": "Total (k8s)", + "refId": "C", + "step": 2 + }, + { + "expr": "container_memory_usage_bytes{job=\"kubernetes-cadvisor\",container_name=~\"discovery|istio-proxy\", pod_name=~\"istio-pilot-.*\"}", + "format": "time_series", + "hide": false, + "intervalFactor": 2, + "legendFormat": "{{ container_name }} (k8s)", + "refId": "B", + "step": 2 + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Memory", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "bytes", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 7, + "w": 6, + "x": 6, + "y": 40 + }, + "id": 602, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(rate(container_cpu_usage_seconds_total{job=\"kubernetes-cadvisor\",container_name=~\"discovery|istio-proxy\", pod_name=~\"istio-pilot-.*\"}[1m]))", + "format": "time_series", + "hide": false, + "intervalFactor": 2, + "legendFormat": "Total (k8s)", + "refId": "A", + "step": 2 + }, + { + "expr": "sum(rate(container_cpu_usage_seconds_total{job=\"kubernetes-cadvisor\",container_name=~\"discovery|istio-proxy\", pod_name=~\"istio-pilot-.*\"}[1m])) by (container_name)", + "format": "time_series", + "hide": false, + "intervalFactor": 2, + "legendFormat": "{{ container_name }} (k8s)", + "refId": "B", + "step": 2 + }, + { + "expr": "irate(process_cpu_seconds_total{job=\"pilot\"}[1m])", + "format": "time_series", + "hide": false, + "intervalFactor": 2, + "legendFormat": "pilot (self-reported)", + "refId": "C", + "step": 2 + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "vCPU", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 7, + "w": 6, + "x": 12, + "y": 40 + }, + "id": 74, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "process_open_fds{job=\"pilot\"}", + "format": "time_series", + "hide": true, + "instant": false, + "interval": "", + "intervalFactor": 2, + "legendFormat": "Open FDs (pilot)", + "refId": "A" + }, + { + "expr": "container_fs_usage_bytes{job=\"kubernetes-cadvisor\", container_name=~\"discovery|istio-proxy\", pod_name=~\"istio-pilot-.*\"}", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "{{ container_name }}", + "refId": "B", + "step": 2 + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Disk", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "bytes", + "label": "", + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "decimals": null, + "format": "none", + "label": "", + "logBase": 1024, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 7, + "w": 6, + "x": 18, + "y": 40 + }, + "id": 402, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": false, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "go_goroutines{job=\"pilot\"}", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "Number of Goroutines", + "refId": "A", + "step": 2 + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Goroutines", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": "", + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 47 + }, + "id": 93, + "panels": [], + "title": "Mixer Resource Usage", + "type": "row" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 7, + "w": 6, + "x": 0, + "y": 48 + }, + "id": 94, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "process_virtual_memory_bytes{job=~\"istio-telemetry|istio-policy\"}", + "format": "time_series", + "instant": false, + "intervalFactor": 2, + "legendFormat": "Virtual Memory", + "refId": "I", + "step": 2 + }, + { + "expr": "process_resident_memory_bytes{job=~\"istio-telemetry|istio-policy\"}", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "Resident Memory", + "refId": "H", + "step": 2 + }, + { + "expr": "go_memstats_heap_sys_bytes{job=~\"istio-telemetry|istio-policy\"}", + "format": "time_series", + "hide": true, + "intervalFactor": 2, + "legendFormat": "heap sys", + "refId": "A" + }, + { + "expr": "go_memstats_heap_alloc_bytes{job=~\"istio-telemetry|istio-policy\"}", + "format": "time_series", + "hide": true, + "intervalFactor": 2, + "legendFormat": "heap alloc", + "refId": "D" + }, + { + "expr": "go_memstats_alloc_bytes{job=~\"istio-telemetry|istio-policy\"}", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "Alloc", + "refId": "F", + "step": 2 + }, + { + "expr": "go_memstats_heap_inuse_bytes{job=~\"istio-telemetry|istio-policy\"}", + "format": "time_series", + "hide": false, + "intervalFactor": 2, + "legendFormat": "Heap in-use", + "refId": "E", + "step": 2 + }, + { + "expr": "go_memstats_stack_inuse_bytes{job=~\"istio-policy|istio-telemetry\"}", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "Stack in-use", + "refId": "G", + "step": 2 + }, + { + "expr": "sum(container_memory_usage_bytes{job=\"kubernetes-cadvisor\",container_name=~\"mixer|istio-proxy\", pod_name=~\"istio-telemetry-.*\"})", + "format": "time_series", + "hide": false, + "intervalFactor": 2, + "legendFormat": "Total (k8s)", + "refId": "C", + "step": 2 + }, + { + "expr": "container_memory_usage_bytes{job=\"kubernetes-cadvisor\",container_name=~\"mixer|istio-proxy\", pod_name=~\"istio-telemetry-.*\"}", + "format": "time_series", + "hide": false, + "intervalFactor": 2, + "legendFormat": "{{ container_name }} (k8s)", + "refId": "B", + "step": 2 + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Memory", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "bytes", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 7, + "w": 6, + "x": 6, + "y": 48 + }, + "id": 95, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(rate(container_cpu_usage_seconds_total{job=\"kubernetes-cadvisor\",container_name=~\"mixer|istio-proxy\", pod_name=~\"istio-telemetry-.*\"}[1m]))", + "format": "time_series", + "hide": false, + "intervalFactor": 2, + "legendFormat": "Total (k8s)", + "refId": "A", + "step": 2 + }, + { + "expr": "sum(rate(container_cpu_usage_seconds_total{job=\"kubernetes-cadvisor\",container_name=~\"mixer|istio-proxy\", pod_name=~\"istio-telemetry-.*\"}[1m])) by (container_name)", + "format": "time_series", + "hide": false, + "intervalFactor": 2, + "legendFormat": "{{ container_name }} (k8s)", + "refId": "B", + "step": 2 + }, + { + "expr": "irate(process_cpu_seconds_total{job=~\"istio-policy|istio-telemetry\"}[1m])", + "format": "time_series", + "hide": false, + "intervalFactor": 2, + "legendFormat": "mixer (self-reported)", + "refId": "C", + "step": 2 + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "vCPU", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 7, + "w": 6, + "x": 12, + "y": 48 + }, + "id": 96, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "process_open_fds{job=~\"istio-policy|istio-telemetry\"}", + "format": "time_series", + "hide": true, + "instant": false, + "interval": "", + "intervalFactor": 2, + "legendFormat": "Open FDs (pilot)", + "refId": "A" + }, + { + "expr": "container_fs_usage_bytes{job=\"kubernetes-cadvisor\", container_name=~\"mixer|istio-proxy\", pod_name=~\"istio-telemetry-.*\"}", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "{{ container_name }}", + "refId": "B", + "step": 2 + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Disk", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "bytes", + "label": "", + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "decimals": null, + "format": "none", + "label": "", + "logBase": 1024, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 7, + "w": 6, + "x": 18, + "y": 48 + }, + "id": 97, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": false, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "go_goroutines{job=\"istio-telemetry\"}", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "Number of Goroutines", + "refId": "A", + "step": 2 + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Goroutines", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": "", + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + } + ], + "refresh": "10s", + "schemaVersion": 18, + "style": "dark", + "tags": [], + "templating": { + "list": [] + }, + "time": { + "from": "now-5m", + "to": "now" + }, + "timepicker": { + "refresh_intervals": [ + "5s", + "10s", + "30s", + "1m", + "5m", + "15m", + "30m", + "1h", + "2h", + "1d" + ], + "time_options": [ + "5m", + "15m", + "1h", + "6h", + "12h", + "24h", + "2d", + "7d", + "30d" + ] + }, + "timezone": "", + "title": "Istio Performance Dashboard", + "uid": "vu8e0VWZk", + "version": 22 +} +' +--- +apiVersion: v1 +kind: ConfigMap +metadata: + name: istio-grafana-configuration-dashboards-istio-service-dashboard + namespace: istio-system + labels: + app: grafana + chart: grafana + heritage: Tiller + release: istio + istio: grafana +data: + istio-service-dashboard.json: '{ + "annotations": { + "list": [ + { + "builtIn": 1, + "datasource": "-- Grafana --", + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations & Alerts", + "type": "dashboard" + } + ] + }, + "editable": false, + "gnetId": null, + "graphTooltip": 0, + "iteration": 1536442501501, + "links": [], + "panels": [ + { + "content": "
\nSERVICE: $service\n
", + "gridPos": { + "h": 3, + "w": 24, + "x": 0, + "y": 0 + }, + "id": 89, + "links": [], + "mode": "html", + "title": "", + "transparent": true, + "type": "text" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "datasource": "Prometheus", + "format": "ops", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "gridPos": { + "h": 4, + "w": 6, + "x": 0, + "y": 3 + }, + "id": 12, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": true, + "lineColor": "rgb(31, 120, 193)", + "show": true + }, + "tableColumn": "", + "targets": [ + { + "expr": "round(sum(irate(istio_requests_total{reporter=\"source\",destination_service=~\"$service\"}[5m])), 0.001)", + "format": "time_series", + "intervalFactor": 1, + "refId": "A", + "step": 4 + } + ], + "thresholds": "", + "title": "Client Request Volume", + "transparent": false, + "type": "singlestat", + "valueFontSize": "80%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "current" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "rgba(50, 172, 45, 0.97)", + "rgba(237, 129, 40, 0.89)", + "rgba(245, 54, 54, 0.9)" + ], + "datasource": "Prometheus", + "decimals": null, + "format": "percentunit", + "gauge": { + "maxValue": 100, + "minValue": 80, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": false + }, + "gridPos": { + "h": 4, + "w": 6, + "x": 6, + "y": 3 + }, + "id": 14, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": true, + "lineColor": "rgb(31, 120, 193)", + "show": true + }, + "tableColumn": "", + "targets": [ + { + "expr": "sum(irate(istio_requests_total{reporter=\"source\",destination_service=~\"$service\",response_code!~\"5.*\"}[5m])) / sum(irate(istio_requests_total{reporter=\"source\",destination_service=~\"$service\"}[5m]))", + "format": "time_series", + "intervalFactor": 1, + "refId": "B" + } + ], + "thresholds": "95, 99, 99.5", + "title": "Client Success Rate (non-5xx responses)", + "transparent": false, + "type": "singlestat", + "valueFontSize": "80%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "avg" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 4, + "w": 6, + "x": 12, + "y": 3 + }, + "id": 87, + "legend": { + "alignAsTable": false, + "avg": false, + "current": false, + "hideEmpty": false, + "hideZero": false, + "max": false, + "min": false, + "rightSide": true, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "(histogram_quantile(0.50, sum(irate(istio_request_duration_milliseconds_bucket{reporter=\"source\",destination_service=~\"$service\"}[1m])) by (le)) / 1000) or histogram_quantile(0.50, sum(irate(istio_request_duration_seconds_bucket{reporter=\"source\",destination_service=~\"$service\"}[1m])) by (le))", + "format": "time_series", + "interval": "", + "intervalFactor": 1, + "legendFormat": "P50", + "refId": "A" + }, + { + "expr": "(histogram_quantile(0.90, sum(irate(istio_request_duration_milliseconds_bucket{reporter=\"source\",destination_service=~\"$service\"}[1m])) by (le)) / 1000) or histogram_quantile(0.90, sum(irate(istio_request_duration_seconds_bucket{reporter=\"source\",destination_service=~\"$service\"}[1m])) by (le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "P90", + "refId": "B" + }, + { + "expr": "(histogram_quantile(0.99, sum(irate(istio_request_duration_milliseconds_bucket{reporter=\"source\",destination_service=~\"$service\"}[1m])) by (le)) / 1000) or histogram_quantile(0.99, sum(irate(istio_request_duration_seconds_bucket{reporter=\"source\",destination_service=~\"$service\"}[1m])) by (le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "P99", + "refId": "C" + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Client Request Duration", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "s", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "#299c46", + "rgba(237, 129, 40, 0.89)", + "#d44a3a" + ], + "datasource": "Prometheus", + "format": "Bps", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "gridPos": { + "h": 4, + "w": 6, + "x": 18, + "y": 3 + }, + "id": 84, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": true, + "lineColor": "rgb(31, 120, 193)", + "show": true + }, + "tableColumn": "", + "targets": [ + { + "expr": "sum(irate(istio_tcp_received_bytes_total{reporter=\"source\", destination_service=~\"$service\"}[1m]))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "", + "refId": "A" + } + ], + "thresholds": "", + "title": "TCP Received Bytes", + "transparent": false, + "type": "singlestat", + "valueFontSize": "80%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "avg" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "datasource": "Prometheus", + "format": "ops", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "gridPos": { + "h": 4, + "w": 6, + "x": 0, + "y": 7 + }, + "id": 97, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": true, + "lineColor": "rgb(31, 120, 193)", + "show": true + }, + "tableColumn": "", + "targets": [ + { + "expr": "round(sum(irate(istio_requests_total{reporter=\"destination\",destination_service=~\"$service\"}[5m])), 0.001)", + "format": "time_series", + "intervalFactor": 1, + "refId": "A", + "step": 4 + } + ], + "thresholds": "", + "title": "Server Request Volume", + "transparent": false, + "type": "singlestat", + "valueFontSize": "80%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "current" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "rgba(50, 172, 45, 0.97)", + "rgba(237, 129, 40, 0.89)", + "rgba(245, 54, 54, 0.9)" + ], + "datasource": "Prometheus", + "decimals": null, + "format": "percentunit", + "gauge": { + "maxValue": 100, + "minValue": 80, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": false + }, + "gridPos": { + "h": 4, + "w": 6, + "x": 6, + "y": 7 + }, + "id": 98, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": true, + "lineColor": "rgb(31, 120, 193)", + "show": true + }, + "tableColumn": "", + "targets": [ + { + "expr": "sum(irate(istio_requests_total{reporter=\"destination\",destination_service=~\"$service\",response_code!~\"5.*\"}[5m])) / sum(irate(istio_requests_total{reporter=\"destination\",destination_service=~\"$service\"}[5m]))", + "format": "time_series", + "intervalFactor": 1, + "refId": "B" + } + ], + "thresholds": "95, 99, 99.5", + "title": "Server Success Rate (non-5xx responses)", + "transparent": false, + "type": "singlestat", + "valueFontSize": "80%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "avg" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 4, + "w": 6, + "x": 12, + "y": 7 + }, + "id": 99, + "legend": { + "alignAsTable": false, + "avg": false, + "current": false, + "hideEmpty": false, + "hideZero": false, + "max": false, + "min": false, + "rightSide": true, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "(histogram_quantile(0.50, sum(irate(istio_request_duration_milliseconds_bucket{reporter=\"destination\",destination_service=~\"$service\"}[1m])) by (le)) / 1000) or histogram_quantile(0.50, sum(irate(istio_request_duration_seconds_bucket{reporter=\"destination\",destination_service=~\"$service\"}[1m])) by (le))", + "format": "time_series", + "interval": "", + "intervalFactor": 1, + "legendFormat": "P50", + "refId": "A" + }, + { + "expr": "(histogram_quantile(0.90, sum(irate(istio_request_duration_milliseconds_bucket{reporter=\"destination\",destination_service=~\"$service\"}[1m])) by (le)) / 1000) or histogram_quantile(0.90, sum(irate(istio_request_duration_seconds_bucket{reporter=\"destination\",destination_service=~\"$service\"}[1m])) by (le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "P90", + "refId": "B" + }, + { + "expr": "(histogram_quantile(0.99, sum(irate(istio_request_duration_milliseconds_bucket{reporter=\"destination\",destination_service=~\"$service\"}[1m])) by (le)) / 1000) or histogram_quantile(0.99, sum(irate(istio_request_duration_seconds_bucket{reporter=\"destination\",destination_service=~\"$service\"}[1m])) by (le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "P99", + "refId": "C" + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Server Request Duration", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "s", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "#299c46", + "rgba(237, 129, 40, 0.89)", + "#d44a3a" + ], + "datasource": "Prometheus", + "format": "Bps", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "gridPos": { + "h": 4, + "w": 6, + "x": 18, + "y": 7 + }, + "id": 100, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": true, + "lineColor": "rgb(31, 120, 193)", + "show": true + }, + "tableColumn": "", + "targets": [ + { + "expr": "sum(irate(istio_tcp_sent_bytes_total{reporter=\"source\", destination_service=~\"$service\"}[1m])) ", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "", + "refId": "A" + } + ], + "thresholds": "", + "title": "TCP Sent Bytes", + "transparent": false, + "type": "singlestat", + "valueFontSize": "80%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "avg" + }, + { + "content": "
\nCLIENT WORKLOADS\n
", + "gridPos": { + "h": 3, + "w": 24, + "x": 0, + "y": 11 + }, + "id": 45, + "links": [], + "mode": "html", + "title": "", + "transparent": true, + "type": "text" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 0, + "gridPos": { + "h": 6, + "w": 12, + "x": 0, + "y": 14 + }, + "id": 25, + "legend": { + "avg": false, + "current": false, + "hideEmpty": true, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null as zero", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "round(sum(irate(istio_requests_total{connection_security_policy=\"mutual_tls\",destination_service=~\"$service\",reporter=\"source\",source_workload=~\"$srcwl\",source_workload_namespace=~\"$srcns\"}[5m])) by (source_workload, source_workload_namespace, response_code), 0.001)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{ source_workload }}.{{ source_workload_namespace }} : {{ response_code }} (🔐mTLS)", + "refId": "B", + "step": 2 + }, + { + "expr": "round(sum(irate(istio_requests_total{connection_security_policy!=\"mutual_tls\", destination_service=~\"$service\", reporter=\"source\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[5m])) by (source_workload, source_workload_namespace, response_code), 0.001)", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ source_workload }}.{{ source_workload_namespace }} : {{ response_code }}", + "refId": "A", + "step": 2 + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Incoming Requests by Source And Response Code", + "tooltip": { + "shared": false, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [ + "total" + ] + }, + "yaxes": [ + { + "format": "ops", + "label": null, + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 6, + "w": 12, + "x": 12, + "y": 14 + }, + "id": 26, + "legend": { + "avg": false, + "current": false, + "hideEmpty": true, + "hideZero": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(irate(istio_requests_total{reporter=\"source\", connection_security_policy=\"mutual_tls\", destination_service=~\"$service\",response_code!~\"5.*\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[5m])) by (source_workload, source_workload_namespace) / sum(irate(istio_requests_total{reporter=\"source\", connection_security_policy=\"mutual_tls\", destination_service=~\"$service\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[5m])) by (source_workload, source_workload_namespace)", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ source_workload }}.{{ source_workload_namespace }} (🔐mTLS)", + "refId": "A", + "step": 2 + }, + { + "expr": "sum(irate(istio_requests_total{reporter=\"source\", connection_security_policy!=\"mutual_tls\", destination_service=~\"$service\",response_code!~\"5.*\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[5m])) by (source_workload, source_workload_namespace) / sum(irate(istio_requests_total{reporter=\"source\", connection_security_policy!=\"mutual_tls\", destination_service=~\"$service\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[5m])) by (source_workload, source_workload_namespace)", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ source_workload }}.{{ source_workload_namespace }}", + "refId": "B", + "step": 2 + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Incoming Success Rate (non-5xx responses) By Source", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "percentunit", + "label": null, + "logBase": 1, + "max": "1.01", + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "description": "", + "fill": 1, + "gridPos": { + "h": 6, + "w": 8, + "x": 0, + "y": 20 + }, + "id": 27, + "legend": { + "alignAsTable": false, + "avg": false, + "current": false, + "hideEmpty": true, + "hideZero": false, + "max": false, + "min": false, + "rightSide": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "(histogram_quantile(0.50, sum(irate(istio_request_duration_milliseconds_bucket{reporter=\"source\", connection_security_policy=\"mutual_tls\", destination_service=~\"$service\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le)) / 1000) or histogram_quantile(0.50, sum(irate(istio_request_duration_seconds_bucket{reporter=\"source\", connection_security_policy=\"mutual_tls\", destination_service=~\"$service\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{source_workload}}.{{source_workload_namespace}} P50 (🔐mTLS)", + "refId": "D", + "step": 2 + }, + { + "expr": "(histogram_quantile(0.90, sum(irate(istio_request_duration_milliseconds_bucket{reporter=\"source\", connection_security_policy=\"mutual_tls\", destination_service=~\"$service\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le)) / 1000) or histogram_quantile(0.90, sum(irate(istio_request_duration_seconds_bucket{reporter=\"source\", connection_security_policy=\"mutual_tls\", destination_service=~\"$service\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{source_workload}}.{{source_workload_namespace}} P90 (🔐mTLS)", + "refId": "A", + "step": 2 + }, + { + "expr": "(histogram_quantile(0.95, sum(irate(istio_request_duration_milliseconds_bucket{reporter=\"source\", connection_security_policy=\"mutual_tls\", destination_service=~\"$service\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le)) / 1000) or histogram_quantile(0.95, sum(irate(istio_request_duration_seconds_bucket{reporter=\"source\", connection_security_policy=\"mutual_tls\", destination_service=~\"$service\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{source_workload}}.{{source_workload_namespace}} P95 (🔐mTLS)", + "refId": "B", + "step": 2 + }, + { + "expr": "(histogram_quantile(0.99, sum(irate(istio_request_duration_milliseconds_bucket{reporter=\"source\", connection_security_policy=\"mutual_tls\", destination_service=~\"$service\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le)) / 1000) or histogram_quantile(0.99, sum(irate(istio_request_duration_seconds_bucket{reporter=\"source\", connection_security_policy=\"mutual_tls\", destination_service=~\"$service\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{source_workload}}.{{source_workload_namespace}} P99 (🔐mTLS)", + "refId": "C", + "step": 2 + }, + { + "expr": "(histogram_quantile(0.50, sum(irate(istio_request_duration_milliseconds_bucket{reporter=\"source\", connection_security_policy!=\"mutual_tls\", destination_service=~\"$service\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le)) / 1000) or histogram_quantile(0.50, sum(irate(istio_request_duration_seconds_bucket{reporter=\"source\", connection_security_policy!=\"mutual_tls\", destination_service=~\"$service\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{source_workload}}.{{source_workload_namespace}} P50", + "refId": "E", + "step": 2 + }, + { + "expr": "(histogram_quantile(0.90, sum(irate(istio_request_duration_milliseconds_bucket{reporter=\"source\", connection_security_policy!=\"mutual_tls\", destination_service=~\"$service\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le)) / 1000) or histogram_quantile(0.90, sum(irate(istio_request_duration_seconds_bucket{reporter=\"source\", connection_security_policy!=\"mutual_tls\", destination_service=~\"$service\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{source_workload}}.{{source_workload_namespace}} P90", + "refId": "F", + "step": 2 + }, + { + "expr": "(histogram_quantile(0.95, sum(irate(istio_request_duration_milliseconds_bucket{reporter=\"source\", connection_security_policy!=\"mutual_tls\", destination_service=~\"$service\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le)) / 1000) or histogram_quantile(0.95, sum(irate(istio_request_duration_seconds_bucket{reporter=\"source\", connection_security_policy!=\"mutual_tls\", destination_service=~\"$service\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{source_workload}}.{{source_workload_namespace}} P95", + "refId": "G", + "step": 2 + }, + { + "expr": "(histogram_quantile(0.99, sum(irate(istio_request_duration_milliseconds_bucket{reporter=\"source\", connection_security_policy!=\"mutual_tls\", destination_service=~\"$service\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le)) / 1000) or histogram_quantile(0.99, sum(irate(istio_request_duration_seconds_bucket{reporter=\"source\", connection_security_policy!=\"mutual_tls\", destination_service=~\"$service\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{source_workload}}.{{source_workload_namespace}} P99", + "refId": "H", + "step": 2 + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Incoming Request Duration by Source", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "s", + "label": null, + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 6, + "w": 8, + "x": 8, + "y": 20 + }, + "id": 28, + "legend": { + "alignAsTable": false, + "avg": false, + "current": false, + "hideEmpty": true, + "max": false, + "min": false, + "rightSide": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "histogram_quantile(0.50, sum(irate(istio_request_bytes_bucket{reporter=\"source\", connection_security_policy=\"mutual_tls\", destination_service=~\"$service\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{source_workload}}.{{source_workload_namespace}} P50 (🔐mTLS)", + "refId": "D", + "step": 2 + }, + { + "expr": "histogram_quantile(0.90, sum(irate(istio_request_bytes_bucket{reporter=\"source\", connection_security_policy=\"mutual_tls\", destination_service=~\"$service\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{source_workload}}.{{source_workload_namespace}} P90 (🔐mTLS)", + "refId": "A", + "step": 2 + }, + { + "expr": "histogram_quantile(0.95, sum(irate(istio_request_bytes_bucket{reporter=\"source\", connection_security_policy=\"mutual_tls\", destination_service=~\"$service\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{source_workload}}.{{source_workload_namespace}} P95 (🔐mTLS)", + "refId": "B", + "step": 2 + }, + { + "expr": "histogram_quantile(0.99, sum(irate(istio_request_bytes_bucket{reporter=\"source\", connection_security_policy=\"mutual_tls\", destination_service=~\"$service\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{source_workload}}.{{source_workload_namespace}} P99 (🔐mTLS)", + "refId": "C", + "step": 2 + }, + { + "expr": "histogram_quantile(0.50, sum(irate(istio_request_bytes_bucket{reporter=\"source\", connection_security_policy!=\"mutual_tls\", destination_service=~\"$service\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{source_workload}}.{{source_workload_namespace}} P50", + "refId": "E", + "step": 2 + }, + { + "expr": "histogram_quantile(0.90, sum(irate(istio_request_bytes_bucket{reporter=\"source\", connection_security_policy!=\"mutual_tls\", destination_service=~\"$service\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{source_workload}}.{{source_workload_namespace}} P90", + "refId": "F", + "step": 2 + }, + { + "expr": "histogram_quantile(0.95, sum(irate(istio_request_bytes_bucket{reporter=\"source\", connection_security_policy!=\"mutual_tls\", destination_service=~\"$service\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{source_workload}}.{{source_workload_namespace}} P95", + "refId": "G", + "step": 2 + }, + { + "expr": "histogram_quantile(0.99, sum(irate(istio_request_bytes_bucket{reporter=\"source\", connection_security_policy!=\"mutual_tls\", destination_service=~\"$service\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{source_workload}}.{{source_workload_namespace}} P99", + "refId": "H", + "step": 2 + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Incoming Request Size By Source", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "decbytes", + "label": null, + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 6, + "w": 8, + "x": 16, + "y": 20 + }, + "id": 68, + "legend": { + "alignAsTable": false, + "avg": false, + "current": false, + "hideEmpty": true, + "max": false, + "min": false, + "rightSide": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "histogram_quantile(0.50, sum(irate(istio_response_bytes_bucket{reporter=\"source\", connection_security_policy=\"mutual_tls\", destination_service=~\"$service\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{source_workload}}.{{source_workload_namespace}} P50 (🔐mTLS)", + "refId": "D", + "step": 2 + }, + { + "expr": "histogram_quantile(0.90, sum(irate(istio_response_bytes_bucket{reporter=\"source\", connection_security_policy=\"mutual_tls\", destination_service=~\"$service\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{source_workload}}.{{source_workload_namespace}} P90 (🔐mTLS)", + "refId": "A", + "step": 2 + }, + { + "expr": "histogram_quantile(0.95, sum(irate(istio_response_bytes_bucket{reporter=\"source\", connection_security_policy=\"mutual_tls\", destination_service=~\"$service\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{source_workload}}.{{source_workload_namespace}} P95 (🔐mTLS)", + "refId": "B", + "step": 2 + }, + { + "expr": "histogram_quantile(0.99, sum(irate(istio_response_bytes_bucket{reporter=\"source\", connection_security_policy=\"mutual_tls\", destination_service=~\"$service\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{source_workload}}.{{source_workload_namespace}} P99 (🔐mTLS)", + "refId": "C", + "step": 2 + }, + { + "expr": "histogram_quantile(0.50, sum(irate(istio_response_bytes_bucket{reporter=\"source\", connection_security_policy!=\"mutual_tls\", destination_service=~\"$service\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{source_workload}}.{{source_workload_namespace}} P50", + "refId": "E", + "step": 2 + }, + { + "expr": "histogram_quantile(0.90, sum(irate(istio_response_bytes_bucket{reporter=\"source\", connection_security_policy!=\"mutual_tls\", destination_service=~\"$service\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{source_workload}}.{{source_workload_namespace}} P90", + "refId": "F", + "step": 2 + }, + { + "expr": "histogram_quantile(0.95, sum(irate(istio_response_bytes_bucket{reporter=\"source\", connection_security_policy!=\"mutual_tls\", destination_service=~\"$service\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{source_workload}}.{{source_workload_namespace}} P95", + "refId": "G", + "step": 2 + }, + { + "expr": "histogram_quantile(0.99, sum(irate(istio_response_bytes_bucket{reporter=\"source\", connection_security_policy!=\"mutual_tls\", destination_service=~\"$service\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{source_workload}}.{{source_workload_namespace}} P99", + "refId": "H", + "step": 2 + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Response Size By Source", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "decbytes", + "label": null, + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 6, + "w": 12, + "x": 0, + "y": 26 + }, + "id": 80, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "round(sum(irate(istio_tcp_received_bytes_total{reporter=\"source\", connection_security_policy=\"mutual_tls\", destination_service=~\"$service\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace), 0.001)", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ source_workload }}.{{ source_workload_namespace}} (🔐mTLS)", + "refId": "A", + "step": 2 + }, + { + "expr": "round(sum(irate(istio_tcp_received_bytes_total{reporter=\"source\", connection_security_policy!=\"mutual_tls\", destination_service=~\"$service\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace), 0.001)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{ source_workload }}.{{ source_workload_namespace}}", + "refId": "B", + "step": 2 + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Bytes Received from Incoming TCP Connection", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "Bps", + "label": null, + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 6, + "w": 12, + "x": 12, + "y": 26 + }, + "id": 82, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "round(sum(irate(istio_tcp_sent_bytes_total{connection_security_policy=\"mutual_tls\", reporter=\"source\", destination_service=~\"$service\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace), 0.001)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{ source_workload }}.{{ source_workload_namespace}} (🔐mTLS)", + "refId": "A", + "step": 2 + }, + { + "expr": "round(sum(irate(istio_tcp_sent_bytes_total{connection_security_policy!=\"mutual_tls\", reporter=\"source\", destination_service=~\"$service\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace), 0.001)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{ source_workload }}.{{ source_workload_namespace}}", + "refId": "B", + "step": 2 + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Bytes Sent to Incoming TCP Connection", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "Bps", + "label": null, + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "content": "
\nSERVICE WORKLOADS\n
", + "gridPos": { + "h": 3, + "w": 24, + "x": 0, + "y": 32 + }, + "id": 69, + "links": [], + "mode": "html", + "title": "", + "transparent": true, + "type": "text" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 0, + "gridPos": { + "h": 6, + "w": 12, + "x": 0, + "y": 35 + }, + "id": 90, + "legend": { + "avg": false, + "current": false, + "hideEmpty": true, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null as zero", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "round(sum(irate(istio_requests_total{connection_security_policy=\"mutual_tls\",destination_service=~\"$service\",reporter=\"destination\",destination_workload=~\"$dstwl\",destination_workload_namespace=~\"$dstns\"}[5m])) by (destination_workload, destination_workload_namespace, response_code), 0.001)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{ destination_workload }}.{{ destination_workload_namespace }} : {{ response_code }} (🔐mTLS)", + "refId": "B", + "step": 2 + }, + { + "expr": "round(sum(irate(istio_requests_total{connection_security_policy!=\"mutual_tls\", destination_service=~\"$service\", reporter=\"destination\", destination_workload=~\"$dstwl\", destination_workload_namespace=~\"$dstns\"}[5m])) by (destination_workload, destination_workload_namespace, response_code), 0.001)", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_workload }}.{{ destination_workload_namespace }} : {{ response_code }}", + "refId": "A", + "step": 2 + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Incoming Requests by Destination And Response Code", + "tooltip": { + "shared": false, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [ + "total" + ] + }, + "yaxes": [ + { + "format": "ops", + "label": null, + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 6, + "w": 12, + "x": 12, + "y": 35 + }, + "id": 91, + "legend": { + "avg": false, + "current": false, + "hideEmpty": true, + "hideZero": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(irate(istio_requests_total{reporter=\"destination\", connection_security_policy=\"mutual_tls\", destination_service=~\"$service\",response_code!~\"5.*\", destination_workload=~\"$dstwl\", destination_workload_namespace=~\"$dstns\"}[5m])) by (destination_workload, destination_workload_namespace) / sum(irate(istio_requests_total{reporter=\"destination\", connection_security_policy=\"mutual_tls\", destination_service=~\"$service\", destination_workload=~\"$dstwl\", destination_workload_namespace=~\"$dstns\"}[5m])) by (destination_workload, destination_workload_namespace)", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_workload }}.{{ destination_workload_namespace }} (🔐mTLS)", + "refId": "A", + "step": 2 + }, + { + "expr": "sum(irate(istio_requests_total{reporter=\"destination\", connection_security_policy!=\"mutual_tls\", destination_service=~\"$service\",response_code!~\"5.*\", destination_workload=~\"$dstwl\", destination_workload_namespace=~\"$dstns\"}[5m])) by (destination_workload, destination_workload_namespace) / sum(irate(istio_requests_total{reporter=\"destination\", connection_security_policy!=\"mutual_tls\", destination_service=~\"$service\", destination_workload=~\"$dstwl\", destination_workload_namespace=~\"$dstns\"}[5m])) by (destination_workload, destination_workload_namespace)", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_workload }}.{{ destination_workload_namespace }}", + "refId": "B", + "step": 2 + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Incoming Success Rate (non-5xx responses) By Source", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "percentunit", + "label": null, + "logBase": 1, + "max": "1.01", + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "description": "", + "fill": 1, + "gridPos": { + "h": 6, + "w": 8, + "x": 0, + "y": 41 + }, + "id": 94, + "legend": { + "alignAsTable": false, + "avg": false, + "current": false, + "hideEmpty": true, + "hideZero": false, + "max": false, + "min": false, + "rightSide": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "(histogram_quantile(0.50, sum(irate(istio_request_duration_milliseconds_bucket{reporter=\"destination\", connection_security_policy=\"mutual_tls\", destination_service=~\"$service\", destination_workload=~\"$dstwl\", destination_workload_namespace=~\"$dstns\"}[1m])) by (destination_workload, destination_workload_namespace, le)) / 1000) or histogram_quantile(0.50, sum(irate(istio_request_duration_seconds_bucket{reporter=\"destination\", connection_security_policy=\"mutual_tls\", destination_service=~\"$service\", destination_workload=~\"$dstwl\", destination_workload_namespace=~\"$dstns\"}[1m])) by (destination_workload, destination_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_workload }}.{{ destination_workload_namespace }} P50 (🔐mTLS)", + "refId": "D", + "step": 2 + }, + { + "expr": "(histogram_quantile(0.90, sum(irate(istio_request_duration_milliseconds_bucket{reporter=\"destination\", connection_security_policy=\"mutual_tls\", destination_service=~\"$service\", destination_workload=~\"$dstwl\", destination_workload_namespace=~\"$dstns\"}[1m])) by (destination_workload, destination_workload_namespace, le)) / 1000) or histogram_quantile(0.90, sum(irate(istio_request_duration_seconds_bucket{reporter=\"destination\", connection_security_policy=\"mutual_tls\", destination_service=~\"$service\", destination_workload=~\"$dstwl\", destination_workload_namespace=~\"$dstns\"}[1m])) by (destination_workload, destination_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_workload }}.{{ destination_workload_namespace }} P90 (🔐mTLS)", + "refId": "A", + "step": 2 + }, + { + "expr": "(histogram_quantile(0.95, sum(irate(istio_request_duration_milliseconds_bucket{reporter=\"destination\", connection_security_policy=\"mutual_tls\", destination_service=~\"$service\", destination_workload=~\"$dstwl\", destination_workload_namespace=~\"$dstns\"}[1m])) by (destination_workload, destination_workload_namespace, le)) / 1000) or histogram_quantile(0.95, sum(irate(istio_request_duration_seconds_bucket{reporter=\"destination\", connection_security_policy=\"mutual_tls\", destination_service=~\"$service\", destination_workload=~\"$dstwl\", destination_workload_namespace=~\"$dstns\"}[1m])) by (destination_workload, destination_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_workload }}.{{ destination_workload_namespace }} P95 (🔐mTLS)", + "refId": "B", + "step": 2 + }, + { + "expr": "(histogram_quantile(0.99, sum(irate(istio_request_duration_milliseconds_bucket{reporter=\"destination\", connection_security_policy=\"mutual_tls\", destination_service=~\"$service\", destination_workload=~\"$dstwl\", destination_workload_namespace=~\"$dstns\"}[1m])) by (destination_workload, destination_workload_namespace, le)) / 1000) or histogram_quantile(0.99, sum(irate(istio_request_duration_seconds_bucket{reporter=\"destination\", connection_security_policy=\"mutual_tls\", destination_service=~\"$service\", destination_workload=~\"$dstwl\", destination_workload_namespace=~\"$dstns\"}[1m])) by (destination_workload, destination_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_workload }}.{{ destination_workload_namespace }} P99 (🔐mTLS)", + "refId": "C", + "step": 2 + }, + { + "expr": "(histogram_quantile(0.50, sum(irate(istio_request_duration_milliseconds_bucket{reporter=\"destination\", connection_security_policy!=\"mutual_tls\", destination_service=~\"$service\", destination_workload=~\"$dstwl\", destination_workload_namespace=~\"$dstns\"}[1m])) by (destination_workload, destination_workload_namespace, le)) / 1000) or histogram_quantile(0.50, sum(irate(istio_request_duration_seconds_bucket{reporter=\"destination\", connection_security_policy!=\"mutual_tls\", destination_service=~\"$service\", destination_workload=~\"$dstwl\", destination_workload_namespace=~\"$dstns\"}[1m])) by (destination_workload, destination_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_workload }}.{{ destination_workload_namespace }} P50", + "refId": "E", + "step": 2 + }, + { + "expr": "(histogram_quantile(0.90, sum(irate(istio_request_duration_milliseconds_bucket{reporter=\"destination\", connection_security_policy!=\"mutual_tls\", destination_service=~\"$service\", destination_workload=~\"$dstwl\", destination_workload_namespace=~\"$dstns\"}[1m])) by (destination_workload, destination_workload_namespace, le)) / 1000) or histogram_quantile(0.90, sum(irate(istio_request_duration_seconds_bucket{reporter=\"destination\", connection_security_policy!=\"mutual_tls\", destination_service=~\"$service\", destination_workload=~\"$dstwl\", destination_workload_namespace=~\"$dstns\"}[1m])) by (destination_workload, destination_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_workload }}.{{ destination_workload_namespace }} P90", + "refId": "F", + "step": 2 + }, + { + "expr": "(histogram_quantile(0.95, sum(irate(istio_request_duration_milliseconds_bucket{reporter=\"destination\", connection_security_policy!=\"mutual_tls\", destination_service=~\"$service\", destination_workload=~\"$dstwl\", destination_workload_namespace=~\"$dstns\"}[1m])) by (destination_workload, destination_workload_namespace, le)) / 1000) or histogram_quantile(0.95, sum(irate(istio_request_duration_seconds_bucket{reporter=\"destination\", connection_security_policy!=\"mutual_tls\", destination_service=~\"$service\", destination_workload=~\"$dstwl\", destination_workload_namespace=~\"$dstns\"}[1m])) by (destination_workload, destination_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_workload }}.{{ destination_workload_namespace }} P95", + "refId": "G", + "step": 2 + }, + { + "expr": "(histogram_quantile(0.99, sum(irate(istio_request_duration_milliseconds_bucket{reporter=\"destination\", connection_security_policy!=\"mutual_tls\", destination_service=~\"$service\", destination_workload=~\"$dstwl\", destination_workload_namespace=~\"$dstns\"}[1m])) by (destination_workload, destination_workload_namespace, le)) / 1000) or histogram_quantile(0.99, sum(irate(istio_request_duration_seconds_bucket{reporter=\"destination\", connection_security_policy!=\"mutual_tls\", destination_service=~\"$service\", destination_workload=~\"$dstwl\", destination_workload_namespace=~\"$dstns\"}[1m])) by (destination_workload, destination_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_workload }}.{{ destination_workload_namespace }} P99", + "refId": "H", + "step": 2 + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Incoming Request Duration by Source", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "s", + "label": null, + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 6, + "w": 8, + "x": 8, + "y": 41 + }, + "id": 95, + "legend": { + "alignAsTable": false, + "avg": false, + "current": false, + "hideEmpty": true, + "max": false, + "min": false, + "rightSide": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "histogram_quantile(0.50, sum(irate(istio_request_bytes_bucket{reporter=\"destination\", connection_security_policy=\"mutual_tls\", destination_service=~\"$service\", destination_workload=~\"$dstwl\", destination_workload_namespace=~\"$dstns\"}[1m])) by (destination_workload, destination_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_workload }}.{{ destination_workload_namespace }} P50 (🔐mTLS)", + "refId": "D", + "step": 2 + }, + { + "expr": "histogram_quantile(0.90, sum(irate(istio_request_bytes_bucket{reporter=\"destination\", connection_security_policy=\"mutual_tls\", destination_service=~\"$service\", destination_workload=~\"$dstwl\", destination_workload_namespace=~\"$dstns\"}[1m])) by (destination_workload, destination_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_workload }}.{{ destination_workload_namespace }} P90 (🔐mTLS)", + "refId": "A", + "step": 2 + }, + { + "expr": "histogram_quantile(0.95, sum(irate(istio_request_bytes_bucket{reporter=\"destination\", connection_security_policy=\"mutual_tls\", destination_service=~\"$service\", destination_workload=~\"$dstwl\", destination_workload_namespace=~\"$dstns\"}[1m])) by (destination_workload, destination_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_workload }}.{{ destination_workload_namespace }} P95 (🔐mTLS)", + "refId": "B", + "step": 2 + }, + { + "expr": "histogram_quantile(0.99, sum(irate(istio_request_bytes_bucket{reporter=\"destination\", connection_security_policy=\"mutual_tls\", destination_service=~\"$service\", destination_workload=~\"$dstwl\", destination_workload_namespace=~\"$dstns\"}[1m])) by (destination_workload, destination_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_workload }}.{{ destination_workload_namespace }} P99 (🔐mTLS)", + "refId": "C", + "step": 2 + }, + { + "expr": "histogram_quantile(0.50, sum(irate(istio_request_bytes_bucket{reporter=\"destination\", connection_security_policy!=\"mutual_tls\", destination_service=~\"$service\", destination_workload=~\"$dstwl\", destination_workload_namespace=~\"$dstns\"}[1m])) by (destination_workload, destination_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_workload }}.{{ destination_workload_namespace }} P50", + "refId": "E", + "step": 2 + }, + { + "expr": "histogram_quantile(0.90, sum(irate(istio_request_bytes_bucket{reporter=\"destination\", connection_security_policy!=\"mutual_tls\", destination_service=~\"$service\", destination_workload=~\"$dstwl\", destination_workload_namespace=~\"$dstns\"}[1m])) by (destination_workload, destination_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_workload }}.{{ destination_workload_namespace }} P90", + "refId": "F", + "step": 2 + }, + { + "expr": "histogram_quantile(0.95, sum(irate(istio_request_bytes_bucket{reporter=\"destination\", connection_security_policy!=\"mutual_tls\", destination_service=~\"$service\", destination_workload=~\"$dstwl\", destination_workload_namespace=~\"$dstns\"}[1m])) by (destination_workload, destination_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_workload }}.{{ destination_workload_namespace }} P95", + "refId": "G", + "step": 2 + }, + { + "expr": "histogram_quantile(0.99, sum(irate(istio_request_bytes_bucket{reporter=\"destination\", connection_security_policy!=\"mutual_tls\", destination_service=~\"$service\", destination_workload=~\"$dstwl\", destination_workload_namespace=~\"$dstns\"}[1m])) by (destination_workload, destination_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_workload }}.{{ destination_workload_namespace }} P99", + "refId": "H", + "step": 2 + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Incoming Request Size By Source", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "decbytes", + "label": null, + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 6, + "w": 8, + "x": 16, + "y": 41 + }, + "id": 96, + "legend": { + "alignAsTable": false, + "avg": false, + "current": false, + "hideEmpty": true, + "max": false, + "min": false, + "rightSide": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "histogram_quantile(0.50, sum(irate(istio_response_bytes_bucket{reporter=\"destination\", connection_security_policy=\"mutual_tls\", destination_service=~\"$service\", destination_workload=~\"$dstwl\", destination_workload_namespace=~\"$dstns\"}[1m])) by (destination_workload, destination_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_workload }}.{{ destination_workload_namespace }} P50 (🔐mTLS)", + "refId": "D", + "step": 2 + }, + { + "expr": "histogram_quantile(0.90, sum(irate(istio_response_bytes_bucket{reporter=\"destination\", connection_security_policy=\"mutual_tls\", destination_service=~\"$service\", destination_workload=~\"$dstwl\", destination_workload_namespace=~\"$dstns\"}[1m])) by (destination_workload, destination_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_workload }}.{{ destination_workload_namespace }} P90 (🔐mTLS)", + "refId": "A", + "step": 2 + }, + { + "expr": "histogram_quantile(0.95, sum(irate(istio_response_bytes_bucket{reporter=\"destination\", connection_security_policy=\"mutual_tls\", destination_service=~\"$service\", destination_workload=~\"$dstwl\", destination_workload_namespace=~\"$dstns\"}[1m])) by (destination_workload, destination_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_workload }}.{{ destination_workload_namespace }} P95 (🔐mTLS)", + "refId": "B", + "step": 2 + }, + { + "expr": "histogram_quantile(0.99, sum(irate(istio_response_bytes_bucket{reporter=\"destination\", connection_security_policy=\"mutual_tls\", destination_service=~\"$service\", destination_workload=~\"$dstwl\", destination_workload_namespace=~\"$dstns\"}[1m])) by (destination_workload, destination_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_workload }}.{{ destination_workload_namespace }} P99 (🔐mTLS)", + "refId": "C", + "step": 2 + }, + { + "expr": "histogram_quantile(0.50, sum(irate(istio_response_bytes_bucket{reporter=\"destination\", connection_security_policy!=\"mutual_tls\", destination_service=~\"$service\", destination_workload=~\"$dstwl\", destination_workload_namespace=~\"$dstns\"}[1m])) by (destination_workload, destination_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_workload }}.{{ destination_workload_namespace }} P50", + "refId": "E", + "step": 2 + }, + { + "expr": "histogram_quantile(0.90, sum(irate(istio_response_bytes_bucket{reporter=\"destination\", connection_security_policy!=\"mutual_tls\", destination_service=~\"$service\", destination_workload=~\"$dstwl\", destination_workload_namespace=~\"$dstns\"}[1m])) by (destination_workload, destination_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_workload }}.{{ destination_workload_namespace }} P90", + "refId": "F", + "step": 2 + }, + { + "expr": "histogram_quantile(0.95, sum(irate(istio_response_bytes_bucket{reporter=\"destination\", connection_security_policy!=\"mutual_tls\", destination_service=~\"$service\", destination_workload=~\"$dstwl\", destination_workload_namespace=~\"$dstns\"}[1m])) by (destination_workload, destination_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_workload }}.{{ destination_workload_namespace }} P95", + "refId": "G", + "step": 2 + }, + { + "expr": "histogram_quantile(0.99, sum(irate(istio_response_bytes_bucket{reporter=\"destination\", connection_security_policy!=\"mutual_tls\", destination_service=~\"$service\", destination_workload=~\"$dstwl\", destination_workload_namespace=~\"$dstns\"}[1m])) by (destination_workload, destination_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_workload }}.{{ destination_workload_namespace }} P99", + "refId": "H", + "step": 2 + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Response Size By Source", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "decbytes", + "label": null, + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 6, + "w": 12, + "x": 0, + "y": 47 + }, + "id": 92, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "round(sum(irate(istio_tcp_received_bytes_total{reporter=\"source\", connection_security_policy=\"mutual_tls\", destination_service=~\"$service\", destination_workload=~\"$dstwl\", destination_workload_namespace=~\"$dstns\"}[1m])) by (destination_workload, destination_workload_namespace), 0.001)", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_workload }}.{{ destination_workload_namespace}} (🔐mTLS)", + "refId": "A", + "step": 2 + }, + { + "expr": "round(sum(irate(istio_tcp_received_bytes_total{reporter=\"source\", connection_security_policy!=\"mutual_tls\", destination_service=~\"$service\", destination_workload=~\"$dstwl\", destination_workload_namespace=~\"$dstns\"}[1m])) by (destination_workload, destination_workload_namespace), 0.001)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{ destination_workload }}.{{ destination_workload_namespace}}", + "refId": "B", + "step": 2 + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Bytes Received from Incoming TCP Connection", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "Bps", + "label": null, + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 6, + "w": 12, + "x": 12, + "y": 47 + }, + "id": 93, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "round(sum(irate(istio_tcp_sent_bytes_total{connection_security_policy=\"mutual_tls\", reporter=\"source\", destination_service=~\"$service\", destination_workload=~\"$dstwl\", destination_workload_namespace=~\"$dstns\"}[1m])) by (destination_workload, destination_workload_namespace), 0.001)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{ destination_workload }}.{{destination_workload_namespace }} (🔐mTLS)", + "refId": "A", + "step": 2 + }, + { + "expr": "round(sum(irate(istio_tcp_sent_bytes_total{connection_security_policy!=\"mutual_tls\", reporter=\"source\", destination_service=~\"$service\", destination_workload=~\"$dstwl\", destination_workload_namespace=~\"$dstns\"}[1m])) by (destination_workload, destination_workload_namespace), 0.001)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{ destination_workload }}.{{destination_workload_namespace }}", + "refId": "B", + "step": 2 + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Bytes Sent to Incoming TCP Connection", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "Bps", + "label": null, + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + } + ], + "refresh": "10s", + "schemaVersion": 16, + "style": "dark", + "tags": [], + "templating": { + "list": [ + { + "allValue": null, + "datasource": "Prometheus", + "hide": 0, + "includeAll": false, + "label": "Service", + "multi": false, + "name": "service", + "options": [], + "query": "label_values(destination_service)", + "refresh": 1, + "regex": "", + "sort": 0, + "tagValuesQuery": "", + "tags": [], + "tagsQuery": "", + "type": "query", + "useTags": false + }, + { + "allValue": null, + "current": { + "text": "All", + "value": "$__all" + }, + "datasource": "Prometheus", + "hide": 0, + "includeAll": true, + "label": "Client Workload Namespace", + "multi": true, + "name": "srcns", + "options": [], + "query": "query_result( sum(istio_requests_total{reporter=\"destination\", destination_service=\"$service\"}) by (source_workload_namespace) or sum(istio_tcp_sent_bytes_total{reporter=\"destination\", destination_service=~\"$service\"}) by (source_workload_namespace))", + "refresh": 1, + "regex": "/.*namespace=\"([^\"]*).*/", + "sort": 2, + "tagValuesQuery": "", + "tags": [], + "tagsQuery": "", + "type": "query", + "useTags": false + }, + { + "allValue": null, + "current": { + "text": "All", + "value": "$__all" + }, + "datasource": "Prometheus", + "hide": 0, + "includeAll": true, + "label": "Client Workload", + "multi": true, + "name": "srcwl", + "options": [], + "query": "query_result( sum(istio_requests_total{reporter=\"destination\", destination_service=~\"$service\", source_workload_namespace=~\"$srcns\"}) by (source_workload) or sum(istio_tcp_sent_bytes_total{reporter=\"destination\", destination_service=~\"$service\", source_workload_namespace=~\"$srcns\"}) by (source_workload))", + "refresh": 1, + "regex": "/.*workload=\"([^\"]*).*/", + "sort": 3, + "tagValuesQuery": "", + "tags": [], + "tagsQuery": "", + "type": "query", + "useTags": false + }, + { + "allValue": null, + "current": { + "text": "All", + "value": "$__all" + }, + "datasource": "Prometheus", + "hide": 0, + "includeAll": true, + "label": "Service Workload Namespace", + "multi": true, + "name": "dstns", + "options": [], + "query": "query_result( sum(istio_requests_total{reporter=\"destination\", destination_service=\"$service\"}) by (destination_workload_namespace) or sum(istio_tcp_sent_bytes_total{reporter=\"destination\", destination_service=~\"$service\"}) by (destination_workload_namespace))", + "refresh": 1, + "regex": "/.*namespace=\"([^\"]*).*/", + "sort": 2, + "tagValuesQuery": "", + "tags": [], + "tagsQuery": "", + "type": "query", + "useTags": false + }, + { + "allValue": null, + "current": { + "text": "All", + "value": "$__all" + }, + "datasource": "Prometheus", + "hide": 0, + "includeAll": true, + "label": "Service Workload", + "multi": true, + "name": "dstwl", + "options": [], + "query": "query_result( sum(istio_requests_total{reporter=\"destination\", destination_service=~\"$service\", destination_workload_namespace=~\"$dstns\"}) by (destination_workload) or sum(istio_tcp_sent_bytes_total{reporter=\"destination\", destination_service=~\"$service\", destination_workload_namespace=~\"$dstns\"}) by (destination_workload))", + "refresh": 1, + "regex": "/.*workload=\"([^\"]*).*/", + "sort": 3, + "tagValuesQuery": "", + "tags": [], + "tagsQuery": "", + "type": "query", + "useTags": false + } + ] + }, + "time": { + "from": "now-5m", + "to": "now" + }, + "timepicker": { + "refresh_intervals": [ + "5s", + "10s", + "30s", + "1m", + "5m", + "15m", + "30m", + "1h", + "2h", + "1d" + ], + "time_options": [ + "5m", + "15m", + "1h", + "6h", + "12h", + "24h", + "2d", + "7d", + "30d" + ] + }, + "timezone": "", + "title": "Istio Service Dashboard", + "uid": "LJ_uJAvmk", + "version": 1 +} +' +--- +apiVersion: v1 +kind: ConfigMap +metadata: + name: istio-grafana-configuration-dashboards-istio-workload-dashboard + namespace: istio-system + labels: + app: grafana + chart: grafana + heritage: Tiller + release: istio + istio: grafana +data: + istio-workload-dashboard.json: '{ + "__inputs": [ + { + "name": "DS_PROMETHEUS", + "label": "Prometheus", + "description": "", + "type": "datasource", + "pluginId": "prometheus", + "pluginName": "Prometheus" + } + ], + "__requires": [ + { + "type": "grafana", + "id": "grafana", + "name": "Grafana", + "version": "5.0.4" + }, + { + "type": "panel", + "id": "graph", + "name": "Graph", + "version": "5.0.0" + }, + { + "type": "datasource", + "id": "prometheus", + "name": "Prometheus", + "version": "5.0.0" + }, + { + "type": "panel", + "id": "singlestat", + "name": "Singlestat", + "version": "5.0.0" + }, + { + "type": "panel", + "id": "text", + "name": "Text", + "version": "5.0.0" + } + ], + "annotations": { + "list": [ + { + "builtIn": 1, + "datasource": "-- Grafana --", + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations & Alerts", + "type": "dashboard" + } + ] + }, + "editable": false, + "gnetId": null, + "graphTooltip": 0, + "id": null, + "iteration": 1531345461465, + "links": [], + "panels": [ + { + "content": "
\nWORKLOAD: $workload.$namespace\n
", + "gridPos": { + "h": 3, + "w": 24, + "x": 0, + "y": 0 + }, + "id": 89, + "links": [], + "mode": "html", + "title": "", + "transparent": true, + "type": "text" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "datasource": "Prometheus", + "format": "ops", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "gridPos": { + "h": 4, + "w": 8, + "x": 0, + "y": 3 + }, + "id": 12, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": true, + "lineColor": "rgb(31, 120, 193)", + "show": true + }, + "tableColumn": "", + "targets": [ + { + "expr": "round(sum(irate(istio_requests_total{reporter=\"destination\",destination_workload_namespace=~\"$namespace\",destination_workload=~\"$workload\"}[5m])), 0.001)", + "format": "time_series", + "intervalFactor": 1, + "refId": "A", + "step": 4 + } + ], + "thresholds": "", + "title": "Incoming Request Volume", + "transparent": false, + "type": "singlestat", + "valueFontSize": "80%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "current" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "rgba(50, 172, 45, 0.97)", + "rgba(237, 129, 40, 0.89)", + "rgba(245, 54, 54, 0.9)" + ], + "datasource": "Prometheus", + "decimals": null, + "format": "percentunit", + "gauge": { + "maxValue": 100, + "minValue": 80, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": false + }, + "gridPos": { + "h": 4, + "w": 8, + "x": 8, + "y": 3 + }, + "id": 14, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": true, + "lineColor": "rgb(31, 120, 193)", + "show": true + }, + "tableColumn": "", + "targets": [ + { + "expr": "sum(irate(istio_requests_total{reporter=\"destination\",destination_workload_namespace=~\"$namespace\",destination_workload=~\"$workload\",response_code!~\"5.*\"}[5m])) / sum(irate(istio_requests_total{reporter=\"destination\",destination_workload_namespace=~\"$namespace\",destination_workload=~\"$workload\"}[5m]))", + "format": "time_series", + "intervalFactor": 1, + "refId": "B" + } + ], + "thresholds": "95, 99, 99.5", + "title": "Incoming Success Rate (non-5xx responses)", + "transparent": false, + "type": "singlestat", + "valueFontSize": "80%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "avg" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 4, + "w": 8, + "x": 16, + "y": 3 + }, + "id": 87, + "legend": { + "alignAsTable": false, + "avg": false, + "current": false, + "hideEmpty": false, + "hideZero": false, + "max": false, + "min": false, + "rightSide": true, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "(histogram_quantile(0.50, sum(irate(istio_request_duration_milliseconds_bucket{reporter=\"destination\",destination_workload=~\"$workload\", destination_workload_namespace=~\"$namespace\"}[1m])) by (le)) / 1000) or histogram_quantile(0.50, sum(irate(istio_request_duration_seconds_bucket{reporter=\"destination\",destination_workload=~\"$workload\", destination_workload_namespace=~\"$namespace\"}[1m])) by (le))", + "format": "time_series", + "interval": "", + "intervalFactor": 1, + "legendFormat": "P50", + "refId": "A" + }, + { + "expr": "(histogram_quantile(0.50, sum(irate(istio_request_duration_milliseconds_bucket{reporter=\"destination\",destination_workload=~\"$workload\", destination_workload_namespace=~\"$namespace\"}[1m])) by (le)) / 1000) or histogram_quantile(0.90, sum(irate(istio_request_duration_seconds_bucket{reporter=\"destination\",destination_workload=~\"$workload\", destination_workload_namespace=~\"$namespace\"}[1m])) by (le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "P90", + "refId": "B" + }, + { + "expr": "(histogram_quantile(0.50, sum(irate(istio_request_duration_milliseconds_bucket{reporter=\"destination\",destination_workload=~\"$workload\", destination_workload_namespace=~\"$namespace\"}[1m])) by (le)) / 1000) or histogram_quantile(0.99, sum(irate(istio_request_duration_seconds_bucket{reporter=\"destination\",destination_workload=~\"$workload\", destination_workload_namespace=~\"$namespace\"}[1m])) by (le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "P99", + "refId": "C" + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Request Duration", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "s", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ] + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "#299c46", + "rgba(237, 129, 40, 0.89)", + "#d44a3a" + ], + "datasource": "Prometheus", + "format": "Bps", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "gridPos": { + "h": 4, + "w": 12, + "x": 0, + "y": 7 + }, + "id": 84, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": true, + "lineColor": "rgb(31, 120, 193)", + "show": true + }, + "tableColumn": "", + "targets": [ + { + "expr": "sum(irate(istio_tcp_sent_bytes_total{reporter=\"destination\", destination_workload_namespace=~\"$namespace\", destination_workload=~\"$workload\"}[1m])) + sum(irate(istio_tcp_received_bytes_total{reporter=\"destination\", destination_workload_namespace=~\"$namespace\", destination_workload=~\"$workload\"}[1m]))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "", + "refId": "A" + } + ], + "thresholds": "", + "title": "TCP Server Traffic", + "transparent": false, + "type": "singlestat", + "valueFontSize": "80%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "avg" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "#299c46", + "rgba(237, 129, 40, 0.89)", + "#d44a3a" + ], + "datasource": "Prometheus", + "format": "Bps", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "gridPos": { + "h": 4, + "w": 12, + "x": 12, + "y": 7 + }, + "id": 85, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": true, + "lineColor": "rgb(31, 120, 193)", + "show": true + }, + "tableColumn": "", + "targets": [ + { + "expr": "sum(irate(istio_tcp_sent_bytes_total{reporter=\"source\", source_workload_namespace=~\"$namespace\", source_workload=~\"$workload\"}[1m])) + sum(irate(istio_tcp_received_bytes_total{reporter=\"source\", source_workload_namespace=~\"$namespace\", source_workload=~\"$workload\"}[1m]))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "", + "refId": "A" + } + ], + "thresholds": "", + "title": "TCP Client Traffic", + "transparent": false, + "type": "singlestat", + "valueFontSize": "80%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "avg" + }, + { + "content": "
\nINBOUND WORKLOADS\n
", + "gridPos": { + "h": 3, + "w": 24, + "x": 0, + "y": 11 + }, + "id": 45, + "links": [], + "mode": "html", + "title": "", + "transparent": true, + "type": "text" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 0, + "gridPos": { + "h": 6, + "w": 12, + "x": 0, + "y": 14 + }, + "id": 25, + "legend": { + "avg": false, + "current": false, + "hideEmpty": true, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null as zero", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "round(sum(irate(istio_requests_total{connection_security_policy=\"mutual_tls\", destination_workload_namespace=~\"$namespace\", destination_workload=~\"$workload\", reporter=\"destination\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[5m])) by (source_workload, source_workload_namespace, response_code), 0.001)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{ source_workload }}.{{ source_workload_namespace }} : {{ response_code }} (🔐mTLS)", + "refId": "B", + "step": 2 + }, + { + "expr": "round(sum(irate(istio_requests_total{connection_security_policy!=\"mutual_tls\", destination_workload_namespace=~\"$namespace\", destination_workload=~\"$workload\", reporter=\"destination\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[5m])) by (source_workload, source_workload_namespace, response_code), 0.001)", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ source_workload }}.{{ source_workload_namespace }} : {{ response_code }}", + "refId": "A", + "step": 2 + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Incoming Requests by Source And Response Code", + "tooltip": { + "shared": false, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [ + "total" + ] + }, + "yaxes": [ + { + "format": "ops", + "label": null, + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ] + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 6, + "w": 12, + "x": 12, + "y": 14 + }, + "id": 26, + "legend": { + "avg": false, + "current": false, + "hideEmpty": true, + "hideZero": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(irate(istio_requests_total{reporter=\"destination\", connection_security_policy=\"mutual_tls\", destination_workload_namespace=~\"$namespace\", destination_workload=~\"$workload\",response_code!~\"5.*\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[5m])) by (source_workload, source_workload_namespace) / sum(irate(istio_requests_total{reporter=\"destination\", connection_security_policy=\"mutual_tls\", destination_workload_namespace=~\"$namespace\", destination_workload=~\"$workload\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[5m])) by (source_workload, source_workload_namespace)", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ source_workload }}.{{ source_workload_namespace }} (🔐mTLS)", + "refId": "A", + "step": 2 + }, + { + "expr": "sum(irate(istio_requests_total{reporter=\"destination\", connection_security_policy!=\"mutual_tls\", destination_workload_namespace=~\"$namespace\", destination_workload=~\"$workload\",response_code!~\"5.*\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[5m])) by (source_workload, source_workload_namespace) / sum(irate(istio_requests_total{reporter=\"destination\", connection_security_policy!=\"mutual_tls\", destination_workload_namespace=~\"$namespace\", destination_workload=~\"$workload\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[5m])) by (source_workload, source_workload_namespace)", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ source_workload }}.{{ source_workload_namespace }}", + "refId": "B", + "step": 2 + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Incoming Success Rate (non-5xx responses) By Source", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "percentunit", + "label": null, + "logBase": 1, + "max": "1.01", + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ] + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "description": "", + "fill": 1, + "gridPos": { + "h": 6, + "w": 8, + "x": 0, + "y": 20 + }, + "id": 27, + "legend": { + "alignAsTable": false, + "avg": false, + "current": false, + "hideEmpty": true, + "hideZero": false, + "max": false, + "min": false, + "rightSide": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "(histogram_quantile(0.50, sum(irate(istio_request_duration_milliseconds_bucket{reporter=\"destination\", connection_security_policy=\"mutual_tls\", destination_workload=~\"$workload\", destination_workload_namespace=~\"$namespace\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le)) / 1000) or histogram_quantile(0.50, sum(irate(istio_request_duration_seconds_bucket{reporter=\"destination\", connection_security_policy=\"mutual_tls\", destination_workload=~\"$workload\", destination_workload_namespace=~\"$namespace\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{source_workload}}.{{source_workload_namespace}} P50 (🔐mTLS)", + "refId": "D", + "step": 2 + }, + { + "expr": "(histogram_quantile(0.90, sum(irate(istio_request_duration_milliseconds_bucket{reporter=\"destination\", connection_security_policy=\"mutual_tls\", destination_workload=~\"$workload\", destination_workload_namespace=~\"$namespace\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le)) / 1000) or histogram_quantile(0.90, sum(irate(istio_request_duration_seconds_bucket{reporter=\"destination\", connection_security_policy=\"mutual_tls\", destination_workload=~\"$workload\", destination_workload_namespace=~\"$namespace\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{source_workload}}.{{source_workload_namespace}} P90 (🔐mTLS)", + "refId": "A", + "step": 2 + }, + { + "expr": "(histogram_quantile(0.95, sum(irate(istio_request_duration_milliseconds_bucket{reporter=\"destination\", connection_security_policy=\"mutual_tls\", destination_workload=~\"$workload\", destination_workload_namespace=~\"$namespace\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le)) / 1000) or histogram_quantile(0.95, sum(irate(istio_request_duration_seconds_bucket{reporter=\"destination\", connection_security_policy=\"mutual_tls\", destination_workload=~\"$workload\", destination_workload_namespace=~\"$namespace\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{source_workload}}.{{source_workload_namespace}} P95 (🔐mTLS)", + "refId": "B", + "step": 2 + }, + { + "expr": "(histogram_quantile(0.99, sum(irate(istio_request_duration_milliseconds_bucket{reporter=\"destination\", connection_security_policy=\"mutual_tls\", destination_workload=~\"$workload\", destination_workload_namespace=~\"$namespace\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le)) / 1000) or histogram_quantile(0.99, sum(irate(istio_request_duration_seconds_bucket{reporter=\"destination\", connection_security_policy=\"mutual_tls\", destination_workload=~\"$workload\", destination_workload_namespace=~\"$namespace\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{source_workload}}.{{source_workload_namespace}} P99 (🔐mTLS)", + "refId": "C", + "step": 2 + }, + { + "expr": "(histogram_quantile(0.50, sum(irate(istio_request_duration_milliseconds_bucket{reporter=\"destination\", connection_security_policy!=\"mutual_tls\", destination_workload=~\"$workload\", destination_workload_namespace=~\"$namespace\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le)) / 1000) or histogram_quantile(0.50, sum(irate(istio_request_duration_seconds_bucket{reporter=\"destination\", connection_security_policy!=\"mutual_tls\", destination_workload=~\"$workload\", destination_workload_namespace=~\"$namespace\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{source_workload}}.{{source_workload_namespace}} P50", + "refId": "E", + "step": 2 + }, + { + "expr": "(histogram_quantile(0.90, sum(irate(istio_request_duration_milliseconds_bucket{reporter=\"destination\", connection_security_policy!=\"mutual_tls\", destination_workload=~\"$workload\", destination_workload_namespace=~\"$namespace\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le)) / 1000) or histogram_quantile(0.90, sum(irate(istio_request_duration_seconds_bucket{reporter=\"destination\", connection_security_policy!=\"mutual_tls\", destination_workload=~\"$workload\", destination_workload_namespace=~\"$namespace\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{source_workload}}.{{source_workload_namespace}} P90", + "refId": "F", + "step": 2 + }, + { + "expr": "(histogram_quantile(0.95, sum(irate(istio_request_duration_milliseconds_bucket{reporter=\"destination\", connection_security_policy!=\"mutual_tls\", destination_workload=~\"$workload\", destination_workload_namespace=~\"$namespace\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le)) / 1000) or histogram_quantile(0.95, sum(irate(istio_request_duration_seconds_bucket{reporter=\"destination\", connection_security_policy!=\"mutual_tls\", destination_workload=~\"$workload\", destination_workload_namespace=~\"$namespace\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{source_workload}}.{{source_workload_namespace}} P95", + "refId": "G", + "step": 2 + }, + { + "expr": "(histogram_quantile(0.99, sum(irate(istio_request_duration_milliseconds_bucket{reporter=\"destination\", connection_security_policy!=\"mutual_tls\", destination_workload=~\"$workload\", destination_workload_namespace=~\"$namespace\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le)) / 1000) or histogram_quantile(0.99, sum(irate(istio_request_duration_seconds_bucket{reporter=\"destination\", connection_security_policy!=\"mutual_tls\", destination_workload=~\"$workload\", destination_workload_namespace=~\"$namespace\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{source_workload}}.{{source_workload_namespace}} P99", + "refId": "H", + "step": 2 + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Incoming Request Duration by Source", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "s", + "label": null, + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ] + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 6, + "w": 8, + "x": 8, + "y": 20 + }, + "id": 28, + "legend": { + "alignAsTable": false, + "avg": false, + "current": false, + "hideEmpty": true, + "max": false, + "min": false, + "rightSide": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "histogram_quantile(0.50, sum(irate(istio_request_bytes_bucket{reporter=\"destination\", connection_security_policy=\"mutual_tls\", destination_workload=~\"$workload\", destination_workload_namespace=~\"$namespace\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{source_workload}}.{{source_workload_namespace}} P50 (🔐mTLS)", + "refId": "D", + "step": 2 + }, + { + "expr": "histogram_quantile(0.90, sum(irate(istio_request_bytes_bucket{reporter=\"destination\", connection_security_policy=\"mutual_tls\", destination_workload=~\"$workload\", destination_workload_namespace=~\"$namespace\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{source_workload}}.{{source_workload_namespace}} P90 (🔐mTLS)", + "refId": "A", + "step": 2 + }, + { + "expr": "histogram_quantile(0.95, sum(irate(istio_request_bytes_bucket{reporter=\"destination\", connection_security_policy=\"mutual_tls\", destination_workload=~\"$workload\", destination_workload_namespace=~\"$namespace\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{source_workload}}.{{source_workload_namespace}} P95 (🔐mTLS)", + "refId": "B", + "step": 2 + }, + { + "expr": "histogram_quantile(0.99, sum(irate(istio_request_bytes_bucket{reporter=\"destination\", connection_security_policy=\"mutual_tls\", destination_workload=~\"$workload\", destination_workload_namespace=~\"$namespace\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{source_workload}}.{{source_workload_namespace}} P99 (🔐mTLS)", + "refId": "C", + "step": 2 + }, + { + "expr": "histogram_quantile(0.50, sum(irate(istio_request_bytes_bucket{reporter=\"destination\", connection_security_policy!=\"mutual_tls\", destination_workload=~\"$workload\", destination_workload_namespace=~\"$namespace\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{source_workload}}.{{source_workload_namespace}} P50", + "refId": "E", + "step": 2 + }, + { + "expr": "histogram_quantile(0.90, sum(irate(istio_request_bytes_bucket{reporter=\"destination\", connection_security_policy!=\"mutual_tls\", destination_workload=~\"$workload\", destination_workload_namespace=~\"$namespace\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{source_workload}}.{{source_workload_namespace}} P90", + "refId": "F", + "step": 2 + }, + { + "expr": "histogram_quantile(0.95, sum(irate(istio_request_bytes_bucket{reporter=\"destination\", connection_security_policy!=\"mutual_tls\", destination_workload=~\"$workload\", destination_workload_namespace=~\"$namespace\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{source_workload}}.{{source_workload_namespace}} P95", + "refId": "G", + "step": 2 + }, + { + "expr": "histogram_quantile(0.99, sum(irate(istio_request_bytes_bucket{reporter=\"destination\", connection_security_policy!=\"mutual_tls\", destination_workload=~\"$workload\", destination_workload_namespace=~\"$namespace\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{source_workload}}.{{source_workload_namespace}} P99", + "refId": "H", + "step": 2 + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Incoming Request Size By Source", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "decbytes", + "label": null, + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ] + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 6, + "w": 8, + "x": 16, + "y": 20 + }, + "id": 68, + "legend": { + "alignAsTable": false, + "avg": false, + "current": false, + "hideEmpty": true, + "max": false, + "min": false, + "rightSide": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "histogram_quantile(0.50, sum(irate(istio_response_bytes_bucket{reporter=\"destination\", connection_security_policy=\"mutual_tls\", destination_workload=~\"$workload\", destination_workload_namespace=~\"$namespace\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{source_workload}}.{{source_workload_namespace}} P50 (🔐mTLS)", + "refId": "D", + "step": 2 + }, + { + "expr": "histogram_quantile(0.90, sum(irate(istio_response_bytes_bucket{reporter=\"destination\", connection_security_policy=\"mutual_tls\", destination_workload=~\"$workload\", destination_workload_namespace=~\"$namespace\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{source_workload}}.{{source_workload_namespace}} P90 (🔐mTLS)", + "refId": "A", + "step": 2 + }, + { + "expr": "histogram_quantile(0.95, sum(irate(istio_response_bytes_bucket{reporter=\"destination\", connection_security_policy=\"mutual_tls\", destination_workload=~\"$workload\", destination_workload_namespace=~\"$namespace\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{source_workload}}.{{source_workload_namespace}} P95 (🔐mTLS)", + "refId": "B", + "step": 2 + }, + { + "expr": "histogram_quantile(0.99, sum(irate(istio_response_bytes_bucket{reporter=\"destination\", connection_security_policy=\"mutual_tls\", destination_workload=~\"$workload\", destination_workload_namespace=~\"$namespace\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{source_workload}}.{{source_workload_namespace}} P99 (🔐mTLS)", + "refId": "C", + "step": 2 + }, + { + "expr": "histogram_quantile(0.50, sum(irate(istio_response_bytes_bucket{reporter=\"destination\", connection_security_policy!=\"mutual_tls\", destination_workload=~\"$workload\", destination_workload_namespace=~\"$namespace\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{source_workload}}.{{source_workload_namespace}} P50", + "refId": "E", + "step": 2 + }, + { + "expr": "histogram_quantile(0.90, sum(irate(istio_response_bytes_bucket{reporter=\"destination\", connection_security_policy!=\"mutual_tls\", destination_workload=~\"$workload\", destination_workload_namespace=~\"$namespace\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{source_workload}}.{{source_workload_namespace}} P90", + "refId": "F", + "step": 2 + }, + { + "expr": "histogram_quantile(0.95, sum(irate(istio_response_bytes_bucket{reporter=\"destination\", connection_security_policy!=\"mutual_tls\", destination_workload=~\"$workload\", destination_workload_namespace=~\"$namespace\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{source_workload}}.{{source_workload_namespace}} P95", + "refId": "G", + "step": 2 + }, + { + "expr": "histogram_quantile(0.99, sum(irate(istio_response_bytes_bucket{reporter=\"destination\", connection_security_policy!=\"mutual_tls\", destination_workload=~\"$workload\", destination_workload_namespace=~\"$namespace\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{source_workload}}.{{source_workload_namespace}} P99", + "refId": "H", + "step": 2 + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Response Size By Source", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "decbytes", + "label": null, + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ] + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 6, + "w": 12, + "x": 0, + "y": 26 + }, + "id": 80, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "round(sum(irate(istio_tcp_received_bytes_total{reporter=\"destination\", connection_security_policy=\"mutual_tls\", destination_workload_namespace=~\"$namespace\", destination_workload=~\"$workload\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace), 0.001)", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ source_workload }}.{{ source_workload_namespace}} (🔐mTLS)", + "refId": "A", + "step": 2 + }, + { + "expr": "round(sum(irate(istio_tcp_received_bytes_total{reporter=\"destination\", connection_security_policy!=\"mutual_tls\", destination_workload_namespace=~\"$namespace\", destination_workload=~\"$workload\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace), 0.001)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{ source_workload }}.{{ source_workload_namespace}}", + "refId": "B", + "step": 2 + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Bytes Received from Incoming TCP Connection", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "Bps", + "label": null, + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ] + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 6, + "w": 12, + "x": 12, + "y": 26 + }, + "id": 82, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "round(sum(irate(istio_tcp_sent_bytes_total{connection_security_policy=\"mutual_tls\", reporter=\"destination\", destination_workload_namespace=~\"$namespace\", destination_workload=~\"$workload\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace), 0.001)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{ source_workload }}.{{ source_workload_namespace}} (🔐mTLS)", + "refId": "A", + "step": 2 + }, + { + "expr": "round(sum(irate(istio_tcp_sent_bytes_total{connection_security_policy!=\"mutual_tls\", reporter=\"destination\", destination_workload_namespace=~\"$namespace\", destination_workload=~\"$workload\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace), 0.001)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{ source_workload }}.{{ source_workload_namespace}}", + "refId": "B", + "step": 2 + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Bytes Sent to Incoming TCP Connection", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "Bps", + "label": null, + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ] + }, + { + "content": "
\nOUTBOUND SERVICES\n
", + "gridPos": { + "h": 3, + "w": 24, + "x": 0, + "y": 32 + }, + "id": 69, + "links": [], + "mode": "html", + "title": "", + "transparent": true, + "type": "text" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 0, + "gridPos": { + "h": 6, + "w": 12, + "x": 0, + "y": 35 + }, + "id": 70, + "legend": { + "avg": false, + "current": false, + "hideEmpty": true, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null as zero", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "round(sum(irate(istio_requests_total{connection_security_policy=\"mutual_tls\", source_workload_namespace=~\"$namespace\", source_workload=~\"$workload\", reporter=\"source\", destination_service=~\"$dstsvc\"}[5m])) by (destination_service, response_code), 0.001)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{ destination_service }} : {{ response_code }} (🔐mTLS)", + "refId": "B", + "step": 2 + }, + { + "expr": "round(sum(irate(istio_requests_total{connection_security_policy!=\"mutual_tls\", source_workload_namespace=~\"$namespace\", source_workload=~\"$workload\", reporter=\"source\", destination_service=~\"$dstsvc\"}[5m])) by (destination_service, response_code), 0.001)", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_service }} : {{ response_code }}", + "refId": "A", + "step": 2 + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Outgoing Requests by Destination And Response Code", + "tooltip": { + "shared": false, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [ + "total" + ] + }, + "yaxes": [ + { + "format": "ops", + "label": null, + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ] + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 6, + "w": 12, + "x": 12, + "y": 35 + }, + "id": 71, + "legend": { + "avg": false, + "current": false, + "hideEmpty": true, + "hideZero": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(irate(istio_requests_total{reporter=\"source\", connection_security_policy=\"mutual_tls\", source_workload_namespace=~\"$namespace\", source_workload=~\"$workload\",response_code!~\"5.*\", destination_service=~\"$dstsvc\"}[5m])) by (destination_service) / sum(irate(istio_requests_total{reporter=\"source\", connection_security_policy=\"mutual_tls\", source_workload_namespace=~\"$namespace\", source_workload=~\"$workload\", destination_service=~\"$dstsvc\"}[5m])) by (destination_service)", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_service }} (🔐mTLS)", + "refId": "A", + "step": 2 + }, + { + "expr": "sum(irate(istio_requests_total{reporter=\"source\", connection_security_policy!=\"mutual_tls\", source_workload_namespace=~\"$namespace\", source_workload=~\"$workload\",response_code!~\"5.*\", destination_service=~\"$dstsvc\"}[5m])) by (destination_service) / sum(irate(istio_requests_total{reporter=\"source\", connection_security_policy!=\"mutual_tls\", source_workload_namespace=~\"$namespace\", source_workload=~\"$workload\", destination_service=~\"$dstsvc\"}[5m])) by (destination_service)", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{destination_service }}", + "refId": "B", + "step": 2 + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Outgoing Success Rate (non-5xx responses) By Destination", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "percentunit", + "label": null, + "logBase": 1, + "max": "1.01", + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ] + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "description": "", + "fill": 1, + "gridPos": { + "h": 6, + "w": 8, + "x": 0, + "y": 41 + }, + "id": 72, + "legend": { + "alignAsTable": false, + "avg": false, + "current": false, + "hideEmpty": true, + "hideZero": false, + "max": false, + "min": false, + "rightSide": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "(histogram_quantile(0.50, sum(irate(istio_request_duration_milliseconds_bucket{reporter=\"source\", connection_security_policy=\"mutual_tls\", source_workload=~\"$workload\", source_workload_namespace=~\"$namespace\", destination_service=~\"$dstsvc\"}[1m])) by (destination_service, le)) / 1000) or histogram_quantile(0.50, sum(irate(istio_request_duration_seconds_bucket{reporter=\"source\", connection_security_policy=\"mutual_tls\", source_workload=~\"$workload\", source_workload_namespace=~\"$namespace\", destination_service=~\"$dstsvc\"}[1m])) by (destination_service, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_service }} P50 (🔐mTLS)", + "refId": "D", + "step": 2 + }, + { + "expr": "(histogram_quantile(0.90, sum(irate(istio_request_duration_milliseconds_bucket{reporter=\"source\", connection_security_policy=\"mutual_tls\", source_workload=~\"$workload\", source_workload_namespace=~\"$namespace\", destination_service=~\"$dstsvc\"}[1m])) by (destination_service, le)) / 1000) or histogram_quantile(0.90, sum(irate(istio_request_duration_seconds_bucket{reporter=\"source\", connection_security_policy=\"mutual_tls\", source_workload=~\"$workload\", source_workload_namespace=~\"$namespace\", destination_service=~\"$dstsvc\"}[1m])) by (destination_service, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_service }} P90 (🔐mTLS)", + "refId": "A", + "step": 2 + }, + { + "expr": "(histogram_quantile(0.95, sum(irate(istio_request_duration_milliseconds_bucket{reporter=\"source\", connection_security_policy=\"mutual_tls\", source_workload=~\"$workload\", source_workload_namespace=~\"$namespace\", destination_service=~\"$dstsvc\"}[1m])) by (destination_service, le)) / 1000) or histogram_quantile(0.95, sum(irate(istio_request_duration_seconds_bucket{reporter=\"source\", connection_security_policy=\"mutual_tls\", source_workload=~\"$workload\", source_workload_namespace=~\"$namespace\", destination_service=~\"$dstsvc\"}[1m])) by (destination_service, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_service }} P95 (🔐mTLS)", + "refId": "B", + "step": 2 + }, + { + "expr": "(histogram_quantile(0.99, sum(irate(istio_request_duration_milliseconds_bucket{reporter=\"source\", connection_security_policy=\"mutual_tls\", source_workload=~\"$workload\", source_workload_namespace=~\"$namespace\", destination_service=~\"$dstsvc\"}[1m])) by (destination_service, le)) / 1000) or histogram_quantile(0.99, sum(irate(istio_request_duration_seconds_bucket{reporter=\"source\", connection_security_policy=\"mutual_tls\", source_workload=~\"$workload\", source_workload_namespace=~\"$namespace\", destination_service=~\"$dstsvc\"}[1m])) by (destination_service, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_service }} P99 (🔐mTLS)", + "refId": "C", + "step": 2 + }, + { + "expr": "(histogram_quantile(0.50, sum(irate(istio_request_duration_milliseconds_bucket{reporter=\"source\", connection_security_policy!=\"mutual_tls\", source_workload=~\"$workload\", source_workload_namespace=~\"$namespace\", destination_service=~\"$dstsvc\"}[1m])) by (destination_service, le)) / 1000) or histogram_quantile(0.50, sum(irate(istio_request_duration_seconds_bucket{reporter=\"source\", connection_security_policy!=\"mutual_tls\", source_workload=~\"$workload\", source_workload_namespace=~\"$namespace\", destination_service=~\"$dstsvc\"}[1m])) by (destination_service, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_service }} P50", + "refId": "E", + "step": 2 + }, + { + "expr": "(histogram_quantile(0.90, sum(irate(istio_request_duration_milliseconds_bucket{reporter=\"source\", connection_security_policy!=\"mutual_tls\", source_workload=~\"$workload\", source_workload_namespace=~\"$namespace\", destination_service=~\"$dstsvc\"}[1m])) by (destination_service, le)) / 1000) or histogram_quantile(0.90, sum(irate(istio_request_duration_seconds_bucket{reporter=\"source\", connection_security_policy!=\"mutual_tls\", source_workload=~\"$workload\", source_workload_namespace=~\"$namespace\", destination_service=~\"$dstsvc\"}[1m])) by (destination_service, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_service }} P90", + "refId": "F", + "step": 2 + }, + { + "expr": "(histogram_quantile(0.95, sum(irate(istio_request_duration_milliseconds_bucket{reporter=\"source\", connection_security_policy!=\"mutual_tls\", source_workload=~\"$workload\", source_workload_namespace=~\"$namespace\", destination_service=~\"$dstsvc\"}[1m])) by (destination_service, le)) / 1000) or histogram_quantile(0.95, sum(irate(istio_request_duration_seconds_bucket{reporter=\"source\", connection_security_policy!=\"mutual_tls\", source_workload=~\"$workload\", source_workload_namespace=~\"$namespace\", destination_service=~\"$dstsvc\"}[1m])) by (destination_service, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_service }} P95", + "refId": "G", + "step": 2 + }, + { + "expr": "(histogram_quantile(0.99, sum(irate(istio_request_duration_milliseconds_bucket{reporter=\"source\", connection_security_policy!=\"mutual_tls\", source_workload=~\"$workload\", source_workload_namespace=~\"$namespace\", destination_service=~\"$dstsvc\"}[1m])) by (destination_service, le)) / 1000) or histogram_quantile(0.99, sum(irate(istio_request_duration_seconds_bucket{reporter=\"source\", connection_security_policy!=\"mutual_tls\", source_workload=~\"$workload\", source_workload_namespace=~\"$namespace\", destination_service=~\"$dstsvc\"}[1m])) by (destination_service, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_service }} P99", + "refId": "H", + "step": 2 + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Outgoing Request Duration by Destination", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "s", + "label": null, + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ] + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 6, + "w": 8, + "x": 8, + "y": 41 + }, + "id": 73, + "legend": { + "alignAsTable": false, + "avg": false, + "current": false, + "hideEmpty": true, + "max": false, + "min": false, + "rightSide": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "histogram_quantile(0.50, sum(irate(istio_request_bytes_bucket{reporter=\"source\", connection_security_policy=\"mutual_tls\", source_workload=~\"$workload\", source_workload_namespace=~\"$namespace\", destination_service=~\"$dstsvc\"}[1m])) by (destination_service, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_service }} P50 (🔐mTLS)", + "refId": "D", + "step": 2 + }, + { + "expr": "histogram_quantile(0.90, sum(irate(istio_request_bytes_bucket{reporter=\"source\", connection_security_policy=\"mutual_tls\", source_workload=~\"$workload\", source_workload_namespace=~\"$namespace\", destination_service=~\"$dstsvc\"}[1m])) by (destination_service, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_service }} P90 (🔐mTLS)", + "refId": "A", + "step": 2 + }, + { + "expr": "histogram_quantile(0.95, sum(irate(istio_request_bytes_bucket{reporter=\"source\", connection_security_policy=\"mutual_tls\", source_workload=~\"$workload\", source_workload_namespace=~\"$namespace\", destination_service=~\"$dstsvc\"}[1m])) by (destination_service, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_service }} P95 (🔐mTLS)", + "refId": "B", + "step": 2 + }, + { + "expr": "histogram_quantile(0.99, sum(irate(istio_request_bytes_bucket{reporter=\"source\", connection_security_policy=\"mutual_tls\", source_workload=~\"$workload\", source_workload_namespace=~\"$namespace\", destination_service=~\"$dstsvc\"}[1m])) by (destination_service, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_service }} P99 (🔐mTLS)", + "refId": "C", + "step": 2 + }, + { + "expr": "histogram_quantile(0.50, sum(irate(istio_request_bytes_bucket{reporter=\"source\", connection_security_policy!=\"mutual_tls\", source_workload=~\"$workload\", source_workload_namespace=~\"$namespace\", destination_service=~\"$dstsvc\"}[1m])) by (destination_service, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_service }} P50", + "refId": "E", + "step": 2 + }, + { + "expr": "histogram_quantile(0.90, sum(irate(istio_request_bytes_bucket{reporter=\"source\", connection_security_policy!=\"mutual_tls\", source_workload=~\"$workload\", source_workload_namespace=~\"$namespace\", destination_service=~\"$dstsvc\"}[1m])) by (destination_service, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_service }} P90", + "refId": "F", + "step": 2 + }, + { + "expr": "histogram_quantile(0.95, sum(irate(istio_request_bytes_bucket{reporter=\"source\", connection_security_policy!=\"mutual_tls\", source_workload=~\"$workload\", source_workload_namespace=~\"$namespace\", destination_service=~\"$dstsvc\"}[1m])) by (destination_service, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_service }} P95", + "refId": "G", + "step": 2 + }, + { + "expr": "histogram_quantile(0.99, sum(irate(istio_request_bytes_bucket{reporter=\"source\", connection_security_policy!=\"mutual_tls\", source_workload=~\"$workload\", source_workload_namespace=~\"$namespace\", destination_service=~\"$dstsvc\"}[1m])) by (destination_service, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_service }} P99", + "refId": "H", + "step": 2 + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Outgoing Request Size By Destination", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "decbytes", + "label": null, + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ] + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 6, + "w": 8, + "x": 16, + "y": 41 + }, + "id": 74, + "legend": { + "alignAsTable": false, + "avg": false, + "current": false, + "hideEmpty": true, + "max": false, + "min": false, + "rightSide": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "histogram_quantile(0.50, sum(irate(istio_response_bytes_bucket{reporter=\"source\", connection_security_policy=\"mutual_tls\", source_workload=~\"$workload\", source_workload_namespace=~\"$namespace\", destination_service=~\"$dstsvc\"}[1m])) by (destination_service, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_service }} P50 (🔐mTLS)", + "refId": "D", + "step": 2 + }, + { + "expr": "histogram_quantile(0.90, sum(irate(istio_response_bytes_bucket{reporter=\"source\", connection_security_policy=\"mutual_tls\", source_workload=~\"$workload\", source_workload_namespace=~\"$namespace\", destination_service=~\"$dstsvc\"}[1m])) by (destination_service, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_service }} P90 (🔐mTLS)", + "refId": "A", + "step": 2 + }, + { + "expr": "histogram_quantile(0.95, sum(irate(istio_response_bytes_bucket{reporter=\"source\", connection_security_policy=\"mutual_tls\", source_workload=~\"$workload\", source_workload_namespace=~\"$namespace\", destination_service=~\"$dstsvc\"}[1m])) by (destination_service, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_service }} P95 (🔐mTLS)", + "refId": "B", + "step": 2 + }, + { + "expr": "histogram_quantile(0.99, sum(irate(istio_response_bytes_bucket{reporter=\"source\", connection_security_policy=\"mutual_tls\", source_workload=~\"$workload\", source_workload_namespace=~\"$namespace\", destination_service=~\"$dstsvc\"}[1m])) by (destination_service, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_service }} P99 (🔐mTLS)", + "refId": "C", + "step": 2 + }, + { + "expr": "histogram_quantile(0.50, sum(irate(istio_response_bytes_bucket{reporter=\"source\", connection_security_policy!=\"mutual_tls\", source_workload=~\"$workload\", source_workload_namespace=~\"$namespace\", destination_service=~\"$dstsvc\"}[1m])) by (destination_service, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_service }} P50", + "refId": "E", + "step": 2 + }, + { + "expr": "histogram_quantile(0.90, sum(irate(istio_response_bytes_bucket{reporter=\"source\", connection_security_policy!=\"mutual_tls\", source_workload=~\"$workload\", source_workload_namespace=~\"$namespace\", destination_service=~\"$dstsvc\"}[1m])) by (destination_service, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_service }} P90", + "refId": "F", + "step": 2 + }, + { + "expr": "histogram_quantile(0.95, sum(irate(istio_response_bytes_bucket{reporter=\"source\", connection_security_policy!=\"mutual_tls\", source_workload=~\"$workload\", source_workload_namespace=~\"$namespace\", destination_service=~\"$dstsvc\"}[1m])) by (destination_service, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_service }} P95", + "refId": "G", + "step": 2 + }, + { + "expr": "histogram_quantile(0.99, sum(irate(istio_response_bytes_bucket{reporter=\"source\", connection_security_policy!=\"mutual_tls\", source_workload=~\"$workload\", source_workload_namespace=~\"$namespace\", destination_service=~\"$dstsvc\"}[1m])) by (destination_service, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_service }} P99", + "refId": "H", + "step": 2 + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Response Size By Destination", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "decbytes", + "label": null, + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ] + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 6, + "w": 12, + "x": 0, + "y": 47 + }, + "id": 76, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "round(sum(irate(istio_tcp_sent_bytes_total{connection_security_policy=\"mutual_tls\", reporter=\"source\", source_workload_namespace=~\"$namespace\", source_workload=~\"$workload\", destination_service=~\"$dstsvc\"}[1m])) by (destination_service), 0.001)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{ destination_service }} (🔐mTLS)", + "refId": "A", + "step": 2 + }, + { + "expr": "round(sum(irate(istio_tcp_sent_bytes_total{connection_security_policy!=\"mutual_tls\", reporter=\"source\", source_workload_namespace=~\"$namespace\", source_workload=~\"$workload\", destination_service=~\"$dstsvc\"}[1m])) by (destination_service), 0.001)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{ destination_service }}", + "refId": "B", + "step": 2 + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Bytes Sent on Outgoing TCP Connection", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "Bps", + "label": null, + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ] + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 6, + "w": 12, + "x": 12, + "y": 47 + }, + "id": 78, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "round(sum(irate(istio_tcp_received_bytes_total{reporter=\"source\", connection_security_policy=\"mutual_tls\", source_workload_namespace=~\"$namespace\", source_workload=~\"$workload\", destination_service=~\"$dstsvc\"}[1m])) by (destination_service), 0.001)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{ destination_service }} (🔐mTLS)", + "refId": "A", + "step": 2 + }, + { + "expr": "round(sum(irate(istio_tcp_received_bytes_total{reporter=\"source\", connection_security_policy!=\"mutual_tls\", source_workload_namespace=~\"$namespace\", source_workload=~\"$workload\", destination_service=~\"$dstsvc\"}[1m])) by (destination_service), 0.001)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{ destination_service }}", + "refId": "B", + "step": 2 + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Bytes Received from Outgoing TCP Connection", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "Bps", + "label": null, + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ] + } + ], + "refresh": "10s", + "schemaVersion": 16, + "style": "dark", + "tags": [], + "templating": { + "list": [ + { + "allValue": null, + "current": {}, + "datasource": "Prometheus", + "hide": 0, + "includeAll": false, + "label": "Namespace", + "multi": false, + "name": "namespace", + "options": [], + "query": "query_result(sum(istio_requests_total) by (destination_workload_namespace) or sum(istio_tcp_sent_bytes_total) by (destination_workload_namespace))", + "refresh": 1, + "regex": "/.*_namespace=\"([^\"]*).*/", + "sort": 0, + "tagValuesQuery": "", + "tags": [], + "tagsQuery": "", + "type": "query", + "useTags": false + }, + { + "allValue": null, + "current": {}, + "datasource": "Prometheus", + "hide": 0, + "includeAll": false, + "label": "Workload", + "multi": false, + "name": "workload", + "options": [], + "query": "query_result((sum(istio_requests_total{destination_workload_namespace=~\"$namespace\"}) by (destination_workload) or sum(istio_requests_total{source_workload_namespace=~\"$namespace\"}) by (source_workload)) or (sum(istio_tcp_sent_bytes_total{destination_workload_namespace=~\"$namespace\"}) by (destination_workload) or sum(istio_tcp_sent_bytes_total{source_workload_namespace=~\"$namespace\"}) by (source_workload)))", + "refresh": 1, + "regex": "/.*workload=\"([^\"]*).*/", + "sort": 1, + "tagValuesQuery": "", + "tags": [], + "tagsQuery": "", + "type": "query", + "useTags": false + }, + { + "allValue": null, + "current": {}, + "datasource": "Prometheus", + "hide": 0, + "includeAll": true, + "label": "Inbound Workload Namespace", + "multi": true, + "name": "srcns", + "options": [], + "query": "query_result( sum(istio_requests_total{reporter=\"destination\", destination_workload=\"$workload\", destination_workload_namespace=~\"$namespace\"}) by (source_workload_namespace) or sum(istio_tcp_sent_bytes_total{reporter=\"destination\", destination_workload=\"$workload\", destination_workload_namespace=~\"$namespace\"}) by (source_workload_namespace))", + "refresh": 1, + "regex": "/.*namespace=\"([^\"]*).*/", + "sort": 2, + "tagValuesQuery": "", + "tags": [], + "tagsQuery": "", + "type": "query", + "useTags": false + }, + { + "allValue": null, + "current": {}, + "datasource": "Prometheus", + "hide": 0, + "includeAll": true, + "label": "Inbound Workload", + "multi": true, + "name": "srcwl", + "options": [], + "query": "query_result( sum(istio_requests_total{reporter=\"destination\", destination_workload=\"$workload\", destination_workload_namespace=~\"$namespace\", source_workload_namespace=~\"$srcns\"}) by (source_workload) or sum(istio_tcp_sent_bytes_total{reporter=\"destination\", destination_workload=\"$workload\", destination_workload_namespace=~\"$namespace\", source_workload_namespace=~\"$srcns\"}) by (source_workload))", + "refresh": 1, + "regex": "/.*workload=\"([^\"]*).*/", + "sort": 3, + "tagValuesQuery": "", + "tags": [], + "tagsQuery": "", + "type": "query", + "useTags": false + }, + { + "allValue": null, + "current": {}, + "datasource": "Prometheus", + "hide": 0, + "includeAll": true, + "label": "Destination Service", + "multi": true, + "name": "dstsvc", + "options": [], + "query": "query_result( sum(istio_requests_total{reporter=\"source\", source_workload=~\"$workload\", source_workload_namespace=~\"$namespace\"}) by (destination_service) or sum(istio_tcp_sent_bytes_total{reporter=\"source\", source_workload=~\"$workload\", source_workload_namespace=~\"$namespace\"}) by (destination_service))", + "refresh": 1, + "regex": "/.*destination_service=\"([^\"]*).*/", + "sort": 4, + "tagValuesQuery": "", + "tags": [], + "tagsQuery": "", + "type": "query", + "useTags": false + } + ] + }, + "time": { + "from": "now-5m", + "to": "now" + }, + "timepicker": { + "refresh_intervals": [ + "5s", + "10s", + "30s", + "1m", + "5m", + "15m", + "30m", + "1h", + "2h", + "1d" + ], + "time_options": [ + "5m", + "15m", + "1h", + "6h", + "12h", + "24h", + "2d", + "7d", + "30d" + ] + }, + "timezone": "", + "title": "Istio Workload Dashboard", + "uid": "UbsSZTDik", + "version": 1 +} +' +--- +apiVersion: v1 +kind: ConfigMap +metadata: + name: istio-grafana-configuration-dashboards-mixer-dashboard + namespace: istio-system + labels: + app: grafana + chart: grafana + heritage: Tiller + release: istio + istio: grafana +data: + mixer-dashboard.json: '{ + "__inputs": [ + { + "name": "DS_PROMETHEUS", + "label": "Prometheus", + "description": "", + "type": "datasource", + "pluginId": "prometheus", + "pluginName": "Prometheus" + } + ], + "__requires": [ + { + "type": "grafana", + "id": "grafana", + "name": "Grafana", + "version": "5.2.3" + }, + { + "type": "panel", + "id": "graph", + "name": "Graph", + "version": "5.0.0" + }, + { + "type": "datasource", + "id": "prometheus", + "name": "Prometheus", + "version": "5.0.0" + }, + { + "type": "panel", + "id": "text", + "name": "Text", + "version": "5.0.0" + } + ], + "annotations": { + "list": [ + { + "builtIn": 1, + "datasource": "-- Grafana --", + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "limit": 100, + "name": "Annotations & Alerts", + "showIn": 0, + "type": "dashboard" + } + ] + }, + "editable": false, + "gnetId": null, + "graphTooltip": 1, + "id": null, + "iteration": 1543881232533, + "links": [], + "panels": [ + { + "content": "

Deployed Versions

", + "gridPos": { + "h": 3, + "w": 24, + "x": 0, + "y": 0 + }, + "height": "40", + "id": 62, + "links": [], + "mode": "html", + "title": "", + "transparent": true, + "type": "text" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 5, + "w": 24, + "x": 0, + "y": 3 + }, + "id": 64, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(istio_build{component=\"mixer\"}) by (tag)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{ tag }}", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Mixer Versions", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "content": "

Resource Usage

", + "gridPos": { + "h": 3, + "w": 24, + "x": 0, + "y": 8 + }, + "height": "40", + "id": 29, + "links": [], + "mode": "html", + "title": "", + "transparent": true, + "type": "text" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 7, + "w": 6, + "x": 0, + "y": 11 + }, + "id": 5, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(process_virtual_memory_bytes{job=~\"istio-telemetry|istio-policy\"}) by (job)", + "format": "time_series", + "instant": false, + "intervalFactor": 2, + "legendFormat": "Virtual Memory ({{ job }})", + "refId": "I" + }, + { + "expr": "sum(process_resident_memory_bytes{job=~\"istio-telemetry|istio-policy\"}) by (job)", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "Resident Memory ({{ job }})", + "refId": "H" + }, + { + "expr": "sum(go_memstats_heap_sys_bytes{job=~\"istio-telemetry|istio-policy\"}) by (job)", + "format": "time_series", + "hide": true, + "intervalFactor": 2, + "legendFormat": "heap sys ({{ job }})", + "refId": "A" + }, + { + "expr": "sum(go_memstats_heap_alloc_bytes{job=~\"istio-telemetry|istio-policy\"}) by (job)", + "format": "time_series", + "hide": true, + "intervalFactor": 2, + "legendFormat": "heap alloc ({{ job }})", + "refId": "D" + }, + { + "expr": "sum(go_memstats_alloc_bytes{job=~\"istio-telemetry|istio-policy\"}) by (job)", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "Alloc ({{ job }})", + "refId": "F" + }, + { + "expr": "sum(go_memstats_heap_inuse_bytes{job=~\"istio-telemetry|istio-policy\"}) by (job)", + "format": "time_series", + "hide": false, + "intervalFactor": 2, + "legendFormat": "Heap in-use ({{ job }})", + "refId": "E" + }, + { + "expr": "sum(go_memstats_stack_inuse_bytes{job=~\"istio-telemetry|istio-policy\"}) by (job)", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "Stack in-use ({{ job }})", + "refId": "G" + }, + { + "expr": "sum(label_replace(container_memory_usage_bytes{job=\"kubernetes-cadvisor\", container_name=~\"mixer|istio-proxy\", pod_name=~\"istio-telemetry-.*|istio-policy-.*\"}, \"service\", \"$1\" , \"pod_name\", \"(istio-telemetry|istio-policy)-.*\")) by (service)", + "format": "time_series", + "hide": false, + "intervalFactor": 2, + "legendFormat": "{{ service }} total (k8s)", + "refId": "C" + }, + { + "expr": "sum(label_replace(container_memory_usage_bytes{job=\"kubernetes-cadvisor\", container_name=~\"mixer|istio-proxy\", pod_name=~\"istio-telemetry-.*|istio-policy-.*\"}, \"service\", \"$1\" , \"pod_name\", \"(istio-telemetry|istio-policy)-.*\")) by (container_name, service)", + "format": "time_series", + "hide": false, + "intervalFactor": 2, + "legendFormat": "{{ service }} - {{ container_name }} (k8s)", + "refId": "B" + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Memory", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "bytes", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 7, + "w": 6, + "x": 6, + "y": 11 + }, + "id": 6, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "label_replace(sum(rate(container_cpu_usage_seconds_total{job=\"kubernetes-cadvisor\",container_name=~\"mixer|istio-proxy\", pod_name=~\"istio-telemetry-.*|istio-policy-.*\"}[1m])) by (pod_name), \"service\", \"$1\" , \"pod_name\", \"(istio-telemetry|istio-policy)-.*\")", + "format": "time_series", + "hide": false, + "intervalFactor": 2, + "legendFormat": "{{ service }} total (k8s)", + "refId": "A" + }, + { + "expr": "label_replace(sum(rate(container_cpu_usage_seconds_total{job=\"kubernetes-cadvisor\",container_name=~\"mixer|istio-proxy\", pod_name=~\"istio-telemetry-.*|istio-policy-.*\"}[1m])) by (container_name, pod_name), \"service\", \"$1\" , \"pod_name\", \"(istio-telemetry|istio-policy)-.*\")", + "format": "time_series", + "hide": false, + "intervalFactor": 2, + "legendFormat": "{{ service }} - {{ container_name }} (k8s)", + "refId": "B" + }, + { + "expr": "sum(irate(process_cpu_seconds_total{job=~\"istio-telemetry|istio-policy\"}[1m])) by (job)", + "format": "time_series", + "hide": false, + "intervalFactor": 2, + "legendFormat": "{{ job }} (self-reported)", + "refId": "C" + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "CPU", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 7, + "w": 6, + "x": 12, + "y": 11 + }, + "id": 7, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(process_open_fds{job=~\"istio-telemetry|istio-policy\"}) by (job)", + "format": "time_series", + "hide": true, + "instant": false, + "interval": "", + "intervalFactor": 2, + "legendFormat": "Open FDs ({{ job }})", + "refId": "A" + }, + { + "expr": "sum(label_replace(container_fs_usage_bytes{job=\"kubernetes-cadvisor\", container_name=~\"mixer|istio-proxy\", pod_name=~\"istio-telemetry-.*|istio-policy-.*\"}, \"service\", \"$1\" , \"pod_name\", \"(istio-telemetry|istio-policy)-.*\")) by (container_name, service)", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "{{ service }} - {{ container_name }}", + "refId": "B" + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Disk", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "bytes", + "label": "", + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "decimals": null, + "format": "none", + "label": "", + "logBase": 1024, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 7, + "w": 6, + "x": 18, + "y": 11 + }, + "id": 4, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": false, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(go_goroutines{job=~\"istio-telemetry|istio-policy\"}) by (job)", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "Number of Goroutines ({{ job }})", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Goroutines", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": "", + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "content": "

Mixer Overview

", + "gridPos": { + "h": 3, + "w": 24, + "x": 0, + "y": 18 + }, + "height": "40px", + "id": 30, + "links": [], + "mode": "html", + "title": "", + "transparent": true, + "type": "text" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 6, + "w": 6, + "x": 0, + "y": 21 + }, + "id": 9, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(rate(grpc_io_server_completed_rpcs[1m]))", + "format": "time_series", + "hide": false, + "intervalFactor": 2, + "legendFormat": "mixer (Total)", + "refId": "B" + }, + { + "expr": "sum(rate(grpc_io_server_completed_rpcs[1m])) by (grpc_server_method)", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "mixer ({{ grpc_server_method }})", + "refId": "C" + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Incoming Requests", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "ops", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 6, + "w": 6, + "x": 6, + "y": 21 + }, + "id": 8, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [ + { + "alias": "{}", + "yaxis": 1 + } + ], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "histogram_quantile(0.5, sum(rate(grpc_io_server_server_latency_bucket{}[1m])) by (grpc_server_method, le))", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "{{ grpc_server_method }} 0.5", + "refId": "B" + }, + { + "expr": "histogram_quantile(0.9, sum(rate(grpc_io_server_server_latency_bucket{}[1m])) by (grpc_server_method, le))", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "{{ grpc_server_method }} 0.9", + "refId": "C" + }, + { + "expr": "histogram_quantile(0.99, sum(rate(grpc_io_server_server_latency_bucket{}[1m])) by (grpc_server_method, le))", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "{{ grpc_server_method }} 0.99", + "refId": "D" + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Response Durations", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "ms", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 6, + "w": 6, + "x": 12, + "y": 21 + }, + "id": 11, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(rate(grpc_server_handled_total{grpc_code=~\"Unknown|Unimplemented|Internal|DataLoss\"}[1m])) by (grpc_method)", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "Mixer {{ grpc_method }}", + "refId": "B" + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Server Error Rate (5xx responses)", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 6, + "w": 6, + "x": 18, + "y": 21 + }, + "id": 12, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(irate(grpc_server_handled_total{grpc_code!=\"OK\",grpc_service=~\".*Mixer\"}[1m])) by (grpc_method)", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "Mixer {{ grpc_method }}", + "refId": "B" + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Non-successes (4xxs)", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "content": "

Adapters and Config

", + "gridPos": { + "h": 3, + "w": 24, + "x": 0, + "y": 27 + }, + "id": 28, + "links": [], + "mode": "html", + "title": "", + "transparent": true, + "type": "text" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 7, + "w": 12, + "x": 0, + "y": 30 + }, + "id": 13, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(irate(mixer_runtime_dispatches_total{adapter=~\"$adapter\"}[1m])) by (adapter)", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "{{ adapter }}", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Adapter Dispatch Count", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 7, + "w": 12, + "x": 12, + "y": 30 + }, + "id": 14, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "histogram_quantile(0.5, sum(irate(mixer_runtime_dispatch_duration_seconds_bucket{adapter=~\"$adapter\"}[1m])) by (adapter, le))", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "{{ adapter }} - p50", + "refId": "A" + }, + { + "expr": "histogram_quantile(0.9, sum(irate(mixer_runtime_dispatch_duration_seconds_bucket{adapter=~\"$adapter\"}[1m])) by (adapter, le))", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "{{ adapter }} - p90 ", + "refId": "B" + }, + { + "expr": "histogram_quantile(0.99, sum(irate(mixer_runtime_dispatch_duration_seconds_bucket{adapter=~\"$adapter\"}[1m])) by (adapter, le))", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "{{ adapter }} - p99", + "refId": "C" + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Adapter Dispatch Duration", + "tooltip": { + "shared": true, + "sort": 1, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "s", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 7, + "w": 6, + "x": 0, + "y": 37 + }, + "id": 60, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "scalar(topk(1, max(mixer_config_rule_config_count) by (configID)))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Rules", + "refId": "A" + }, + { + "expr": "scalar(topk(1, max(mixer_config_rule_config_error_count) by (configID)))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Config Errors", + "refId": "B" + }, + { + "expr": "scalar(topk(1, max(mixer_config_rule_config_match_error_count) by (configID)))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Match Errors", + "refId": "C" + }, + { + "expr": "scalar(topk(1, max(mixer_config_unsatisfied_action_handler_count) by (configID)))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Unsatisfied Actions", + "refId": "D" + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Rules", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 7, + "w": 6, + "x": 6, + "y": 37 + }, + "id": 56, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "scalar(topk(1, max(mixer_config_instance_config_count) by (configID)))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Instances", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Instances in Latest Config", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 7, + "w": 6, + "x": 12, + "y": 37 + }, + "id": 54, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "scalar(topk(1, max(mixer_config_handler_config_count) by (configID)))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Handlers", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Handlers in Latest Config", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 7, + "w": 6, + "x": 18, + "y": 37 + }, + "id": 58, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "scalar(topk(1, max(mixer_config_attribute_count) by (configID)))", + "format": "time_series", + "instant": false, + "intervalFactor": 1, + "legendFormat": "Attributes", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Attributes in Latest Config", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "content": "

Individual Adapters

", + "gridPos": { + "h": 3, + "w": 24, + "x": 0, + "y": 44 + }, + "id": 23, + "links": [], + "mode": "html", + "title": "", + "transparent": true, + "type": "text" + }, + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 47 + }, + "id": 46, + "panels": [], + "repeat": "adapter", + "title": "$adapter Adapter", + "type": "row" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 7, + "w": 12, + "x": 0, + "y": 48 + }, + "id": 17, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "label_replace(irate(mixer_runtime_dispatches_total{adapter=~\"$adapter\"}[1m]),\"handler\", \"$1 ($3)\", \"handler\", \"(.*)\\\\.(.*)\\\\.(.*)\")", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "{{ handler }} (error: {{ error }})", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Dispatch Count By Handler", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 7, + "w": 12, + "x": 12, + "y": 48 + }, + "id": 18, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "label_replace(histogram_quantile(0.5, sum(rate(mixer_runtime_dispatch_duration_seconds_bucket{adapter=~\"$adapter\"}[1m])) by (handler, error, le)), \"handler_short\", \"$1 ($3)\", \"handler\", \"(.*)\\\\.(.*)\\\\.(.*)\")", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "p50 - {{ handler_short }} (error: {{ error }})", + "refId": "A" + }, + { + "expr": "label_replace(histogram_quantile(0.9, sum(irate(mixer_runtime_dispatch_duration_seconds_bucket{adapter=~\"$adapter\"}[1m])) by (handler, error, le)), \"handler_short\", \"$1 ($3)\", \"handler\", \"(.*)\\\\.(.*)\\\\.(.*)\")", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "p90 - {{ handler_short }} (error: {{ error }})", + "refId": "D" + }, + { + "expr": "label_replace(histogram_quantile(0.99, sum(irate(mixer_runtime_dispatch_duration_seconds_bucket{adapter=~\"$adapter\"}[1m])) by (handler, error, le)), \"handler_short\", \"$1 ($3)\", \"handler\", \"(.*)\\\\.(.*)\\\\.(.*)\")", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "p99 - {{ handler_short }} (error: {{ error }})", + "refId": "E" + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Dispatch Duration By Handler", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "s", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + } + ], + "refresh": "5s", + "schemaVersion": 16, + "style": "dark", + "tags": [], + "templating": { + "list": [ + { + "allValue": null, + "current": {}, + "datasource": "Prometheus", + "hide": 0, + "includeAll": true, + "label": "Adapter", + "multi": true, + "name": "adapter", + "options": [], + "query": "label_values(adapter)", + "refresh": 2, + "regex": "", + "sort": 1, + "tagValuesQuery": "", + "tags": [], + "tagsQuery": "", + "type": "query", + "useTags": false + } + ] + }, + "time": { + "from": "now-5m", + "to": "now" + }, + "timepicker": { + "refresh_intervals": [ + "5s", + "10s", + "30s", + "1m", + "5m", + "15m", + "30m", + "1h", + "2h", + "1d" + ], + "time_options": [ + "5m", + "15m", + "1h", + "6h", + "12h", + "24h", + "2d", + "7d", + "30d" + ] + }, + "timezone": "", + "title": "Istio Mixer Dashboard", + "version": 4 +} +' +--- +apiVersion: v1 +kind: ConfigMap +metadata: + name: istio-grafana-configuration-dashboards-pilot-dashboard + namespace: istio-system + labels: + app: grafana + chart: grafana + heritage: Tiller + release: istio + istio: grafana +data: + pilot-dashboard.json: '{ + "annotations": { + "list": [ + { + "builtIn": 1, + "datasource": "-- Grafana --", + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations & Alerts", + "type": "dashboard" + } + ] + }, + "editable": false, + "gnetId": null, + "graphTooltip": 1, + "id": 11, + "links": [], + "panels": [ + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 0 + }, + "id": 60, + "panels": [], + "title": "Deployed Versions", + "type": "row" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 5, + "w": 24, + "x": 0, + "y": 1 + }, + "id": 56, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(istio_build{component=\"pilot\"}) by (tag)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{ tag }}", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Pilot Versions", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 6 + }, + "id": 62, + "panels": [], + "title": "Resource Usage", + "type": "row" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 7, + "w": 6, + "x": 0, + "y": 7 + }, + "id": 5, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "process_virtual_memory_bytes{job=\"pilot\"}", + "format": "time_series", + "instant": false, + "intervalFactor": 2, + "legendFormat": "Virtual Memory", + "refId": "I", + "step": 2 + }, + { + "expr": "process_resident_memory_bytes{job=\"pilot\"}", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "Resident Memory", + "refId": "H", + "step": 2 + }, + { + "expr": "go_memstats_heap_sys_bytes{job=\"pilot\"}", + "format": "time_series", + "hide": true, + "intervalFactor": 2, + "legendFormat": "heap sys", + "refId": "A" + }, + { + "expr": "go_memstats_heap_alloc_bytes{job=\"pilot\"}", + "format": "time_series", + "hide": true, + "intervalFactor": 2, + "legendFormat": "heap alloc", + "refId": "D" + }, + { + "expr": "go_memstats_alloc_bytes{job=\"pilot\"}", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "Alloc", + "refId": "F", + "step": 2 + }, + { + "expr": "go_memstats_heap_inuse_bytes{job=\"pilot\"}", + "format": "time_series", + "hide": false, + "intervalFactor": 2, + "legendFormat": "Heap in-use", + "refId": "E", + "step": 2 + }, + { + "expr": "go_memstats_stack_inuse_bytes{job=\"pilot\"}", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "Stack in-use", + "refId": "G", + "step": 2 + }, + { + "expr": "container_memory_usage_bytes{job=\"kubernetes-cadvisor\", container_name=~\"discovery\", pod_name=~\"istio-pilot-.*\"}", + "format": "time_series", + "hide": false, + "intervalFactor": 2, + "legendFormat": "Discovery (container)", + "refId": "B", + "step": 2 + }, + { + "expr": "container_memory_usage_bytes{job=\"kubernetes-cadvisor\", container_name=~\"istio-proxy\", pod_name=~\"istio-pilot-.*\"}", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Sidecar (container)", + "refId": "C" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Memory", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "bytes", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 7, + "w": 6, + "x": 6, + "y": 7 + }, + "id": 6, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(irate(container_cpu_usage_seconds_total{job=\"kubernetes-cadvisor\",container_name=\"discovery\", pod_name=~\"istio-pilot-.*\"}[1m]))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Discovery (container)", + "refId": "A" + }, + { + "expr": "irate(process_cpu_seconds_total{job=\"pilot\"}[1m])", + "format": "time_series", + "hide": false, + "intervalFactor": 2, + "legendFormat": "Discovery (process)", + "refId": "C", + "step": 2 + }, + { + "expr": "sum(irate(container_cpu_usage_seconds_total{job=\"kubernetes-cadvisor\",container_name=\"istio-proxy\", pod_name=~\"istio-pilot-.*\"}[1m]))", + "format": "time_series", + "hide": false, + "intervalFactor": 2, + "legendFormat": "Sidecar (container)", + "refId": "B", + "step": 2 + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "CPU", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 7, + "w": 6, + "x": 12, + "y": 7 + }, + "id": 7, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "container_fs_usage_bytes{job=\"kubernetes-cadvisor\", container_name=\"discovery\", pod_name=~\"istio-pilot-.*\"}", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "Discovery", + "refId": "B", + "step": 2 + }, + { + "expr": "container_fs_usage_bytes{job=\"kubernetes-cadvisor\", container_name=\"istio-proxy\", pod_name=~\"istio-pilot-.*\"}", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Sidecar", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Disk", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "bytes", + "label": "", + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "decimals": null, + "format": "none", + "label": "", + "logBase": 1024, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 7, + "w": 6, + "x": 18, + "y": 7 + }, + "id": 4, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": false, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "go_goroutines{job=\"pilot\"}", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "Number of Goroutines", + "refId": "A", + "step": 2 + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Goroutines", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": "", + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 14 + }, + "id": 58, + "panels": [], + "title": "Pilot Push Information", + "type": "row" + }, + { + "aliasColors": {}, + "bars": true, + "dashLength": 10, + "dashes": false, + "description": "Shows the rate of pilot pushes", + "fill": 1, + "gridPos": { + "h": 8, + "w": 8, + "x": 0, + "y": 15 + }, + "id": 622, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": false, + "linewidth": 1, + "links": [], + "nullPointMode": "null as zero", + "paceLength": 10, + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": true, + "steppedLine": false, + "targets": [ + { + "expr": "sum(irate(pilot_xds_pushes{type=\"cds\"}[1m]))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Cluster", + "refId": "C" + }, + { + "expr": "sum(irate(pilot_xds_pushes{type=\"eds\"}[1m]))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Endpoints", + "refId": "D" + }, + { + "expr": "sum(irate(pilot_xds_pushes{type=\"lds\"}[1m]))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Listeners", + "refId": "A" + }, + { + "expr": "sum(irate(pilot_xds_pushes{type=\"rds\"}[1m]))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Routes", + "refId": "E" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Pilot Pushes", + "tooltip": { + "shared": false, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [ + "total" + ] + }, + "yaxes": [ + { + "format": "ops", + "label": null, + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "description": "Captures a variety of pilot errors", + "fill": 1, + "gridPos": { + "h": 8, + "w": 8, + "x": 8, + "y": 15 + }, + "id": 67, + "legend": { + "avg": false, + "current": false, + "hideEmpty": true, + "hideZero": true, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(pilot_xds_cds_reject{job=\"pilot\"}) or (absent(pilot_xds_cds_reject{job=\"pilot\"}) - 1)", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "Rejected CDS Configs", + "refId": "C" + }, + { + "expr": "sum(pilot_xds_eds_reject{job=\"pilot\"}) or (absent(pilot_xds_eds_reject{job=\"pilot\"}) - 1)", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "Rejected EDS Configs", + "refId": "D" + }, + { + "expr": "sum(pilot_xds_rds_reject{job=\"pilot\"}) or (absent(pilot_xds_rds_reject{job=\"pilot\"}) - 1)", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "Rejected RDS Configs", + "refId": "A" + }, + { + "expr": "sum(pilot_xds_lds_reject{job=\"pilot\"}) or (absent(pilot_xds_lds_reject{job=\"pilot\"}) - 1)", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "Rejected LDS Configs", + "refId": "B" + }, + { + "expr": "sum(rate(pilot_xds_write_timeout{job=\"pilot\"}[1m]))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Write Timeouts", + "refId": "F" + }, + { + "expr": "sum(rate(pilot_total_xds_internal_errors{job=\"pilot\"}[1m]))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "Internal Errors", + "refId": "H" + }, + { + "expr": "sum(rate(pilot_total_xds_rejects{job=\"pilot\"}[1m]))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "Config Rejection Rate", + "refId": "E" + }, + { + "expr": "sum(rate(pilot_xds_push_context_errors{job=\"pilot\"}[1m]))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "Push Context Errors", + "refId": "K" + }, + { + "expr": "sum(rate(pilot_xds_pushes{type!~\"lds|cds|rds|eds\"}[1m])) by (type)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Push Errors ({{ type }})", + "refId": "L" + }, + { + "expr": "sum(rate(pilot_xds_push_errors{job=\"pilot\"}[1m])) by (type)", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "Push Errors ({{ type }})", + "refId": "I" + }, + { + "expr": "sum(rate(pilot_xds_push_timeout{job=\"pilot\"}[1m]))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Push Timeouts", + "refId": "G" + }, + { + "expr": "sum(rate(pilot_xds_push_timeout_failures{job=\"pilot\"}[1m]))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Push Timeouts Failures", + "refId": "J" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Pilot Errors", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "description": "Shows the total time it takes to push a config update to a proxy", + "fill": 1, + "gridPos": { + "h": 8, + "w": 8, + "x": 16, + "y": 15 + }, + "id": 624, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "histogram_quantile(0.5, sum(rate(pilot_proxy_convergence_time_bucket[1m])) by (le))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "p50 ", + "refId": "A" + }, + { + "expr": "histogram_quantile(0.9, sum(rate(pilot_proxy_convergence_time_bucket[1m])) by (le))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "p90", + "refId": "B" + }, + { + "expr": "histogram_quantile(0.99, sum(rate(pilot_proxy_convergence_time_bucket[1m])) by (le))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "p99", + "refId": "C" + }, + { + "expr": "histogram_quantile(0.999, sum(rate(pilot_proxy_convergence_time_bucket[1m])) by (le))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "p99.9", + "refId": "D" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Proxy Push Time", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "s", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 8, + "w": 8, + "x": 0, + "y": 23 + }, + "id": 45, + "legend": { + "avg": false, + "current": false, + "hideEmpty": true, + "hideZero": true, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null as zero", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "pilot_conflict_inbound_listener{job=\"pilot\"}", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "Inbound Listeners", + "refId": "B" + }, + { + "expr": "pilot_conflict_outbound_listener_http_over_current_tcp{job=\"pilot\"}", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "Outbound Listeners (http over current tcp)", + "refId": "A" + }, + { + "expr": "pilot_conflict_outbound_listener_tcp_over_current_tcp{job=\"pilot\"}", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "Outbound Listeners (tcp over current tcp)", + "refId": "C" + }, + { + "expr": "pilot_conflict_outbound_listener_tcp_over_current_http{job=\"pilot\"}", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "Outbound Listeners (tcp over current http)", + "refId": "D" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Conflicts", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 8, + "w": 8, + "x": 8, + "y": 23 + }, + "id": 47, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "pilot_virt_services{job=\"pilot\"}", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Virtual Services", + "refId": "A" + }, + { + "expr": "pilot_services{job=\"pilot\"}", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Services", + "refId": "B" + }, + { + "expr": "pilot_xds{job=\"pilot\"}", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Connected Endpoints", + "refId": "E" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "ADS Monitoring", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "columns": [], + "datasource": "Prometheus", + "description": "Clusters in this table do not have any endpoints known to pilot. This could be from referencing subsets that do not have any instances, or pods marked as NotReady", + "fontSize": "100%", + "gridPos": { + "h": 8, + "w": 8, + "x": 16, + "y": 23 + }, + "id": 51, + "links": [], + "pageSize": null, + "scroll": true, + "showHeader": true, + "sort": { + "col": null, + "desc": false + }, + "styles": [ + { + "alias": "Time", + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "pattern": "Time", + "type": "date" + }, + { + "alias": "Clusters", + "colorMode": null, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "decimals": 2, + "pattern": "/.*/", + "thresholds": [], + "type": "number", + "unit": "short" + } + ], + "targets": [ + { + "expr": "sum(pilot_xds_eds_instances{job=\"pilot\", cluster=~\".+\\\\|.+\"}) by (cluster) < 1", + "format": "time_series", + "hide": false, + "instant": true, + "intervalFactor": 1, + "legendFormat": "{{cluster}}", + "refId": "B" + } + ], + "timeFrom": null, + "timeShift": null, + "title": "Clusters with no known endpoints", + "transform": "timeseries_aggregations", + "type": "table" + }, + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 31 + }, + "id": 64, + "panels": [], + "title": "Envoy Information", + "type": "row" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "description": "Shows details about Envoy proxies in the mesh", + "fill": 1, + "gridPos": { + "h": 8, + "w": 8, + "x": 0, + "y": 32 + }, + "id": 40, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(irate(envoy_cluster_upstream_cx_total{cluster_name=\"xds-grpc\"}[1m]))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "XDS Connections", + "refId": "C" + }, + { + "expr": "sum(irate(envoy_cluster_upstream_cx_connect_fail{cluster_name=\"xds-grpc\"}[1m]))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "XDS Connection Failures", + "refId": "A" + }, + { + "expr": "sum(increase(envoy_server_hot_restart_epoch[1m]))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Envoy Restarts", + "refId": "B" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Envoy Details", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "ops", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "ops", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 8, + "w": 8, + "x": 8, + "y": 32 + }, + "id": 41, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(envoy_cluster_upstream_cx_active{cluster_name=\"xds-grpc\"})", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "XDS Active Connections", + "refId": "C", + "step": 2 + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "XDS Active Connections", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "description": "Shows the size of XDS requests and responses", + "fill": 1, + "gridPos": { + "h": 8, + "w": 8, + "x": 16, + "y": 32 + }, + "id": 42, + "legend": { + "avg": false, + "current": false, + "hideEmpty": false, + "hideZero": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "max(rate(envoy_cluster_upstream_cx_rx_bytes_total{cluster_name=\"xds-grpc\"}[1m]))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "XDS Response Bytes Max", + "refId": "D" + }, + { + "expr": "quantile(0.5, rate(envoy_cluster_upstream_cx_rx_bytes_total{cluster_name=\"xds-grpc\"}[1m]))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "XDS Response Bytes Average", + "refId": "B" + }, + { + "expr": "max(rate(envoy_cluster_upstream_cx_tx_bytes_total{cluster_name=\"xds-grpc\"}[1m]))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "XDS Request Bytes Max", + "refId": "A" + }, + { + "expr": "quantile(.5, rate(envoy_cluster_upstream_cx_tx_bytes_total{cluster_name=\"xds-grpc\"}[1m]))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "XDS Request Bytes Average", + "refId": "C" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "XDS Requests Size", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "Bps", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "ops", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + } + ], + "refresh": "5s", + "schemaVersion": 18, + "style": "dark", + "tags": [], + "templating": { + "list": [] + }, + "time": { + "from": "now-5m", + "to": "now" + }, + "timepicker": { + "refresh_intervals": [ + "5s", + "10s", + "30s", + "1m", + "5m", + "15m", + "30m", + "1h", + "2h", + "1d" + ], + "time_options": [ + "5m", + "15m", + "1h", + "6h", + "12h", + "24h", + "2d", + "7d", + "30d" + ] + }, + "timezone": "browser", + "title": "Istio Pilot Dashboard", + "uid": "3--MLVZZk", + "version": 11 +}' +--- + +--- +# Source: istio/charts/grafana/templates/configmap.yaml +apiVersion: v1 +kind: ConfigMap +metadata: + name: istio-grafana + namespace: istio-system + labels: + app: grafana + chart: grafana + heritage: Tiller + release: istio + istio: grafana +data: + datasources.yaml: | + apiVersion: 1 + datasources: + - access: proxy + editable: true + isDefault: true + jsonData: + timeInterval: 5s + name: Prometheus + orgId: 1 + type: prometheus + url: http://prometheus:9090 + + dashboardproviders.yaml: | + apiVersion: 1 + providers: + - disableDeletion: false + folder: istio + name: istio + options: + path: /var/lib/grafana/dashboards/istio + orgId: 1 + type: file + +--- +# Source: istio/charts/kiali/templates/configmap.yaml +apiVersion: v1 +kind: ConfigMap +metadata: + name: kiali + namespace: istio-system + labels: + app: kiali + chart: kiali + heritage: Tiller + release: istio +data: + config.yaml: | + istio_namespace: istio-system + auth: + strategy: login + server: + port: 20001 + web_root: /kiali + external_services: + tracing: + url: + grafana: + url: + prometheus: + url: http://prometheus:9090 + +--- +# Source: istio/charts/prometheus/templates/configmap.yaml +apiVersion: v1 +kind: ConfigMap +metadata: + name: prometheus + namespace: istio-system + labels: + app: prometheus + chart: prometheus + heritage: Tiller + release: istio +data: + prometheus.yml: |- + global: + scrape_interval: 15s + scrape_configs: + + - job_name: 'istio-mesh' + kubernetes_sd_configs: + - role: endpoints + namespaces: + names: + - istio-system + + relabel_configs: + - source_labels: [__meta_kubernetes_service_name, __meta_kubernetes_endpoint_port_name] + action: keep + regex: istio-telemetry;prometheus + + # Scrape config for envoy stats + - job_name: 'envoy-stats' + metrics_path: /stats/prometheus + kubernetes_sd_configs: + - role: pod + + relabel_configs: + - source_labels: [__meta_kubernetes_pod_container_port_name] + action: keep + regex: '.*-envoy-prom' + - source_labels: [__address__, __meta_kubernetes_pod_annotation_prometheus_io_port] + action: replace + regex: ([^:]+)(?::\d+)?;(\d+) + replacement: $1:15090 + target_label: __address__ + - action: labelmap + regex: __meta_kubernetes_pod_label_(.+) + - source_labels: [__meta_kubernetes_namespace] + action: replace + target_label: namespace + - source_labels: [__meta_kubernetes_pod_name] + action: replace + target_label: pod_name + + - job_name: 'istio-policy' + kubernetes_sd_configs: + - role: endpoints + namespaces: + names: + - istio-system + + + relabel_configs: + - source_labels: [__meta_kubernetes_service_name, __meta_kubernetes_endpoint_port_name] + action: keep + regex: istio-policy;http-monitoring + + - job_name: 'istio-telemetry' + kubernetes_sd_configs: + - role: endpoints + namespaces: + names: + - istio-system + + relabel_configs: + - source_labels: [__meta_kubernetes_service_name, __meta_kubernetes_endpoint_port_name] + action: keep + regex: istio-telemetry;http-monitoring + + - job_name: 'pilot' + kubernetes_sd_configs: + - role: endpoints + namespaces: + names: + - istio-system + + relabel_configs: + - source_labels: [__meta_kubernetes_service_name, __meta_kubernetes_endpoint_port_name] + action: keep + regex: istio-pilot;http-monitoring + + - job_name: 'galley' + kubernetes_sd_configs: + - role: endpoints + namespaces: + names: + - istio-system + + relabel_configs: + - source_labels: [__meta_kubernetes_service_name, __meta_kubernetes_endpoint_port_name] + action: keep + regex: istio-galley;http-monitoring + + - job_name: 'citadel' + kubernetes_sd_configs: + - role: endpoints + namespaces: + names: + - istio-system + + relabel_configs: + - source_labels: [__meta_kubernetes_service_name, __meta_kubernetes_endpoint_port_name] + action: keep + regex: istio-citadel;http-monitoring + + # scrape config for API servers + - job_name: 'kubernetes-apiservers' + kubernetes_sd_configs: + - role: endpoints + namespaces: + names: + - default + scheme: https + tls_config: + ca_file: /var/run/secrets/kubernetes.io/serviceaccount/ca.crt + bearer_token_file: /var/run/secrets/kubernetes.io/serviceaccount/token + relabel_configs: + - source_labels: [__meta_kubernetes_service_name, __meta_kubernetes_endpoint_port_name] + action: keep + regex: kubernetes;https + + # scrape config for nodes (kubelet) + - job_name: 'kubernetes-nodes' + scheme: https + tls_config: + ca_file: /var/run/secrets/kubernetes.io/serviceaccount/ca.crt + bearer_token_file: /var/run/secrets/kubernetes.io/serviceaccount/token + kubernetes_sd_configs: + - role: node + relabel_configs: + - action: labelmap + regex: __meta_kubernetes_node_label_(.+) + - target_label: __address__ + replacement: kubernetes.default.svc:443 + - source_labels: [__meta_kubernetes_node_name] + regex: (.+) + target_label: __metrics_path__ + replacement: /api/v1/nodes/${1}/proxy/metrics + + # Scrape config for Kubelet cAdvisor. + # + # This is required for Kubernetes 1.7.3 and later, where cAdvisor metrics + # (those whose names begin with 'container_') have been removed from the + # Kubelet metrics endpoint. This job scrapes the cAdvisor endpoint to + # retrieve those metrics. + # + # In Kubernetes 1.7.0-1.7.2, these metrics are only exposed on the cAdvisor + # HTTP endpoint; use "replacement: /api/v1/nodes/${1}:4194/proxy/metrics" + # in that case (and ensure cAdvisor's HTTP server hasn't been disabled with + # the --cadvisor-port=0 Kubelet flag). + # + # This job is not necessary and should be removed in Kubernetes 1.6 and + # earlier versions, or it will cause the metrics to be scraped twice. + - job_name: 'kubernetes-cadvisor' + scheme: https + tls_config: + ca_file: /var/run/secrets/kubernetes.io/serviceaccount/ca.crt + bearer_token_file: /var/run/secrets/kubernetes.io/serviceaccount/token + kubernetes_sd_configs: + - role: node + relabel_configs: + - action: labelmap + regex: __meta_kubernetes_node_label_(.+) + - target_label: __address__ + replacement: kubernetes.default.svc:443 + - source_labels: [__meta_kubernetes_node_name] + regex: (.+) + target_label: __metrics_path__ + replacement: /api/v1/nodes/${1}/proxy/metrics/cadvisor + + # scrape config for service endpoints. + - job_name: 'kubernetes-service-endpoints' + kubernetes_sd_configs: + - role: endpoints + relabel_configs: + - source_labels: [__meta_kubernetes_service_annotation_prometheus_io_scrape] + action: keep + regex: true + - source_labels: [__meta_kubernetes_service_annotation_prometheus_io_scheme] + action: replace + target_label: __scheme__ + regex: (https?) + - source_labels: [__meta_kubernetes_service_annotation_prometheus_io_path] + action: replace + target_label: __metrics_path__ + regex: (.+) + - source_labels: [__address__, __meta_kubernetes_service_annotation_prometheus_io_port] + action: replace + target_label: __address__ + regex: ([^:]+)(?::\d+)?;(\d+) + replacement: $1:$2 + - action: labelmap + regex: __meta_kubernetes_service_label_(.+) + - source_labels: [__meta_kubernetes_namespace] + action: replace + target_label: kubernetes_namespace + - source_labels: [__meta_kubernetes_service_name] + action: replace + target_label: kubernetes_name + + - job_name: 'kubernetes-pods' + kubernetes_sd_configs: + - role: pod + relabel_configs: # If first two labels are present, pod should be scraped by the istio-secure job. + - source_labels: [__meta_kubernetes_pod_annotation_prometheus_io_scrape] + action: keep + regex: true + # Keep target if there's no sidecar or if prometheus.io/scheme is explicitly set to "http" + - source_labels: [__meta_kubernetes_pod_annotation_sidecar_istio_io_status, __meta_kubernetes_pod_annotation_prometheus_io_scheme] + action: keep + regex: ((;.*)|(.*;http)) + - source_labels: [__meta_kubernetes_pod_annotation_istio_mtls] + action: drop + regex: (true) + - source_labels: [__meta_kubernetes_pod_annotation_prometheus_io_path] + action: replace + target_label: __metrics_path__ + regex: (.+) + - source_labels: [__address__, __meta_kubernetes_pod_annotation_prometheus_io_port] + action: replace + regex: ([^:]+)(?::\d+)?;(\d+) + replacement: $1:$2 + target_label: __address__ + - action: labelmap + regex: __meta_kubernetes_pod_label_(.+) + - source_labels: [__meta_kubernetes_namespace] + action: replace + target_label: namespace + - source_labels: [__meta_kubernetes_pod_name] + action: replace + target_label: pod_name + + - job_name: 'kubernetes-pods-istio-secure' + scheme: https + tls_config: + ca_file: /etc/istio-certs/root-cert.pem + cert_file: /etc/istio-certs/cert-chain.pem + key_file: /etc/istio-certs/key.pem + insecure_skip_verify: true # prometheus does not support secure naming. + kubernetes_sd_configs: + - role: pod + relabel_configs: + - source_labels: [__meta_kubernetes_pod_annotation_prometheus_io_scrape] + action: keep + regex: true + # sidecar status annotation is added by sidecar injector and + # istio_workload_mtls_ability can be specifically placed on a pod to indicate its ability to receive mtls traffic. + - source_labels: [__meta_kubernetes_pod_annotation_sidecar_istio_io_status, __meta_kubernetes_pod_annotation_istio_mtls] + action: keep + regex: (([^;]+);([^;]*))|(([^;]*);(true)) + - source_labels: [__meta_kubernetes_pod_annotation_prometheus_io_scheme] + action: drop + regex: (http) + - source_labels: [__meta_kubernetes_pod_annotation_prometheus_io_path] + action: replace + target_label: __metrics_path__ + regex: (.+) + - source_labels: [__address__] # Only keep address that is host:port + action: keep # otherwise an extra target with ':443' is added for https scheme + regex: ([^:]+):(\d+) + - source_labels: [__address__, __meta_kubernetes_pod_annotation_prometheus_io_port] + action: replace + regex: ([^:]+)(?::\d+)?;(\d+) + replacement: $1:$2 + target_label: __address__ + - action: labelmap + regex: __meta_kubernetes_pod_label_(.+) + - source_labels: [__meta_kubernetes_namespace] + action: replace + target_label: namespace + - source_labels: [__meta_kubernetes_pod_name] + action: replace + target_label: pod_name +--- +# Source: istio/charts/security/templates/configmap.yaml +apiVersion: v1 +kind: ConfigMap +metadata: + name: istio-security-custom-resources + namespace: istio-system + labels: + app: security + chart: security + heritage: Tiller + release: istio + istio: citadel +data: + custom-resources.yaml: |- + # These policy and destination rules effectively enable mTLS for all services in the mesh. For now, + # they are added to Istio installation yaml for backward compatible. In future, they should be in + # a separated yaml file so that customer can enable mTLS independent from installation. + + # Authentication policy to enable mutual TLS for all services (that have sidecar) in the mesh. + apiVersion: "authentication.istio.io/v1alpha1" + kind: "MeshPolicy" + metadata: + name: "default" + labels: + app: security + chart: security + heritage: Tiller + release: istio + spec: + peers: + - mtls: {} + --- + # Corresponding destination rule to configure client side to use mutual TLS when talking to + # any service (host) in the mesh. + apiVersion: networking.istio.io/v1alpha3 + kind: DestinationRule + metadata: + name: "default" + namespace: istio-system + labels: + app: security + chart: security + heritage: Tiller + release: istio + spec: + host: "*.local" + trafficPolicy: + tls: + mode: ISTIO_MUTUAL + --- + # Destination rule to disable (m)TLS when talking to API server, as API server doesn't have sidecar. + # Customer should add similar destination rules for other services that don't have sidecar. + apiVersion: networking.istio.io/v1alpha3 + kind: DestinationRule + metadata: + name: "api-server" + namespace: istio-system + labels: + app: security + chart: security + heritage: Tiller + release: istio + spec: + host: "kubernetes.default.svc.cluster.local" + trafficPolicy: + tls: + mode: DISABLE + run.sh: |- + #!/bin/sh + + set -x + + if [ "$#" -ne "1" ]; then + echo "first argument should be path to custom resource yaml" + exit 1 + fi + + pathToResourceYAML=${1} + + kubectl get validatingwebhookconfiguration istio-galley 2>/dev/null + if [ "$?" -eq 0 ]; then + echo "istio-galley validatingwebhookconfiguration found - waiting for istio-galley deployment to be ready" + while true; do + kubectl -n istio-system get deployment istio-galley 2>/dev/null + if [ "$?" -eq 0 ]; then + break + fi + sleep 1 + done + kubectl -n istio-system rollout status deployment istio-galley + if [ "$?" -ne 0 ]; then + echo "istio-galley deployment rollout status check failed" + exit 1 + fi + echo "istio-galley deployment ready for configuration validation" + fi + sleep 5 + kubectl apply -f ${pathToResourceYAML} + + +--- +# Source: istio/templates/configmap.yaml + +apiVersion: v1 +kind: ConfigMap +metadata: + name: istio + namespace: istio-system + labels: + app: istio + chart: istio + heritage: Tiller + release: istio +data: + mesh: |- + # Set the following variable to true to disable policy checks by the Mixer. + # Note that metrics will still be reported to the Mixer. + disablePolicyChecks: false + # reportBatchMaxEntries is the number of requests that are batched before telemetry data is sent to the mixer server + reportBatchMaxEntries: 100 + # reportBatchMaxTime is the max waiting time before the telemetry data of a request is sent to the mixer server + reportBatchMaxTime: 1s + + # Set enableTracing to false to disable request tracing. + enableTracing: true + + # Set accessLogFile to empty string to disable access log. + accessLogFile: "/dev/stdout" + + # If accessLogEncoding is TEXT, value will be used directly as the log format + # example: "[%START_TIME%] %REQ(:METHOD)% %REQ(X-ENVOY-ORIGINAL-PATH?:PATH)% %PROTOCOL%\n" + # If AccessLogEncoding is JSON, value will be parsed as map[string]string + # example: '{"start_time": "%START_TIME%", "req_method": "%REQ(:METHOD)%"}' + # Leave empty to use default log format + accessLogFormat: "" + + # Set accessLogEncoding to JSON or TEXT to configure sidecar access log + accessLogEncoding: 'TEXT' + + enableEnvoyAccessLogService: false + mixerCheckServer: istio-policy.istio-system.svc.cluster.local:15004 + mixerReportServer: istio-telemetry.istio-system.svc.cluster.local:15004 + # policyCheckFailOpen allows traffic in cases when the mixer policy service cannot be reached. + # Default is false which means the traffic is denied when the client is unable to connect to Mixer. + policyCheckFailOpen: false + # Let Pilot give ingresses the public IP of the Istio ingressgateway + ingressService: istio-ingressgateway + + # Default connect timeout for dynamic clusters generated by Pilot and returned via XDS + connectTimeout: 10s + + # Automatic protocol detection uses a set of heuristics to + # determine whether the connection is using TLS or not (on the + # server side), as well as the application protocol being used + # (e.g., http vs tcp). These heuristics rely on the client sending + # the first bits of data. For server first protocols like MySQL, + # MongoDB, etc., Envoy will timeout on the protocol detection after + # the specified period, defaulting to non mTLS plain TCP + # traffic. Set this field to tweak the period that Envoy will wait + # for the client to send the first bits of data. (MUST BE >=1ms) + protocolDetectionTimeout: 100ms + + # DNS refresh rate for Envoy clusters of type STRICT_DNS + dnsRefreshRate: 300s + + # Unix Domain Socket through which envoy communicates with NodeAgent SDS to get + # key/cert for mTLS. Use secret-mount files instead of SDS if set to empty. + sdsUdsPath: "" + + # The trust domain corresponds to the trust root of a system. + # Refer to https://github.com/spiffe/spiffe/blob/master/standards/SPIFFE-ID.md#21-trust-domain + trustDomain: "" + + # Set the default behavior of the sidecar for handling outbound traffic from the application: + # ALLOW_ANY - outbound traffic to unknown destinations will be allowed, in case there are no + # services or ServiceEntries for the destination port + # REGISTRY_ONLY - restrict outbound traffic to services defined in the service registry as well + # as those defined through ServiceEntries + outboundTrafficPolicy: + mode: ALLOW_ANY + localityLbSetting: + enabled: true + # The namespace to treat as the administrative root namespace for istio + # configuration. + rootNamespace: istio-system + configSources: + - address: istio-galley.istio-system.svc:9901 + tlsSettings: + mode: ISTIO_MUTUAL + + defaultConfig: + # + # TCP connection timeout between Envoy & the application, and between Envoys. Used for static clusters + # defined in Envoy's configuration file + connectTimeout: 10s + # + ### ADVANCED SETTINGS ############# + # Where should envoy's configuration be stored in the istio-proxy container + configPath: "/etc/istio/proxy" + binaryPath: "/usr/local/bin/envoy" + # The pseudo service name used for Envoy. + serviceCluster: istio-proxy + # These settings that determine how long an old Envoy + # process should be kept alive after an occasional reload. + drainDuration: 45s + parentShutdownDuration: 1m0s + # + # The mode used to redirect inbound connections to Envoy. This setting + # has no effect on outbound traffic: iptables REDIRECT is always used for + # outbound connections. + # If "REDIRECT", use iptables REDIRECT to NAT and redirect to Envoy. + # The "REDIRECT" mode loses source addresses during redirection. + # If "TPROXY", use iptables TPROXY to redirect to Envoy. + # The "TPROXY" mode preserves both the source and destination IP + # addresses and ports, so that they can be used for advanced filtering + # and manipulation. + # The "TPROXY" mode also configures the sidecar to run with the + # CAP_NET_ADMIN capability, which is required to use TPROXY. + #interceptionMode: REDIRECT + # + # Port where Envoy listens (on local host) for admin commands + # You can exec into the istio-proxy container in a pod and + # curl the admin port (curl http://localhost:15000/) to obtain + # diagnostic information from Envoy. See + # https://lyft.github.io/envoy/docs/operations/admin.html + # for more details + proxyAdminPort: 15000 + # + # Set concurrency to a specific number to control the number of Proxy worker threads. + # If set to 0 (default), then start worker thread for each CPU thread/core. + concurrency: 2 + # + tracing: + zipkin: + # Address of the Zipkin collector + address: zipkin.istio-system:9411 + # + # Mutual TLS authentication between sidecars and istio control plane. + controlPlaneAuthPolicy: MUTUAL_TLS + # + # Address where istio Pilot service is running + discoveryAddress: istio-pilot.istio-system:15011 + + # Configuration file for the mesh networks to be used by the Split Horizon EDS. + meshNetworks: |- + networks: {} + +--- +# Source: istio/templates/sidecar-injector-configmap.yaml + +apiVersion: v1 +kind: ConfigMap +metadata: + name: istio-sidecar-injector + namespace: istio-system + labels: + app: istio + chart: istio + heritage: Tiller + release: istio + istio: sidecar-injector +data: + values: |- + {"certmanager":{"enabled":false},"galley":{"enabled":true,"global":{"arch":{"amd64":2,"ppc64le":2,"s390x":2},"configValidation":true,"controlPlaneSecurityEnabled":true,"defaultNodeSelector":{},"defaultPodDisruptionBudget":{"enabled":true},"defaultResources":{"requests":{"cpu":"10m"}},"defaultTolerations":[],"disablePolicyChecks":false,"enableHelmTest":false,"enableTracing":true,"hub":"docker.io/istio","imagePullPolicy":"IfNotPresent","imagePullSecrets":[],"k8sIngress":{"enableHttps":false,"enabled":false,"gatewayName":"ingressgateway"},"localityLbSetting":{"enabled":true},"logging":{"level":"default:info"},"meshExpansion":{"enabled":false,"useILB":false},"meshID":"","meshNetworks":{},"monitoringPort":15014,"mtls":{"enabled":true},"multiCluster":{"clusterName":"","enabled":false},"oneNamespace":false,"outboundTrafficPolicy":{"mode":"ALLOW_ANY"},"policyCheckFailOpen":false,"priorityClassName":"","proxy":{"accessLogEncoding":"TEXT","accessLogFile":"/dev/stdout","accessLogFormat":"","autoInject":"enabled","clusterDomain":"cluster.local","componentLogLevel":"","concurrency":2,"dnsRefreshRate":"300s","enableCoreDump":false,"enableCoreDumpImage":"ubuntu:xenial","envoyAccessLogService":{"enabled":false,"host":null,"port":null,"tcpKeepalive":{"interval":"10s","probes":3,"time":"10s"},"tlsSettings":{"caCertificates":null,"clientCertificate":null,"mode":"DISABLE","privateKey":null,"sni":null,"subjectAltNames":[]}},"envoyMetricsService":{"enabled":false,"host":null,"port":null},"envoyStatsd":{"enabled":false,"host":null,"port":null},"excludeIPRanges":"","excludeInboundPorts":"","excludeOutboundPorts":"","image":"proxyv2","includeIPRanges":"*","includeInboundPorts":"*","init":{"resources":{"limits":{"cpu":"100m","memory":"50Mi"},"requests":{"cpu":"10m","memory":"10Mi"}}},"kubevirtInterfaces":"","logLevel":"","privileged":false,"protocolDetectionTimeout":"100ms","readinessFailureThreshold":30,"readinessInitialDelaySeconds":1,"readinessPeriodSeconds":2,"resources":{"limits":{"cpu":"2000m","memory":"1024Mi"},"requests":{"cpu":"10m","memory":"40Mi"}},"statusPort":15020,"tracer":"zipkin"},"proxy_init":{"image":"proxy_init"},"sds":{"enabled":false,"token":{"aud":"istio-ca"},"udsPath":""},"tag":"1.3.5","tracer":{"datadog":{"address":"$(HOST_IP):8126"},"lightstep":{"accessToken":"","address":"","cacertPath":"","secure":true},"zipkin":{"address":""}},"trustDomain":"","useMCP":true},"image":"galley","nodeSelector":{},"podAntiAffinityLabelSelector":[],"podAntiAffinityTermLabelSelector":[],"replicaCount":1,"rollingMaxSurge":"100%","rollingMaxUnavailable":"25%","tolerations":[]},"gateways":{"enabled":true,"global":{"arch":{"amd64":2,"ppc64le":2,"s390x":2},"configValidation":true,"controlPlaneSecurityEnabled":true,"defaultNodeSelector":{},"defaultPodDisruptionBudget":{"enabled":true},"defaultResources":{"requests":{"cpu":"10m"}},"defaultTolerations":[],"disablePolicyChecks":false,"enableHelmTest":false,"enableTracing":true,"hub":"docker.io/istio","imagePullPolicy":"IfNotPresent","imagePullSecrets":[],"k8sIngress":{"enableHttps":false,"enabled":false,"gatewayName":"ingressgateway"},"localityLbSetting":{"enabled":true},"logging":{"level":"default:info"},"meshExpansion":{"enabled":false,"useILB":false},"meshID":"","meshNetworks":{},"monitoringPort":15014,"mtls":{"enabled":true},"multiCluster":{"clusterName":"","enabled":false},"oneNamespace":false,"outboundTrafficPolicy":{"mode":"ALLOW_ANY"},"policyCheckFailOpen":false,"priorityClassName":"","proxy":{"accessLogEncoding":"TEXT","accessLogFile":"/dev/stdout","accessLogFormat":"","autoInject":"enabled","clusterDomain":"cluster.local","componentLogLevel":"","concurrency":2,"dnsRefreshRate":"300s","enableCoreDump":false,"enableCoreDumpImage":"ubuntu:xenial","envoyAccessLogService":{"enabled":false,"host":null,"port":null,"tcpKeepalive":{"interval":"10s","probes":3,"time":"10s"},"tlsSettings":{"caCertificates":null,"clientCertificate":null,"mode":"DISABLE","privateKey":null,"sni":null,"subjectAltNames":[]}},"envoyMetricsService":{"enabled":false,"host":null,"port":null},"envoyStatsd":{"enabled":false,"host":null,"port":null},"excludeIPRanges":"","excludeInboundPorts":"","excludeOutboundPorts":"","image":"proxyv2","includeIPRanges":"*","includeInboundPorts":"*","init":{"resources":{"limits":{"cpu":"100m","memory":"50Mi"},"requests":{"cpu":"10m","memory":"10Mi"}}},"kubevirtInterfaces":"","logLevel":"","privileged":false,"protocolDetectionTimeout":"100ms","readinessFailureThreshold":30,"readinessInitialDelaySeconds":1,"readinessPeriodSeconds":2,"resources":{"limits":{"cpu":"2000m","memory":"1024Mi"},"requests":{"cpu":"10m","memory":"40Mi"}},"statusPort":15020,"tracer":"zipkin"},"proxy_init":{"image":"proxy_init"},"sds":{"enabled":false,"token":{"aud":"istio-ca"},"udsPath":""},"tag":"1.3.5","tracer":{"datadog":{"address":"$(HOST_IP):8126"},"lightstep":{"accessToken":"","address":"","cacertPath":"","secure":true},"zipkin":{"address":""}},"trustDomain":"","useMCP":true},"istio-egressgateway":{"autoscaleEnabled":false,"autoscaleMax":5,"autoscaleMin":1,"cpu":{"targetAverageUtilization":80},"enabled":true,"env":{"ISTIO_META_ROUTER_MODE":"sni-dnat"},"labels":{"app":"istio-egressgateway","istio":"egressgateway"},"nodeSelector":{},"podAnnotations":{},"podAntiAffinityLabelSelector":[],"podAntiAffinityTermLabelSelector":[],"ports":[{"name":"http2","port":80},{"name":"https","port":443},{"name":"tls","port":15443,"targetPort":15443}],"resources":{"limits":{"cpu":"2000m","memory":"1024Mi"},"requests":{"cpu":"10m","memory":"40Mi"}},"rollingMaxSurge":"100%","rollingMaxUnavailable":"25%","secretVolumes":[{"mountPath":"/etc/istio/egressgateway-certs","name":"egressgateway-certs","secretName":"istio-egressgateway-certs"},{"mountPath":"/etc/istio/egressgateway-ca-certs","name":"egressgateway-ca-certs","secretName":"istio-egressgateway-ca-certs"}],"serviceAnnotations":{},"tolerations":[],"type":"ClusterIP"},"istio-ilbgateway":{"autoscaleEnabled":true,"autoscaleMax":5,"autoscaleMin":1,"cpu":{"targetAverageUtilization":80},"enabled":false,"labels":{"app":"istio-ilbgateway","istio":"ilbgateway"},"loadBalancerIP":"","nodeSelector":{},"podAnnotations":{},"ports":[{"name":"grpc-pilot-mtls","port":15011},{"name":"grpc-pilot","port":15010},{"name":"tcp-citadel-grpc-tls","port":8060,"targetPort":8060},{"name":"tcp-dns","port":5353}],"resources":{"requests":{"cpu":"800m","memory":"512Mi"}},"rollingMaxSurge":"100%","rollingMaxUnavailable":"25%","secretVolumes":[{"mountPath":"/etc/istio/ilbgateway-certs","name":"ilbgateway-certs","secretName":"istio-ilbgateway-certs"},{"mountPath":"/etc/istio/ilbgateway-ca-certs","name":"ilbgateway-ca-certs","secretName":"istio-ilbgateway-ca-certs"}],"serviceAnnotations":{"cloud.google.com/load-balancer-type":"internal"},"tolerations":[],"type":"LoadBalancer"},"istio-ingressgateway":{"applicationPorts":"","autoscaleEnabled":false,"autoscaleMax":5,"autoscaleMin":1,"cpu":{"targetAverageUtilization":80},"enabled":true,"env":{"ISTIO_META_ROUTER_MODE":"sni-dnat"},"externalIPs":[],"labels":{"app":"istio-ingressgateway","istio":"ingressgateway"},"loadBalancerIP":"","loadBalancerSourceRanges":[],"meshExpansionPorts":[{"name":"tcp-pilot-grpc-tls","port":15011,"targetPort":15011},{"name":"tcp-mixer-grpc-tls","port":15004,"targetPort":15004},{"name":"tcp-citadel-grpc-tls","port":8060,"targetPort":8060},{"name":"tcp-dns-tls","port":853,"targetPort":853}],"nodeSelector":{},"podAnnotations":{},"podAntiAffinityLabelSelector":[],"podAntiAffinityTermLabelSelector":[],"ports":[{"name":"status-port","port":15020,"targetPort":15020},{"name":"http2","nodePort":31380,"port":80,"targetPort":80},{"name":"https","nodePort":31390,"port":443},{"name":"tcp","nodePort":31400,"port":31400},{"name":"https-kiali","port":15029,"targetPort":15029},{"name":"https-prometheus","port":15030,"targetPort":15030},{"name":"https-grafana","port":15031,"targetPort":15031},{"name":"https-tracing","port":15032,"targetPort":15032},{"name":"tls","port":15443,"targetPort":15443}],"resources":{"limits":{"cpu":"2000m","memory":"1024Mi"},"requests":{"cpu":"10m","memory":"40Mi"}},"rollingMaxSurge":"100%","rollingMaxUnavailable":"25%","sds":{"enabled":false,"image":"node-agent-k8s","resources":{"limits":{"cpu":"2000m","memory":"1024Mi"},"requests":{"cpu":"100m","memory":"128Mi"}}},"secretVolumes":[{"mountPath":"/etc/istio/ingressgateway-certs","name":"ingressgateway-certs","secretName":"istio-ingressgateway-certs"},{"mountPath":"/etc/istio/ingressgateway-ca-certs","name":"ingressgateway-ca-certs","secretName":"istio-ingressgateway-ca-certs"}],"serviceAnnotations":{},"tolerations":[],"type":"LoadBalancer"}},"global":{"arch":{"amd64":2,"ppc64le":2,"s390x":2},"configValidation":true,"controlPlaneSecurityEnabled":true,"defaultNodeSelector":{},"defaultPodDisruptionBudget":{"enabled":true},"defaultResources":{"requests":{"cpu":"10m"}},"defaultTolerations":[],"disablePolicyChecks":false,"enableHelmTest":false,"enableTracing":true,"hub":"docker.io/istio","imagePullPolicy":"IfNotPresent","imagePullSecrets":[],"k8sIngress":{"enableHttps":false,"enabled":false,"gatewayName":"ingressgateway"},"localityLbSetting":{"enabled":true},"logging":{"level":"default:info"},"meshExpansion":{"enabled":false,"useILB":false},"meshID":"","meshNetworks":{},"monitoringPort":15014,"mtls":{"enabled":true},"multiCluster":{"clusterName":"","enabled":false},"oneNamespace":false,"outboundTrafficPolicy":{"mode":"ALLOW_ANY"},"policyCheckFailOpen":false,"priorityClassName":"","proxy":{"accessLogEncoding":"TEXT","accessLogFile":"/dev/stdout","accessLogFormat":"","autoInject":"enabled","clusterDomain":"cluster.local","componentLogLevel":"","concurrency":2,"dnsRefreshRate":"300s","enableCoreDump":false,"enableCoreDumpImage":"ubuntu:xenial","envoyAccessLogService":{"enabled":false,"host":null,"port":null,"tcpKeepalive":{"interval":"10s","probes":3,"time":"10s"},"tlsSettings":{"caCertificates":null,"clientCertificate":null,"mode":"DISABLE","privateKey":null,"sni":null,"subjectAltNames":[]}},"envoyMetricsService":{"enabled":false,"host":null,"port":null},"envoyStatsd":{"enabled":false,"host":null,"port":null},"excludeIPRanges":"","excludeInboundPorts":"","excludeOutboundPorts":"","image":"proxyv2","includeIPRanges":"*","includeInboundPorts":"*","init":{"resources":{"limits":{"cpu":"100m","memory":"50Mi"},"requests":{"cpu":"10m","memory":"10Mi"}}},"kubevirtInterfaces":"","logLevel":"","privileged":false,"protocolDetectionTimeout":"100ms","readinessFailureThreshold":30,"readinessInitialDelaySeconds":1,"readinessPeriodSeconds":2,"resources":{"limits":{"cpu":"2000m","memory":"1024Mi"},"requests":{"cpu":"10m","memory":"40Mi"}},"statusPort":15020,"tracer":"zipkin"},"proxy_init":{"image":"proxy_init"},"sds":{"enabled":false,"token":{"aud":"istio-ca"},"udsPath":""},"tag":"1.3.5","tracer":{"datadog":{"address":"$(HOST_IP):8126"},"lightstep":{"accessToken":"","address":"","cacertPath":"","secure":true},"zipkin":{"address":""}},"trustDomain":"","useMCP":true},"grafana":{"accessMode":"ReadWriteMany","contextPath":"/grafana","dashboardProviders":{"dashboardproviders.yaml":{"apiVersion":1,"providers":[{"disableDeletion":false,"folder":"istio","name":"istio","options":{"path":"/var/lib/grafana/dashboards/istio"},"orgId":1,"type":"file"}]}},"datasources":{"datasources.yaml":{"apiVersion":1,"datasources":[{"access":"proxy","editable":true,"isDefault":true,"jsonData":{"timeInterval":"5s"},"name":"Prometheus","orgId":1,"type":"prometheus","url":"http://prometheus:9090"}]}},"enabled":true,"env":{},"envSecrets":{},"global":{"arch":{"amd64":2,"ppc64le":2,"s390x":2},"configValidation":true,"controlPlaneSecurityEnabled":true,"defaultNodeSelector":{},"defaultPodDisruptionBudget":{"enabled":true},"defaultResources":{"requests":{"cpu":"10m"}},"defaultTolerations":[],"disablePolicyChecks":false,"enableHelmTest":false,"enableTracing":true,"hub":"docker.io/istio","imagePullPolicy":"IfNotPresent","imagePullSecrets":[],"k8sIngress":{"enableHttps":false,"enabled":false,"gatewayName":"ingressgateway"},"localityLbSetting":{"enabled":true},"logging":{"level":"default:info"},"meshExpansion":{"enabled":false,"useILB":false},"meshID":"","meshNetworks":{},"monitoringPort":15014,"mtls":{"enabled":true},"multiCluster":{"clusterName":"","enabled":false},"oneNamespace":false,"outboundTrafficPolicy":{"mode":"ALLOW_ANY"},"policyCheckFailOpen":false,"priorityClassName":"","proxy":{"accessLogEncoding":"TEXT","accessLogFile":"/dev/stdout","accessLogFormat":"","autoInject":"enabled","clusterDomain":"cluster.local","componentLogLevel":"","concurrency":2,"dnsRefreshRate":"300s","enableCoreDump":false,"enableCoreDumpImage":"ubuntu:xenial","envoyAccessLogService":{"enabled":false,"host":null,"port":null,"tcpKeepalive":{"interval":"10s","probes":3,"time":"10s"},"tlsSettings":{"caCertificates":null,"clientCertificate":null,"mode":"DISABLE","privateKey":null,"sni":null,"subjectAltNames":[]}},"envoyMetricsService":{"enabled":false,"host":null,"port":null},"envoyStatsd":{"enabled":false,"host":null,"port":null},"excludeIPRanges":"","excludeInboundPorts":"","excludeOutboundPorts":"","image":"proxyv2","includeIPRanges":"*","includeInboundPorts":"*","init":{"resources":{"limits":{"cpu":"100m","memory":"50Mi"},"requests":{"cpu":"10m","memory":"10Mi"}}},"kubevirtInterfaces":"","logLevel":"","privileged":false,"protocolDetectionTimeout":"100ms","readinessFailureThreshold":30,"readinessInitialDelaySeconds":1,"readinessPeriodSeconds":2,"resources":{"limits":{"cpu":"2000m","memory":"1024Mi"},"requests":{"cpu":"10m","memory":"40Mi"}},"statusPort":15020,"tracer":"zipkin"},"proxy_init":{"image":"proxy_init"},"sds":{"enabled":false,"token":{"aud":"istio-ca"},"udsPath":""},"tag":"1.3.5","tracer":{"datadog":{"address":"$(HOST_IP):8126"},"lightstep":{"accessToken":"","address":"","cacertPath":"","secure":true},"zipkin":{"address":""}},"trustDomain":"","useMCP":true},"image":{"repository":"grafana/grafana","tag":"6.1.6"},"ingress":{"annotations":null,"enabled":false,"hosts":["grafana.local"],"tls":null},"nodeSelector":{},"persist":false,"podAntiAffinityLabelSelector":[],"podAntiAffinityTermLabelSelector":[],"replicaCount":1,"security":{"enabled":false,"passphraseKey":"passphrase","secretName":"grafana","usernameKey":"username"},"service":{"annotations":{},"externalPort":3000,"loadBalancerIP":null,"loadBalancerSourceRanges":null,"name":"http","type":"ClusterIP"},"storageClassName":"","tolerations":[]},"istio_cni":{"enabled":false},"istiocoredns":{"enabled":false},"kiali":{"contextPath":"/kiali","createDemoSecret":true,"dashboard":{"auth":{"strategy":"login"},"grafanaURL":null,"jaegerURL":null,"secretName":"kiali","viewOnlyMode":false},"enabled":true,"global":{"arch":{"amd64":2,"ppc64le":2,"s390x":2},"configValidation":true,"controlPlaneSecurityEnabled":true,"defaultNodeSelector":{},"defaultPodDisruptionBudget":{"enabled":true},"defaultResources":{"requests":{"cpu":"10m"}},"defaultTolerations":[],"disablePolicyChecks":false,"enableHelmTest":false,"enableTracing":true,"hub":"docker.io/istio","imagePullPolicy":"IfNotPresent","imagePullSecrets":[],"k8sIngress":{"enableHttps":false,"enabled":false,"gatewayName":"ingressgateway"},"localityLbSetting":{"enabled":true},"logging":{"level":"default:info"},"meshExpansion":{"enabled":false,"useILB":false},"meshID":"","meshNetworks":{},"monitoringPort":15014,"mtls":{"enabled":true},"multiCluster":{"clusterName":"","enabled":false},"oneNamespace":false,"outboundTrafficPolicy":{"mode":"ALLOW_ANY"},"policyCheckFailOpen":false,"priorityClassName":"","proxy":{"accessLogEncoding":"TEXT","accessLogFile":"/dev/stdout","accessLogFormat":"","autoInject":"enabled","clusterDomain":"cluster.local","componentLogLevel":"","concurrency":2,"dnsRefreshRate":"300s","enableCoreDump":false,"enableCoreDumpImage":"ubuntu:xenial","envoyAccessLogService":{"enabled":false,"host":null,"port":null,"tcpKeepalive":{"interval":"10s","probes":3,"time":"10s"},"tlsSettings":{"caCertificates":null,"clientCertificate":null,"mode":"DISABLE","privateKey":null,"sni":null,"subjectAltNames":[]}},"envoyMetricsService":{"enabled":false,"host":null,"port":null},"envoyStatsd":{"enabled":false,"host":null,"port":null},"excludeIPRanges":"","excludeInboundPorts":"","excludeOutboundPorts":"","image":"proxyv2","includeIPRanges":"*","includeInboundPorts":"*","init":{"resources":{"limits":{"cpu":"100m","memory":"50Mi"},"requests":{"cpu":"10m","memory":"10Mi"}}},"kubevirtInterfaces":"","logLevel":"","privileged":false,"protocolDetectionTimeout":"100ms","readinessFailureThreshold":30,"readinessInitialDelaySeconds":1,"readinessPeriodSeconds":2,"resources":{"limits":{"cpu":"2000m","memory":"1024Mi"},"requests":{"cpu":"10m","memory":"40Mi"}},"statusPort":15020,"tracer":"zipkin"},"proxy_init":{"image":"proxy_init"},"sds":{"enabled":false,"token":{"aud":"istio-ca"},"udsPath":""},"tag":"1.3.5","tracer":{"datadog":{"address":"$(HOST_IP):8126"},"lightstep":{"accessToken":"","address":"","cacertPath":"","secure":true},"zipkin":{"address":""}},"trustDomain":"","useMCP":true},"hub":"quay.io/kiali","image":"kiali","ingress":{"annotations":null,"enabled":false,"hosts":["kiali.local"],"tls":null},"nodeSelector":{},"podAntiAffinityLabelSelector":[],"podAntiAffinityTermLabelSelector":[],"prometheusAddr":"http://prometheus:9090","replicaCount":1,"security":{"cert_file":"/kiali-cert/cert-chain.pem","enabled":false,"private_key_file":"/kiali-cert/key.pem"},"tag":"v1.4","tolerations":[]},"mixer":{"adapters":{"kubernetesenv":{"enabled":true},"prometheus":{"enabled":true,"metricsExpiryDuration":"10m"},"stdio":{"enabled":true,"outputAsJson":true},"useAdapterCRDs":false},"env":{"GODEBUG":"gctrace=1","GOMAXPROCS":"6"},"global":{"arch":{"amd64":2,"ppc64le":2,"s390x":2},"configValidation":true,"controlPlaneSecurityEnabled":true,"defaultNodeSelector":{},"defaultPodDisruptionBudget":{"enabled":true},"defaultResources":{"requests":{"cpu":"10m"}},"defaultTolerations":[],"disablePolicyChecks":false,"enableHelmTest":false,"enableTracing":true,"hub":"docker.io/istio","imagePullPolicy":"IfNotPresent","imagePullSecrets":[],"k8sIngress":{"enableHttps":false,"enabled":false,"gatewayName":"ingressgateway"},"localityLbSetting":{"enabled":true},"logging":{"level":"default:info"},"meshExpansion":{"enabled":false,"useILB":false},"meshID":"","meshNetworks":{},"monitoringPort":15014,"mtls":{"enabled":true},"multiCluster":{"clusterName":"","enabled":false},"oneNamespace":false,"outboundTrafficPolicy":{"mode":"ALLOW_ANY"},"policyCheckFailOpen":false,"priorityClassName":"","proxy":{"accessLogEncoding":"TEXT","accessLogFile":"/dev/stdout","accessLogFormat":"","autoInject":"enabled","clusterDomain":"cluster.local","componentLogLevel":"","concurrency":2,"dnsRefreshRate":"300s","enableCoreDump":false,"enableCoreDumpImage":"ubuntu:xenial","envoyAccessLogService":{"enabled":false,"host":null,"port":null,"tcpKeepalive":{"interval":"10s","probes":3,"time":"10s"},"tlsSettings":{"caCertificates":null,"clientCertificate":null,"mode":"DISABLE","privateKey":null,"sni":null,"subjectAltNames":[]}},"envoyMetricsService":{"enabled":false,"host":null,"port":null},"envoyStatsd":{"enabled":false,"host":null,"port":null},"excludeIPRanges":"","excludeInboundPorts":"","excludeOutboundPorts":"","image":"proxyv2","includeIPRanges":"*","includeInboundPorts":"*","init":{"resources":{"limits":{"cpu":"100m","memory":"50Mi"},"requests":{"cpu":"10m","memory":"10Mi"}}},"kubevirtInterfaces":"","logLevel":"","privileged":false,"protocolDetectionTimeout":"100ms","readinessFailureThreshold":30,"readinessInitialDelaySeconds":1,"readinessPeriodSeconds":2,"resources":{"limits":{"cpu":"2000m","memory":"1024Mi"},"requests":{"cpu":"10m","memory":"40Mi"}},"statusPort":15020,"tracer":"zipkin"},"proxy_init":{"image":"proxy_init"},"sds":{"enabled":false,"token":{"aud":"istio-ca"},"udsPath":""},"tag":"1.3.5","tracer":{"datadog":{"address":"$(HOST_IP):8126"},"lightstep":{"accessToken":"","address":"","cacertPath":"","secure":true},"zipkin":{"address":""}},"trustDomain":"","useMCP":true},"image":"mixer","nodeSelector":{},"podAnnotations":{},"podAntiAffinityLabelSelector":[],"podAntiAffinityTermLabelSelector":[],"policy":{"autoscaleEnabled":false,"autoscaleMax":5,"autoscaleMin":1,"cpu":{"targetAverageUtilization":80},"enabled":true,"replicaCount":1,"resources":{"requests":{"cpu":"10m","memory":"100Mi"}},"rollingMaxSurge":"100%","rollingMaxUnavailable":"25%"},"telemetry":{"autoscaleEnabled":false,"autoscaleMax":5,"autoscaleMin":1,"cpu":{"targetAverageUtilization":80},"enabled":true,"loadshedding":{"latencyThreshold":"100ms","mode":"enforce"},"replicaCount":1,"reportBatchMaxEntries":100,"reportBatchMaxTime":"1s","resources":{"limits":{"cpu":"4800m","memory":"4G"},"requests":{"cpu":"50m","memory":"100Mi"}},"rollingMaxSurge":"100%","rollingMaxUnavailable":"25%","sessionAffinityEnabled":false},"tolerations":[]},"nodeagent":{"enabled":false},"pilot":{"autoscaleEnabled":false,"autoscaleMax":5,"autoscaleMin":1,"cpu":{"targetAverageUtilization":80},"enableProtocolSniffingForInbound":false,"enableProtocolSniffingForOutbound":true,"enabled":true,"env":{"GODEBUG":"gctrace=1","PILOT_PUSH_THROTTLE":100},"global":{"arch":{"amd64":2,"ppc64le":2,"s390x":2},"configValidation":true,"controlPlaneSecurityEnabled":true,"defaultNodeSelector":{},"defaultPodDisruptionBudget":{"enabled":true},"defaultResources":{"requests":{"cpu":"10m"}},"defaultTolerations":[],"disablePolicyChecks":false,"enableHelmTest":false,"enableTracing":true,"hub":"docker.io/istio","imagePullPolicy":"IfNotPresent","imagePullSecrets":[],"k8sIngress":{"enableHttps":false,"enabled":false,"gatewayName":"ingressgateway"},"localityLbSetting":{"enabled":true},"logging":{"level":"default:info"},"meshExpansion":{"enabled":false,"useILB":false},"meshID":"","meshNetworks":{},"monitoringPort":15014,"mtls":{"enabled":true},"multiCluster":{"clusterName":"","enabled":false},"oneNamespace":false,"outboundTrafficPolicy":{"mode":"ALLOW_ANY"},"policyCheckFailOpen":false,"priorityClassName":"","proxy":{"accessLogEncoding":"TEXT","accessLogFile":"/dev/stdout","accessLogFormat":"","autoInject":"enabled","clusterDomain":"cluster.local","componentLogLevel":"","concurrency":2,"dnsRefreshRate":"300s","enableCoreDump":false,"enableCoreDumpImage":"ubuntu:xenial","envoyAccessLogService":{"enabled":false,"host":null,"port":null,"tcpKeepalive":{"interval":"10s","probes":3,"time":"10s"},"tlsSettings":{"caCertificates":null,"clientCertificate":null,"mode":"DISABLE","privateKey":null,"sni":null,"subjectAltNames":[]}},"envoyMetricsService":{"enabled":false,"host":null,"port":null},"envoyStatsd":{"enabled":false,"host":null,"port":null},"excludeIPRanges":"","excludeInboundPorts":"","excludeOutboundPorts":"","image":"proxyv2","includeIPRanges":"*","includeInboundPorts":"*","init":{"resources":{"limits":{"cpu":"100m","memory":"50Mi"},"requests":{"cpu":"10m","memory":"10Mi"}}},"kubevirtInterfaces":"","logLevel":"","privileged":false,"protocolDetectionTimeout":"100ms","readinessFailureThreshold":30,"readinessInitialDelaySeconds":1,"readinessPeriodSeconds":2,"resources":{"limits":{"cpu":"2000m","memory":"1024Mi"},"requests":{"cpu":"10m","memory":"40Mi"}},"statusPort":15020,"tracer":"zipkin"},"proxy_init":{"image":"proxy_init"},"sds":{"enabled":false,"token":{"aud":"istio-ca"},"udsPath":""},"tag":"1.3.5","tracer":{"datadog":{"address":"$(HOST_IP):8126"},"lightstep":{"accessToken":"","address":"","cacertPath":"","secure":true},"zipkin":{"address":""}},"trustDomain":"","useMCP":true},"image":"pilot","keepaliveMaxServerConnectionAge":"30m","nodeSelector":{},"podAntiAffinityLabelSelector":[],"podAntiAffinityTermLabelSelector":[],"resources":{"requests":{"cpu":"10m","memory":"100Mi"}},"rollingMaxSurge":"100%","rollingMaxUnavailable":"25%","sidecar":true,"tolerations":[],"traceSampling":100},"prometheus":{"contextPath":"/prometheus","enabled":true,"global":{"arch":{"amd64":2,"ppc64le":2,"s390x":2},"configValidation":true,"controlPlaneSecurityEnabled":true,"defaultNodeSelector":{},"defaultPodDisruptionBudget":{"enabled":true},"defaultResources":{"requests":{"cpu":"10m"}},"defaultTolerations":[],"disablePolicyChecks":false,"enableHelmTest":false,"enableTracing":true,"hub":"docker.io/istio","imagePullPolicy":"IfNotPresent","imagePullSecrets":[],"k8sIngress":{"enableHttps":false,"enabled":false,"gatewayName":"ingressgateway"},"localityLbSetting":{"enabled":true},"logging":{"level":"default:info"},"meshExpansion":{"enabled":false,"useILB":false},"meshID":"","meshNetworks":{},"monitoringPort":15014,"mtls":{"enabled":true},"multiCluster":{"clusterName":"","enabled":false},"oneNamespace":false,"outboundTrafficPolicy":{"mode":"ALLOW_ANY"},"policyCheckFailOpen":false,"priorityClassName":"","proxy":{"accessLogEncoding":"TEXT","accessLogFile":"/dev/stdout","accessLogFormat":"","autoInject":"enabled","clusterDomain":"cluster.local","componentLogLevel":"","concurrency":2,"dnsRefreshRate":"300s","enableCoreDump":false,"enableCoreDumpImage":"ubuntu:xenial","envoyAccessLogService":{"enabled":false,"host":null,"port":null,"tcpKeepalive":{"interval":"10s","probes":3,"time":"10s"},"tlsSettings":{"caCertificates":null,"clientCertificate":null,"mode":"DISABLE","privateKey":null,"sni":null,"subjectAltNames":[]}},"envoyMetricsService":{"enabled":false,"host":null,"port":null},"envoyStatsd":{"enabled":false,"host":null,"port":null},"excludeIPRanges":"","excludeInboundPorts":"","excludeOutboundPorts":"","image":"proxyv2","includeIPRanges":"*","includeInboundPorts":"*","init":{"resources":{"limits":{"cpu":"100m","memory":"50Mi"},"requests":{"cpu":"10m","memory":"10Mi"}}},"kubevirtInterfaces":"","logLevel":"","privileged":false,"protocolDetectionTimeout":"100ms","readinessFailureThreshold":30,"readinessInitialDelaySeconds":1,"readinessPeriodSeconds":2,"resources":{"limits":{"cpu":"2000m","memory":"1024Mi"},"requests":{"cpu":"10m","memory":"40Mi"}},"statusPort":15020,"tracer":"zipkin"},"proxy_init":{"image":"proxy_init"},"sds":{"enabled":false,"token":{"aud":"istio-ca"},"udsPath":""},"tag":"1.3.5","tracer":{"datadog":{"address":"$(HOST_IP):8126"},"lightstep":{"accessToken":"","address":"","cacertPath":"","secure":true},"zipkin":{"address":""}},"trustDomain":"","useMCP":true},"hub":"docker.io/prom","image":"prometheus","ingress":{"annotations":null,"enabled":false,"hosts":["prometheus.local"],"tls":null},"nodeSelector":{},"podAntiAffinityLabelSelector":[],"podAntiAffinityTermLabelSelector":[],"replicaCount":1,"retention":"6h","scrapeInterval":"15s","security":{"enabled":true},"service":{"annotations":{},"nodePort":{"enabled":false,"port":32090}},"tag":"v2.8.0","tolerations":[]},"security":{"citadelHealthCheck":false,"createMeshPolicy":true,"enableNamespacesByDefault":true,"enabled":true,"env":{},"global":{"arch":{"amd64":2,"ppc64le":2,"s390x":2},"configValidation":true,"controlPlaneSecurityEnabled":true,"defaultNodeSelector":{},"defaultPodDisruptionBudget":{"enabled":true},"defaultResources":{"requests":{"cpu":"10m"}},"defaultTolerations":[],"disablePolicyChecks":false,"enableHelmTest":false,"enableTracing":true,"hub":"docker.io/istio","imagePullPolicy":"IfNotPresent","imagePullSecrets":[],"k8sIngress":{"enableHttps":false,"enabled":false,"gatewayName":"ingressgateway"},"localityLbSetting":{"enabled":true},"logging":{"level":"default:info"},"meshExpansion":{"enabled":false,"useILB":false},"meshID":"","meshNetworks":{},"monitoringPort":15014,"mtls":{"enabled":true},"multiCluster":{"clusterName":"","enabled":false},"oneNamespace":false,"outboundTrafficPolicy":{"mode":"ALLOW_ANY"},"policyCheckFailOpen":false,"priorityClassName":"","proxy":{"accessLogEncoding":"TEXT","accessLogFile":"/dev/stdout","accessLogFormat":"","autoInject":"enabled","clusterDomain":"cluster.local","componentLogLevel":"","concurrency":2,"dnsRefreshRate":"300s","enableCoreDump":false,"enableCoreDumpImage":"ubuntu:xenial","envoyAccessLogService":{"enabled":false,"host":null,"port":null,"tcpKeepalive":{"interval":"10s","probes":3,"time":"10s"},"tlsSettings":{"caCertificates":null,"clientCertificate":null,"mode":"DISABLE","privateKey":null,"sni":null,"subjectAltNames":[]}},"envoyMetricsService":{"enabled":false,"host":null,"port":null},"envoyStatsd":{"enabled":false,"host":null,"port":null},"excludeIPRanges":"","excludeInboundPorts":"","excludeOutboundPorts":"","image":"proxyv2","includeIPRanges":"*","includeInboundPorts":"*","init":{"resources":{"limits":{"cpu":"100m","memory":"50Mi"},"requests":{"cpu":"10m","memory":"10Mi"}}},"kubevirtInterfaces":"","logLevel":"","privileged":false,"protocolDetectionTimeout":"100ms","readinessFailureThreshold":30,"readinessInitialDelaySeconds":1,"readinessPeriodSeconds":2,"resources":{"limits":{"cpu":"2000m","memory":"1024Mi"},"requests":{"cpu":"10m","memory":"40Mi"}},"statusPort":15020,"tracer":"zipkin"},"proxy_init":{"image":"proxy_init"},"sds":{"enabled":false,"token":{"aud":"istio-ca"},"udsPath":""},"tag":"1.3.5","tracer":{"datadog":{"address":"$(HOST_IP):8126"},"lightstep":{"accessToken":"","address":"","cacertPath":"","secure":true},"zipkin":{"address":""}},"trustDomain":"","useMCP":true},"image":"citadel","nodeSelector":{},"podAntiAffinityLabelSelector":[],"podAntiAffinityTermLabelSelector":[],"replicaCount":1,"rollingMaxSurge":"100%","rollingMaxUnavailable":"25%","selfSigned":true,"tolerations":[],"workloadCertTtl":"2160h"},"sidecarInjectorWebhook":{"alwaysInjectSelector":[],"enableNamespacesByDefault":false,"enabled":true,"global":{"arch":{"amd64":2,"ppc64le":2,"s390x":2},"configValidation":true,"controlPlaneSecurityEnabled":true,"defaultNodeSelector":{},"defaultPodDisruptionBudget":{"enabled":true},"defaultResources":{"requests":{"cpu":"10m"}},"defaultTolerations":[],"disablePolicyChecks":false,"enableHelmTest":false,"enableTracing":true,"hub":"docker.io/istio","imagePullPolicy":"IfNotPresent","imagePullSecrets":[],"k8sIngress":{"enableHttps":false,"enabled":false,"gatewayName":"ingressgateway"},"localityLbSetting":{"enabled":true},"logging":{"level":"default:info"},"meshExpansion":{"enabled":false,"useILB":false},"meshID":"","meshNetworks":{},"monitoringPort":15014,"mtls":{"enabled":true},"multiCluster":{"clusterName":"","enabled":false},"oneNamespace":false,"outboundTrafficPolicy":{"mode":"ALLOW_ANY"},"policyCheckFailOpen":false,"priorityClassName":"","proxy":{"accessLogEncoding":"TEXT","accessLogFile":"/dev/stdout","accessLogFormat":"","autoInject":"enabled","clusterDomain":"cluster.local","componentLogLevel":"","concurrency":2,"dnsRefreshRate":"300s","enableCoreDump":false,"enableCoreDumpImage":"ubuntu:xenial","envoyAccessLogService":{"enabled":false,"host":null,"port":null,"tcpKeepalive":{"interval":"10s","probes":3,"time":"10s"},"tlsSettings":{"caCertificates":null,"clientCertificate":null,"mode":"DISABLE","privateKey":null,"sni":null,"subjectAltNames":[]}},"envoyMetricsService":{"enabled":false,"host":null,"port":null},"envoyStatsd":{"enabled":false,"host":null,"port":null},"excludeIPRanges":"","excludeInboundPorts":"","excludeOutboundPorts":"","image":"proxyv2","includeIPRanges":"*","includeInboundPorts":"*","init":{"resources":{"limits":{"cpu":"100m","memory":"50Mi"},"requests":{"cpu":"10m","memory":"10Mi"}}},"kubevirtInterfaces":"","logLevel":"","privileged":false,"protocolDetectionTimeout":"100ms","readinessFailureThreshold":30,"readinessInitialDelaySeconds":1,"readinessPeriodSeconds":2,"resources":{"limits":{"cpu":"2000m","memory":"1024Mi"},"requests":{"cpu":"10m","memory":"40Mi"}},"statusPort":15020,"tracer":"zipkin"},"proxy_init":{"image":"proxy_init"},"sds":{"enabled":false,"token":{"aud":"istio-ca"},"udsPath":""},"tag":"1.3.5","tracer":{"datadog":{"address":"$(HOST_IP):8126"},"lightstep":{"accessToken":"","address":"","cacertPath":"","secure":true},"zipkin":{"address":""}},"trustDomain":"","useMCP":true},"image":"sidecar_injector","neverInjectSelector":[],"nodeSelector":{},"podAntiAffinityLabelSelector":[],"podAntiAffinityTermLabelSelector":[],"replicaCount":1,"rewriteAppHTTPProbe":false,"rollingMaxSurge":"100%","rollingMaxUnavailable":"25%","tolerations":[]},"tracing":{"enabled":true,"global":{"arch":{"amd64":2,"ppc64le":2,"s390x":2},"configValidation":true,"controlPlaneSecurityEnabled":true,"defaultNodeSelector":{},"defaultPodDisruptionBudget":{"enabled":true},"defaultResources":{"requests":{"cpu":"10m"}},"defaultTolerations":[],"disablePolicyChecks":false,"enableHelmTest":false,"enableTracing":true,"hub":"docker.io/istio","imagePullPolicy":"IfNotPresent","imagePullSecrets":[],"k8sIngress":{"enableHttps":false,"enabled":false,"gatewayName":"ingressgateway"},"localityLbSetting":{"enabled":true},"logging":{"level":"default:info"},"meshExpansion":{"enabled":false,"useILB":false},"meshID":"","meshNetworks":{},"monitoringPort":15014,"mtls":{"enabled":true},"multiCluster":{"clusterName":"","enabled":false},"oneNamespace":false,"outboundTrafficPolicy":{"mode":"ALLOW_ANY"},"policyCheckFailOpen":false,"priorityClassName":"","proxy":{"accessLogEncoding":"TEXT","accessLogFile":"/dev/stdout","accessLogFormat":"","autoInject":"enabled","clusterDomain":"cluster.local","componentLogLevel":"","concurrency":2,"dnsRefreshRate":"300s","enableCoreDump":false,"enableCoreDumpImage":"ubuntu:xenial","envoyAccessLogService":{"enabled":false,"host":null,"port":null,"tcpKeepalive":{"interval":"10s","probes":3,"time":"10s"},"tlsSettings":{"caCertificates":null,"clientCertificate":null,"mode":"DISABLE","privateKey":null,"sni":null,"subjectAltNames":[]}},"envoyMetricsService":{"enabled":false,"host":null,"port":null},"envoyStatsd":{"enabled":false,"host":null,"port":null},"excludeIPRanges":"","excludeInboundPorts":"","excludeOutboundPorts":"","image":"proxyv2","includeIPRanges":"*","includeInboundPorts":"*","init":{"resources":{"limits":{"cpu":"100m","memory":"50Mi"},"requests":{"cpu":"10m","memory":"10Mi"}}},"kubevirtInterfaces":"","logLevel":"","privileged":false,"protocolDetectionTimeout":"100ms","readinessFailureThreshold":30,"readinessInitialDelaySeconds":1,"readinessPeriodSeconds":2,"resources":{"limits":{"cpu":"2000m","memory":"1024Mi"},"requests":{"cpu":"10m","memory":"40Mi"}},"statusPort":15020,"tracer":"zipkin"},"proxy_init":{"image":"proxy_init"},"sds":{"enabled":false,"token":{"aud":"istio-ca"},"udsPath":""},"tag":"1.3.5","tracer":{"datadog":{"address":"$(HOST_IP):8126"},"lightstep":{"accessToken":"","address":"","cacertPath":"","secure":true},"zipkin":{"address":""}},"trustDomain":"","useMCP":true},"ingress":{"annotations":null,"enabled":false,"hosts":null,"tls":null},"jaeger":{"accessMode":"ReadWriteMany","hub":"docker.io/jaegertracing","image":"all-in-one","memory":{"max_traces":50000},"persist":false,"spanStorageType":"badger","storageClassName":"","tag":1.14},"nodeSelector":{},"podAntiAffinityLabelSelector":[],"podAntiAffinityTermLabelSelector":[],"provider":"jaeger","service":{"annotations":{},"externalPort":9411,"name":"http","type":"ClusterIP"},"tolerations":[],"zipkin":{"hub":"docker.io/openzipkin","image":"zipkin","javaOptsHeap":700,"maxSpans":500000,"node":{"cpus":2},"probeStartupDelay":200,"queryPort":9411,"resources":{"limits":{"cpu":"300m","memory":"900Mi"},"requests":{"cpu":"150m","memory":"900Mi"}},"tag":"2.14.2"}}} + + config: |- + policy: enabled + alwaysInjectSelector: + [] + neverInjectSelector: + [] + template: |- + rewriteAppHTTPProbe: {{ valueOrDefault .Values.sidecarInjectorWebhook.rewriteAppHTTPProbe false }} + {{- if or (not .Values.istio_cni.enabled) .Values.global.proxy.enableCoreDump }} + initContainers: + {{ if ne (annotation .ObjectMeta `sidecar.istio.io/interceptionMode` .ProxyConfig.InterceptionMode) `NONE` }} + {{- if not .Values.istio_cni.enabled }} + - name: istio-init + {{- if contains "/" .Values.global.proxy_init.image }} + image: "{{ .Values.global.proxy_init.image }}" + {{- else }} + image: "{{ .Values.global.hub }}/{{ .Values.global.proxy_init.image }}:{{ .Values.global.tag }}" + {{- end }} + args: + - "-p" + - "15001" + - "-z" + - "15006" + - "-u" + - 1337 + - "-m" + - "{{ annotation .ObjectMeta `sidecar.istio.io/interceptionMode` .ProxyConfig.InterceptionMode }}" + - "-i" + - "{{ annotation .ObjectMeta `traffic.sidecar.istio.io/includeOutboundIPRanges` .Values.global.proxy.includeIPRanges }}" + - "-x" + - "{{ annotation .ObjectMeta `traffic.sidecar.istio.io/excludeOutboundIPRanges` .Values.global.proxy.excludeIPRanges }}" + - "-b" + - "{{ annotation .ObjectMeta `traffic.sidecar.istio.io/includeInboundPorts` `*` }}" + - "-d" + - "{{ excludeInboundPort (annotation .ObjectMeta `status.sidecar.istio.io/port` .Values.global.proxy.statusPort) (annotation .ObjectMeta `traffic.sidecar.istio.io/excludeInboundPorts` .Values.global.proxy.excludeInboundPorts) }}" + {{ if or (isset .ObjectMeta.Annotations `traffic.sidecar.istio.io/excludeOutboundPorts`) (ne .Values.global.proxy.excludeOutboundPorts "") -}} + - "-o" + - "{{ annotation .ObjectMeta `traffic.sidecar.istio.io/excludeOutboundPorts` .Values.global.proxy.excludeOutboundPorts }}" + {{ end -}} + {{ if (isset .ObjectMeta.Annotations `traffic.sidecar.istio.io/kubevirtInterfaces`) -}} + - "-k" + - "{{ index .ObjectMeta.Annotations `traffic.sidecar.istio.io/kubevirtInterfaces` }}" + {{ end -}} + imagePullPolicy: "{{ .Values.global.imagePullPolicy }}" + {{- if .Values.global.proxy.init.resources }} + resources: + {{ toYaml .Values.global.proxy.init.resources | indent 4 }} + {{- else }} + resources: {} + {{- end }} + securityContext: + runAsUser: 0 + runAsNonRoot: false + capabilities: + add: + - NET_ADMIN + {{- if .Values.global.proxy.privileged }} + privileged: true + {{- end }} + restartPolicy: Always + {{- end }} + {{ end -}} + {{- if eq .Values.global.proxy.enableCoreDump true }} + - name: enable-core-dump + args: + - -c + - sysctl -w kernel.core_pattern=/var/lib/istio/core.proxy && ulimit -c unlimited + command: + - /bin/sh + image: {{ $.Values.global.proxy.enableCoreDumpImage }} + imagePullPolicy: IfNotPresent + resources: {} + securityContext: + runAsUser: 0 + runAsNonRoot: false + privileged: true + {{ end }} + {{- end }} + containers: + - name: istio-proxy + {{- if contains "/" (annotation .ObjectMeta `sidecar.istio.io/proxyImage` .Values.global.proxy.image) }} + image: "{{ annotation .ObjectMeta `sidecar.istio.io/proxyImage` .Values.global.proxy.image }}" + {{- else }} + image: "{{ annotation .ObjectMeta `sidecar.istio.io/proxyImage` .Values.global.hub }}/{{ .Values.global.proxy.image }}:{{ .Values.global.tag }}" + {{- end }} + ports: + - containerPort: 15090 + protocol: TCP + name: http-envoy-prom + args: + - proxy + - sidecar + - --domain + - $(POD_NAMESPACE).svc.{{ .Values.global.proxy.clusterDomain }} + - --configPath + - "{{ .ProxyConfig.ConfigPath }}" + - --binaryPath + - "{{ .ProxyConfig.BinaryPath }}" + - --serviceCluster + {{ if ne "" (index .ObjectMeta.Labels "app") -}} + - "{{ index .ObjectMeta.Labels `app` }}.$(POD_NAMESPACE)" + {{ else -}} + - "{{ valueOrDefault .DeploymentMeta.Name `istio-proxy` }}.{{ valueOrDefault .DeploymentMeta.Namespace `default` }}" + {{ end -}} + - --drainDuration + - "{{ formatDuration .ProxyConfig.DrainDuration }}" + - --parentShutdownDuration + - "{{ formatDuration .ProxyConfig.ParentShutdownDuration }}" + - --discoveryAddress + - "{{ annotation .ObjectMeta `sidecar.istio.io/discoveryAddress` .ProxyConfig.DiscoveryAddress }}" + {{- if eq .Values.global.proxy.tracer "lightstep" }} + - --lightstepAddress + - "{{ .ProxyConfig.GetTracing.GetLightstep.GetAddress }}" + - --lightstepAccessToken + - "{{ .ProxyConfig.GetTracing.GetLightstep.GetAccessToken }}" + - --lightstepSecure={{ .ProxyConfig.GetTracing.GetLightstep.GetSecure }} + - --lightstepCacertPath + - "{{ .ProxyConfig.GetTracing.GetLightstep.GetCacertPath }}" + {{- else if eq .Values.global.proxy.tracer "zipkin" }} + - --zipkinAddress + - "{{ .ProxyConfig.GetTracing.GetZipkin.GetAddress }}" + {{- else if eq .Values.global.proxy.tracer "datadog" }} + - --datadogAgentAddress + - "{{ .ProxyConfig.GetTracing.GetDatadog.GetAddress }}" + {{- end }} + {{- if .Values.global.proxy.logLevel }} + - --proxyLogLevel={{ .Values.global.proxy.logLevel }} + {{- end}} + {{- if .Values.global.proxy.componentLogLevel }} + - --proxyComponentLogLevel={{ .Values.global.proxy.componentLogLevel }} + {{- end}} + - --dnsRefreshRate + - {{ .Values.global.proxy.dnsRefreshRate }} + - --connectTimeout + - "{{ formatDuration .ProxyConfig.ConnectTimeout }}" + {{- if .Values.global.proxy.envoyStatsd.enabled }} + - --statsdUdpAddress + - "{{ .ProxyConfig.StatsdUdpAddress }}" + {{- end }} + {{- if .Values.global.proxy.envoyMetricsService.enabled }} + - --envoyMetricsServiceAddress + - "{{ .ProxyConfig.GetEnvoyMetricsService.GetAddress }}" + {{- end }} + {{- if .Values.global.proxy.envoyAccessLogService.enabled }} + - --envoyAccessLogService + - '{{ structToJSON .ProxyConfig.EnvoyAccessLogService }}' + {{- end }} + - --proxyAdminPort + - "{{ .ProxyConfig.ProxyAdminPort }}" + {{ if gt .ProxyConfig.Concurrency 0 -}} + - --concurrency + - "{{ .ProxyConfig.Concurrency }}" + {{ end -}} + - --controlPlaneAuthPolicy + - "{{ annotation .ObjectMeta `sidecar.istio.io/controlPlaneAuthPolicy` .ProxyConfig.ControlPlaneAuthPolicy }}" + {{- if (ne (annotation .ObjectMeta "status.sidecar.istio.io/port" .Values.global.proxy.statusPort) "0") }} + - --statusPort + - "{{ annotation .ObjectMeta `status.sidecar.istio.io/port` .Values.global.proxy.statusPort }}" + - --applicationPorts + - "{{ annotation .ObjectMeta `readiness.status.sidecar.istio.io/applicationPorts` (applicationPorts .Spec.Containers) }}" + {{- end }} + {{- if .Values.global.trustDomain }} + - --trust-domain={{ .Values.global.trustDomain }} + {{- end }} + env: + - name: POD_NAME + valueFrom: + fieldRef: + fieldPath: metadata.name + - name: ISTIO_META_POD_PORTS + value: |- + [ + {{- range $index1, $c := .Spec.Containers }} + {{- range $index2, $p := $c.Ports }} + {{if or (ne $index1 0) (ne $index2 0)}},{{end}}{{ structToJSON $p }} + {{- end}} + {{- end}} + ] + - name: ISTIO_META_CLUSTER_ID + value: "{{ valueOrDefault .Values.global.multicluster.clusterName `Kubernetes` }}" + - name: POD_NAMESPACE + valueFrom: + fieldRef: + fieldPath: metadata.namespace + - name: INSTANCE_IP + valueFrom: + fieldRef: + fieldPath: status.podIP + - name: SERVICE_ACCOUNT + valueFrom: + fieldRef: + fieldPath: spec.serviceAccountName + {{- if eq .Values.global.proxy.tracer "datadog" }} + - name: HOST_IP + valueFrom: + fieldRef: + fieldPath: status.hostIP + {{- if isset .ObjectMeta.Annotations `apm.datadoghq.com/env` }} + {{- range $key, $value := fromJSON (index .ObjectMeta.Annotations `apm.datadoghq.com/env`) }} + - name: {{ $key }} + value: "{{ $value }}" + {{- end }} + {{- end }} + {{- end }} + - name: ISTIO_META_POD_NAME + valueFrom: + fieldRef: + fieldPath: metadata.name + - name: ISTIO_META_CONFIG_NAMESPACE + valueFrom: + fieldRef: + fieldPath: metadata.namespace + - name: SDS_ENABLED + value: {{ $.Values.global.sds.enabled }} + - name: ISTIO_META_INTERCEPTION_MODE + value: "{{ or (index .ObjectMeta.Annotations `sidecar.istio.io/interceptionMode`) .ProxyConfig.InterceptionMode.String }}" + - name: ISTIO_META_INCLUDE_INBOUND_PORTS + value: "{{ annotation .ObjectMeta `traffic.sidecar.istio.io/includeInboundPorts` (applicationPorts .Spec.Containers) }}" + {{- if .Values.global.network }} + - name: ISTIO_META_NETWORK + value: "{{ .Values.global.network }}" + {{- end }} + {{ if .ObjectMeta.Annotations }} + - name: ISTIO_METAJSON_ANNOTATIONS + value: | + {{ toJSON .ObjectMeta.Annotations }} + {{ end }} + {{ if .ObjectMeta.Labels }} + - name: ISTIO_METAJSON_LABELS + value: | + {{ toJSON .ObjectMeta.Labels }} + {{ end }} + {{- if .DeploymentMeta.Name }} + - name: ISTIO_META_WORKLOAD_NAME + value: {{ .DeploymentMeta.Name }} + {{ end }} + {{- if and .TypeMeta.APIVersion .DeploymentMeta.Name }} + - name: ISTIO_META_OWNER + value: kubernetes://api/{{ .TypeMeta.APIVersion }}/namespaces/{{ valueOrDefault .DeploymentMeta.Namespace `default` }}/{{ toLower .TypeMeta.Kind}}s/{{ .DeploymentMeta.Name }} + {{- end}} + {{- if (isset .ObjectMeta.Annotations `sidecar.istio.io/bootstrapOverride`) }} + - name: ISTIO_BOOTSTRAP_OVERRIDE + value: "/etc/istio/custom-bootstrap/custom_bootstrap.json" + {{- end }} + {{- if .Values.global.sds.customTokenDirectory }} + - name: ISTIO_META_SDS_TOKEN_PATH + value: "{{ .Values.global.sds.customTokenDirectory -}}/sdstoken" + {{- end }} + {{- if .Values.global.meshID }} + - name: ISTIO_META_MESH_ID + value: "{{ .Values.global.meshID }}" + {{- else if .Values.global.trustDomain }} + - name: ISTIO_META_MESH_ID + value: "{{ .Values.global.trustDomain }}" + {{- end }} + imagePullPolicy: {{ .Values.global.imagePullPolicy }} + {{ if ne (annotation .ObjectMeta `status.sidecar.istio.io/port` .Values.global.proxy.statusPort) `0` }} + readinessProbe: + httpGet: + path: /healthz/ready + port: {{ annotation .ObjectMeta `status.sidecar.istio.io/port` .Values.global.proxy.statusPort }} + initialDelaySeconds: {{ annotation .ObjectMeta `readiness.status.sidecar.istio.io/initialDelaySeconds` .Values.global.proxy.readinessInitialDelaySeconds }} + periodSeconds: {{ annotation .ObjectMeta `readiness.status.sidecar.istio.io/periodSeconds` .Values.global.proxy.readinessPeriodSeconds }} + failureThreshold: {{ annotation .ObjectMeta `readiness.status.sidecar.istio.io/failureThreshold` .Values.global.proxy.readinessFailureThreshold }} + {{ end -}} + securityContext: + {{- if .Values.global.proxy.privileged }} + privileged: true + {{- end }} + {{- if ne .Values.global.proxy.enableCoreDump true }} + readOnlyRootFilesystem: true + {{- end }} + {{ if eq (annotation .ObjectMeta `sidecar.istio.io/interceptionMode` .ProxyConfig.InterceptionMode) `TPROXY` -}} + capabilities: + add: + - NET_ADMIN + runAsGroup: 1337 + {{ else -}} + {{ if .Values.global.sds.enabled }} + runAsGroup: 1337 + {{- end }} + runAsUser: 1337 + {{- end }} + resources: + {{ if or (isset .ObjectMeta.Annotations `sidecar.istio.io/proxyCPU`) (isset .ObjectMeta.Annotations `sidecar.istio.io/proxyMemory`) -}} + requests: + {{ if (isset .ObjectMeta.Annotations `sidecar.istio.io/proxyCPU`) -}} + cpu: "{{ index .ObjectMeta.Annotations `sidecar.istio.io/proxyCPU` }}" + {{ end}} + {{ if (isset .ObjectMeta.Annotations `sidecar.istio.io/proxyMemory`) -}} + memory: "{{ index .ObjectMeta.Annotations `sidecar.istio.io/proxyMemory` }}" + {{ end }} + {{ else -}} + {{- if .Values.global.proxy.resources }} + {{ toYaml .Values.global.proxy.resources | indent 4 }} + {{- end }} + {{ end -}} + volumeMounts: + {{ if (isset .ObjectMeta.Annotations `sidecar.istio.io/bootstrapOverride`) }} + - mountPath: /etc/istio/custom-bootstrap + name: custom-bootstrap-volume + {{- end }} + - mountPath: /etc/istio/proxy + name: istio-envoy + {{- if .Values.global.sds.enabled }} + - mountPath: /var/run/sds + name: sds-uds-path + readOnly: true + - mountPath: /var/run/secrets/tokens + name: istio-token + {{- if .Values.global.sds.customTokenDirectory }} + - mountPath: "{{ .Values.global.sds.customTokenDirectory -}}" + name: custom-sds-token + readOnly: true + {{- end }} + {{- else }} + - mountPath: /etc/certs/ + name: istio-certs + readOnly: true + {{- end }} + {{- if and (eq .Values.global.proxy.tracer "lightstep") .Values.global.tracer.lightstep.cacertPath }} + - mountPath: {{ directory .ProxyConfig.GetTracing.GetLightstep.GetCacertPath }} + name: lightstep-certs + readOnly: true + {{- end }} + {{- if isset .ObjectMeta.Annotations `sidecar.istio.io/userVolumeMount` }} + {{ range $index, $value := fromJSON (index .ObjectMeta.Annotations `sidecar.istio.io/userVolumeMount`) }} + - name: "{{ $index }}" + {{ toYaml $value | indent 4 }} + {{ end }} + {{- end }} + volumes: + {{- if (isset .ObjectMeta.Annotations `sidecar.istio.io/bootstrapOverride`) }} + - name: custom-bootstrap-volume + configMap: + name: {{ annotation .ObjectMeta `sidecar.istio.io/bootstrapOverride` "" }} + {{- end }} + - emptyDir: + medium: Memory + name: istio-envoy + {{- if .Values.global.sds.enabled }} + - name: sds-uds-path + hostPath: + path: /var/run/sds + - name: istio-token + projected: + sources: + - serviceAccountToken: + path: istio-token + expirationSeconds: 43200 + audience: {{ .Values.global.sds.token.aud }} + {{- if .Values.global.sds.customTokenDirectory }} + - name: custom-sds-token + secret: + secretName: sdstokensecret + {{- end }} + {{- else }} + - name: istio-certs + secret: + optional: true + {{ if eq .Spec.ServiceAccountName "" }} + secretName: istio.default + {{ else -}} + secretName: {{ printf "istio.%s" .Spec.ServiceAccountName }} + {{ end -}} + {{- if isset .ObjectMeta.Annotations `sidecar.istio.io/userVolume` }} + {{range $index, $value := fromJSON (index .ObjectMeta.Annotations `sidecar.istio.io/userVolume`) }} + - name: "{{ $index }}" + {{ toYaml $value | indent 2 }} + {{ end }} + {{ end }} + {{- end }} + {{- if and (eq .Values.global.proxy.tracer "lightstep") .Values.global.tracer.lightstep.cacertPath }} + - name: lightstep-certs + secret: + optional: true + secretName: lightstep.cacert + {{- end }} + {{- if .Values.global.podDNSSearchNamespaces }} + dnsConfig: + searches: + {{- range .Values.global.podDNSSearchNamespaces }} + - {{ render . }} + {{- end }} + {{- end }} + podRedirectAnnot: + sidecar.istio.io/interceptionMode: "{{ annotation .ObjectMeta `sidecar.istio.io/interceptionMode` .ProxyConfig.InterceptionMode }}" + traffic.sidecar.istio.io/includeOutboundIPRanges: "{{ annotation .ObjectMeta `traffic.sidecar.istio.io/includeOutboundIPRanges` .Values.global.proxy.includeIPRanges }}" + traffic.sidecar.istio.io/excludeOutboundIPRanges: "{{ annotation .ObjectMeta `traffic.sidecar.istio.io/excludeOutboundIPRanges` .Values.global.proxy.excludeIPRanges }}" + traffic.sidecar.istio.io/includeInboundPorts: "{{ annotation .ObjectMeta `traffic.sidecar.istio.io/includeInboundPorts` (includeInboundPorts .Spec.Containers) }}" + traffic.sidecar.istio.io/excludeInboundPorts: "{{ excludeInboundPort (annotation .ObjectMeta `status.sidecar.istio.io/port` .Values.global.proxy.statusPort) (annotation .ObjectMeta `traffic.sidecar.istio.io/excludeInboundPorts` .Values.global.proxy.excludeInboundPorts) }}" + {{ if or (isset .ObjectMeta.Annotations `traffic.sidecar.istio.io/excludeOutboundPorts`) (ne .Values.global.proxy.excludeOutboundPorts "") }} + traffic.sidecar.istio.io/excludeOutboundPorts: "{{ annotation .ObjectMeta `traffic.sidecar.istio.io/excludeOutboundPorts` .Values.global.proxy.excludeOutboundPorts }}" + {{- end }} + traffic.sidecar.istio.io/kubevirtInterfaces: "{{ index .ObjectMeta.Annotations `traffic.sidecar.istio.io/kubevirtInterfaces` }}" + +--- +# Source: istio/charts/galley/templates/serviceaccount.yaml +apiVersion: v1 +kind: ServiceAccount +metadata: + name: istio-galley-service-account + namespace: istio-system + labels: + app: galley + chart: galley + heritage: Tiller + release: istio + +--- +# Source: istio/charts/gateways/templates/serviceaccount.yaml + +apiVersion: v1 +kind: ServiceAccount +metadata: + name: istio-egressgateway-service-account + namespace: istio-system + labels: + app: istio-egressgateway + chart: gateways + heritage: Tiller + release: istio +--- +apiVersion: v1 +kind: ServiceAccount +metadata: + name: istio-ingressgateway-service-account + namespace: istio-system + labels: + app: istio-ingressgateway + chart: gateways + heritage: Tiller + release: istio +--- + + +--- +# Source: istio/charts/grafana/templates/create-custom-resources-job.yaml +apiVersion: v1 +kind: ServiceAccount +metadata: + name: istio-grafana-post-install-account + namespace: istio-system + labels: + app: grafana + chart: grafana + heritage: Tiller + release: istio +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: istio-grafana-post-install-istio-system + labels: + app: grafana + chart: grafana + heritage: Tiller + release: istio +rules: +- apiGroups: ["authentication.istio.io"] # needed to create default authn policy + resources: ["*"] + verbs: ["*"] +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: istio-grafana-post-install-role-binding-istio-system + labels: + app: grafana + chart: grafana + heritage: Tiller + release: istio +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: istio-grafana-post-install-istio-system +subjects: + - kind: ServiceAccount + name: istio-grafana-post-install-account + namespace: istio-system +--- +apiVersion: batch/v1 +kind: Job +metadata: + name: istio-grafana-post-install-1.3.5 + namespace: istio-system + annotations: + "helm.sh/hook": post-install + "helm.sh/hook-delete-policy": hook-succeeded + labels: + app: grafana + chart: grafana + heritage: Tiller + release: istio +spec: + template: + metadata: + name: istio-grafana-post-install + labels: + app: istio-grafana + chart: grafana + heritage: Tiller + release: istio + spec: + serviceAccountName: istio-grafana-post-install-account + containers: + - name: kubectl + image: "docker.io/istio/kubectl:1.3.5" + command: [ "/bin/bash", "/tmp/grafana/run.sh", "/tmp/grafana/custom-resources.yaml" ] + volumeMounts: + - mountPath: "/tmp/grafana" + name: tmp-configmap-grafana + volumes: + - name: tmp-configmap-grafana + configMap: + name: istio-grafana-custom-resources + restartPolicy: OnFailure + affinity: + nodeAffinity: + requiredDuringSchedulingIgnoredDuringExecution: + nodeSelectorTerms: + - matchExpressions: + - key: beta.kubernetes.io/arch + operator: In + values: + - "amd64" + - "ppc64le" + - "s390x" + preferredDuringSchedulingIgnoredDuringExecution: + - weight: 2 + preference: + matchExpressions: + - key: beta.kubernetes.io/arch + operator: In + values: + - "amd64" + - weight: 2 + preference: + matchExpressions: + - key: beta.kubernetes.io/arch + operator: In + values: + - "ppc64le" + - weight: 2 + preference: + matchExpressions: + - key: beta.kubernetes.io/arch + operator: In + values: + - "s390x" + +--- +# Source: istio/charts/kiali/templates/serviceaccount.yaml +apiVersion: v1 +kind: ServiceAccount +metadata: + name: kiali-service-account + namespace: istio-system + labels: + app: kiali + chart: kiali + heritage: Tiller + release: istio + +--- +# Source: istio/charts/mixer/templates/serviceaccount.yaml + +apiVersion: v1 +kind: ServiceAccount +metadata: + name: istio-mixer-service-account + namespace: istio-system + labels: + app: mixer + chart: mixer + heritage: Tiller + release: istio + +--- +# Source: istio/charts/pilot/templates/serviceaccount.yaml +apiVersion: v1 +kind: ServiceAccount +metadata: + name: istio-pilot-service-account + namespace: istio-system + labels: + app: pilot + chart: pilot + heritage: Tiller + release: istio + +--- +# Source: istio/charts/prometheus/templates/serviceaccount.yaml +apiVersion: v1 +kind: ServiceAccount +metadata: + name: prometheus + namespace: istio-system + labels: + app: prometheus + chart: prometheus + heritage: Tiller + release: istio + +--- +# Source: istio/charts/security/templates/create-custom-resources-job.yaml + +apiVersion: v1 +kind: ServiceAccount +metadata: + name: istio-security-post-install-account + namespace: istio-system + labels: + app: security + chart: security + heritage: Tiller + release: istio +--- +apiVersion: rbac.authorization.k8s.io/v1beta1 +kind: ClusterRole +metadata: + name: istio-security-post-install-istio-system + labels: + app: security + chart: security + heritage: Tiller + release: istio +rules: +- apiGroups: ["authentication.istio.io"] # needed to create default authn policy + resources: ["*"] + verbs: ["*"] +- apiGroups: ["networking.istio.io"] # needed to create security destination rules + resources: ["*"] + verbs: ["*"] +- apiGroups: ["admissionregistration.k8s.io"] + resources: ["validatingwebhookconfigurations"] + verbs: ["get"] +- apiGroups: ["extensions", "apps"] + resources: ["deployments", "replicasets"] + verbs: ["get", "list", "watch"] +--- +apiVersion: rbac.authorization.k8s.io/v1beta1 +kind: ClusterRoleBinding +metadata: + name: istio-security-post-install-role-binding-istio-system + labels: + app: security + chart: security + heritage: Tiller + release: istio +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: istio-security-post-install-istio-system +subjects: + - kind: ServiceAccount + name: istio-security-post-install-account + namespace: istio-system +--- +apiVersion: batch/v1 +kind: Job +metadata: + name: istio-security-post-install-1.3.5 + namespace: istio-system + annotations: + "helm.sh/hook": post-install,post-upgrade + "helm.sh/hook-delete-policy": hook-succeeded + labels: + app: security + chart: security + heritage: Tiller + release: istio +spec: + template: + metadata: + name: istio-security-post-install + labels: + app: security + chart: security + heritage: Tiller + release: istio + spec: + serviceAccountName: istio-security-post-install-account + containers: + - name: kubectl + image: "docker.io/istio/kubectl:1.3.5" + imagePullPolicy: IfNotPresent + command: [ "/bin/bash", "/tmp/security/run.sh", "/tmp/security/custom-resources.yaml" ] + volumeMounts: + - mountPath: "/tmp/security" + name: tmp-configmap-security + volumes: + - name: tmp-configmap-security + configMap: + name: istio-security-custom-resources + restartPolicy: OnFailure + affinity: + nodeAffinity: + requiredDuringSchedulingIgnoredDuringExecution: + nodeSelectorTerms: + - matchExpressions: + - key: beta.kubernetes.io/arch + operator: In + values: + - "amd64" + - "ppc64le" + - "s390x" + preferredDuringSchedulingIgnoredDuringExecution: + - weight: 2 + preference: + matchExpressions: + - key: beta.kubernetes.io/arch + operator: In + values: + - "amd64" + - weight: 2 + preference: + matchExpressions: + - key: beta.kubernetes.io/arch + operator: In + values: + - "ppc64le" + - weight: 2 + preference: + matchExpressions: + - key: beta.kubernetes.io/arch + operator: In + values: + - "s390x" + +--- +# Source: istio/charts/security/templates/serviceaccount.yaml +apiVersion: v1 +kind: ServiceAccount +metadata: + name: istio-citadel-service-account + namespace: istio-system + labels: + app: security + chart: security + heritage: Tiller + release: istio + +--- +# Source: istio/charts/sidecarInjectorWebhook/templates/serviceaccount.yaml +apiVersion: v1 +kind: ServiceAccount +metadata: + name: istio-sidecar-injector-service-account + namespace: istio-system + labels: + app: sidecarInjectorWebhook + chart: sidecarInjectorWebhook + heritage: Tiller + release: istio + istio: sidecar-injector + +--- +# Source: istio/templates/serviceaccount.yaml +apiVersion: v1 +kind: ServiceAccount +metadata: + name: istio-multi + namespace: istio-system + +--- +# Source: istio/charts/galley/templates/clusterrole.yaml +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: istio-galley-istio-system + labels: + app: galley + chart: galley + heritage: Tiller + release: istio +rules: +- apiGroups: ["admissionregistration.k8s.io"] + resources: ["validatingwebhookconfigurations"] + verbs: ["*"] +- apiGroups: ["config.istio.io"] # istio mixer CRD watcher + resources: ["*"] + verbs: ["get", "list", "watch"] +- apiGroups: ["networking.istio.io"] + resources: ["*"] + verbs: ["get", "list", "watch"] +- apiGroups: ["authentication.istio.io"] + resources: ["*"] + verbs: ["get", "list", "watch"] +- apiGroups: ["rbac.istio.io"] + resources: ["*"] + verbs: ["get", "list", "watch"] +- apiGroups: ["extensions","apps"] + resources: ["deployments"] + resourceNames: ["istio-galley"] + verbs: ["get"] +- apiGroups: [""] + resources: ["pods", "nodes", "services", "endpoints", "namespaces"] + verbs: ["get", "list", "watch"] +- apiGroups: ["extensions"] + resources: ["ingresses"] + verbs: ["get", "list", "watch"] +- apiGroups: ["extensions"] + resources: ["deployments/finalizers"] + resourceNames: ["istio-galley"] + verbs: ["update"] +- apiGroups: ["apiextensions.k8s.io"] + resources: ["customresourcedefinitions"] + verbs: ["get", "list", "watch"] + +--- +# Source: istio/charts/kiali/templates/clusterrole.yaml +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: kiali + labels: + app: kiali + chart: kiali + heritage: Tiller + release: istio +rules: +- apiGroups: [""] + resources: + - configmaps + - endpoints + - namespaces + - nodes + - pods + - pods/log + - replicationcontrollers + - services + verbs: + - get + - list + - watch +- apiGroups: ["extensions", "apps"] + resources: + - deployments + - replicasets + - statefulsets + verbs: + - get + - list + - watch +- apiGroups: ["autoscaling"] + resources: + - horizontalpodautoscalers + verbs: + - get + - list + - watch +- apiGroups: ["batch"] + resources: + - cronjobs + - jobs + verbs: + - get + - list + - watch +- apiGroups: ["config.istio.io"] + resources: + - adapters + - apikeys + - bypasses + - authorizations + - checknothings + - circonuses + - cloudwatches + - deniers + - dogstatsds + - edges + - fluentds + - handlers + - instances + - kubernetesenvs + - kuberneteses + - listcheckers + - listentries + - logentries + - memquotas + - metrics + - noops + - opas + - prometheuses + - quotas + - quotaspecbindings + - quotaspecs + - rbacs + - redisquotas + - reportnothings + - rules + - signalfxs + - solarwindses + - stackdrivers + - statsds + - stdios + - templates + - tracespans + - zipkins + verbs: + - create + - delete + - get + - list + - patch + - watch +- apiGroups: ["networking.istio.io"] + resources: + - destinationrules + - gateways + - serviceentries + - sidecars + - virtualservices + verbs: + - create + - delete + - get + - list + - patch + - watch +- apiGroups: ["authentication.istio.io"] + resources: + - meshpolicies + - policies + verbs: + - create + - delete + - get + - list + - patch + - watch +- apiGroups: ["rbac.istio.io"] + resources: + - clusterrbacconfigs + - rbacconfigs + - servicerolebindings + - serviceroles + verbs: + - create + - delete + - get + - list + - patch + - watch +- apiGroups: ["monitoring.kiali.io"] + resources: + - monitoringdashboards + verbs: + - get + - list +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: kiali-viewer + labels: + app: kiali + chart: kiali + heritage: Tiller + release: istio +rules: +- apiGroups: [""] + resources: + - configmaps + - endpoints + - namespaces + - nodes + - pods + - pods/log + - replicationcontrollers + - services + verbs: + - get + - list + - watch +- apiGroups: ["extensions", "apps"] + resources: + - deployments + - replicasets + - statefulsets + verbs: + - get + - list + - watch +- apiGroups: ["autoscaling"] + resources: + - horizontalpodautoscalers + verbs: + - get + - list + - watch +- apiGroups: ["batch"] + resources: + - cronjobs + - jobs + verbs: + - get + - list + - watch +- apiGroups: ["config.istio.io"] + resources: + - adapters + - apikeys + - bypasses + - authorizations + - checknothings + - circonuses + - cloudwatches + - deniers + - dogstatsds + - edges + - fluentds + - handlers + - instances + - kubernetesenvs + - kuberneteses + - listcheckers + - listentries + - logentries + - memquotas + - metrics + - noops + - opas + - prometheuses + - quotas + - quotaspecbindings + - quotaspecs + - rbacs + - redisquotas + - reportnothings + - rules + - signalfxs + - solarwindses + - stackdrivers + - statsds + - stdios + - templates + - tracespans + - zipkins + verbs: + - get + - list + - watch +- apiGroups: ["networking.istio.io"] + resources: + - destinationrules + - gateways + - serviceentries + - sidecars + - virtualservices + verbs: + - get + - list + - watch +- apiGroups: ["authentication.istio.io"] + resources: + - meshpolicies + - policies + verbs: + - get + - list + - watch +- apiGroups: ["rbac.istio.io"] + resources: + - clusterrbacconfigs + - rbacconfigs + - servicerolebindings + - serviceroles + verbs: + - get + - list + - watch +- apiGroups: ["monitoring.kiali.io"] + resources: + - monitoringdashboards + verbs: + - get + - list + +--- +# Source: istio/charts/mixer/templates/clusterrole.yaml + +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: istio-mixer-istio-system + labels: + app: mixer + chart: mixer + heritage: Tiller + release: istio +rules: +- apiGroups: ["config.istio.io"] # istio CRD watcher + resources: ["*"] + verbs: ["create", "get", "list", "watch", "patch"] +- apiGroups: ["apiextensions.k8s.io"] + resources: ["customresourcedefinitions"] + verbs: ["get", "list", "watch"] +- apiGroups: [""] + resources: ["configmaps", "endpoints", "pods", "services", "namespaces", "secrets", "replicationcontrollers"] + verbs: ["get", "list", "watch"] +- apiGroups: ["extensions", "apps"] + resources: ["replicasets"] + verbs: ["get", "list", "watch"] + +--- +# Source: istio/charts/pilot/templates/clusterrole.yaml +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: istio-pilot-istio-system + labels: + app: pilot + chart: pilot + heritage: Tiller + release: istio +rules: +- apiGroups: ["config.istio.io"] + resources: ["*"] + verbs: ["*"] +- apiGroups: ["rbac.istio.io"] + resources: ["*"] + verbs: ["get", "watch", "list"] +- apiGroups: ["networking.istio.io"] + resources: ["*"] + verbs: ["*"] +- apiGroups: ["authentication.istio.io"] + resources: ["*"] + verbs: ["*"] +- apiGroups: ["apiextensions.k8s.io"] + resources: ["customresourcedefinitions"] + verbs: ["*"] +- apiGroups: ["extensions"] + resources: ["ingresses", "ingresses/status"] + verbs: ["*"] +- apiGroups: [""] + resources: ["configmaps"] + verbs: ["create", "get", "list", "watch", "update"] +- apiGroups: [""] + resources: ["endpoints", "pods", "services", "namespaces", "nodes", "secrets"] + verbs: ["get", "list", "watch"] + +--- +# Source: istio/charts/prometheus/templates/clusterrole.yaml +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: prometheus-istio-system + labels: + app: prometheus + chart: prometheus + heritage: Tiller + release: istio +rules: +- apiGroups: [""] + resources: + - nodes + - services + - endpoints + - pods + - nodes/proxy + verbs: ["get", "list", "watch"] +- apiGroups: [""] + resources: + - configmaps + verbs: ["get"] +- nonResourceURLs: ["/metrics"] + verbs: ["get"] + +--- +# Source: istio/charts/security/templates/clusterrole.yaml +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: istio-citadel-istio-system + labels: + app: security + chart: security + heritage: Tiller + release: istio +rules: +- apiGroups: [""] + resources: ["configmaps"] + verbs: ["create", "get", "update"] +- apiGroups: [""] + resources: ["secrets"] + verbs: ["create", "get", "watch", "list", "update", "delete"] +- apiGroups: [""] + resources: ["serviceaccounts", "services", "namespaces"] + verbs: ["get", "watch", "list"] +- apiGroups: ["authentication.k8s.io"] + resources: ["tokenreviews"] + verbs: ["create"] + +--- +# Source: istio/charts/sidecarInjectorWebhook/templates/clusterrole.yaml +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: istio-sidecar-injector-istio-system + labels: + app: sidecarInjectorWebhook + chart: sidecarInjectorWebhook + heritage: Tiller + release: istio + istio: sidecar-injector +rules: +- apiGroups: [""] + resources: ["configmaps"] + verbs: ["get", "list", "watch"] +- apiGroups: ["admissionregistration.k8s.io"] + resources: ["mutatingwebhookconfigurations"] + verbs: ["get", "list", "watch", "patch"] + +--- +# Source: istio/templates/clusterrole.yaml +kind: ClusterRole +apiVersion: rbac.authorization.k8s.io/v1 +metadata: + name: istio-reader +rules: + - apiGroups: [''] + resources: ['nodes', 'pods', 'services', 'endpoints', "replicationcontrollers"] + verbs: ['get', 'watch', 'list'] + - apiGroups: ["extensions", "apps"] + resources: ["replicasets"] + verbs: ["get", "list", "watch"] + +--- +# Source: istio/charts/galley/templates/clusterrolebinding.yaml +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: istio-galley-admin-role-binding-istio-system + labels: + app: galley + chart: galley + heritage: Tiller + release: istio +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: istio-galley-istio-system +subjects: + - kind: ServiceAccount + name: istio-galley-service-account + namespace: istio-system + +--- +# Source: istio/charts/kiali/templates/clusterrolebinding.yaml + +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: istio-kiali-admin-role-binding-istio-system + labels: + app: kiali + chart: kiali + heritage: Tiller + release: istio +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: kiali +subjects: +- kind: ServiceAccount + name: kiali-service-account + namespace: istio-system + +--- +# Source: istio/charts/mixer/templates/clusterrolebinding.yaml + +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: istio-mixer-admin-role-binding-istio-system + labels: + app: mixer + chart: mixer + heritage: Tiller + release: istio +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: istio-mixer-istio-system +subjects: + - kind: ServiceAccount + name: istio-mixer-service-account + namespace: istio-system + +--- +# Source: istio/charts/pilot/templates/clusterrolebinding.yaml +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: istio-pilot-istio-system + labels: + app: pilot + chart: pilot + heritage: Tiller + release: istio +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: istio-pilot-istio-system +subjects: + - kind: ServiceAccount + name: istio-pilot-service-account + namespace: istio-system + +--- +# Source: istio/charts/prometheus/templates/clusterrolebindings.yaml +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: prometheus-istio-system + labels: + app: prometheus + chart: prometheus + heritage: Tiller + release: istio +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: prometheus-istio-system +subjects: +- kind: ServiceAccount + name: prometheus + namespace: istio-system + +--- +# Source: istio/charts/security/templates/clusterrolebinding.yaml +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: istio-citadel-istio-system + labels: + app: security + chart: security + heritage: Tiller + release: istio +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: istio-citadel-istio-system +subjects: + - kind: ServiceAccount + name: istio-citadel-service-account + namespace: istio-system + +--- +# Source: istio/charts/sidecarInjectorWebhook/templates/clusterrolebinding.yaml +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: istio-sidecar-injector-admin-role-binding-istio-system + labels: + app: sidecarInjectorWebhook + chart: sidecarInjectorWebhook + heritage: Tiller + release: istio + istio: sidecar-injector +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: istio-sidecar-injector-istio-system +subjects: + - kind: ServiceAccount + name: istio-sidecar-injector-service-account + namespace: istio-system + +--- +# Source: istio/templates/clusterrolebinding.yaml +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: istio-multi + labels: + chart: istio-1.1.0 +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: istio-reader +subjects: +- kind: ServiceAccount + name: istio-multi + namespace: istio-system + +--- +# Source: istio/charts/gateways/templates/role.yaml + +apiVersion: rbac.authorization.k8s.io/v1 +kind: Role +metadata: + name: istio-ingressgateway-sds + namespace: istio-system +rules: +- apiGroups: [""] + resources: ["secrets"] + verbs: ["get", "watch", "list"] +--- + +--- +# Source: istio/charts/gateways/templates/rolebindings.yaml + +apiVersion: rbac.authorization.k8s.io/v1 +kind: RoleBinding +metadata: + name: istio-ingressgateway-sds + namespace: istio-system +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: Role + name: istio-ingressgateway-sds +subjects: +- kind: ServiceAccount + name: istio-ingressgateway-service-account +--- + +--- +# Source: istio/charts/galley/templates/service.yaml +apiVersion: v1 +kind: Service +metadata: + name: istio-galley + namespace: istio-system + labels: + app: galley + chart: galley + heritage: Tiller + release: istio + istio: galley +spec: + ports: + - port: 443 + name: https-validation + - port: 15014 + name: http-monitoring + - port: 9901 + name: grpc-mcp + selector: + istio: galley + +--- +# Source: istio/charts/gateways/templates/service.yaml + +apiVersion: v1 +kind: Service +metadata: + name: istio-egressgateway + namespace: istio-system + annotations: + labels: + chart: gateways + heritage: Tiller + release: istio + app: istio-egressgateway + istio: egressgateway +spec: + type: ClusterIP + selector: + release: istio + app: istio-egressgateway + istio: egressgateway + ports: + - + name: http2 + port: 80 + - + name: https + port: 443 + - + name: tls + port: 15443 + targetPort: 15443 +--- +apiVersion: v1 +kind: Service +metadata: + name: istio-ingressgateway + namespace: istio-system + annotations: + labels: + chart: gateways + heritage: Tiller + release: istio + app: istio-ingressgateway + istio: ingressgateway +spec: + type: LoadBalancer + selector: + release: istio + app: istio-ingressgateway + istio: ingressgateway + ports: + - + name: status-port + port: 15020 + targetPort: 15020 + - + name: http2 + nodePort: 31380 + port: 80 + targetPort: 80 + - + name: https + nodePort: 31390 + port: 443 + - + name: tcp + nodePort: 31400 + port: 31400 + - + name: https-kiali + port: 15029 + targetPort: 15029 + - + name: https-prometheus + port: 15030 + targetPort: 15030 + - + name: https-grafana + port: 15031 + targetPort: 15031 + - + name: https-tracing + port: 15032 + targetPort: 15032 + - + name: tls + port: 15443 + targetPort: 15443 +--- + +--- +# Source: istio/charts/grafana/templates/service.yaml +apiVersion: v1 +kind: Service +metadata: + name: grafana + namespace: istio-system + annotations: + labels: + app: grafana + chart: grafana + heritage: Tiller + release: istio +spec: + type: ClusterIP + ports: + - port: 3000 + targetPort: 3000 + protocol: TCP + name: http + selector: + app: grafana + +--- +# Source: istio/charts/kiali/templates/service.yaml +apiVersion: v1 +kind: Service +metadata: + name: kiali + namespace: istio-system + labels: + app: kiali + chart: kiali + heritage: Tiller + release: istio +spec: + ports: + - name: http-kiali + protocol: TCP + port: 20001 + selector: + app: kiali + +--- +# Source: istio/charts/mixer/templates/service.yaml + +apiVersion: v1 +kind: Service +metadata: + name: istio-policy + namespace: istio-system + annotations: + networking.istio.io/exportTo: "*" + labels: + app: mixer + chart: mixer + heritage: Tiller + release: istio + istio: mixer +spec: + ports: + - name: grpc-mixer + port: 9091 + - name: grpc-mixer-mtls + port: 15004 + - name: http-monitoring + port: 15014 + selector: + istio: mixer + istio-mixer-type: policy +--- +apiVersion: v1 +kind: Service +metadata: + name: istio-telemetry + namespace: istio-system + annotations: + networking.istio.io/exportTo: "*" + labels: + app: mixer + chart: mixer + heritage: Tiller + release: istio + istio: mixer +spec: + ports: + - name: grpc-mixer + port: 9091 + - name: grpc-mixer-mtls + port: 15004 + - name: http-monitoring + port: 15014 + - name: prometheus + port: 42422 + selector: + istio: mixer + istio-mixer-type: telemetry +--- + + +--- +# Source: istio/charts/pilot/templates/service.yaml +apiVersion: v1 +kind: Service +metadata: + name: istio-pilot + namespace: istio-system + labels: + app: pilot + chart: pilot + heritage: Tiller + release: istio + istio: pilot +spec: + ports: + - port: 15010 + name: grpc-xds # direct + - port: 15011 + name: https-xds # mTLS + - port: 8080 + name: http-legacy-discovery # direct + - port: 15014 + name: http-monitoring + selector: + istio: pilot + +--- +# Source: istio/charts/prometheus/templates/service.yaml +apiVersion: v1 +kind: Service +metadata: + name: prometheus + namespace: istio-system + annotations: + prometheus.io/scrape: 'true' + labels: + app: prometheus + chart: prometheus + heritage: Tiller + release: istio +spec: + selector: + app: prometheus + ports: + - name: http-prometheus + protocol: TCP + port: 9090 + +--- +# Source: istio/charts/security/templates/service.yaml +apiVersion: v1 +kind: Service +metadata: + # we use the normal name here (e.g. 'prometheus') + # as grafana is configured to use this as a data source + name: istio-citadel + namespace: istio-system + labels: + app: security + chart: security + heritage: Tiller + release: istio + istio: citadel +spec: + ports: + - name: grpc-citadel + port: 8060 + targetPort: 8060 + protocol: TCP + - name: http-monitoring + port: 15014 + selector: + istio: citadel + +--- +# Source: istio/charts/sidecarInjectorWebhook/templates/service.yaml +apiVersion: v1 +kind: Service +metadata: + name: istio-sidecar-injector + namespace: istio-system + labels: + app: sidecarInjectorWebhook + chart: sidecarInjectorWebhook + heritage: Tiller + release: istio + istio: sidecar-injector +spec: + ports: + - port: 443 + name: https-inject + - port: 15014 + name: http-monitoring + selector: + istio: sidecar-injector + +--- +# Source: istio/charts/galley/templates/deployment.yaml +apiVersion: apps/v1 +kind: Deployment +metadata: + name: istio-galley + namespace: istio-system + labels: + app: galley + chart: galley + heritage: Tiller + release: istio + istio: galley +spec: + replicas: 1 + selector: + matchLabels: + istio: galley + strategy: + rollingUpdate: + maxSurge: 100% + maxUnavailable: 25% + template: + metadata: + labels: + app: galley + chart: galley + heritage: Tiller + release: istio + istio: galley + annotations: + sidecar.istio.io/inject: "false" + spec: + serviceAccountName: istio-galley-service-account + containers: + - name: galley + image: "docker.io/istio/galley:1.3.5" + imagePullPolicy: IfNotPresent + ports: + - containerPort: 443 + - containerPort: 15014 + - containerPort: 9901 + command: + - /usr/local/bin/galley + - server + - --meshConfigFile=/etc/mesh-config/mesh + - --livenessProbeInterval=1s + - --livenessProbePath=/healthliveness + - --readinessProbePath=/healthready + - --readinessProbeInterval=1s + - --deployment-namespace=istio-system + - --insecure=false + - --validation-webhook-config-file + - /etc/config/validatingwebhookconfiguration.yaml + - --monitoringPort=15014 + - --log_output_level=default:info + volumeMounts: + - name: certs + mountPath: /etc/certs + readOnly: true + - name: config + mountPath: /etc/config + readOnly: true + - name: mesh-config + mountPath: /etc/mesh-config + readOnly: true + livenessProbe: + exec: + command: + - /usr/local/bin/galley + - probe + - --probe-path=/healthliveness + - --interval=10s + initialDelaySeconds: 5 + periodSeconds: 5 + readinessProbe: + exec: + command: + - /usr/local/bin/galley + - probe + - --probe-path=/healthready + - --interval=10s + initialDelaySeconds: 5 + periodSeconds: 5 + resources: + requests: + cpu: 10m + + volumes: + - name: certs + secret: + secretName: istio.istio-galley-service-account + - name: config + configMap: + name: istio-galley-configuration + - name: mesh-config + configMap: + name: istio + affinity: + nodeAffinity: + requiredDuringSchedulingIgnoredDuringExecution: + nodeSelectorTerms: + - matchExpressions: + - key: beta.kubernetes.io/arch + operator: In + values: + - "amd64" + - "ppc64le" + - "s390x" + preferredDuringSchedulingIgnoredDuringExecution: + - weight: 2 + preference: + matchExpressions: + - key: beta.kubernetes.io/arch + operator: In + values: + - "amd64" + - weight: 2 + preference: + matchExpressions: + - key: beta.kubernetes.io/arch + operator: In + values: + - "ppc64le" + - weight: 2 + preference: + matchExpressions: + - key: beta.kubernetes.io/arch + operator: In + values: + - "s390x" + +--- +# Source: istio/charts/gateways/templates/deployment.yaml + +apiVersion: apps/v1 +kind: Deployment +metadata: + name: istio-egressgateway + namespace: istio-system + labels: + chart: gateways + heritage: Tiller + release: istio + app: istio-egressgateway + istio: egressgateway +spec: + replicas: 1 + selector: + matchLabels: + app: istio-egressgateway + istio: egressgateway + strategy: + rollingUpdate: + maxSurge: 100% + maxUnavailable: 25% + template: + metadata: + labels: + chart: gateways + heritage: Tiller + release: istio + app: istio-egressgateway + istio: egressgateway + annotations: + sidecar.istio.io/inject: "false" + spec: + serviceAccountName: istio-egressgateway-service-account + containers: + - name: istio-proxy + image: "docker.io/istio/proxyv2:1.3.5" + imagePullPolicy: IfNotPresent + ports: + - containerPort: 80 + - containerPort: 443 + - containerPort: 15443 + - containerPort: 15090 + protocol: TCP + name: http-envoy-prom + args: + - proxy + - router + - --domain + - $(POD_NAMESPACE).svc.cluster.local + - --log_output_level=default:info + - --drainDuration + - '45s' #drainDuration + - --parentShutdownDuration + - '1m0s' #parentShutdownDuration + - --connectTimeout + - '10s' #connectTimeout + - --serviceCluster + - istio-egressgateway + - --zipkinAddress + - zipkin:9411 + - --proxyAdminPort + - "15000" + - --statusPort + - "15020" + - --controlPlaneAuthPolicy + - MUTUAL_TLS + - --discoveryAddress + - istio-pilot:15011 + readinessProbe: + failureThreshold: 30 + httpGet: + path: /healthz/ready + port: 15020 + scheme: HTTP + initialDelaySeconds: 1 + periodSeconds: 2 + successThreshold: 1 + timeoutSeconds: 1 + resources: + limits: + cpu: 2000m + memory: 1024Mi + requests: + cpu: 10m + memory: 40Mi + + env: + - name: NODE_NAME + valueFrom: + fieldRef: + apiVersion: v1 + fieldPath: spec.nodeName + - name: POD_NAME + valueFrom: + fieldRef: + apiVersion: v1 + fieldPath: metadata.name + - name: POD_NAMESPACE + valueFrom: + fieldRef: + apiVersion: v1 + fieldPath: metadata.namespace + - name: INSTANCE_IP + valueFrom: + fieldRef: + apiVersion: v1 + fieldPath: status.podIP + - name: HOST_IP + valueFrom: + fieldRef: + apiVersion: v1 + fieldPath: status.hostIP + - name: SERVICE_ACCOUNT + valueFrom: + fieldRef: + fieldPath: spec.serviceAccountName + - name: ISTIO_META_POD_NAME + valueFrom: + fieldRef: + apiVersion: v1 + fieldPath: metadata.name + - name: ISTIO_META_CONFIG_NAMESPACE + valueFrom: + fieldRef: + fieldPath: metadata.namespace + - name: SDS_ENABLED + value: "false" + - name: ISTIO_META_WORKLOAD_NAME + value: istio-egressgateway + - name: ISTIO_META_OWNER + value: kubernetes://api/apps/v1/namespaces/istio-system/deployments/istio-egressgateway + - name: ISTIO_META_ROUTER_MODE + value: sni-dnat + volumeMounts: + - name: istio-certs + mountPath: /etc/certs + readOnly: true + - name: egressgateway-certs + mountPath: "/etc/istio/egressgateway-certs" + readOnly: true + - name: egressgateway-ca-certs + mountPath: "/etc/istio/egressgateway-ca-certs" + readOnly: true + volumes: + - name: istio-certs + secret: + secretName: istio.istio-egressgateway-service-account + optional: true + - name: egressgateway-certs + secret: + secretName: "istio-egressgateway-certs" + optional: true + - name: egressgateway-ca-certs + secret: + secretName: "istio-egressgateway-ca-certs" + optional: true + affinity: + nodeAffinity: + requiredDuringSchedulingIgnoredDuringExecution: + nodeSelectorTerms: + - matchExpressions: + - key: beta.kubernetes.io/arch + operator: In + values: + - "amd64" + - "ppc64le" + - "s390x" + preferredDuringSchedulingIgnoredDuringExecution: + - weight: 2 + preference: + matchExpressions: + - key: beta.kubernetes.io/arch + operator: In + values: + - "amd64" + - weight: 2 + preference: + matchExpressions: + - key: beta.kubernetes.io/arch + operator: In + values: + - "ppc64le" + - weight: 2 + preference: + matchExpressions: + - key: beta.kubernetes.io/arch + operator: In + values: + - "s390x" +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: istio-ingressgateway + namespace: istio-system + labels: + chart: gateways + heritage: Tiller + release: istio + app: istio-ingressgateway + istio: ingressgateway +spec: + replicas: 1 + selector: + matchLabels: + app: istio-ingressgateway + istio: ingressgateway + strategy: + rollingUpdate: + maxSurge: 100% + maxUnavailable: 25% + template: + metadata: + labels: + chart: gateways + heritage: Tiller + release: istio + app: istio-ingressgateway + istio: ingressgateway + annotations: + sidecar.istio.io/inject: "false" + spec: + serviceAccountName: istio-ingressgateway-service-account + containers: + - name: istio-proxy + image: "docker.io/istio/proxyv2:1.3.5" + imagePullPolicy: IfNotPresent + ports: + - containerPort: 15020 + - containerPort: 80 + - containerPort: 443 + - containerPort: 31400 + - containerPort: 15029 + - containerPort: 15030 + - containerPort: 15031 + - containerPort: 15032 + - containerPort: 15443 + - containerPort: 15090 + protocol: TCP + name: http-envoy-prom + args: + - proxy + - router + - --domain + - $(POD_NAMESPACE).svc.cluster.local + - --log_output_level=default:info + - --drainDuration + - '45s' #drainDuration + - --parentShutdownDuration + - '1m0s' #parentShutdownDuration + - --connectTimeout + - '10s' #connectTimeout + - --serviceCluster + - istio-ingressgateway + - --zipkinAddress + - zipkin:9411 + - --proxyAdminPort + - "15000" + - --statusPort + - "15020" + - --controlPlaneAuthPolicy + - MUTUAL_TLS + - --discoveryAddress + - istio-pilot:15011 + readinessProbe: + failureThreshold: 30 + httpGet: + path: /healthz/ready + port: 15020 + scheme: HTTP + initialDelaySeconds: 1 + periodSeconds: 2 + successThreshold: 1 + timeoutSeconds: 1 + resources: + limits: + cpu: 2000m + memory: 1024Mi + requests: + cpu: 10m + memory: 40Mi + + env: + - name: NODE_NAME + valueFrom: + fieldRef: + apiVersion: v1 + fieldPath: spec.nodeName + - name: POD_NAME + valueFrom: + fieldRef: + apiVersion: v1 + fieldPath: metadata.name + - name: POD_NAMESPACE + valueFrom: + fieldRef: + apiVersion: v1 + fieldPath: metadata.namespace + - name: INSTANCE_IP + valueFrom: + fieldRef: + apiVersion: v1 + fieldPath: status.podIP + - name: HOST_IP + valueFrom: + fieldRef: + apiVersion: v1 + fieldPath: status.hostIP + - name: SERVICE_ACCOUNT + valueFrom: + fieldRef: + fieldPath: spec.serviceAccountName + - name: ISTIO_META_POD_NAME + valueFrom: + fieldRef: + apiVersion: v1 + fieldPath: metadata.name + - name: ISTIO_META_CONFIG_NAMESPACE + valueFrom: + fieldRef: + fieldPath: metadata.namespace + - name: SDS_ENABLED + value: "false" + - name: ISTIO_META_WORKLOAD_NAME + value: istio-ingressgateway + - name: ISTIO_META_OWNER + value: kubernetes://api/apps/v1/namespaces/istio-system/deployments/istio-ingressgateway + - name: ISTIO_META_ROUTER_MODE + value: sni-dnat + volumeMounts: + - name: istio-certs + mountPath: /etc/certs + readOnly: true + - name: ingressgateway-certs + mountPath: "/etc/istio/ingressgateway-certs" + readOnly: true + - name: ingressgateway-ca-certs + mountPath: "/etc/istio/ingressgateway-ca-certs" + readOnly: true + volumes: + - name: istio-certs + secret: + secretName: istio.istio-ingressgateway-service-account + optional: true + - name: ingressgateway-certs + secret: + secretName: "istio-ingressgateway-certs" + optional: true + - name: ingressgateway-ca-certs + secret: + secretName: "istio-ingressgateway-ca-certs" + optional: true + affinity: + nodeAffinity: + requiredDuringSchedulingIgnoredDuringExecution: + nodeSelectorTerms: + - matchExpressions: + - key: beta.kubernetes.io/arch + operator: In + values: + - "amd64" + - "ppc64le" + - "s390x" + preferredDuringSchedulingIgnoredDuringExecution: + - weight: 2 + preference: + matchExpressions: + - key: beta.kubernetes.io/arch + operator: In + values: + - "amd64" + - weight: 2 + preference: + matchExpressions: + - key: beta.kubernetes.io/arch + operator: In + values: + - "ppc64le" + - weight: 2 + preference: + matchExpressions: + - key: beta.kubernetes.io/arch + operator: In + values: + - "s390x" +--- + +--- +# Source: istio/charts/grafana/templates/deployment.yaml +apiVersion: apps/v1 +kind: Deployment +metadata: + name: grafana + namespace: istio-system + labels: + app: grafana + chart: grafana + heritage: Tiller + release: istio +spec: + replicas: 1 + selector: + matchLabels: + app: grafana + template: + metadata: + labels: + app: grafana + chart: grafana + heritage: Tiller + release: istio + annotations: + sidecar.istio.io/inject: "false" + prometheus.io/scrape: "true" + spec: + securityContext: + runAsUser: 472 + fsGroup: 472 + containers: + - name: grafana + image: "grafana/grafana:6.1.6" + imagePullPolicy: IfNotPresent + ports: + - containerPort: 3000 + readinessProbe: + httpGet: + path: /api/health + port: 3000 + env: + - name: GRAFANA_PORT + value: "3000" + - name: GF_AUTH_BASIC_ENABLED + value: "false" + - name: GF_AUTH_ANONYMOUS_ENABLED + value: "true" + - name: GF_AUTH_ANONYMOUS_ORG_ROLE + value: Admin + - name: GF_PATHS_DATA + value: /data/grafana + resources: + requests: + cpu: 10m + + volumeMounts: + - name: data + mountPath: /data/grafana + - name: dashboards-istio-citadel-dashboard + mountPath: "/var/lib/grafana/dashboards/istio/citadel-dashboard.json" + subPath: citadel-dashboard.json + readOnly: true + - name: dashboards-istio-galley-dashboard + mountPath: "/var/lib/grafana/dashboards/istio/galley-dashboard.json" + subPath: galley-dashboard.json + readOnly: true + - name: dashboards-istio-istio-mesh-dashboard + mountPath: "/var/lib/grafana/dashboards/istio/istio-mesh-dashboard.json" + subPath: istio-mesh-dashboard.json + readOnly: true + - name: dashboards-istio-istio-performance-dashboard + mountPath: "/var/lib/grafana/dashboards/istio/istio-performance-dashboard.json" + subPath: istio-performance-dashboard.json + readOnly: true + - name: dashboards-istio-istio-service-dashboard + mountPath: "/var/lib/grafana/dashboards/istio/istio-service-dashboard.json" + subPath: istio-service-dashboard.json + readOnly: true + - name: dashboards-istio-istio-workload-dashboard + mountPath: "/var/lib/grafana/dashboards/istio/istio-workload-dashboard.json" + subPath: istio-workload-dashboard.json + readOnly: true + - name: dashboards-istio-mixer-dashboard + mountPath: "/var/lib/grafana/dashboards/istio/mixer-dashboard.json" + subPath: mixer-dashboard.json + readOnly: true + - name: dashboards-istio-pilot-dashboard + mountPath: "/var/lib/grafana/dashboards/istio/pilot-dashboard.json" + subPath: pilot-dashboard.json + readOnly: true + - name: config + mountPath: "/etc/grafana/provisioning/datasources/datasources.yaml" + subPath: datasources.yaml + - name: config + mountPath: "/etc/grafana/provisioning/dashboards/dashboardproviders.yaml" + subPath: dashboardproviders.yaml + affinity: + nodeAffinity: + requiredDuringSchedulingIgnoredDuringExecution: + nodeSelectorTerms: + - matchExpressions: + - key: beta.kubernetes.io/arch + operator: In + values: + - "amd64" + - "ppc64le" + - "s390x" + preferredDuringSchedulingIgnoredDuringExecution: + - weight: 2 + preference: + matchExpressions: + - key: beta.kubernetes.io/arch + operator: In + values: + - "amd64" + - weight: 2 + preference: + matchExpressions: + - key: beta.kubernetes.io/arch + operator: In + values: + - "ppc64le" + - weight: 2 + preference: + matchExpressions: + - key: beta.kubernetes.io/arch + operator: In + values: + - "s390x" + volumes: + - name: config + configMap: + name: istio-grafana + - name: data + emptyDir: {} + - name: dashboards-istio-citadel-dashboard + configMap: + name: istio-grafana-configuration-dashboards-citadel-dashboard + - name: dashboards-istio-galley-dashboard + configMap: + name: istio-grafana-configuration-dashboards-galley-dashboard + - name: dashboards-istio-istio-mesh-dashboard + configMap: + name: istio-grafana-configuration-dashboards-istio-mesh-dashboard + - name: dashboards-istio-istio-performance-dashboard + configMap: + name: istio-grafana-configuration-dashboards-istio-performance-dashboard + - name: dashboards-istio-istio-service-dashboard + configMap: + name: istio-grafana-configuration-dashboards-istio-service-dashboard + - name: dashboards-istio-istio-workload-dashboard + configMap: + name: istio-grafana-configuration-dashboards-istio-workload-dashboard + - name: dashboards-istio-mixer-dashboard + configMap: + name: istio-grafana-configuration-dashboards-mixer-dashboard + - name: dashboards-istio-pilot-dashboard + configMap: + name: istio-grafana-configuration-dashboards-pilot-dashboard + +--- +# Source: istio/charts/kiali/templates/deployment.yaml +apiVersion: apps/v1 +kind: Deployment +metadata: + name: kiali + namespace: istio-system + labels: + app: kiali + chart: kiali + heritage: Tiller + release: istio +spec: + replicas: 1 + selector: + matchLabels: + app: kiali + template: + metadata: + name: kiali + labels: + app: kiali + chart: kiali + heritage: Tiller + release: istio + annotations: + sidecar.istio.io/inject: "false" + scheduler.alpha.kubernetes.io/critical-pod: "" + prometheus.io/scrape: "true" + prometheus.io/port: "9090" + kiali.io/runtimes: go,kiali + spec: + serviceAccountName: kiali-service-account + containers: + - image: "quay.io/kiali/kiali:v1.4" + imagePullPolicy: IfNotPresent + name: kiali + command: + - "/opt/kiali/kiali" + - "-config" + - "/kiali-configuration/config.yaml" + - "-v" + - "3" + readinessProbe: + httpGet: + path: /kiali/healthz + port: 20001 + scheme: 'HTTP' + initialDelaySeconds: 5 + periodSeconds: 30 + livenessProbe: + httpGet: + path: /kiali/healthz + port: 20001 + scheme: 'HTTP' + initialDelaySeconds: 5 + periodSeconds: 30 + env: + - name: ACTIVE_NAMESPACE + valueFrom: + fieldRef: + fieldPath: metadata.namespace + volumeMounts: + - name: kiali-configuration + mountPath: "/kiali-configuration" + - name: kiali-cert + mountPath: "/kiali-cert" + - name: kiali-secret + mountPath: "/kiali-secret" + resources: + requests: + cpu: 10m + + volumes: + - name: kiali-configuration + configMap: + name: kiali + - name: kiali-cert + secret: + secretName: istio.kiali-service-account + optional: true + - name: kiali-secret + secret: + secretName: kiali + optional: true + affinity: + nodeAffinity: + requiredDuringSchedulingIgnoredDuringExecution: + nodeSelectorTerms: + - matchExpressions: + - key: beta.kubernetes.io/arch + operator: In + values: + - "amd64" + - "ppc64le" + - "s390x" + preferredDuringSchedulingIgnoredDuringExecution: + - weight: 2 + preference: + matchExpressions: + - key: beta.kubernetes.io/arch + operator: In + values: + - "amd64" + - weight: 2 + preference: + matchExpressions: + - key: beta.kubernetes.io/arch + operator: In + values: + - "ppc64le" + - weight: 2 + preference: + matchExpressions: + - key: beta.kubernetes.io/arch + operator: In + values: + - "s390x" + +--- +# Source: istio/charts/mixer/templates/deployment.yaml + +apiVersion: apps/v1 +kind: Deployment +metadata: + name: istio-policy + namespace: istio-system + labels: + app: istio-mixer + chart: mixer + heritage: Tiller + release: istio + istio: mixer +spec: + replicas: 1 + strategy: + rollingUpdate: + maxSurge: 100% + maxUnavailable: 25% + selector: + matchLabels: + istio: mixer + istio-mixer-type: policy + template: + metadata: + labels: + app: policy + chart: mixer + heritage: Tiller + release: istio + istio: mixer + istio-mixer-type: policy + annotations: + sidecar.istio.io/inject: "false" + spec: + serviceAccountName: istio-mixer-service-account + volumes: + - name: istio-certs + secret: + secretName: istio.istio-mixer-service-account + optional: true + - name: uds-socket + emptyDir: {} + - name: policy-adapter-secret + secret: + secretName: policy-adapter-secret + optional: true + affinity: + nodeAffinity: + requiredDuringSchedulingIgnoredDuringExecution: + nodeSelectorTerms: + - matchExpressions: + - key: beta.kubernetes.io/arch + operator: In + values: + - "amd64" + - "ppc64le" + - "s390x" + preferredDuringSchedulingIgnoredDuringExecution: + - weight: 2 + preference: + matchExpressions: + - key: beta.kubernetes.io/arch + operator: In + values: + - "amd64" + - weight: 2 + preference: + matchExpressions: + - key: beta.kubernetes.io/arch + operator: In + values: + - "ppc64le" + - weight: 2 + preference: + matchExpressions: + - key: beta.kubernetes.io/arch + operator: In + values: + - "s390x" + containers: + - name: mixer + image: "docker.io/istio/mixer:1.3.5" + imagePullPolicy: IfNotPresent + ports: + - containerPort: 15014 + - containerPort: 42422 + args: + - --monitoringPort=15014 + - --address + - unix:///sock/mixer.socket + - --log_output_level=default:info + - --configStoreURL=mcps://istio-galley.istio-system.svc:9901 + - --configDefaultNamespace=istio-system + - --useAdapterCRDs=false + - --useTemplateCRDs=false + - --trace_zipkin_url=http://zipkin.istio-system:9411/api/v1/spans + env: + - name: GODEBUG + value: "gctrace=1" + - name: GOMAXPROCS + value: "6" + resources: + requests: + cpu: 10m + memory: 100Mi + + volumeMounts: + - name: istio-certs + mountPath: /etc/certs + readOnly: true + - name: uds-socket + mountPath: /sock + livenessProbe: + httpGet: + path: /version + port: 15014 + initialDelaySeconds: 5 + periodSeconds: 5 + - name: istio-proxy + image: "docker.io/istio/proxyv2:1.3.5" + imagePullPolicy: IfNotPresent + ports: + - containerPort: 9091 + - containerPort: 15004 + - containerPort: 15090 + protocol: TCP + name: http-envoy-prom + args: + - proxy + - --domain + - $(POD_NAMESPACE).svc.cluster.local + - --serviceCluster + - istio-policy + - --templateFile + - /etc/istio/proxy/envoy_policy.yaml.tmpl + - --controlPlaneAuthPolicy + - MUTUAL_TLS + env: + - name: POD_NAME + valueFrom: + fieldRef: + apiVersion: v1 + fieldPath: metadata.name + - name: POD_NAMESPACE + valueFrom: + fieldRef: + apiVersion: v1 + fieldPath: metadata.namespace + - name: INSTANCE_IP + valueFrom: + fieldRef: + apiVersion: v1 + fieldPath: status.podIP + - name: SDS_ENABLED + value: "false" + resources: + limits: + cpu: 2000m + memory: 1024Mi + requests: + cpu: 10m + memory: 40Mi + + volumeMounts: + - name: istio-certs + mountPath: /etc/certs + readOnly: true + - name: uds-socket + mountPath: /sock + - name: policy-adapter-secret + mountPath: /var/run/secrets/istio.io/policy/adapter + readOnly: true + +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: istio-telemetry + namespace: istio-system + labels: + app: istio-mixer + chart: mixer + heritage: Tiller + release: istio + istio: mixer +spec: + replicas: 1 + strategy: + rollingUpdate: + maxSurge: 100% + maxUnavailable: 25% + selector: + matchLabels: + istio: mixer + istio-mixer-type: telemetry + template: + metadata: + labels: + app: telemetry + chart: mixer + heritage: Tiller + release: istio + istio: mixer + istio-mixer-type: telemetry + annotations: + sidecar.istio.io/inject: "false" + spec: + serviceAccountName: istio-mixer-service-account + volumes: + - name: istio-certs + secret: + secretName: istio.istio-mixer-service-account + optional: true + - name: uds-socket + emptyDir: {} + - name: telemetry-adapter-secret + secret: + secretName: telemetry-adapter-secret + optional: true + affinity: + nodeAffinity: + requiredDuringSchedulingIgnoredDuringExecution: + nodeSelectorTerms: + - matchExpressions: + - key: beta.kubernetes.io/arch + operator: In + values: + - "amd64" + - "ppc64le" + - "s390x" + preferredDuringSchedulingIgnoredDuringExecution: + - weight: 2 + preference: + matchExpressions: + - key: beta.kubernetes.io/arch + operator: In + values: + - "amd64" + - weight: 2 + preference: + matchExpressions: + - key: beta.kubernetes.io/arch + operator: In + values: + - "ppc64le" + - weight: 2 + preference: + matchExpressions: + - key: beta.kubernetes.io/arch + operator: In + values: + - "s390x" + containers: + - name: mixer + image: "docker.io/istio/mixer:1.3.5" + imagePullPolicy: IfNotPresent + ports: + - containerPort: 15014 + - containerPort: 42422 + args: + - --monitoringPort=15014 + - --address + - unix:///sock/mixer.socket + - --log_output_level=default:info + - --configStoreURL=mcps://istio-galley.istio-system.svc:9901 + - --certFile=/etc/certs/cert-chain.pem + - --keyFile=/etc/certs/key.pem + - --caCertFile=/etc/certs/root-cert.pem + - --configDefaultNamespace=istio-system + - --useAdapterCRDs=false + - --trace_zipkin_url=http://zipkin.istio-system:9411/api/v1/spans + - --averageLatencyThreshold + - 100ms + - --loadsheddingMode + - enforce + env: + - name: GODEBUG + value: "gctrace=1" + - name: GOMAXPROCS + value: "6" + resources: + limits: + cpu: 4800m + memory: 4G + requests: + cpu: 50m + memory: 100Mi + + volumeMounts: + - name: istio-certs + mountPath: /etc/certs + readOnly: true + - name: telemetry-adapter-secret + mountPath: /var/run/secrets/istio.io/telemetry/adapter + readOnly: true + - name: uds-socket + mountPath: /sock + livenessProbe: + httpGet: + path: /version + port: 15014 + initialDelaySeconds: 5 + periodSeconds: 5 + - name: istio-proxy + image: "docker.io/istio/proxyv2:1.3.5" + imagePullPolicy: IfNotPresent + ports: + - containerPort: 9091 + - containerPort: 15004 + - containerPort: 15090 + protocol: TCP + name: http-envoy-prom + args: + - proxy + - --domain + - $(POD_NAMESPACE).svc.cluster.local + - --serviceCluster + - istio-telemetry + - --templateFile + - /etc/istio/proxy/envoy_telemetry.yaml.tmpl + - --controlPlaneAuthPolicy + - MUTUAL_TLS + env: + - name: POD_NAME + valueFrom: + fieldRef: + apiVersion: v1 + fieldPath: metadata.name + - name: POD_NAMESPACE + valueFrom: + fieldRef: + apiVersion: v1 + fieldPath: metadata.namespace + - name: INSTANCE_IP + valueFrom: + fieldRef: + apiVersion: v1 + fieldPath: status.podIP + - name: SDS_ENABLED + value: "false" + resources: + limits: + cpu: 2000m + memory: 1024Mi + requests: + cpu: 10m + memory: 40Mi + + volumeMounts: + - name: istio-certs + mountPath: /etc/certs + readOnly: true + - name: uds-socket + mountPath: /sock + +--- + +--- +# Source: istio/charts/pilot/templates/deployment.yaml +apiVersion: apps/v1 +kind: Deployment +metadata: + name: istio-pilot + namespace: istio-system + # TODO: default template doesn't have this, which one is right ? + labels: + app: pilot + chart: pilot + heritage: Tiller + release: istio + istio: pilot + annotations: + checksum/config-volume: f8da08b6b8c170dde721efd680270b2901e750d4aa186ebb6c22bef5b78a43f9 +spec: + replicas: 1 + strategy: + rollingUpdate: + maxSurge: 100% + maxUnavailable: 25% + selector: + matchLabels: + istio: pilot + template: + metadata: + labels: + app: pilot + chart: pilot + heritage: Tiller + release: istio + istio: pilot + annotations: + sidecar.istio.io/inject: "false" + spec: + serviceAccountName: istio-pilot-service-account + containers: + - name: discovery + image: "docker.io/istio/pilot:1.3.5" + imagePullPolicy: IfNotPresent + args: + - "discovery" + - --monitoringAddr=:15014 + - --log_output_level=default:info + - --domain + - cluster.local + - --secureGrpcAddr + - "" + - --keepaliveMaxServerConnectionAge + - "30m" + ports: + - containerPort: 8080 + - containerPort: 15010 + readinessProbe: + httpGet: + path: /ready + port: 8080 + initialDelaySeconds: 5 + periodSeconds: 30 + timeoutSeconds: 5 + env: + - name: POD_NAME + valueFrom: + fieldRef: + apiVersion: v1 + fieldPath: metadata.name + - name: POD_NAMESPACE + valueFrom: + fieldRef: + apiVersion: v1 + fieldPath: metadata.namespace + - name: GODEBUG + value: "gctrace=1" + - name: PILOT_PUSH_THROTTLE + value: "100" + - name: PILOT_TRACE_SAMPLING + value: "100" + - name: PILOT_ENABLE_PROTOCOL_SNIFFING_FOR_OUTBOUND + value: "true" + - name: PILOT_ENABLE_PROTOCOL_SNIFFING_FOR_INBOUND + value: "false" + resources: + requests: + cpu: 10m + memory: 100Mi + + volumeMounts: + - name: config-volume + mountPath: /etc/istio/config + - name: istio-certs + mountPath: /etc/certs + readOnly: true + - name: istio-proxy + image: "docker.io/istio/proxyv2:1.3.5" + imagePullPolicy: IfNotPresent + ports: + - containerPort: 15003 + - containerPort: 15005 + - containerPort: 15007 + - containerPort: 15011 + args: + - proxy + - --domain + - $(POD_NAMESPACE).svc.cluster.local + - --serviceCluster + - istio-pilot + - --templateFile + - /etc/istio/proxy/envoy_pilot.yaml.tmpl + - --controlPlaneAuthPolicy + - MUTUAL_TLS + env: + - name: POD_NAME + valueFrom: + fieldRef: + apiVersion: v1 + fieldPath: metadata.name + - name: POD_NAMESPACE + valueFrom: + fieldRef: + apiVersion: v1 + fieldPath: metadata.namespace + - name: INSTANCE_IP + valueFrom: + fieldRef: + apiVersion: v1 + fieldPath: status.podIP + - name: SDS_ENABLED + value: "false" + resources: + limits: + cpu: 2000m + memory: 1024Mi + requests: + cpu: 10m + memory: 40Mi + + volumeMounts: + - name: istio-certs + mountPath: /etc/certs + readOnly: true + volumes: + - name: config-volume + configMap: + name: istio + - name: istio-certs + secret: + secretName: istio.istio-pilot-service-account + optional: true + affinity: + nodeAffinity: + requiredDuringSchedulingIgnoredDuringExecution: + nodeSelectorTerms: + - matchExpressions: + - key: beta.kubernetes.io/arch + operator: In + values: + - "amd64" + - "ppc64le" + - "s390x" + preferredDuringSchedulingIgnoredDuringExecution: + - weight: 2 + preference: + matchExpressions: + - key: beta.kubernetes.io/arch + operator: In + values: + - "amd64" + - weight: 2 + preference: + matchExpressions: + - key: beta.kubernetes.io/arch + operator: In + values: + - "ppc64le" + - weight: 2 + preference: + matchExpressions: + - key: beta.kubernetes.io/arch + operator: In + values: + - "s390x" + +--- +# Source: istio/charts/prometheus/templates/deployment.yaml +# TODO: the original template has service account, roles, etc +apiVersion: apps/v1 +kind: Deployment +metadata: + name: prometheus + namespace: istio-system + labels: + app: prometheus + chart: prometheus + heritage: Tiller + release: istio +spec: + replicas: 1 + selector: + matchLabels: + app: prometheus + template: + metadata: + labels: + app: prometheus + chart: prometheus + heritage: Tiller + release: istio + annotations: + sidecar.istio.io/inject: "false" + spec: + serviceAccountName: prometheus + containers: + - name: prometheus + image: "docker.io/prom/prometheus:v2.8.0" + imagePullPolicy: IfNotPresent + args: + - '--storage.tsdb.retention=6h' + - '--config.file=/etc/prometheus/prometheus.yml' + ports: + - containerPort: 9090 + name: http + livenessProbe: + httpGet: + path: /-/healthy + port: 9090 + readinessProbe: + httpGet: + path: /-/ready + port: 9090 + resources: + requests: + cpu: 10m + + volumeMounts: + - name: config-volume + mountPath: /etc/prometheus + - mountPath: /etc/istio-certs + name: istio-certs + volumes: + - name: config-volume + configMap: + name: prometheus + - name: istio-certs + secret: + defaultMode: 420 + secretName: istio.default + affinity: + nodeAffinity: + requiredDuringSchedulingIgnoredDuringExecution: + nodeSelectorTerms: + - matchExpressions: + - key: beta.kubernetes.io/arch + operator: In + values: + - "amd64" + - "ppc64le" + - "s390x" + preferredDuringSchedulingIgnoredDuringExecution: + - weight: 2 + preference: + matchExpressions: + - key: beta.kubernetes.io/arch + operator: In + values: + - "amd64" + - weight: 2 + preference: + matchExpressions: + - key: beta.kubernetes.io/arch + operator: In + values: + - "ppc64le" + - weight: 2 + preference: + matchExpressions: + - key: beta.kubernetes.io/arch + operator: In + values: + - "s390x" + +--- +# Source: istio/charts/security/templates/deployment.yaml +# istio CA watching all namespaces +apiVersion: apps/v1 +kind: Deployment +metadata: + name: istio-citadel + namespace: istio-system + labels: + app: security + chart: security + heritage: Tiller + release: istio + istio: citadel +spec: + replicas: 1 + selector: + matchLabels: + istio: citadel + strategy: + rollingUpdate: + maxSurge: 100% + maxUnavailable: 25% + template: + metadata: + labels: + app: security + chart: security + heritage: Tiller + release: istio + istio: citadel + annotations: + sidecar.istio.io/inject: "false" + spec: + serviceAccountName: istio-citadel-service-account + containers: + - name: citadel + image: "docker.io/istio/citadel:1.3.5" + imagePullPolicy: IfNotPresent + args: + - --append-dns-names=true + - --grpc-port=8060 + - --citadel-storage-namespace=istio-system + - --custom-dns-names=istio-pilot-service-account.istio-system:istio-pilot.istio-system + - --monitoring-port=15014 + - --self-signed-ca=true + - --workload-cert-ttl=2160h + env: + - name: CITADEL_ENABLE_NAMESPACES_BY_DEFAULT + value: "true" + resources: + requests: + cpu: 10m + + affinity: + nodeAffinity: + requiredDuringSchedulingIgnoredDuringExecution: + nodeSelectorTerms: + - matchExpressions: + - key: beta.kubernetes.io/arch + operator: In + values: + - "amd64" + - "ppc64le" + - "s390x" + preferredDuringSchedulingIgnoredDuringExecution: + - weight: 2 + preference: + matchExpressions: + - key: beta.kubernetes.io/arch + operator: In + values: + - "amd64" + - weight: 2 + preference: + matchExpressions: + - key: beta.kubernetes.io/arch + operator: In + values: + - "ppc64le" + - weight: 2 + preference: + matchExpressions: + - key: beta.kubernetes.io/arch + operator: In + values: + - "s390x" + +--- +# Source: istio/charts/sidecarInjectorWebhook/templates/deployment.yaml +apiVersion: apps/v1 +kind: Deployment +metadata: + name: istio-sidecar-injector + namespace: istio-system + labels: + app: sidecarInjectorWebhook + chart: sidecarInjectorWebhook + heritage: Tiller + release: istio + istio: sidecar-injector +spec: + replicas: 1 + selector: + matchLabels: + istio: sidecar-injector + strategy: + rollingUpdate: + maxSurge: 100% + maxUnavailable: 25% + template: + metadata: + labels: + app: sidecarInjectorWebhook + chart: sidecarInjectorWebhook + heritage: Tiller + release: istio + istio: sidecar-injector + annotations: + sidecar.istio.io/inject: "false" + spec: + serviceAccountName: istio-sidecar-injector-service-account + containers: + - name: sidecar-injector-webhook + image: "docker.io/istio/sidecar_injector:1.3.5" + imagePullPolicy: IfNotPresent + args: + - --caCertFile=/etc/istio/certs/root-cert.pem + - --tlsCertFile=/etc/istio/certs/cert-chain.pem + - --tlsKeyFile=/etc/istio/certs/key.pem + - --injectConfig=/etc/istio/inject/config + - --meshConfig=/etc/istio/config/mesh + - --healthCheckInterval=2s + - --healthCheckFile=/health + volumeMounts: + - name: config-volume + mountPath: /etc/istio/config + readOnly: true + - name: certs + mountPath: /etc/istio/certs + readOnly: true + - name: inject-config + mountPath: /etc/istio/inject + readOnly: true + livenessProbe: + exec: + command: + - /usr/local/bin/sidecar-injector + - probe + - --probe-path=/health + - --interval=4s + initialDelaySeconds: 4 + periodSeconds: 4 + readinessProbe: + exec: + command: + - /usr/local/bin/sidecar-injector + - probe + - --probe-path=/health + - --interval=4s + initialDelaySeconds: 4 + periodSeconds: 4 + resources: + requests: + cpu: 10m + + volumes: + - name: config-volume + configMap: + name: istio + - name: certs + secret: + secretName: istio.istio-sidecar-injector-service-account + - name: inject-config + configMap: + name: istio-sidecar-injector + items: + - key: config + path: config + - key: values + path: values + affinity: + nodeAffinity: + requiredDuringSchedulingIgnoredDuringExecution: + nodeSelectorTerms: + - matchExpressions: + - key: beta.kubernetes.io/arch + operator: In + values: + - "amd64" + - "ppc64le" + - "s390x" + preferredDuringSchedulingIgnoredDuringExecution: + - weight: 2 + preference: + matchExpressions: + - key: beta.kubernetes.io/arch + operator: In + values: + - "amd64" + - weight: 2 + preference: + matchExpressions: + - key: beta.kubernetes.io/arch + operator: In + values: + - "ppc64le" + - weight: 2 + preference: + matchExpressions: + - key: beta.kubernetes.io/arch + operator: In + values: + - "s390x" + +--- +# Source: istio/charts/tracing/templates/deployment-jaeger.yaml + + +apiVersion: apps/v1 +kind: Deployment +metadata: + name: istio-tracing + namespace: istio-system + labels: + app: jaeger + chart: tracing + heritage: Tiller + release: istio +spec: + selector: + matchLabels: + app: jaeger + template: + metadata: + labels: + app: jaeger + chart: tracing + heritage: Tiller + release: istio + annotations: + sidecar.istio.io/inject: "false" + prometheus.io/scrape: "true" + prometheus.io/port: "14269" + spec: + containers: + - name: jaeger + image: "docker.io/jaegertracing/all-in-one:1.14" + imagePullPolicy: IfNotPresent + ports: + - containerPort: 9411 + - containerPort: 16686 + - containerPort: 14250 + - containerPort: 14267 + - containerPort: 14268 + - containerPort: 14269 + - containerPort: 5775 + protocol: UDP + - containerPort: 6831 + protocol: UDP + - containerPort: 6832 + protocol: UDP + env: + - name: POD_NAMESPACE + valueFrom: + fieldRef: + apiVersion: v1 + fieldPath: metadata.namespace + - name: BADGER_EPHEMERAL + value: "false" + - name: SPAN_STORAGE_TYPE + value: "badger" + - name: BADGER_DIRECTORY_VALUE + value: "/badger/data" + - name: BADGER_DIRECTORY_KEY + value: "/badger/key" + - name: COLLECTOR_ZIPKIN_HTTP_PORT + value: "9411" + - name: MEMORY_MAX_TRACES + value: "50000" + - name: QUERY_BASE_PATH + value: /jaeger + livenessProbe: + httpGet: + path: / + port: 14269 + readinessProbe: + httpGet: + path: / + port: 14269 + volumeMounts: + - name: data + mountPath: /badger + resources: + requests: + cpu: 10m + + affinity: + nodeAffinity: + requiredDuringSchedulingIgnoredDuringExecution: + nodeSelectorTerms: + - matchExpressions: + - key: beta.kubernetes.io/arch + operator: In + values: + - "amd64" + - "ppc64le" + - "s390x" + preferredDuringSchedulingIgnoredDuringExecution: + - weight: 2 + preference: + matchExpressions: + - key: beta.kubernetes.io/arch + operator: In + values: + - "amd64" + - weight: 2 + preference: + matchExpressions: + - key: beta.kubernetes.io/arch + operator: In + values: + - "ppc64le" + - weight: 2 + preference: + matchExpressions: + - key: beta.kubernetes.io/arch + operator: In + values: + - "s390x" + volumes: + - name: data + emptyDir: {} + + +--- +# Source: istio/charts/tracing/templates/service-jaeger.yaml + + +apiVersion: v1 +kind: List +metadata: + name: jaeger-services + namespace: istio-system + labels: + app: jaeger + chart: tracing + heritage: Tiller + release: istio +items: +- apiVersion: v1 + kind: Service + metadata: + name: jaeger-query + namespace: istio-system + annotations: + labels: + app: jaeger + jaeger-infra: jaeger-service + chart: tracing + heritage: Tiller + release: istio + spec: + ports: + - name: query-http + port: 16686 + protocol: TCP + targetPort: 16686 + selector: + app: jaeger +- apiVersion: v1 + kind: Service + metadata: + name: jaeger-collector + namespace: istio-system + labels: + app: jaeger + jaeger-infra: collector-service + chart: tracing + heritage: Tiller + release: istio + spec: + ports: + - name: jaeger-collector-tchannel + port: 14267 + protocol: TCP + targetPort: 14267 + - name: jaeger-collector-http + port: 14268 + targetPort: 14268 + protocol: TCP + - name: jaeger-collector-grpc + port: 14250 + targetPort: 14250 + protocol: TCP + selector: + app: jaeger + type: ClusterIP +- apiVersion: v1 + kind: Service + metadata: + name: jaeger-agent + namespace: istio-system + labels: + app: jaeger + jaeger-infra: agent-service + chart: tracing + heritage: Tiller + release: istio + spec: + ports: + - name: agent-zipkin-thrift + port: 5775 + protocol: UDP + targetPort: 5775 + - name: agent-compact + port: 6831 + protocol: UDP + targetPort: 6831 + - name: agent-binary + port: 6832 + protocol: UDP + targetPort: 6832 + clusterIP: None + selector: + app: jaeger + + + +--- +# Source: istio/charts/tracing/templates/service.yaml +apiVersion: v1 +kind: List +metadata: + name: tracing-services + namespace: istio-system + labels: + app: jaeger + chart: tracing + heritage: Tiller + release: istio +items: +- apiVersion: v1 + kind: Service + metadata: + name: zipkin + namespace: istio-system + labels: + app: jaeger + chart: tracing + heritage: Tiller + release: istio + spec: + type: ClusterIP + ports: + - port: 9411 + targetPort: 9411 + protocol: TCP + name: http + selector: + app: jaeger +- apiVersion: v1 + kind: Service + metadata: + name: tracing + namespace: istio-system + annotations: + labels: + app: jaeger + chart: tracing + heritage: Tiller + release: istio + spec: + ports: + - name: http-query + port: 80 + protocol: TCP + + targetPort: 16686 + + selector: + app: jaeger + +--- +# Source: istio/charts/sidecarInjectorWebhook/templates/mutatingwebhook.yaml +apiVersion: admissionregistration.k8s.io/v1beta1 +kind: MutatingWebhookConfiguration +metadata: + name: istio-sidecar-injector + labels: + app: sidecarInjectorWebhook + chart: sidecarInjectorWebhook + heritage: Tiller + release: istio +webhooks: + - name: sidecar-injector.istio.io + clientConfig: + service: + name: istio-sidecar-injector + namespace: istio-system + path: "/inject" + caBundle: "" + rules: + - operations: [ "CREATE" ] + apiGroups: [""] + apiVersions: ["v1"] + resources: ["pods"] + failurePolicy: Fail + namespaceSelector: + matchLabels: + istio-injection: enabled + + +--- +# Source: istio/charts/galley/templates/poddisruptionbudget.yaml + +apiVersion: policy/v1beta1 +kind: PodDisruptionBudget +metadata: + name: istio-galley + namespace: istio-system + labels: + app: galley + chart: galley + heritage: Tiller + release: istio + istio: galley +spec: + + minAvailable: 1 + selector: + matchLabels: + app: galley + release: istio + istio: galley + +--- +# Source: istio/charts/gateways/templates/poddisruptionbudget.yaml + +apiVersion: policy/v1beta1 +kind: PodDisruptionBudget +metadata: + name: istio-egressgateway + namespace: istio-system + labels: + chart: gateways + heritage: Tiller + release: istio + app: istio-egressgateway + istio: egressgateway +spec: + + minAvailable: 1 + selector: + matchLabels: + release: istio + app: istio-egressgateway + istio: egressgateway +--- +apiVersion: policy/v1beta1 +kind: PodDisruptionBudget +metadata: + name: istio-ingressgateway + namespace: istio-system + labels: + chart: gateways + heritage: Tiller + release: istio + app: istio-ingressgateway + istio: ingressgateway +spec: + + minAvailable: 1 + selector: + matchLabels: + release: istio + app: istio-ingressgateway + istio: ingressgateway +--- + +--- +# Source: istio/charts/mixer/templates/poddisruptionbudget.yaml + +apiVersion: policy/v1beta1 +kind: PodDisruptionBudget +metadata: + name: istio-policy + namespace: istio-system + labels: + app: policy + chart: mixer + heritage: Tiller + release: istio + version: 1.1.0 + istio: mixer + istio-mixer-type: policy +spec: + + minAvailable: 1 + selector: + matchLabels: + app: policy + release: istio + istio: mixer + istio-mixer-type: policy +--- +apiVersion: policy/v1beta1 +kind: PodDisruptionBudget +metadata: + name: istio-telemetry + namespace: istio-system + labels: + app: telemetry + chart: mixer + heritage: Tiller + release: istio + version: 1.1.0 + istio: mixer + istio-mixer-type: telemetry +spec: + + minAvailable: 1 + selector: + matchLabels: + app: telemetry + release: istio + istio: mixer + istio-mixer-type: telemetry +--- + +--- +# Source: istio/charts/pilot/templates/poddisruptionbudget.yaml + +apiVersion: policy/v1beta1 +kind: PodDisruptionBudget +metadata: + name: istio-pilot + namespace: istio-system + labels: + app: pilot + chart: pilot + heritage: Tiller + release: istio + istio: pilot +spec: + + minAvailable: 1 + selector: + matchLabels: + app: pilot + release: istio + istio: pilot + +--- +# Source: istio/charts/sidecarInjectorWebhook/templates/poddisruptionbudget.yaml + +apiVersion: policy/v1beta1 +kind: PodDisruptionBudget +metadata: + name: istio-sidecar-injector + namespace: istio-system + labels: + app: sidecarInjectorWebhook + release: istio + istio: sidecar-injector +spec: + + minAvailable: 1 + selector: + matchLabels: + app: sidecarInjectorWebhook + release: istio + istio: sidecar-injector +--- +# Source: istio/charts/galley/templates/validatingwebhookconfiguration.yaml.tpl + + +--- +# Source: istio/charts/gateways/templates/autoscale.yaml + + +--- +# Source: istio/charts/gateways/templates/preconfigured.yaml + + +--- +# Source: istio/charts/grafana/templates/grafana-ports-mtls.yaml + + +--- +# Source: istio/charts/grafana/templates/ingress.yaml + +--- +# Source: istio/charts/grafana/templates/pvc.yaml + + +--- +# Source: istio/charts/grafana/templates/tests/test-grafana-connection.yaml + + +--- +# Source: istio/charts/kiali/templates/ingress.yaml + +--- +# Source: istio/charts/kiali/templates/tests/test-kiali-connection.yaml + + +--- +# Source: istio/charts/mixer/templates/autoscale.yaml + + +--- +# Source: istio/charts/pilot/templates/autoscale.yaml + + +--- +# Source: istio/charts/pilot/templates/meshexpansion.yaml + + + +--- +# Source: istio/charts/prometheus/templates/ingress.yaml + +--- +# Source: istio/charts/prometheus/templates/tests/test-prometheus-connection.yaml + + +--- +# Source: istio/charts/security/templates/enable-mesh-mtls.yaml + + +--- +# Source: istio/charts/security/templates/enable-mesh-permissive.yaml + + +--- +# Source: istio/charts/security/templates/meshexpansion.yaml + + +--- +# Source: istio/charts/security/templates/tests/test-citadel-connection.yaml + + +--- +# Source: istio/charts/tracing/templates/deployment-zipkin.yaml + + +--- +# Source: istio/charts/tracing/templates/ingress.yaml + +--- +# Source: istio/charts/tracing/templates/pvc.yaml + + +--- +# Source: istio/charts/tracing/templates/tests/test-tracing-connection.yaml + + +--- +# Source: istio/templates/endpoints.yaml + + +--- +# Source: istio/templates/install-custom-resources.sh.tpl + + +--- +# Source: istio/templates/service.yaml + + +--- +# Source: istio/charts/mixer/templates/config.yaml + +apiVersion: "config.istio.io/v1alpha2" +kind: attributemanifest +metadata: + name: istioproxy + namespace: istio-system + labels: + app: mixer + chart: mixer + heritage: Tiller + release: istio +spec: + attributes: + origin.ip: + valueType: IP_ADDRESS + origin.uid: + valueType: STRING + origin.user: + valueType: STRING + request.headers: + valueType: STRING_MAP + request.id: + valueType: STRING + request.host: + valueType: STRING + request.method: + valueType: STRING + request.path: + valueType: STRING + request.url_path: + valueType: STRING + request.query_params: + valueType: STRING_MAP + request.reason: + valueType: STRING + request.referer: + valueType: STRING + request.scheme: + valueType: STRING + request.total_size: + valueType: INT64 + request.size: + valueType: INT64 + request.time: + valueType: TIMESTAMP + request.useragent: + valueType: STRING + response.code: + valueType: INT64 + response.duration: + valueType: DURATION + response.headers: + valueType: STRING_MAP + response.total_size: + valueType: INT64 + response.size: + valueType: INT64 + response.time: + valueType: TIMESTAMP + response.grpc_status: + valueType: STRING + response.grpc_message: + valueType: STRING + source.uid: + valueType: STRING + source.user: # DEPRECATED + valueType: STRING + source.principal: + valueType: STRING + destination.uid: + valueType: STRING + destination.principal: + valueType: STRING + destination.port: + valueType: INT64 + connection.event: + valueType: STRING + connection.id: + valueType: STRING + connection.received.bytes: + valueType: INT64 + connection.received.bytes_total: + valueType: INT64 + connection.sent.bytes: + valueType: INT64 + connection.sent.bytes_total: + valueType: INT64 + connection.duration: + valueType: DURATION + connection.mtls: + valueType: BOOL + connection.requested_server_name: + valueType: STRING + context.protocol: + valueType: STRING + context.proxy_error_code: + valueType: STRING + context.timestamp: + valueType: TIMESTAMP + context.time: + valueType: TIMESTAMP + # Deprecated, kept for compatibility + context.reporter.local: + valueType: BOOL + context.reporter.kind: + valueType: STRING + context.reporter.uid: + valueType: STRING + api.service: + valueType: STRING + api.version: + valueType: STRING + api.operation: + valueType: STRING + api.protocol: + valueType: STRING + request.auth.principal: + valueType: STRING + request.auth.audiences: + valueType: STRING + request.auth.presenter: + valueType: STRING + request.auth.claims: + valueType: STRING_MAP + request.auth.raw_claims: + valueType: STRING + request.api_key: + valueType: STRING + rbac.permissive.response_code: + valueType: STRING + rbac.permissive.effective_policy_id: + valueType: STRING + check.error_code: + valueType: INT64 + check.error_message: + valueType: STRING + check.cache_hit: + valueType: BOOL + quota.cache_hit: + valueType: BOOL + context.proxy_version: + valueType: STRING + +--- +apiVersion: "config.istio.io/v1alpha2" +kind: attributemanifest +metadata: + name: kubernetes + namespace: istio-system + labels: + app: mixer + chart: mixer + heritage: Tiller + release: istio +spec: + attributes: + source.ip: + valueType: IP_ADDRESS + source.labels: + valueType: STRING_MAP + source.metadata: + valueType: STRING_MAP + source.name: + valueType: STRING + source.namespace: + valueType: STRING + source.owner: + valueType: STRING + source.serviceAccount: + valueType: STRING + source.services: + valueType: STRING + source.workload.uid: + valueType: STRING + source.workload.name: + valueType: STRING + source.workload.namespace: + valueType: STRING + destination.ip: + valueType: IP_ADDRESS + destination.labels: + valueType: STRING_MAP + destination.metadata: + valueType: STRING_MAP + destination.owner: + valueType: STRING + destination.name: + valueType: STRING + destination.container.name: + valueType: STRING + destination.namespace: + valueType: STRING + destination.service.uid: + valueType: STRING + destination.service.name: + valueType: STRING + destination.service.namespace: + valueType: STRING + destination.service.host: + valueType: STRING + destination.serviceAccount: + valueType: STRING + destination.workload.uid: + valueType: STRING + destination.workload.name: + valueType: STRING + destination.workload.namespace: + valueType: STRING +--- +apiVersion: "config.istio.io/v1alpha2" +kind: handler +metadata: + name: stdio + namespace: istio-system + labels: + app: mixer + chart: mixer + heritage: Tiller + release: istio +spec: + compiledAdapter: stdio + params: + outputAsJson: true +--- +apiVersion: "config.istio.io/v1alpha2" +kind: instance +metadata: + name: accesslog + namespace: istio-system + labels: + app: mixer + chart: mixer + heritage: Tiller + release: istio +spec: + compiledTemplate: logentry + params: + severity: '"Info"' + timestamp: request.time + variables: + sourceIp: source.ip | ip("0.0.0.0") + sourceApp: source.labels["app"] | "" + sourcePrincipal: source.principal | "" + sourceName: source.name | "" + sourceWorkload: source.workload.name | "" + sourceNamespace: source.namespace | "" + sourceOwner: source.owner | "" + destinationApp: destination.labels["app"] | "" + destinationIp: destination.ip | ip("0.0.0.0") + destinationServiceHost: destination.service.host | request.host | "" + destinationWorkload: destination.workload.name | "" + destinationName: destination.name | "" + destinationNamespace: destination.namespace | "" + destinationOwner: destination.owner | "" + destinationPrincipal: destination.principal | "" + apiClaims: request.auth.raw_claims | "" + apiKey: request.api_key | request.headers["x-api-key"] | "" + protocol: request.scheme | context.protocol | "http" + method: request.method | "" + url: request.path | "" + responseCode: response.code | 0 + responseFlags: context.proxy_error_code | "" + responseSize: response.size | 0 + permissiveResponseCode: rbac.permissive.response_code | "none" + permissiveResponsePolicyID: rbac.permissive.effective_policy_id | "none" + requestSize: request.size | 0 + requestId: request.headers["x-request-id"] | "" + clientTraceId: request.headers["x-client-trace-id"] | "" + latency: response.duration | "0ms" + connection_security_policy: conditional((context.reporter.kind | "inbound") == "outbound", "unknown", conditional(connection.mtls | false, "mutual_tls", "none")) + requestedServerName: connection.requested_server_name | "" + userAgent: request.useragent | "" + responseTimestamp: response.time + receivedBytes: request.total_size | 0 + sentBytes: response.total_size | 0 + referer: request.referer | "" + httpAuthority: request.headers[":authority"] | request.host | "" + xForwardedFor: request.headers["x-forwarded-for"] | "0.0.0.0" + reporter: conditional((context.reporter.kind | "inbound") == "outbound", "source", "destination") + grpcStatus: response.grpc_status | "" + grpcMessage: response.grpc_message | "" + monitored_resource_type: '"global"' +--- +apiVersion: "config.istio.io/v1alpha2" +kind: instance +metadata: + name: tcpaccesslog + namespace: istio-system + labels: + app: mixer + chart: mixer + heritage: Tiller + release: istio +spec: + compiledTemplate: logentry + params: + severity: '"Info"' + timestamp: context.time | timestamp("2017-01-01T00:00:00Z") + variables: + connectionEvent: connection.event | "" + sourceIp: source.ip | ip("0.0.0.0") + sourceApp: source.labels["app"] | "" + sourcePrincipal: source.principal | "" + sourceName: source.name | "" + sourceWorkload: source.workload.name | "" + sourceNamespace: source.namespace | "" + sourceOwner: source.owner | "" + destinationApp: destination.labels["app"] | "" + destinationIp: destination.ip | ip("0.0.0.0") + destinationServiceHost: destination.service.host | "" + destinationWorkload: destination.workload.name | "" + destinationName: destination.name | "" + destinationNamespace: destination.namespace | "" + destinationOwner: destination.owner | "" + destinationPrincipal: destination.principal | "" + protocol: context.protocol | "tcp" + connectionDuration: connection.duration | "0ms" + connection_security_policy: conditional((context.reporter.kind | "inbound") == "outbound", "unknown", conditional(connection.mtls | false, "mutual_tls", "none")) + requestedServerName: connection.requested_server_name | "" + receivedBytes: connection.received.bytes | 0 + sentBytes: connection.sent.bytes | 0 + totalReceivedBytes: connection.received.bytes_total | 0 + totalSentBytes: connection.sent.bytes_total | 0 + reporter: conditional((context.reporter.kind | "inbound") == "outbound", "source", "destination") + responseFlags: context.proxy_error_code | "" + monitored_resource_type: '"global"' +--- +apiVersion: "config.istio.io/v1alpha2" +kind: rule +metadata: + name: stdio + namespace: istio-system + labels: + app: mixer + chart: mixer + heritage: Tiller + release: istio +spec: + match: context.protocol == "http" || context.protocol == "grpc" + actions: + - handler: stdio + instances: + - accesslog +--- +apiVersion: "config.istio.io/v1alpha2" +kind: rule +metadata: + name: stdiotcp + namespace: istio-system + labels: + app: mixer + chart: mixer + heritage: Tiller + release: istio +spec: + match: context.protocol == "tcp" + actions: + - handler: stdio + instances: + - tcpaccesslog +--- +apiVersion: "config.istio.io/v1alpha2" +kind: instance +metadata: + name: requestcount + namespace: istio-system + labels: + app: mixer + chart: mixer + heritage: Tiller + release: istio +spec: + compiledTemplate: metric + params: + value: "1" + dimensions: + reporter: conditional((context.reporter.kind | "inbound") == "outbound", "source", "destination") + source_workload: source.workload.name | "unknown" + source_workload_namespace: source.workload.namespace | "unknown" + source_principal: source.principal | "unknown" + source_app: source.labels["app"] | "unknown" + source_version: source.labels["version"] | "unknown" + destination_workload: destination.workload.name | "unknown" + destination_workload_namespace: destination.workload.namespace | "unknown" + destination_principal: destination.principal | "unknown" + destination_app: destination.labels["app"] | "unknown" + destination_version: destination.labels["version"] | "unknown" + destination_service: destination.service.host | request.host | "unknown" + destination_service_name: destination.service.name | "unknown" + destination_service_namespace: destination.service.namespace | "unknown" + request_protocol: api.protocol | context.protocol | "unknown" + response_code: response.code | 200 + response_flags: context.proxy_error_code | "-" + permissive_response_code: rbac.permissive.response_code | "none" + permissive_response_policyid: rbac.permissive.effective_policy_id | "none" + connection_security_policy: conditional((context.reporter.kind | "inbound") == "outbound", "unknown", conditional(connection.mtls | false, "mutual_tls", "none")) + monitored_resource_type: '"UNSPECIFIED"' +--- +apiVersion: "config.istio.io/v1alpha2" +kind: instance +metadata: + name: requestduration + namespace: istio-system + labels: + app: mixer + chart: mixer + heritage: Tiller + release: istio +spec: + compiledTemplate: metric + params: + value: response.duration | "0ms" + dimensions: + reporter: conditional((context.reporter.kind | "inbound") == "outbound", "source", "destination") + source_workload: source.workload.name | "unknown" + source_workload_namespace: source.workload.namespace | "unknown" + source_principal: source.principal | "unknown" + source_app: source.labels["app"] | "unknown" + source_version: source.labels["version"] | "unknown" + destination_workload: destination.workload.name | "unknown" + destination_workload_namespace: destination.workload.namespace | "unknown" + destination_principal: destination.principal | "unknown" + destination_app: destination.labels["app"] | "unknown" + destination_version: destination.labels["version"] | "unknown" + destination_service: destination.service.host | request.host | "unknown" + destination_service_name: destination.service.name | "unknown" + destination_service_namespace: destination.service.namespace | "unknown" + request_protocol: api.protocol | context.protocol | "unknown" + response_code: response.code | 200 + response_flags: context.proxy_error_code | "-" + permissive_response_code: rbac.permissive.response_code | "none" + permissive_response_policyid: rbac.permissive.effective_policy_id | "none" + connection_security_policy: conditional((context.reporter.kind | "inbound") == "outbound", "unknown", conditional(connection.mtls | false, "mutual_tls", "none")) + monitored_resource_type: '"UNSPECIFIED"' +--- +apiVersion: "config.istio.io/v1alpha2" +kind: instance +metadata: + name: requestsize + namespace: istio-system + labels: + app: mixer + chart: mixer + heritage: Tiller + release: istio +spec: + compiledTemplate: metric + params: + value: request.size | 0 + dimensions: + reporter: conditional((context.reporter.kind | "inbound") == "outbound", "source", "destination") + source_workload: source.workload.name | "unknown" + source_workload_namespace: source.workload.namespace | "unknown" + source_principal: source.principal | "unknown" + source_app: source.labels["app"] | "unknown" + source_version: source.labels["version"] | "unknown" + destination_workload: destination.workload.name | "unknown" + destination_workload_namespace: destination.workload.namespace | "unknown" + destination_principal: destination.principal | "unknown" + destination_app: destination.labels["app"] | "unknown" + destination_version: destination.labels["version"] | "unknown" + destination_service: destination.service.host | request.host | "unknown" + destination_service_name: destination.service.name | "unknown" + destination_service_namespace: destination.service.namespace | "unknown" + request_protocol: api.protocol | context.protocol | "unknown" + response_code: response.code | 200 + response_flags: context.proxy_error_code | "-" + permissive_response_code: rbac.permissive.response_code | "none" + permissive_response_policyid: rbac.permissive.effective_policy_id | "none" + connection_security_policy: conditional((context.reporter.kind | "inbound") == "outbound", "unknown", conditional(connection.mtls | false, "mutual_tls", "none")) + monitored_resource_type: '"UNSPECIFIED"' +--- +apiVersion: "config.istio.io/v1alpha2" +kind: instance +metadata: + name: responsesize + namespace: istio-system + labels: + app: mixer + chart: mixer + heritage: Tiller + release: istio +spec: + compiledTemplate: metric + params: + value: response.size | 0 + dimensions: + reporter: conditional((context.reporter.kind | "inbound") == "outbound", "source", "destination") + source_workload: source.workload.name | "unknown" + source_workload_namespace: source.workload.namespace | "unknown" + source_principal: source.principal | "unknown" + source_app: source.labels["app"] | "unknown" + source_version: source.labels["version"] | "unknown" + destination_workload: destination.workload.name | "unknown" + destination_workload_namespace: destination.workload.namespace | "unknown" + destination_principal: destination.principal | "unknown" + destination_app: destination.labels["app"] | "unknown" + destination_version: destination.labels["version"] | "unknown" + destination_service: destination.service.host | request.host | "unknown" + destination_service_name: destination.service.name | "unknown" + destination_service_namespace: destination.service.namespace | "unknown" + request_protocol: api.protocol | context.protocol | "unknown" + response_code: response.code | 200 + response_flags: context.proxy_error_code | "-" + permissive_response_code: rbac.permissive.response_code | "none" + permissive_response_policyid: rbac.permissive.effective_policy_id | "none" + connection_security_policy: conditional((context.reporter.kind | "inbound") == "outbound", "unknown", conditional(connection.mtls | false, "mutual_tls", "none")) + monitored_resource_type: '"UNSPECIFIED"' +--- +apiVersion: "config.istio.io/v1alpha2" +kind: instance +metadata: + name: tcpbytesent + namespace: istio-system + labels: + app: mixer + chart: mixer + heritage: Tiller + release: istio +spec: + compiledTemplate: metric + params: + value: connection.sent.bytes | 0 + dimensions: + reporter: conditional((context.reporter.kind | "inbound") == "outbound", "source", "destination") + source_workload: source.workload.name | "unknown" + source_workload_namespace: source.workload.namespace | "unknown" + source_principal: source.principal | "unknown" + source_app: source.labels["app"] | "unknown" + source_version: source.labels["version"] | "unknown" + destination_workload: destination.workload.name | "unknown" + destination_workload_namespace: destination.workload.namespace | "unknown" + destination_principal: destination.principal | "unknown" + destination_app: destination.labels["app"] | "unknown" + destination_version: destination.labels["version"] | "unknown" + destination_service: destination.service.host | "unknown" + destination_service_name: destination.service.name | "unknown" + destination_service_namespace: destination.service.namespace | "unknown" + connection_security_policy: conditional((context.reporter.kind | "inbound") == "outbound", "unknown", conditional(connection.mtls | false, "mutual_tls", "none")) + response_flags: context.proxy_error_code | "-" + monitored_resource_type: '"UNSPECIFIED"' +--- +apiVersion: "config.istio.io/v1alpha2" +kind: instance +metadata: + name: tcpbytereceived + namespace: istio-system + labels: + app: mixer + chart: mixer + heritage: Tiller + release: istio +spec: + compiledTemplate: metric + params: + value: connection.received.bytes | 0 + dimensions: + reporter: conditional((context.reporter.kind | "inbound") == "outbound", "source", "destination") + source_workload: source.workload.name | "unknown" + source_workload_namespace: source.workload.namespace | "unknown" + source_principal: source.principal | "unknown" + source_app: source.labels["app"] | "unknown" + source_version: source.labels["version"] | "unknown" + destination_workload: destination.workload.name | "unknown" + destination_workload_namespace: destination.workload.namespace | "unknown" + destination_principal: destination.principal | "unknown" + destination_app: destination.labels["app"] | "unknown" + destination_version: destination.labels["version"] | "unknown" + destination_service: destination.service.host | "unknown" + destination_service_name: destination.service.name | "unknown" + destination_service_namespace: destination.service.namespace | "unknown" + connection_security_policy: conditional((context.reporter.kind | "inbound") == "outbound", "unknown", conditional(connection.mtls | false, "mutual_tls", "none")) + response_flags: context.proxy_error_code | "-" + monitored_resource_type: '"UNSPECIFIED"' +--- +apiVersion: "config.istio.io/v1alpha2" +kind: instance +metadata: + name: tcpconnectionsopened + namespace: istio-system + labels: + app: mixer + chart: mixer + heritage: Tiller + release: istio +spec: + compiledTemplate: metric + params: + value: "1" + dimensions: + reporter: conditional((context.reporter.kind | "inbound") == "outbound", "source", "destination") + source_workload: source.workload.name | "unknown" + source_workload_namespace: source.workload.namespace | "unknown" + source_principal: source.principal | "unknown" + source_app: source.labels["app"] | "unknown" + source_version: source.labels["version"] | "unknown" + destination_workload: destination.workload.name | "unknown" + destination_workload_namespace: destination.workload.namespace | "unknown" + destination_principal: destination.principal | "unknown" + destination_app: destination.labels["app"] | "unknown" + destination_version: destination.labels["version"] | "unknown" + destination_service: destination.service.host | "unknown" + destination_service_name: destination.service.name | "unknown" + destination_service_namespace: destination.service.namespace | "unknown" + connection_security_policy: conditional((context.reporter.kind | "inbound") == "outbound", "unknown", conditional(connection.mtls | false, "mutual_tls", "none")) + response_flags: context.proxy_error_code | "-" + monitored_resource_type: '"UNSPECIFIED"' +--- +apiVersion: "config.istio.io/v1alpha2" +kind: instance +metadata: + name: tcpconnectionsclosed + namespace: istio-system + labels: + app: mixer + chart: mixer + heritage: Tiller + release: istio +spec: + compiledTemplate: metric + params: + value: "1" + dimensions: + reporter: conditional((context.reporter.kind | "inbound") == "outbound", "source", "destination") + source_workload: source.workload.name | "unknown" + source_workload_namespace: source.workload.namespace | "unknown" + source_principal: source.principal | "unknown" + source_app: source.labels["app"] | "unknown" + source_version: source.labels["version"] | "unknown" + destination_workload: destination.workload.name | "unknown" + destination_workload_namespace: destination.workload.namespace | "unknown" + destination_principal: destination.principal | "unknown" + destination_app: destination.labels["app"] | "unknown" + destination_version: destination.labels["version"] | "unknown" + destination_service: destination.service.host | "unknown" + destination_service_name: destination.service.name | "unknown" + destination_service_namespace: destination.service.namespace | "unknown" + connection_security_policy: conditional((context.reporter.kind | "inbound") == "outbound", "unknown", conditional(connection.mtls | false, "mutual_tls", "none")) + response_flags: context.proxy_error_code | "-" + monitored_resource_type: '"UNSPECIFIED"' +--- +apiVersion: "config.istio.io/v1alpha2" +kind: handler +metadata: + name: prometheus + namespace: istio-system + labels: + app: mixer + chart: mixer + heritage: Tiller + release: istio +spec: + compiledAdapter: prometheus + params: + metricsExpirationPolicy: + metricsExpiryDuration: "10m" + metrics: + - name: requests_total + instance_name: requestcount.instance.istio-system + kind: COUNTER + label_names: + - reporter + - source_app + - source_principal + - source_workload + - source_workload_namespace + - source_version + - destination_app + - destination_principal + - destination_workload + - destination_workload_namespace + - destination_version + - destination_service + - destination_service_name + - destination_service_namespace + - request_protocol + - response_code + - response_flags + - permissive_response_code + - permissive_response_policyid + - connection_security_policy + - name: request_duration_seconds + instance_name: requestduration.instance.istio-system + kind: DISTRIBUTION + label_names: + - reporter + - source_app + - source_principal + - source_workload + - source_workload_namespace + - source_version + - destination_app + - destination_principal + - destination_workload + - destination_workload_namespace + - destination_version + - destination_service + - destination_service_name + - destination_service_namespace + - request_protocol + - response_code + - response_flags + - permissive_response_code + - permissive_response_policyid + - connection_security_policy + buckets: + explicit_buckets: + bounds: [0.005, 0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 1, 2.5, 5, 10] + - name: request_bytes + instance_name: requestsize.instance.istio-system + kind: DISTRIBUTION + label_names: + - reporter + - source_app + - source_principal + - source_workload + - source_workload_namespace + - source_version + - destination_app + - destination_principal + - destination_workload + - destination_workload_namespace + - destination_version + - destination_service + - destination_service_name + - destination_service_namespace + - request_protocol + - response_code + - response_flags + - permissive_response_code + - permissive_response_policyid + - connection_security_policy + buckets: + exponentialBuckets: + numFiniteBuckets: 8 + scale: 1 + growthFactor: 10 + - name: response_bytes + instance_name: responsesize.instance.istio-system + kind: DISTRIBUTION + label_names: + - reporter + - source_app + - source_principal + - source_workload + - source_workload_namespace + - source_version + - destination_app + - destination_principal + - destination_workload + - destination_workload_namespace + - destination_version + - destination_service + - destination_service_name + - destination_service_namespace + - request_protocol + - response_code + - response_flags + - permissive_response_code + - permissive_response_policyid + - connection_security_policy + buckets: + exponentialBuckets: + numFiniteBuckets: 8 + scale: 1 + growthFactor: 10 + - name: tcp_sent_bytes_total + instance_name: tcpbytesent.instance.istio-system + kind: COUNTER + label_names: + - reporter + - source_app + - source_principal + - source_workload + - source_workload_namespace + - source_version + - destination_app + - destination_principal + - destination_workload + - destination_workload_namespace + - destination_version + - destination_service + - destination_service_name + - destination_service_namespace + - connection_security_policy + - response_flags + - name: tcp_received_bytes_total + instance_name: tcpbytereceived.instance.istio-system + kind: COUNTER + label_names: + - reporter + - source_app + - source_principal + - source_workload + - source_workload_namespace + - source_version + - destination_app + - destination_principal + - destination_workload + - destination_workload_namespace + - destination_version + - destination_service + - destination_service_name + - destination_service_namespace + - connection_security_policy + - response_flags + - name: tcp_connections_opened_total + instance_name: tcpconnectionsopened.instance.istio-system + kind: COUNTER + label_names: + - reporter + - source_app + - source_principal + - source_workload + - source_workload_namespace + - source_version + - destination_app + - destination_principal + - destination_workload + - destination_workload_namespace + - destination_version + - destination_service + - destination_service_name + - destination_service_namespace + - connection_security_policy + - response_flags + - name: tcp_connections_closed_total + instance_name: tcpconnectionsclosed.instance.istio-system + kind: COUNTER + label_names: + - reporter + - source_app + - source_principal + - source_workload + - source_workload_namespace + - source_version + - destination_app + - destination_principal + - destination_workload + - destination_workload_namespace + - destination_version + - destination_service + - destination_service_name + - destination_service_namespace + - connection_security_policy + - response_flags +--- +apiVersion: "config.istio.io/v1alpha2" +kind: rule +metadata: + name: promhttp + namespace: istio-system + labels: + app: mixer + chart: mixer + heritage: Tiller + release: istio +spec: + match: (context.protocol == "http" || context.protocol == "grpc") && (match((request.useragent | "-"), "kube-probe*") == false) && (match((request.useragent | "-"), "Prometheus*") == false) + actions: + - handler: prometheus + instances: + - requestcount + - requestduration + - requestsize + - responsesize +--- +apiVersion: "config.istio.io/v1alpha2" +kind: rule +metadata: + name: promtcp + namespace: istio-system + labels: + app: mixer + chart: mixer + heritage: Tiller + release: istio +spec: + match: context.protocol == "tcp" + actions: + - handler: prometheus + instances: + - tcpbytesent + - tcpbytereceived +--- +apiVersion: "config.istio.io/v1alpha2" +kind: rule +metadata: + name: promtcpconnectionopen + namespace: istio-system + labels: + app: mixer + chart: mixer + heritage: Tiller + release: istio +spec: + match: context.protocol == "tcp" && ((connection.event | "na") == "open") + actions: + - handler: prometheus + instances: + - tcpconnectionsopened +--- +apiVersion: "config.istio.io/v1alpha2" +kind: rule +metadata: + name: promtcpconnectionclosed + namespace: istio-system + labels: + app: mixer + chart: mixer + heritage: Tiller + release: istio +spec: + match: context.protocol == "tcp" && ((connection.event | "na") == "close") + actions: + - handler: prometheus + instances: + - tcpconnectionsclosed +--- +apiVersion: "config.istio.io/v1alpha2" +kind: handler +metadata: + name: kubernetesenv + namespace: istio-system + labels: + app: mixer + chart: mixer + heritage: Tiller + release: istio +spec: + compiledAdapter: kubernetesenv + params: + # when running from mixer root, use the following config after adding a + # symbolic link to a kubernetes config file via: + # + # $ ln -s ~/.kube/config mixer/adapter/kubernetes/kubeconfig + # + # kubeconfig_path: "mixer/adapter/kubernetes/kubeconfig" + +--- +apiVersion: "config.istio.io/v1alpha2" +kind: rule +metadata: + name: kubeattrgenrulerule + namespace: istio-system + labels: + app: mixer + chart: mixer + heritage: Tiller + release: istio +spec: + actions: + - handler: kubernetesenv + instances: + - attributes +--- +apiVersion: "config.istio.io/v1alpha2" +kind: rule +metadata: + name: tcpkubeattrgenrulerule + namespace: istio-system + labels: + app: mixer + chart: mixer + heritage: Tiller + release: istio +spec: + match: context.protocol == "tcp" + actions: + - handler: kubernetesenv + instances: + - attributes +--- +apiVersion: "config.istio.io/v1alpha2" +kind: instance +metadata: + name: attributes + namespace: istio-system + labels: + app: mixer + chart: mixer + heritage: Tiller + release: istio +spec: + compiledTemplate: kubernetes + params: + # Pass the required attribute data to the adapter + source_uid: source.uid | "" + source_ip: source.ip | ip("0.0.0.0") # default to unspecified ip addr + destination_uid: destination.uid | "" + destination_port: destination.port | 0 + attributeBindings: + # Fill the new attributes from the adapter produced output. + # $out refers to an instance of OutputTemplate message + source.ip: $out.source_pod_ip | ip("0.0.0.0") + source.uid: $out.source_pod_uid | "unknown" + source.labels: $out.source_labels | emptyStringMap() + source.name: $out.source_pod_name | "unknown" + source.namespace: $out.source_namespace | "default" + source.owner: $out.source_owner | "unknown" + source.serviceAccount: $out.source_service_account_name | "unknown" + source.workload.uid: $out.source_workload_uid | "unknown" + source.workload.name: $out.source_workload_name | "unknown" + source.workload.namespace: $out.source_workload_namespace | "unknown" + destination.ip: $out.destination_pod_ip | ip("0.0.0.0") + destination.uid: $out.destination_pod_uid | "unknown" + destination.labels: $out.destination_labels | emptyStringMap() + destination.name: $out.destination_pod_name | "unknown" + destination.container.name: $out.destination_container_name | "unknown" + destination.namespace: $out.destination_namespace | "default" + destination.owner: $out.destination_owner | "unknown" + destination.serviceAccount: $out.destination_service_account_name | "unknown" + destination.workload.uid: $out.destination_workload_uid | "unknown" + destination.workload.name: $out.destination_workload_name | "unknown" + destination.workload.namespace: $out.destination_workload_namespace | "unknown" +--- +# Configuration needed by Mixer. +# Mixer cluster is delivered via CDS +# Specify mixer cluster settings +apiVersion: networking.istio.io/v1alpha3 +kind: DestinationRule +metadata: + name: istio-policy + namespace: istio-system + labels: + app: mixer + chart: mixer + heritage: Tiller + release: istio +spec: + host: istio-policy.istio-system.svc.cluster.local + trafficPolicy: + portLevelSettings: + - port: + number: 15004 + tls: + mode: ISTIO_MUTUAL + connectionPool: + http: + http2MaxRequests: 10000 + maxRequestsPerConnection: 10000 +--- +apiVersion: networking.istio.io/v1alpha3 +kind: DestinationRule +metadata: + name: istio-telemetry + namespace: istio-system + labels: + app: mixer + chart: mixer + heritage: Tiller + release: istio +spec: + host: istio-telemetry.istio-system.svc.cluster.local + trafficPolicy: + portLevelSettings: + - port: + number: 15004 + tls: + mode: ISTIO_MUTUAL + connectionPool: + http: + http2MaxRequests: 10000 + maxRequestsPerConnection: 10000 +--- + diff --git a/istio-1.3.5/install/kubernetes/istio-demo.yaml b/istio-1.3.5/install/kubernetes/istio-demo.yaml new file mode 100644 index 0000000..58c0b59 --- /dev/null +++ b/istio-1.3.5/install/kubernetes/istio-demo.yaml @@ -0,0 +1,21021 @@ +apiVersion: v1 +kind: Namespace +metadata: + name: istio-system + labels: + istio-injection: disabled +--- +apiVersion: apiextensions.k8s.io/v1beta1 +kind: CustomResourceDefinition +metadata: + name: virtualservices.networking.istio.io + labels: + app: istio-pilot + chart: istio + heritage: Tiller + release: istio + annotations: + "helm.sh/resource-policy": keep +spec: + group: networking.istio.io + names: + kind: VirtualService + listKind: VirtualServiceList + plural: virtualservices + singular: virtualservice + shortNames: + - vs + categories: + - istio-io + - networking-istio-io + scope: Namespaced + versions: + - name: v1alpha3 + served: true + storage: true + additionalPrinterColumns: + - JSONPath: .spec.gateways + description: The names of gateways and sidecars that should apply these routes + name: Gateways + type: string + - JSONPath: .spec.hosts + description: The destination hosts to which traffic is being sent + name: Hosts + type: string + - JSONPath: .metadata.creationTimestamp + description: |- + CreationTimestamp is a timestamp representing the server time when this object was created. It is not guaranteed to be set in happens-before order across separate operations. Clients may not set this value. It is represented in RFC3339 form and is in UTC. + + Populated by the system. Read-only. Null for lists. More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#metadata + name: Age + type: date +--- +apiVersion: apiextensions.k8s.io/v1beta1 +kind: CustomResourceDefinition +metadata: + name: destinationrules.networking.istio.io + labels: + app: istio-pilot + chart: istio + heritage: Tiller + release: istio + annotations: + "helm.sh/resource-policy": keep +spec: + group: networking.istio.io + names: + kind: DestinationRule + listKind: DestinationRuleList + plural: destinationrules + singular: destinationrule + shortNames: + - dr + categories: + - istio-io + - networking-istio-io + scope: Namespaced + versions: + - name: v1alpha3 + served: true + storage: true + additionalPrinterColumns: + - JSONPath: .spec.host + description: The name of a service from the service registry + name: Host + type: string + - JSONPath: .metadata.creationTimestamp + description: |- + CreationTimestamp is a timestamp representing the server time when this object was created. It is not guaranteed to be set in happens-before order across separate operations. Clients may not set this value. It is represented in RFC3339 form and is in UTC. + + Populated by the system. Read-only. Null for lists. More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#metadata + name: Age + type: date +--- +apiVersion: apiextensions.k8s.io/v1beta1 +kind: CustomResourceDefinition +metadata: + name: serviceentries.networking.istio.io + labels: + app: istio-pilot + chart: istio + heritage: Tiller + release: istio + annotations: + "helm.sh/resource-policy": keep +spec: + group: networking.istio.io + names: + kind: ServiceEntry + listKind: ServiceEntryList + plural: serviceentries + singular: serviceentry + shortNames: + - se + categories: + - istio-io + - networking-istio-io + scope: Namespaced + versions: + - name: v1alpha3 + served: true + storage: true + additionalPrinterColumns: + - JSONPath: .spec.hosts + description: The hosts associated with the ServiceEntry + name: Hosts + type: string + - JSONPath: .spec.location + description: Whether the service is external to the mesh or part of the mesh (MESH_EXTERNAL or MESH_INTERNAL) + name: Location + type: string + - JSONPath: .spec.resolution + description: Service discovery mode for the hosts (NONE, STATIC, or DNS) + name: Resolution + type: string + - JSONPath: .metadata.creationTimestamp + description: |- + CreationTimestamp is a timestamp representing the server time when this object was created. It is not guaranteed to be set in happens-before order across separate operations. Clients may not set this value. It is represented in RFC3339 form and is in UTC. + + Populated by the system. Read-only. Null for lists. More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#metadata + name: Age + type: date +--- +apiVersion: apiextensions.k8s.io/v1beta1 +kind: CustomResourceDefinition +metadata: + name: gateways.networking.istio.io + labels: + app: istio-pilot + chart: istio + heritage: Tiller + release: istio + annotations: + "helm.sh/resource-policy": keep +spec: + group: networking.istio.io + names: + kind: Gateway + plural: gateways + singular: gateway + shortNames: + - gw + categories: + - istio-io + - networking-istio-io + scope: Namespaced + versions: + - name: v1alpha3 + served: true + storage: true +--- +apiVersion: apiextensions.k8s.io/v1beta1 +kind: CustomResourceDefinition +metadata: + name: envoyfilters.networking.istio.io + labels: + app: istio-pilot + chart: istio + heritage: Tiller + release: istio + annotations: + "helm.sh/resource-policy": keep +spec: + group: networking.istio.io + names: + kind: EnvoyFilter + plural: envoyfilters + singular: envoyfilter + categories: + - istio-io + - networking-istio-io + scope: Namespaced + versions: + - name: v1alpha3 + served: true + storage: true +--- +kind: CustomResourceDefinition +apiVersion: apiextensions.k8s.io/v1beta1 +metadata: + name: clusterrbacconfigs.rbac.istio.io + labels: + app: istio-pilot + istio: rbac + heritage: Tiller + release: istio + annotations: + "helm.sh/resource-policy": keep +spec: + group: rbac.istio.io + names: + kind: ClusterRbacConfig + plural: clusterrbacconfigs + singular: clusterrbacconfig + categories: + - istio-io + - rbac-istio-io + scope: Cluster + versions: + - name: v1alpha1 + served: true + storage: true +--- +kind: CustomResourceDefinition +apiVersion: apiextensions.k8s.io/v1beta1 +metadata: + name: policies.authentication.istio.io + labels: + app: istio-citadel + chart: istio + heritage: Tiller + release: istio + annotations: + "helm.sh/resource-policy": keep +spec: + group: authentication.istio.io + names: + kind: Policy + plural: policies + singular: policy + categories: + - istio-io + - authentication-istio-io + scope: Namespaced + versions: + - name: v1alpha1 + served: true + storage: true +--- +kind: CustomResourceDefinition +apiVersion: apiextensions.k8s.io/v1beta1 +metadata: + name: meshpolicies.authentication.istio.io + labels: + app: istio-citadel + chart: istio + heritage: Tiller + release: istio + annotations: + "helm.sh/resource-policy": keep +spec: + group: authentication.istio.io + names: + kind: MeshPolicy + listKind: MeshPolicyList + plural: meshpolicies + singular: meshpolicy + categories: + - istio-io + - authentication-istio-io + scope: Cluster + versions: + - name: v1alpha1 + served: true + storage: true +--- +kind: CustomResourceDefinition +apiVersion: apiextensions.k8s.io/v1beta1 +metadata: + name: httpapispecbindings.config.istio.io + labels: + app: istio-mixer + chart: istio + heritage: Tiller + release: istio + annotations: + "helm.sh/resource-policy": keep +spec: + group: config.istio.io + names: + kind: HTTPAPISpecBinding + plural: httpapispecbindings + singular: httpapispecbinding + categories: + - istio-io + - apim-istio-io + scope: Namespaced + versions: + - name: v1alpha2 + served: true + storage: true +--- +kind: CustomResourceDefinition +apiVersion: apiextensions.k8s.io/v1beta1 +metadata: + name: httpapispecs.config.istio.io + labels: + app: istio-mixer + chart: istio + heritage: Tiller + release: istio + annotations: + "helm.sh/resource-policy": keep +spec: + group: config.istio.io + names: + kind: HTTPAPISpec + plural: httpapispecs + singular: httpapispec + categories: + - istio-io + - apim-istio-io + scope: Namespaced + versions: + - name: v1alpha2 + served: true + storage: true +--- +kind: CustomResourceDefinition +apiVersion: apiextensions.k8s.io/v1beta1 +metadata: + name: quotaspecbindings.config.istio.io + labels: + app: istio-mixer + chart: istio + heritage: Tiller + release: istio + annotations: + "helm.sh/resource-policy": keep +spec: + group: config.istio.io + names: + kind: QuotaSpecBinding + plural: quotaspecbindings + singular: quotaspecbinding + categories: + - istio-io + - apim-istio-io + scope: Namespaced + versions: + - name: v1alpha2 + served: true + storage: true +--- +kind: CustomResourceDefinition +apiVersion: apiextensions.k8s.io/v1beta1 +metadata: + name: quotaspecs.config.istio.io + labels: + app: istio-mixer + chart: istio + heritage: Tiller + release: istio + annotations: + "helm.sh/resource-policy": keep +spec: + group: config.istio.io + names: + kind: QuotaSpec + plural: quotaspecs + singular: quotaspec + categories: + - istio-io + - apim-istio-io + scope: Namespaced + versions: + - name: v1alpha2 + served: true + storage: true +--- +kind: CustomResourceDefinition +apiVersion: apiextensions.k8s.io/v1beta1 +metadata: + name: rules.config.istio.io + labels: + app: mixer + package: istio.io.mixer + istio: core + chart: istio + heritage: Tiller + release: istio + annotations: + "helm.sh/resource-policy": keep +spec: + group: config.istio.io + names: + kind: rule + plural: rules + singular: rule + categories: + - istio-io + - policy-istio-io + scope: Namespaced + versions: + - name: v1alpha2 + served: true + storage: true +--- +kind: CustomResourceDefinition +apiVersion: apiextensions.k8s.io/v1beta1 +metadata: + name: attributemanifests.config.istio.io + labels: + app: mixer + package: istio.io.mixer + istio: core + chart: istio + heritage: Tiller + release: istio + annotations: + "helm.sh/resource-policy": keep +spec: + group: config.istio.io + names: + kind: attributemanifest + plural: attributemanifests + singular: attributemanifest + categories: + - istio-io + - policy-istio-io + scope: Namespaced + versions: + - name: v1alpha2 + served: true + storage: true +--- +kind: CustomResourceDefinition +apiVersion: apiextensions.k8s.io/v1beta1 +metadata: + name: rbacconfigs.rbac.istio.io + labels: + app: mixer + package: istio.io.mixer + istio: rbac + chart: istio + heritage: Tiller + release: istio + annotations: + "helm.sh/resource-policy": keep +spec: + group: rbac.istio.io + names: + kind: RbacConfig + plural: rbacconfigs + singular: rbacconfig + categories: + - istio-io + - rbac-istio-io + scope: Namespaced + versions: + - name: v1alpha1 + served: true + storage: true +--- +kind: CustomResourceDefinition +apiVersion: apiextensions.k8s.io/v1beta1 +metadata: + name: serviceroles.rbac.istio.io + labels: + app: mixer + package: istio.io.mixer + istio: rbac + chart: istio + heritage: Tiller + release: istio + annotations: + "helm.sh/resource-policy": keep +spec: + group: rbac.istio.io + names: + kind: ServiceRole + plural: serviceroles + singular: servicerole + categories: + - istio-io + - rbac-istio-io + scope: Namespaced + versions: + - name: v1alpha1 + served: true + storage: true +--- +kind: CustomResourceDefinition +apiVersion: apiextensions.k8s.io/v1beta1 +metadata: + name: servicerolebindings.rbac.istio.io + labels: + app: mixer + package: istio.io.mixer + istio: rbac + chart: istio + heritage: Tiller + release: istio + annotations: + "helm.sh/resource-policy": keep +spec: + group: rbac.istio.io + names: + kind: ServiceRoleBinding + plural: servicerolebindings + singular: servicerolebinding + categories: + - istio-io + - rbac-istio-io + scope: Namespaced + versions: + - name: v1alpha1 + served: true + storage: true + additionalPrinterColumns: + - JSONPath: .spec.roleRef.name + description: The name of the ServiceRole object being referenced + name: Reference + type: string + - JSONPath: .metadata.creationTimestamp + description: |- + CreationTimestamp is a timestamp representing the server time when this object was created. It is not guaranteed to be set in happens-before order across separate operations. Clients may not set this value. It is represented in RFC3339 form and is in UTC. + + Populated by the system. Read-only. Null for lists. More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#metadata + name: Age + type: date +--- +kind: CustomResourceDefinition +apiVersion: apiextensions.k8s.io/v1beta1 +metadata: + name: adapters.config.istio.io + labels: + app: mixer + package: adapter + istio: mixer-adapter + chart: istio + heritage: Tiller + release: istio + annotations: + "helm.sh/resource-policy": keep +spec: + group: config.istio.io + names: + kind: adapter + plural: adapters + singular: adapter + categories: + - istio-io + - policy-istio-io + scope: Namespaced + versions: + - name: v1alpha2 + served: true + storage: true +--- +kind: CustomResourceDefinition +apiVersion: apiextensions.k8s.io/v1beta1 +metadata: + name: instances.config.istio.io + labels: + app: mixer + package: instance + istio: mixer-instance + chart: istio + heritage: Tiller + release: istio + annotations: + "helm.sh/resource-policy": keep +spec: + group: config.istio.io + names: + kind: instance + plural: instances + singular: instance + categories: + - istio-io + - policy-istio-io + scope: Namespaced + versions: + - name: v1alpha2 + served: true + storage: true +--- +kind: CustomResourceDefinition +apiVersion: apiextensions.k8s.io/v1beta1 +metadata: + name: templates.config.istio.io + labels: + app: mixer + package: template + istio: mixer-template + chart: istio + heritage: Tiller + release: istio + annotations: + "helm.sh/resource-policy": keep +spec: + group: config.istio.io + names: + kind: template + plural: templates + singular: template + categories: + - istio-io + - policy-istio-io + scope: Namespaced + versions: + - name: v1alpha2 + served: true + storage: true +--- +kind: CustomResourceDefinition +apiVersion: apiextensions.k8s.io/v1beta1 +metadata: + name: handlers.config.istio.io + labels: + app: mixer + package: handler + istio: mixer-handler + chart: istio + heritage: Tiller + release: istio + annotations: + "helm.sh/resource-policy": keep +spec: + group: config.istio.io + names: + kind: handler + plural: handlers + singular: handler + categories: + - istio-io + - policy-istio-io + scope: Namespaced + versions: + - name: v1alpha2 + served: true + storage: true +--- +apiVersion: apiextensions.k8s.io/v1beta1 +kind: CustomResourceDefinition +metadata: + name: sidecars.networking.istio.io + labels: + app: istio-pilot + chart: istio + heritage: Tiller + release: istio + annotations: + "helm.sh/resource-policy": keep +spec: + group: networking.istio.io + names: + kind: Sidecar + plural: sidecars + singular: sidecar + categories: + - istio-io + - networking-istio-io + scope: Namespaced + versions: + - name: v1alpha3 + served: true + storage: true +--- +kind: CustomResourceDefinition +apiVersion: apiextensions.k8s.io/v1beta1 +metadata: + name: authorizationpolicies.rbac.istio.io + labels: + app: istio-pilot + istio: rbac + heritage: Tiller + release: istio +spec: + group: rbac.istio.io + names: + kind: AuthorizationPolicy + plural: authorizationpolicies + singular: authorizationpolicy + categories: + - istio-io + - rbac-istio-io + scope: Namespaced + versions: + - name: v1alpha1 + served: true + storage: true +--- +apiVersion: apiextensions.k8s.io/v1beta1 +kind: CustomResourceDefinition +metadata: + name: clusterissuers.certmanager.k8s.io + labels: + app: certmanager + chart: certmanager + heritage: Tiller + release: istio + annotations: + "helm.sh/resource-policy": keep +spec: + group: certmanager.k8s.io + versions: + - name: v1alpha1 + served: true + storage: true + names: + kind: ClusterIssuer + plural: clusterissuers + scope: Cluster +--- +apiVersion: apiextensions.k8s.io/v1beta1 +kind: CustomResourceDefinition +metadata: + name: issuers.certmanager.k8s.io + labels: + app: certmanager + chart: certmanager + heritage: Tiller + release: istio + annotations: + "helm.sh/resource-policy": keep +spec: + group: certmanager.k8s.io + versions: + - name: v1alpha1 + served: true + storage: true + names: + kind: Issuer + plural: issuers + scope: Namespaced +--- +apiVersion: apiextensions.k8s.io/v1beta1 +kind: CustomResourceDefinition +metadata: + name: certificates.certmanager.k8s.io + labels: + app: certmanager + chart: certmanager + heritage: Tiller + release: istio + annotations: + "helm.sh/resource-policy": keep +spec: + additionalPrinterColumns: + - JSONPath: .status.conditions[?(@.type=="Ready")].status + name: Ready + type: string + - JSONPath: .spec.secretName + name: Secret + type: string + - JSONPath: .spec.issuerRef.name + name: Issuer + type: string + priority: 1 + - JSONPath: .status.conditions[?(@.type=="Ready")].message + name: Status + type: string + priority: 1 + - JSONPath: .metadata.creationTimestamp + description: |- + CreationTimestamp is a timestamp representing the server time when this object was created. It is not guaranteed to be set in happens-before order across separate operations. Clients may not set this value. It is represented in RFC3339 form and is in UTC. + + Populated by the system. Read-only. Null for lists. More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#metadata + name: Age + type: date + group: certmanager.k8s.io + versions: + - name: v1alpha1 + served: true + storage: true + scope: Namespaced + names: + kind: Certificate + plural: certificates + shortNames: + - cert + - certs +--- +apiVersion: apiextensions.k8s.io/v1beta1 +kind: CustomResourceDefinition +metadata: + name: orders.certmanager.k8s.io + labels: + app: certmanager + chart: certmanager + heritage: Tiller + release: istio + annotations: + "helm.sh/resource-policy": keep +spec: + additionalPrinterColumns: + - JSONPath: .status.state + name: State + type: string + - JSONPath: .spec.issuerRef.name + name: Issuer + type: string + priority: 1 + - JSONPath: .status.reason + name: Reason + type: string + priority: 1 + - JSONPath: .metadata.creationTimestamp + description: |- + CreationTimestamp is a timestamp representing the server time when this object was created. It is not guaranteed to be set in happens-before order across separate operations. Clients may not set this value. It is represented in RFC3339 form and is in UTC. + + Populated by the system. Read-only. Null for lists. More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#metadata + name: Age + type: date + group: certmanager.k8s.io + versions: + - name: v1alpha1 + served: true + storage: true + names: + kind: Order + plural: orders + scope: Namespaced +--- +apiVersion: apiextensions.k8s.io/v1beta1 +kind: CustomResourceDefinition +metadata: + name: challenges.certmanager.k8s.io + labels: + app: certmanager + chart: certmanager + heritage: Tiller + release: istio + annotations: + "helm.sh/resource-policy": keep +spec: + additionalPrinterColumns: + - JSONPath: .status.state + name: State + type: string + - JSONPath: .spec.dnsName + name: Domain + type: string + - JSONPath: .status.reason + name: Reason + type: string + - JSONPath: .metadata.creationTimestamp + description: |- + CreationTimestamp is a timestamp representing the server time when this object was created. It is not guaranteed to be set in happens-before order across separate operations. Clients may not set this value. It is represented in RFC3339 form and is in UTC. + + Populated by the system. Read-only. Null for lists. More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#metadata + name: Age + type: date + group: certmanager.k8s.io + versions: + - name: v1alpha1 + served: true + storage: true + names: + kind: Challenge + plural: challenges + scope: Namespaced +--- +--- +# Source: istio/charts/kiali/templates/demosecret.yaml + +apiVersion: v1 +kind: Secret +metadata: + name: kiali + namespace: istio-system + labels: + app: kiali + chart: kiali + heritage: Tiller + release: istio +type: Opaque +data: + username: YWRtaW4= # admin + passphrase: YWRtaW4= # admin + +--- +# Source: istio/charts/galley/templates/configmap.yaml +apiVersion: v1 +kind: ConfigMap +metadata: + name: istio-galley-configuration + namespace: istio-system + labels: + app: galley + chart: galley + heritage: Tiller + release: istio + istio: galley +data: + validatingwebhookconfiguration.yaml: |- + apiVersion: admissionregistration.k8s.io/v1beta1 + kind: ValidatingWebhookConfiguration + metadata: + name: istio-galley + labels: + app: galley + chart: galley + heritage: Tiller + release: istio + istio: galley + webhooks: + - name: pilot.validation.istio.io + clientConfig: + service: + name: istio-galley + namespace: istio-system + path: "/admitpilot" + caBundle: "" + rules: + - operations: + - CREATE + - UPDATE + apiGroups: + - config.istio.io + apiVersions: + - v1alpha2 + resources: + - httpapispecs + - httpapispecbindings + - quotaspecs + - quotaspecbindings + - operations: + - CREATE + - UPDATE + apiGroups: + - rbac.istio.io + apiVersions: + - "*" + resources: + - "*" + - operations: + - CREATE + - UPDATE + apiGroups: + - authentication.istio.io + apiVersions: + - "*" + resources: + - "*" + - operations: + - CREATE + - UPDATE + apiGroups: + - networking.istio.io + apiVersions: + - "*" + resources: + - destinationrules + - envoyfilters + - gateways + - serviceentries + - sidecars + - virtualservices + failurePolicy: Fail + sideEffects: None + - name: mixer.validation.istio.io + clientConfig: + service: + name: istio-galley + namespace: istio-system + path: "/admitmixer" + caBundle: "" + rules: + - operations: + - CREATE + - UPDATE + apiGroups: + - config.istio.io + apiVersions: + - v1alpha2 + resources: + - rules + - attributemanifests + - circonuses + - deniers + - fluentds + - kubernetesenvs + - listcheckers + - memquotas + - noops + - opas + - prometheuses + - rbacs + - solarwindses + - stackdrivers + - cloudwatches + - dogstatsds + - statsds + - stdios + - apikeys + - authorizations + - checknothings + # - kuberneteses + - listentries + - logentries + - metrics + - quotas + - reportnothings + - tracespans + - adapters + - handlers + - instances + - templates + - zipkins + failurePolicy: Fail + sideEffects: None + +--- +# Source: istio/charts/grafana/templates/configmap-custom-resources.yaml +apiVersion: v1 +kind: ConfigMap +metadata: + name: istio-grafana-custom-resources + namespace: istio-system + labels: + app: grafana + chart: grafana + heritage: Tiller + release: istio + istio: grafana +data: + custom-resources.yaml: |- + apiVersion: authentication.istio.io/v1alpha1 + kind: Policy + metadata: + name: grafana-ports-mtls-disabled + namespace: istio-system + labels: + app: grafana + chart: grafana + heritage: Tiller + release: istio + spec: + targets: + - name: grafana + ports: + - number: 3000 + run.sh: |- + #!/bin/sh + + set -x + + if [ "$#" -ne "1" ]; then + echo "first argument should be path to custom resource yaml" + exit 1 + fi + + pathToResourceYAML=${1} + + kubectl get validatingwebhookconfiguration istio-galley 2>/dev/null + if [ "$?" -eq 0 ]; then + echo "istio-galley validatingwebhookconfiguration found - waiting for istio-galley deployment to be ready" + while true; do + kubectl -n istio-system get deployment istio-galley 2>/dev/null + if [ "$?" -eq 0 ]; then + break + fi + sleep 1 + done + kubectl -n istio-system rollout status deployment istio-galley + if [ "$?" -ne 0 ]; then + echo "istio-galley deployment rollout status check failed" + exit 1 + fi + echo "istio-galley deployment ready for configuration validation" + fi + sleep 5 + kubectl apply -f ${pathToResourceYAML} + + +--- +# Source: istio/charts/grafana/templates/configmap-dashboards.yaml + +apiVersion: v1 +kind: ConfigMap +metadata: + name: istio-grafana-configuration-dashboards-citadel-dashboard + namespace: istio-system + labels: + app: grafana + chart: grafana + heritage: Tiller + release: istio + istio: grafana +data: + citadel-dashboard.json: '{ + "annotations": { + "list": [ + { + "builtIn": 1, + "datasource": "-- Grafana --", + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations & Alerts", + "type": "dashboard" + } + ] + }, + "description": "", + "editable": true, + "gnetId": null, + "graphTooltip": 0, + "links": [], + "panels": [ + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 0 + }, + "id": 8, + "panels": [], + "title": "Performance", + "type": "row" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "description": "CPU usage across Citadel instances.", + "fill": 1, + "gridPos": { + "h": 6, + "w": 8, + "x": 0, + "y": 1 + }, + "id": 10, + "legend": { + "alignAsTable": false, + "avg": false, + "current": false, + "max": false, + "min": false, + "rightSide": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(rate(container_cpu_usage_seconds_total{job=\"kubernetes-cadvisor\",container_name=~\"citadel\", pod_name=~\"istio-citadel-.*\"}[1m]))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Citadel CPU usage rate", + "refId": "A" + }, + { + "expr": "irate(process_cpu_seconds_total{job=\"citadel\"}[1m])", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Citadel CPU usage irate", + "refId": "C" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "CPU", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": "", + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "description": "Citadel process memory statistics.", + "fill": 1, + "gridPos": { + "h": 6, + "w": 8, + "x": 8, + "y": 1 + }, + "id": 12, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "process_virtual_memory_bytes{job=\"citadel\"}", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Virtual Memory", + "refId": "A" + }, + { + "expr": "process_resident_memory_bytes{job=\"citadel\"}", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Resident Memory", + "refId": "B" + }, + { + "expr": "go_memstats_heap_sys_bytes{job=\"citadel\"}", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Heap Memory Total", + "refId": "C" + }, + { + "expr": "go_memstats_alloc_bytes{job=\"citadel\"}", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Heap Memory Allocated", + "refId": "E" + }, + { + "expr": "go_memstats_heap_inuse_bytes{job=\"citadel\"}", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Heap Inuse", + "refId": "F" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Memory", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "fill": 1, + "gridPos": { + "h": 6, + "w": 8, + "x": 16, + "y": 1 + }, + "id": 14, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "go_goroutines{job=\"citadel\"}", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Goroutines", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Goroutines", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 7 + }, + "id": 28, + "panels": [], + "title": "General", + "type": "row" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "description": "Total number of CSR requests made to Citadel.", + "fill": 1, + "gridPos": { + "h": 5, + "w": 12, + "x": 0, + "y": 8 + }, + "id": 30, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "citadel_server_csr_count{job=\"citadel\"}", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "CSR Request Count", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "CSR Requests", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "description": "The number of certificates issuances that have succeeded.", + "fill": 1, + "gridPos": { + "h": 5, + "w": 12, + "x": 12, + "y": 8 + }, + "id": 32, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "citadel_server_success_cert_issuance_count{job=\"citadel\"}", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Certificates Issued", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Certificates Issued", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 13 + }, + "id": 23, + "panels": [], + "title": "Errors", + "type": "row" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "description": "The number of errors occurred when creating the CSR.", + "fill": 1, + "gridPos": { + "h": 5, + "w": 8, + "x": 0, + "y": 14 + }, + "id": 20, + "legend": { + "alignAsTable": false, + "avg": false, + "current": false, + "max": false, + "min": false, + "rightSide": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "citadel_secret_controller_csr_err_count{job=\"citadel\"}", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "CSR Creation Error Count", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "CSR Creation Errors", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": "", + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "fill": 1, + "gridPos": { + "h": 5, + "w": 8, + "x": 8, + "y": 14 + }, + "id": 24, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "citadel_server_csr_parsing_err_count{job=\"citadel\"}", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "CSR Parse Error Count", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "CSR Parse Errors", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "description": "The number of authentication failures.", + "fill": 1, + "gridPos": { + "h": 5, + "w": 8, + "x": 16, + "y": 14 + }, + "id": 26, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "citadel_server_authentication_failure_count{job=\"citadel\"}", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Authentication Failure Count", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Authentication Failures", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 19 + }, + "id": 4, + "panels": [], + "title": "Secret Controller", + "type": "row" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "description": "The number of certificates created due to service account creation.", + "fill": 1, + "gridPos": { + "h": 5, + "w": 8, + "x": 0, + "y": 20 + }, + "id": 2, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": true, + "targets": [ + { + "expr": "citadel_secret_controller_svc_acc_created_cert_count{job=\"citadel\"}", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "SA Secrets Created", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Service Account Secrets Created (due to SA creation)", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "decimals": null, + "format": "short", + "label": "Certs Created", + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "description": "The number of certificates deleted due to service account deletion.", + "fill": 1, + "gridPos": { + "h": 5, + "w": 8, + "x": 8, + "y": 20 + }, + "id": 16, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": true, + "targets": [ + { + "expr": "citadel_secret_controller_svc_acc_deleted_cert_count{job=\"citadel\"}", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "SA Secrets Deleted", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Service Account Secrets Deleted (due to SA deletion)", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "decimals": null, + "format": "short", + "label": "Certs Created", + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "description": "The number of certificates recreated due to secret deletion (service account still exists).", + "fill": 1, + "gridPos": { + "h": 5, + "w": 8, + "x": 16, + "y": 20 + }, + "id": 6, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": true, + "targets": [ + { + "expr": "citadel_secret_controller_secret_deleted_cert_count{job=\"citadel\"}", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "SA Secrets Recreated", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Service Account Secrets Recreated (due to errant deletion)", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "decimals": null, + "format": "short", + "label": "Certs Created", + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + } + ], + "refresh": "5s", + "schemaVersion": 18, + "style": "dark", + "tags": [], + "templating": { + "list": [] + }, + "time": { + "from": "now-5m", + "to": "now" + }, + "timepicker": { + "refresh_intervals": [ + "5s", + "10s", + "30s", + "1m", + "5m", + "15m", + "30m", + "1h", + "2h", + "1d" + ], + "time_options": [ + "5m", + "15m", + "1h", + "6h", + "12h", + "24h", + "2d", + "7d", + "30d" + ] + }, + "timezone": "", + "title": "Istio Citadel Dashboard", + "uid": "OOyOqb4Wz", + "version": 1 +}' +--- +apiVersion: v1 +kind: ConfigMap +metadata: + name: istio-grafana-configuration-dashboards-galley-dashboard + namespace: istio-system + labels: + app: grafana + chart: grafana + heritage: Tiller + release: istio + istio: grafana +data: + galley-dashboard.json: '{ + "__inputs": [ + { + "name": "DS_PROMETHEUS", + "label": "Prometheus", + "description": "", + "type": "datasource", + "pluginId": "prometheus", + "pluginName": "Prometheus" + } + ], + "annotations": { + "list": [ + { + "builtIn": 1, + "datasource": "-- Grafana --", + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations & Alerts", + "type": "dashboard" + } + ] + }, + "editable": false, + "gnetId": null, + "graphTooltip": 0, + "links": [], + "panels": [ + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 5, + "w": 24, + "x": 0, + "y": 0 + }, + "id": 46, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(istio_build{component=\"galley\"}) by (tag)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{ tag }}", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Galley Versions", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 5 + }, + "id": 40, + "panels": [], + "title": "Resource Usage", + "type": "row" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 8, + "w": 6, + "x": 0, + "y": 6 + }, + "id": 36, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "process_virtual_memory_bytes{job=\"galley\"}", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "Virtual Memory", + "refId": "A" + }, + { + "expr": "process_resident_memory_bytes{job=\"galley\"}", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "Resident Memory", + "refId": "B" + }, + { + "expr": "go_memstats_heap_sys_bytes{job=\"galley\"}", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "heap sys", + "refId": "C" + }, + { + "expr": "go_memstats_heap_alloc_bytes{job=\"galley\"}", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "heap alloc", + "refId": "D" + }, + { + "expr": "go_memstats_alloc_bytes{job=\"galley\"}", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "Alloc", + "refId": "F" + }, + { + "expr": "go_memstats_heap_inuse_bytes{job=\"galley\"}", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "Heap in-use", + "refId": "G" + }, + { + "expr": "go_memstats_stack_inuse_bytes{job=\"galley\"}", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "Stack in-use", + "refId": "H" + }, + { + "expr": "sum(container_memory_usage_bytes{job=\"kubernetes-cadvisor\",container_name=~\"galley\", pod_name=~\"istio-galley-.*\"})", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Total (kis)", + "refId": "E" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Memory", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 8, + "w": 6, + "x": 6, + "y": 6 + }, + "id": 38, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(rate(container_cpu_usage_seconds_total{job=\"kubernetes-cadvisor\",container_name=~\"galley\", pod_name=~\"istio-galley-.*\"}[1m]))", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "Total (k8s)", + "refId": "A" + }, + { + "expr": "sum(rate(container_cpu_usage_seconds_total{job=\"kubernetes-cadvisor\",container_name=~\"galley\", pod_name=~\"istio-galley-.*\"}[1m])) by (container_name)", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "{{ container_name }} (k8s)", + "refId": "B" + }, + { + "expr": "irate(process_cpu_seconds_total{job=\"galley\"}[1m])", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "galley (self-reported)", + "refId": "C" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "CPU", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 8, + "w": 6, + "x": 12, + "y": 6 + }, + "id": 42, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "process_open_fds{job=\"galley\"}", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "Open FDs (galley)", + "refId": "A" + }, + { + "expr": "container_fs_usage_bytes{job=\"kubernetes-cadvisor\",container_name=~\"galley\", pod_name=~\"istio-galley-.*\"}", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "{{ container_name }} ", + "refId": "B" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Disk", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 8, + "w": 6, + "x": 18, + "y": 6 + }, + "id": 44, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "go_goroutines{job=\"galley\"}", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "goroutines_total", + "refId": "A" + }, + { + "expr": "istio_mcp_clients_total{component=\"galley\"}", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "clients_total", + "refId": "B" + }, + { + "expr": "go_goroutines{job=\"galley\"}/sum(istio_mcp_clients_total{component=\"galley\"}) without (component)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "avg_goroutines_per_client", + "refId": "C" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Goroutines", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 14 + }, + "id": 10, + "panels": [], + "title": "Runtime", + "type": "row" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 6, + "w": 8, + "x": 0, + "y": 15 + }, + "id": 2, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(rate(galley_runtime_strategy_on_change_total[1m])) * 60", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Strategy Change Events", + "refId": "A" + }, + { + "expr": "sum(rate(galley_runtime_processor_events_processed_total[1m])) * 60", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Processed Events", + "refId": "B" + }, + { + "expr": "sum(rate(galley_runtime_processor_snapshots_published_total[1m])) * 60", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Snapshot Published", + "refId": "C" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Event Rates", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": "Events/min", + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": "", + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 6, + "w": 8, + "x": 8, + "y": 15 + }, + "id": 4, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(rate(galley_runtime_strategy_timer_max_time_reached_total[1m])) * 60", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Max Time Reached", + "refId": "A" + }, + { + "expr": "sum(rate(galley_runtime_strategy_timer_quiesce_reached_total[1m])) * 60", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Quiesce Reached", + "refId": "B" + }, + { + "expr": "sum(rate(galley_runtime_strategy_timer_resets_total[1m])) * 60", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Timer Resets", + "refId": "C" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Timer Rates", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": "Events/min", + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 6, + "w": 8, + "x": 16, + "y": 15 + }, + "id": 8, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 3, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": true, + "steppedLine": false, + "targets": [ + { + "expr": "histogram_quantile(0.50, sum by (le) (galley_runtime_processor_snapshot_events_total_bucket))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "P50", + "refId": "A" + }, + { + "expr": "histogram_quantile(0.90, sum by (le) (galley_runtime_processor_snapshot_events_total_bucket))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "P90", + "refId": "B" + }, + { + "expr": "histogram_quantile(0.95, sum by (le) (galley_runtime_processor_snapshot_events_total_bucket))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "P95", + "refId": "C" + }, + { + "expr": "histogram_quantile(0.99, sum by (le) (galley_runtime_processor_snapshot_events_total_bucket))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "P99", + "refId": "D" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Events Per Snapshot", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 6, + "w": 8, + "x": 8, + "y": 21 + }, + "id": 6, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum by (typeURL) (galley_runtime_state_type_instances_total)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{ typeURL }}", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "State Type Instances", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": "Count", + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 27 + }, + "id": 34, + "panels": [], + "title": "Validation", + "type": "row" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 6, + "w": 8, + "x": 0, + "y": 28 + }, + "id": 28, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "galley_validation_cert_key_updates{job=\"galley\"}", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Key Updates", + "refId": "A" + }, + { + "expr": "galley_validation_cert_key_update_errors{job=\"galley\"}", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Key Update Errors: {{ error }}", + "refId": "B" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Validation Webhook Certificate", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 6, + "w": 8, + "x": 8, + "y": 28 + }, + "id": 30, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(galley_validation_passed{job=\"galley\"}) by (group, version, resource)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Passed: {{ group }}/{{ version }}/{{resource}}", + "refId": "A" + }, + { + "expr": "sum(galley_validation_failed{job=\"galley\"}) by (group, version, resource, reason)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Failed: {{ group }}/{{ version }}/{{resource}} ({{ reason}})", + "refId": "B" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Resource Validation", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 6, + "w": 8, + "x": 16, + "y": 28 + }, + "id": 32, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(galley_validation_http_error{job=\"galley\"}) by (status)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{ status }}", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Validation HTTP Errors", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 34 + }, + "id": 12, + "panels": [], + "title": "Kubernetes Source", + "type": "row" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 6, + "w": 8, + "x": 0, + "y": 35 + }, + "id": 14, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "rate(galley_source_kube_event_success_total[1m]) * 60", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Success", + "refId": "A" + }, + { + "expr": "rate(galley_source_kube_event_error_total[1m]) * 60", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Error", + "refId": "B" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Source Event Rate", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": "Events/min", + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 6, + "w": 8, + "x": 8, + "y": 35 + }, + "id": 16, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "rate(galley_source_kube_dynamic_converter_success_total[1m]) * 60", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{apiVersion=\"{{apiVersion}}\",group=\"{{group}}\",kind=\"{{kind}}\"}", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Kubernetes Object Conversion Successes", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": "Conversions/min", + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 6, + "w": 8, + "x": 16, + "y": 35 + }, + "id": 24, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "rate(galley_source_kube_dynamic_converter_failure_total[1m]) * 60", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Error", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Kubernetes Object Conversion Failures", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": "Failures/min", + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 41 + }, + "id": 18, + "panels": [], + "title": "Mesh Configuration Protocol", + "type": "row" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 6, + "w": 8, + "x": 0, + "y": 42 + }, + "id": 20, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(istio_mcp_clients_total{component=\"galley\"})", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Clients", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Connected Clients", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 6, + "w": 8, + "x": 8, + "y": 42 + }, + "id": 22, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum by(collection)(irate(istio_mcp_request_acks_total{component=\"galley\"}[1m]) * 60)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Request ACKs", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": "ACKs/min", + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 6, + "w": 8, + "x": 16, + "y": 42 + }, + "id": 26, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "rate(istio_mcp_request_nacks_total{component=\"galley\"}[1m]) * 60", + "format": "time_series", + "intervalFactor": 1, + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Request NACKs", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": "NACKs/min", + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + } + ], + "refresh": "5s", + "schemaVersion": 16, + "style": "dark", + "tags": [], + "templating": { + "list": [] + }, + "time": { + "from": "now-5m", + "to": "now" + }, + "timepicker": { + "refresh_intervals": [ + "5s", + "10s", + "30s", + "1m", + "5m", + "15m", + "30m", + "1h", + "2h", + "1d" + ], + "time_options": [ + "5m", + "15m", + "1h", + "6h", + "12h", + "24h", + "2d", + "7d", + "30d" + ] + }, + "timezone": "", + "title": "Istio Galley Dashboard", + "uid": "TSEY6jLmk", + "version": 1 +} +' +--- +apiVersion: v1 +kind: ConfigMap +metadata: + name: istio-grafana-configuration-dashboards-istio-mesh-dashboard + namespace: istio-system + labels: + app: grafana + chart: grafana + heritage: Tiller + release: istio + istio: grafana +data: + istio-mesh-dashboard.json: '{ + "annotations": { + "list": [ + { + "builtIn": 1, + "datasource": "-- Grafana --", + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations & Alerts", + "type": "dashboard" + } + ] + }, + "editable": false, + "gnetId": null, + "graphTooltip": 0, + "id": null, + "links": [], + "panels": [ + { + "content": "
\n
\n Istio\n
\n
\n Istio is an open platform that provides a uniform way to connect,\n manage, and \n secure microservices.\n
\n Need help? Join the Istio community.\n
\n
", + "gridPos": { + "h": 3, + "w": 24, + "x": 0, + "y": 0 + }, + "height": "50px", + "id": 13, + "links": [], + "mode": "html", + "style": { + "font-size": "18pt" + }, + "title": "", + "transparent": true, + "type": "text" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "datasource": "Prometheus", + "format": "ops", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "gridPos": { + "h": 3, + "w": 6, + "x": 0, + "y": 3 + }, + "id": 20, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": true, + "lineColor": "rgb(31, 120, 193)", + "show": true + }, + "tableColumn": "", + "targets": [ + { + "expr": "round(sum(irate(istio_requests_total{reporter=\"destination\"}[1m])), 0.001)", + "intervalFactor": 1, + "refId": "A", + "step": 4 + } + ], + "thresholds": "", + "title": "Global Request Volume", + "type": "singlestat", + "valueFontSize": "80%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "avg" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "datasource": "Prometheus", + "format": "percentunit", + "gauge": { + "maxValue": 100, + "minValue": 80, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": false + }, + "gridPos": { + "h": 3, + "w": 6, + "x": 6, + "y": 3 + }, + "id": 21, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": true, + "lineColor": "rgb(31, 120, 193)", + "show": true + }, + "tableColumn": "", + "targets": [ + { + "expr": "sum(rate(istio_requests_total{reporter=\"destination\", response_code!~\"5.*\"}[1m])) / sum(rate(istio_requests_total{reporter=\"destination\"}[1m]))", + "format": "time_series", + "intervalFactor": 1, + "refId": "A", + "step": 4 + } + ], + "thresholds": "95, 99, 99.5", + "title": "Global Success Rate (non-5xx responses)", + "type": "singlestat", + "valueFontSize": "80%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "avg" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "datasource": "Prometheus", + "format": "ops", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "gridPos": { + "h": 3, + "w": 6, + "x": 12, + "y": 3 + }, + "id": 22, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": true, + "lineColor": "rgb(31, 120, 193)", + "show": true + }, + "tableColumn": "", + "targets": [ + { + "expr": "sum(irate(istio_requests_total{reporter=\"destination\", response_code=~\"4.*\"}[1m])) ", + "format": "time_series", + "intervalFactor": 1, + "refId": "A", + "step": 4 + } + ], + "thresholds": "", + "title": "4xxs", + "type": "singlestat", + "valueFontSize": "80%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "avg" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "datasource": "Prometheus", + "format": "ops", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "gridPos": { + "h": 3, + "w": 6, + "x": 18, + "y": 3 + }, + "id": 23, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": true, + "lineColor": "rgb(31, 120, 193)", + "show": true + }, + "tableColumn": "", + "targets": [ + { + "expr": "sum(irate(istio_requests_total{reporter=\"destination\", response_code=~\"5.*\"}[1m])) ", + "format": "time_series", + "intervalFactor": 1, + "refId": "A", + "step": 4 + } + ], + "thresholds": "", + "title": "5xxs", + "type": "singlestat", + "valueFontSize": "80%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "avg" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "#299c46", + "rgba(237, 129, 40, 0.89)", + "#d44a3a" + ], + "format": "none", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "gridPos": { + "h": 3, + "w": 6, + "x": 0, + "y": 6 + }, + "id": 113, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": false, + "lineColor": "rgb(31, 120, 193)", + "show": true + }, + "tableColumn": "", + "targets": [ + { + "expr": "sum(galley_istio_networking_virtualservices) / count(up{job=\"galley\"})", + "format": "time_series", + "intervalFactor": 1, + "refId": "A" + } + ], + "thresholds": "", + "timeFrom": null, + "timeShift": null, + "title": "Virtual Services", + "type": "singlestat", + "valueFontSize": "80%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "current" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "#299c46", + "rgba(237, 129, 40, 0.89)", + "#d44a3a" + ], + "format": "none", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "gridPos": { + "h": 3, + "w": 6, + "x": 6, + "y": 6 + }, + "id": 114, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": false, + "lineColor": "rgb(31, 120, 193)", + "show": true + }, + "tableColumn": "", + "targets": [ + { + "expr": "sum(galley_istio_networking_destinationrules) / count(up{job=\"galley\"})", + "format": "time_series", + "intervalFactor": 1, + "refId": "A" + } + ], + "thresholds": "", + "timeFrom": null, + "timeShift": null, + "title": "Destination Rules", + "type": "singlestat", + "valueFontSize": "80%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "current" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "#299c46", + "rgba(237, 129, 40, 0.89)", + "#d44a3a" + ], + "format": "none", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "gridPos": { + "h": 3, + "w": 6, + "x": 12, + "y": 6 + }, + "id": 115, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": false, + "lineColor": "rgb(31, 120, 193)", + "show": true + }, + "tableColumn": "", + "targets": [ + { + "expr": "sum(galley_istio_networking_gateways) / count(up{job=\"galley\"})", + "format": "time_series", + "intervalFactor": 1, + "refId": "A" + } + ], + "thresholds": "", + "timeFrom": null, + "timeShift": null, + "title": "Gateways", + "type": "singlestat", + "valueFontSize": "80%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "current" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "#299c46", + "rgba(237, 129, 40, 0.89)", + "#d44a3a" + ], + "format": "none", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "gridPos": { + "h": 3, + "w": 6, + "x": 18, + "y": 6 + }, + "id": 116, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": false, + "lineColor": "rgb(31, 120, 193)", + "show": true + }, + "tableColumn": "", + "targets": [ + { + "expr": "sum(galley_istio_authentication_meshpolicies) / count(up{job=\"galley\"})", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "refId": "A" + } + ], + "thresholds": "", + "timeFrom": null, + "timeShift": null, + "title": "Authentication Mesh Policies", + "type": "singlestat", + "valueFontSize": "80%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "current" + }, + { + "columns": [], + "datasource": "Prometheus", + "fontSize": "100%", + "gridPos": { + "h": 21, + "w": 24, + "x": 0, + "y": 9 + }, + "hideTimeOverride": false, + "id": 73, + "links": [], + "pageSize": null, + "repeat": null, + "repeatDirection": "v", + "scroll": true, + "showHeader": true, + "sort": { + "col": 4, + "desc": true + }, + "styles": [ + { + "alias": "Workload", + "colorMode": null, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "link": false, + "linkTargetBlank": false, + "linkTooltip": "Workload dashboard", + "linkUrl": "/dashboard/db/istio-workload-dashboard?var-namespace=$__cell_2&var-workload=$__cell_", + "pattern": "destination_workload", + "preserveFormat": false, + "sanitize": false, + "thresholds": [], + "type": "hidden", + "unit": "short" + }, + { + "alias": "", + "colorMode": null, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "pattern": "Time", + "thresholds": [], + "type": "hidden", + "unit": "short" + }, + { + "alias": "Requests", + "colorMode": null, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "pattern": "Value #A", + "thresholds": [], + "type": "number", + "unit": "ops" + }, + { + "alias": "P50 Latency", + "colorMode": null, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "pattern": "Value #B", + "thresholds": [], + "type": "number", + "unit": "s" + }, + { + "alias": "P90 Latency", + "colorMode": null, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "pattern": "Value #D", + "thresholds": [], + "type": "number", + "unit": "s" + }, + { + "alias": "P99 Latency", + "colorMode": null, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "pattern": "Value #E", + "thresholds": [], + "type": "number", + "unit": "s" + }, + { + "alias": "Success Rate", + "colorMode": "cell", + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "pattern": "Value #F", + "thresholds": [ + ".95", + " 1.00" + ], + "type": "number", + "unit": "percentunit" + }, + { + "alias": "Workload", + "colorMode": null, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "link": true, + "linkTooltip": "$__cell dashboard", + "linkUrl": "/dashboard/db/istio-workload-dashboard?var-workload=$__cell_2&var-namespace=$__cell_3", + "pattern": "destination_workload_var", + "thresholds": [], + "type": "number", + "unit": "short" + }, + { + "alias": "Service", + "colorMode": null, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "link": true, + "linkTooltip": "$__cell dashboard", + "linkUrl": "/dashboard/db/istio-service-dashboard?var-service=$__cell", + "pattern": "destination_service", + "thresholds": [], + "type": "string", + "unit": "short" + }, + { + "alias": "", + "colorMode": null, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "pattern": "destination_workload_namespace", + "thresholds": [], + "type": "hidden", + "unit": "short" + } + ], + "targets": [ + { + "expr": "label_join(sum(rate(istio_requests_total{reporter=\"destination\", response_code=\"200\"}[1m])) by (destination_workload, destination_workload_namespace, destination_service), \"destination_workload_var\", \".\", \"destination_workload\", \"destination_workload_namespace\")", + "format": "table", + "hide": false, + "instant": true, + "intervalFactor": 1, + "legendFormat": "{{ destination_workload}}.{{ destination_workload_namespace }}", + "refId": "A" + }, + { + "expr": "label_join((histogram_quantile(0.50, sum(rate(istio_request_duration_milliseconds_bucket{reporter=\"destination\"}[1m])) by (le, destination_workload, destination_workload_namespace)) / 1000) or histogram_quantile(0.50, sum(rate(istio_request_duration_seconds_bucket{reporter=\"destination\"}[1m])) by (le, destination_workload, destination_workload_namespace)), \"destination_workload_var\", \".\", \"destination_workload\", \"destination_workload_namespace\")", + "format": "table", + "hide": false, + "instant": true, + "intervalFactor": 1, + "legendFormat": "{{ destination_workload}}.{{ destination_workload_namespace }}", + "refId": "B" + }, + { + "expr": "label_join((histogram_quantile(0.90, sum(rate(istio_request_duration_milliseconds_bucket{reporter=\"destination\"}[1m])) by (le, destination_workload, destination_workload_namespace)) / 1000) or histogram_quantile(0.90, sum(rate(istio_request_duration_seconds_bucket{reporter=\"destination\"}[1m])) by (le, destination_workload, destination_workload_namespace)), \"destination_workload_var\", \".\", \"destination_workload\", \"destination_workload_namespace\")", + "format": "table", + "hide": false, + "instant": true, + "intervalFactor": 1, + "legendFormat": "{{ destination_workload }}.{{ destination_workload_namespace }}", + "refId": "D" + }, + { + "expr": "label_join((histogram_quantile(0.99, sum(rate(istio_request_duration_milliseconds_bucket{reporter=\"destination\"}[1m])) by (le, destination_workload, destination_workload_namespace)) / 1000) or histogram_quantile(0.99, sum(rate(istio_request_duration_seconds_bucket{reporter=\"destination\"}[1m])) by (le, destination_workload, destination_workload_namespace)), \"destination_workload_var\", \".\", \"destination_workload\", \"destination_workload_namespace\")", + "format": "table", + "hide": false, + "instant": true, + "intervalFactor": 1, + "legendFormat": "{{ destination_workload }}.{{ destination_workload_namespace }}", + "refId": "E" + }, + { + "expr": "label_join((sum(rate(istio_requests_total{reporter=\"destination\", response_code!~\"5.*\"}[1m])) by (destination_workload, destination_workload_namespace) / sum(rate(istio_requests_total{reporter=\"destination\"}[1m])) by (destination_workload, destination_workload_namespace)), \"destination_workload_var\", \".\", \"destination_workload\", \"destination_workload_namespace\")", + "format": "table", + "hide": false, + "instant": true, + "interval": "", + "intervalFactor": 1, + "legendFormat": "{{ destination_workload }}.{{ destination_workload_namespace }}", + "refId": "F" + } + ], + "timeFrom": null, + "title": "HTTP/GRPC Workloads", + "transform": "table", + "type": "table" + }, + { + "columns": [], + "datasource": "Prometheus", + "fontSize": "100%", + "gridPos": { + "h": 18, + "w": 24, + "x": 0, + "y": 30 + }, + "hideTimeOverride": false, + "id": 109, + "links": [], + "pageSize": null, + "repeatDirection": "v", + "scroll": true, + "showHeader": true, + "sort": { + "col": 2, + "desc": true + }, + "styles": [ + { + "alias": "Workload", + "colorMode": null, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "link": false, + "linkTargetBlank": false, + "linkTooltip": "$__cell dashboard", + "linkUrl": "/dashboard/db/istio-tcp-workload-dashboard?var-namespace=$__cell_2&&var-workload=$__cell", + "pattern": "destination_workload", + "preserveFormat": false, + "sanitize": false, + "thresholds": [], + "type": "hidden", + "unit": "short" + }, + { + "alias": "Bytes Sent", + "colorMode": null, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "pattern": "Value #A", + "thresholds": [ + "" + ], + "type": "number", + "unit": "Bps" + }, + { + "alias": "Bytes Received", + "colorMode": null, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "pattern": "Value #C", + "thresholds": [], + "type": "number", + "unit": "Bps" + }, + { + "alias": "", + "colorMode": null, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "pattern": "Time", + "thresholds": [], + "type": "hidden", + "unit": "short" + }, + { + "alias": "Workload", + "colorMode": null, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "link": true, + "linkTooltip": "$__cell dashboard", + "linkUrl": "/dashboard/db/istio-workload-dashboard?var-namespace=$__cell_3&var-workload=$__cell_2", + "pattern": "destination_workload_var", + "thresholds": [], + "type": "string", + "unit": "short" + }, + { + "alias": "", + "colorMode": null, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "pattern": "destination_workload_namespace", + "thresholds": [], + "type": "hidden", + "unit": "short" + }, + { + "alias": "Service", + "colorMode": null, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "link": true, + "linkTooltip": "$__cell dashboard", + "linkUrl": "/dashboard/db/istio-service-dashboard?var-service=$__cell", + "pattern": "destination_service", + "thresholds": [], + "type": "number", + "unit": "short" + } + ], + "targets": [ + { + "expr": "label_join(sum(rate(istio_tcp_received_bytes_total{reporter=\"source\"}[1m])) by (destination_workload, destination_workload_namespace, destination_service), \"destination_workload_var\", \".\", \"destination_workload\", \"destination_workload_namespace\")", + "format": "table", + "hide": false, + "instant": true, + "intervalFactor": 1, + "legendFormat": "{{ destination_workload }}", + "refId": "C" + }, + { + "expr": "label_join(sum(rate(istio_tcp_sent_bytes_total{reporter=\"source\"}[1m])) by (destination_workload, destination_workload_namespace, destination_service), \"destination_workload_var\", \".\", \"destination_workload\", \"destination_workload_namespace\")", + "format": "table", + "hide": false, + "instant": true, + "intervalFactor": 1, + "legendFormat": "{{ destination_workload }}", + "refId": "A" + } + ], + "timeFrom": null, + "title": "TCP Workloads", + "transform": "table", + "type": "table" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 9, + "w": 24, + "x": 0, + "y": 48 + }, + "id": 111, + "legend": { + "alignAsTable": false, + "avg": false, + "current": false, + "max": false, + "min": false, + "rightSide": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(istio_build) by (component, tag)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{ component }}: {{ tag }}", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Istio Components by Version", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + } + ], + "refresh": "5s", + "schemaVersion": 18, + "style": "dark", + "tags": [], + "templating": { + "list": [] + }, + "time": { + "from": "now-5m", + "to": "now" + }, + "timepicker": { + "refresh_intervals": [ + "5s", + "10s", + "30s", + "1m", + "5m", + "15m", + "30m", + "1h", + "2h", + "1d" + ], + "time_options": [ + "5m", + "15m", + "1h", + "6h", + "12h", + "24h", + "2d", + "7d", + "30d" + ] + }, + "timezone": "browser", + "title": "Istio Mesh Dashboard", + "uid": "G8wLrJIZk", + "version": 5 +} +' +--- +apiVersion: v1 +kind: ConfigMap +metadata: + name: istio-grafana-configuration-dashboards-istio-performance-dashboard + namespace: istio-system + labels: + app: grafana + chart: grafana + heritage: Tiller + release: istio + istio: grafana +data: + istio-performance-dashboard.json: '{ + "annotations": { + "list": [ + { + "builtIn": 1, + "datasource": "-- Grafana --", + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations & Alerts", + "type": "dashboard" + } + ] + }, + "editable": false, + "gnetId": null, + "graphTooltip": 0, + "id": 9, + "links": [], + "panels": [ + { + "collapsed": true, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 0 + }, + "id": 21, + "panels": [ + { + "content": "The charts on this dashboard are intended to show Istio main components cost in terms resources utilization under steady load.\n\n- **vCPU/1k rps:** shows vCPU utilization by the main Istio components normalized by 1000 requests/second. When idle or low traffic, this chart will be blank. The curve for istio-proxy refers to the services sidecars only.\n- **vCPU:** vCPU utilization by Istio components, not normalized.\n- **Memory:** memory footprint for the components. Telemetry and policy are normalized by 1k rps, and no data is shown when there is no traffic. For ingress and istio-proxy, the data is per instance.\n- **Bytes transferred/ sec:** shows the number of bytes flowing through each Istio component.\n\n\n", + "gridPos": { + "h": 6, + "w": 24, + "x": 0, + "y": 1 + }, + "id": 19, + "links": [], + "mode": "markdown", + "timeFrom": null, + "timeShift": null, + "title": "Performance Dashboard README", + "transparent": true, + "type": "text" + } + ], + "title": "Performance Dashboard Notes", + "type": "row" + }, + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 1 + }, + "id": 6, + "panels": [], + "title": "vCPU Usage", + "type": "row" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "fill": 1, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 2 + }, + "id": 4, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "(sum(irate(container_cpu_usage_seconds_total{job=\"kubernetes-cadvisor\",pod_name=~\"istio-telemetry-.*\",container_name=~\"mixer|istio-proxy\"}[1m]))/ (round(sum(irate(istio_requests_total[1m])), 0.001)/1000))/ (sum(irate(istio_requests_total{source_workload=\"istio-ingressgateway\"}[1m])) >bool 10)", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "istio-telemetry", + "refId": "A" + }, + { + "expr": "(sum(irate(container_cpu_usage_seconds_total{job=\"kubernetes-cadvisor\",pod_name=~\"istio-ingressgateway-.*\",container_name=\"istio-proxy\"}[1m])) / (round(sum(irate(istio_requests_total{source_workload=\"istio-ingressgateway\", reporter=\"source\"}[1m])), 0.001)/1000))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "istio-ingressgateway", + "refId": "B" + }, + { + "expr": "(sum(irate(container_cpu_usage_seconds_total{job=\"kubernetes-cadvisor\",namespace!=\"istio-system\",container_name=\"istio-proxy\"}[1m]))/ (round(sum(irate(istio_requests_total[1m])), 0.001)/1000))/ (sum(irate(istio_requests_total{source_workload=\"istio-ingressgateway\"}[1m])) >bool 10)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "istio-proxy", + "refId": "C" + }, + { + "expr": "(sum(irate(container_cpu_usage_seconds_total{job=\"kubernetes-cadvisor\",pod_name=~\"istio-policy-.*\",container_name=~\"mixer|istio-proxy\"}[1m]))/ (round(sum(irate(istio_requests_total[1m])), 0.001)/1000))/ (sum(irate(istio_requests_total{source_workload=\"istio-ingressgateway\"}[1m])) >bool 10)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "istio-policy", + "refId": "D" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "vCPU / 1k rps", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "fill": 1, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 2 + }, + "id": 7, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(rate(container_cpu_usage_seconds_total{job=\"kubernetes-cadvisor\",pod_name=~\"istio-telemetry-.*\",container_name=~\"mixer|istio-proxy\"}[1m]))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "istio-telemetry", + "refId": "A" + }, + { + "expr": "sum(rate(container_cpu_usage_seconds_total{job=\"kubernetes-cadvisor\",pod_name=~\"istio-ingressgateway-.*\",container_name=\"istio-proxy\"}[1m]))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "istio-ingressgateway", + "refId": "B" + }, + { + "expr": "sum(rate(container_cpu_usage_seconds_total{job=\"kubernetes-cadvisor\",namespace!=\"istio-system\",container_name=\"istio-proxy\"}[1m]))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "istio-proxy", + "refId": "C" + }, + { + "expr": "sum(rate(container_cpu_usage_seconds_total{job=\"kubernetes-cadvisor\",pod_name=~\"istio-policy-.*\",container_name=~\"mixer|istio-proxy\"}[1m]))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "istio-policy", + "refId": "D" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "vCPU", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 10 + }, + "id": 13, + "panels": [], + "title": "Memory and Data Rates", + "type": "row" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "fill": 1, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 11 + }, + "id": 902, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "(sum(container_memory_usage_bytes{job=\"kubernetes-cadvisor\",pod_name=~\"istio-telemetry-.*\"}) / (sum(irate(istio_requests_total[1m])) / 1000)) / (sum(irate(istio_requests_total{source_workload=\"istio-ingressgateway\"}[1m])) >bool 10)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "istio-telemetry / 1k rps", + "refId": "A" + }, + { + "expr": "sum(container_memory_usage_bytes{job=\"kubernetes-cadvisor\",pod_name=~\"istio-ingressgateway-.*\"}) / count(container_memory_usage_bytes{job=\"kubernetes-cadvisor\",pod_name=~\"istio-ingressgateway-.*\",container_name!=\"POD\"})", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "per istio-ingressgateway", + "refId": "B" + }, + { + "expr": "sum(container_memory_usage_bytes{job=\"kubernetes-cadvisor\",namespace!=\"istio-system\",container_name=\"istio-proxy\"}) / count(container_memory_usage_bytes{job=\"kubernetes-cadvisor\",namespace!=\"istio-system\",container_name=\"istio-proxy\"})", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "per istio proxy", + "refId": "C" + }, + { + "expr": "(sum(container_memory_usage_bytes{job=\"kubernetes-cadvisor\",pod_name=~\"istio-policy-.*\"}) / (sum(irate(istio_requests_total[1m])) / 1000))/ (sum(irate(istio_requests_total{source_workload=\"istio-ingressgateway\"}[1m])) >bool 10)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "istio-policy / 1k rps", + "refId": "D" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Memory Usage", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "bytes", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "fill": 1, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 11 + }, + "id": 11, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(irate(istio_response_bytes_sum{destination_workload=\"istio-telemetry\"}[1m])) + sum(irate(istio_request_bytes_sum{destination_workload=\"istio-telemetry\"}[1m]))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "istio-telemetry", + "refId": "A" + }, + { + "expr": "sum(irate(istio_response_bytes_sum{source_workload=\"istio-ingressgateway\", reporter=\"source\"}[1m]))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "istio-ingressgateway", + "refId": "B" + }, + { + "expr": "sum(irate(istio_response_bytes_sum{source_workload_namespace!=\"istio-system\", reporter=\"source\"}[1m])) + sum(irate(istio_response_bytes_sum{destination_workload_namespace!=\"istio-system\", reporter=\"destination\"}[1m])) + sum(irate(istio_request_bytes_sum{source_workload_namespace!=\"istio-system\", reporter=\"source\"}[1m])) + sum(irate(istio_request_bytes_sum{destination_workload_namespace!=\"istio-system\", reporter=\"destination\"}[1m]))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "istio-proxy", + "refId": "C" + }, + { + "expr": "sum(irate(istio_response_bytes_sum{destination_workload=\"istio-policy\"}[1m])) + sum(irate(istio_request_bytes_sum{destination_workload=\"istio-policy\"}[1m]))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "istio_policy", + "refId": "D" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Bytes transferred / sec", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "Bps", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 19 + }, + "id": 17, + "panels": [], + "title": "Istio Component Versions", + "type": "row" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "fill": 1, + "gridPos": { + "h": 8, + "w": 24, + "x": 0, + "y": 20 + }, + "id": 15, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(istio_build) by (component, tag)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{ component }}: {{ tag }}", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Istio Components by Version", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 31 + }, + "id": 71, + "panels": [], + "title": "Proxy Resource Usage", + "type": "row" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 7, + "w": 6, + "x": 0, + "y": 32 + }, + "id": 72, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(container_memory_usage_bytes{job=\"kubernetes-cadvisor\",container_name=\"istio-proxy\"})", + "format": "time_series", + "hide": false, + "intervalFactor": 2, + "legendFormat": "{{ container_name }} (k8s)", + "refId": "B", + "step": 2 + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Memory", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "bytes", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 7, + "w": 6, + "x": 6, + "y": 32 + }, + "id": 73, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(rate(container_cpu_usage_seconds_total{job=\"kubernetes-cadvisor\",container_name=\"istio-proxy\"}[1m]))", + "format": "time_series", + "hide": false, + "intervalFactor": 2, + "legendFormat": "Total (k8s)", + "refId": "A", + "step": 2 + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "vCPU", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 7, + "w": 6, + "x": 12, + "y": 32 + }, + "id": 702, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(container_fs_usage_bytes{job=\"kubernetes-cadvisor\", container_name=\"istio-proxy\"})", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "{{ container_name }}", + "refId": "B", + "step": 2 + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Disk", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "bytes", + "label": "", + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "decimals": null, + "format": "none", + "label": "", + "logBase": 1024, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 39 + }, + "id": 69, + "panels": [], + "title": "Pilot Resource Usage", + "type": "row" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 7, + "w": 6, + "x": 0, + "y": 40 + }, + "id": 5, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "process_virtual_memory_bytes{job=\"pilot\"}", + "format": "time_series", + "instant": false, + "intervalFactor": 2, + "legendFormat": "Virtual Memory", + "refId": "I", + "step": 2 + }, + { + "expr": "process_resident_memory_bytes{job=\"pilot\"}", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "Resident Memory", + "refId": "H", + "step": 2 + }, + { + "expr": "go_memstats_heap_sys_bytes{job=\"pilot\"}", + "format": "time_series", + "hide": true, + "intervalFactor": 2, + "legendFormat": "heap sys", + "refId": "A" + }, + { + "expr": "go_memstats_heap_alloc_bytes{job=\"pilot\"}", + "format": "time_series", + "hide": true, + "intervalFactor": 2, + "legendFormat": "heap alloc", + "refId": "D" + }, + { + "expr": "go_memstats_alloc_bytes{job=\"pilot\"}", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "Alloc", + "refId": "F", + "step": 2 + }, + { + "expr": "go_memstats_heap_inuse_bytes{job=\"pilot\"}", + "format": "time_series", + "hide": false, + "intervalFactor": 2, + "legendFormat": "Heap in-use", + "refId": "E", + "step": 2 + }, + { + "expr": "go_memstats_stack_inuse_bytes{job=\"pilot\"}", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "Stack in-use", + "refId": "G", + "step": 2 + }, + { + "expr": "sum(container_memory_usage_bytes{job=\"kubernetes-cadvisor\",container_name=~\"discovery|istio-proxy\", pod_name=~\"istio-pilot-.*\"})", + "format": "time_series", + "hide": false, + "intervalFactor": 2, + "legendFormat": "Total (k8s)", + "refId": "C", + "step": 2 + }, + { + "expr": "container_memory_usage_bytes{job=\"kubernetes-cadvisor\",container_name=~\"discovery|istio-proxy\", pod_name=~\"istio-pilot-.*\"}", + "format": "time_series", + "hide": false, + "intervalFactor": 2, + "legendFormat": "{{ container_name }} (k8s)", + "refId": "B", + "step": 2 + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Memory", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "bytes", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 7, + "w": 6, + "x": 6, + "y": 40 + }, + "id": 602, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(rate(container_cpu_usage_seconds_total{job=\"kubernetes-cadvisor\",container_name=~\"discovery|istio-proxy\", pod_name=~\"istio-pilot-.*\"}[1m]))", + "format": "time_series", + "hide": false, + "intervalFactor": 2, + "legendFormat": "Total (k8s)", + "refId": "A", + "step": 2 + }, + { + "expr": "sum(rate(container_cpu_usage_seconds_total{job=\"kubernetes-cadvisor\",container_name=~\"discovery|istio-proxy\", pod_name=~\"istio-pilot-.*\"}[1m])) by (container_name)", + "format": "time_series", + "hide": false, + "intervalFactor": 2, + "legendFormat": "{{ container_name }} (k8s)", + "refId": "B", + "step": 2 + }, + { + "expr": "irate(process_cpu_seconds_total{job=\"pilot\"}[1m])", + "format": "time_series", + "hide": false, + "intervalFactor": 2, + "legendFormat": "pilot (self-reported)", + "refId": "C", + "step": 2 + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "vCPU", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 7, + "w": 6, + "x": 12, + "y": 40 + }, + "id": 74, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "process_open_fds{job=\"pilot\"}", + "format": "time_series", + "hide": true, + "instant": false, + "interval": "", + "intervalFactor": 2, + "legendFormat": "Open FDs (pilot)", + "refId": "A" + }, + { + "expr": "container_fs_usage_bytes{job=\"kubernetes-cadvisor\", container_name=~\"discovery|istio-proxy\", pod_name=~\"istio-pilot-.*\"}", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "{{ container_name }}", + "refId": "B", + "step": 2 + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Disk", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "bytes", + "label": "", + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "decimals": null, + "format": "none", + "label": "", + "logBase": 1024, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 7, + "w": 6, + "x": 18, + "y": 40 + }, + "id": 402, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": false, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "go_goroutines{job=\"pilot\"}", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "Number of Goroutines", + "refId": "A", + "step": 2 + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Goroutines", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": "", + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 47 + }, + "id": 93, + "panels": [], + "title": "Mixer Resource Usage", + "type": "row" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 7, + "w": 6, + "x": 0, + "y": 48 + }, + "id": 94, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "process_virtual_memory_bytes{job=~\"istio-telemetry|istio-policy\"}", + "format": "time_series", + "instant": false, + "intervalFactor": 2, + "legendFormat": "Virtual Memory", + "refId": "I", + "step": 2 + }, + { + "expr": "process_resident_memory_bytes{job=~\"istio-telemetry|istio-policy\"}", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "Resident Memory", + "refId": "H", + "step": 2 + }, + { + "expr": "go_memstats_heap_sys_bytes{job=~\"istio-telemetry|istio-policy\"}", + "format": "time_series", + "hide": true, + "intervalFactor": 2, + "legendFormat": "heap sys", + "refId": "A" + }, + { + "expr": "go_memstats_heap_alloc_bytes{job=~\"istio-telemetry|istio-policy\"}", + "format": "time_series", + "hide": true, + "intervalFactor": 2, + "legendFormat": "heap alloc", + "refId": "D" + }, + { + "expr": "go_memstats_alloc_bytes{job=~\"istio-telemetry|istio-policy\"}", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "Alloc", + "refId": "F", + "step": 2 + }, + { + "expr": "go_memstats_heap_inuse_bytes{job=~\"istio-telemetry|istio-policy\"}", + "format": "time_series", + "hide": false, + "intervalFactor": 2, + "legendFormat": "Heap in-use", + "refId": "E", + "step": 2 + }, + { + "expr": "go_memstats_stack_inuse_bytes{job=~\"istio-policy|istio-telemetry\"}", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "Stack in-use", + "refId": "G", + "step": 2 + }, + { + "expr": "sum(container_memory_usage_bytes{job=\"kubernetes-cadvisor\",container_name=~\"mixer|istio-proxy\", pod_name=~\"istio-telemetry-.*\"})", + "format": "time_series", + "hide": false, + "intervalFactor": 2, + "legendFormat": "Total (k8s)", + "refId": "C", + "step": 2 + }, + { + "expr": "container_memory_usage_bytes{job=\"kubernetes-cadvisor\",container_name=~\"mixer|istio-proxy\", pod_name=~\"istio-telemetry-.*\"}", + "format": "time_series", + "hide": false, + "intervalFactor": 2, + "legendFormat": "{{ container_name }} (k8s)", + "refId": "B", + "step": 2 + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Memory", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "bytes", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 7, + "w": 6, + "x": 6, + "y": 48 + }, + "id": 95, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(rate(container_cpu_usage_seconds_total{job=\"kubernetes-cadvisor\",container_name=~\"mixer|istio-proxy\", pod_name=~\"istio-telemetry-.*\"}[1m]))", + "format": "time_series", + "hide": false, + "intervalFactor": 2, + "legendFormat": "Total (k8s)", + "refId": "A", + "step": 2 + }, + { + "expr": "sum(rate(container_cpu_usage_seconds_total{job=\"kubernetes-cadvisor\",container_name=~\"mixer|istio-proxy\", pod_name=~\"istio-telemetry-.*\"}[1m])) by (container_name)", + "format": "time_series", + "hide": false, + "intervalFactor": 2, + "legendFormat": "{{ container_name }} (k8s)", + "refId": "B", + "step": 2 + }, + { + "expr": "irate(process_cpu_seconds_total{job=~\"istio-policy|istio-telemetry\"}[1m])", + "format": "time_series", + "hide": false, + "intervalFactor": 2, + "legendFormat": "mixer (self-reported)", + "refId": "C", + "step": 2 + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "vCPU", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 7, + "w": 6, + "x": 12, + "y": 48 + }, + "id": 96, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "process_open_fds{job=~\"istio-policy|istio-telemetry\"}", + "format": "time_series", + "hide": true, + "instant": false, + "interval": "", + "intervalFactor": 2, + "legendFormat": "Open FDs (pilot)", + "refId": "A" + }, + { + "expr": "container_fs_usage_bytes{job=\"kubernetes-cadvisor\", container_name=~\"mixer|istio-proxy\", pod_name=~\"istio-telemetry-.*\"}", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "{{ container_name }}", + "refId": "B", + "step": 2 + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Disk", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "bytes", + "label": "", + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "decimals": null, + "format": "none", + "label": "", + "logBase": 1024, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 7, + "w": 6, + "x": 18, + "y": 48 + }, + "id": 97, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": false, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "go_goroutines{job=\"istio-telemetry\"}", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "Number of Goroutines", + "refId": "A", + "step": 2 + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Goroutines", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": "", + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + } + ], + "refresh": "10s", + "schemaVersion": 18, + "style": "dark", + "tags": [], + "templating": { + "list": [] + }, + "time": { + "from": "now-5m", + "to": "now" + }, + "timepicker": { + "refresh_intervals": [ + "5s", + "10s", + "30s", + "1m", + "5m", + "15m", + "30m", + "1h", + "2h", + "1d" + ], + "time_options": [ + "5m", + "15m", + "1h", + "6h", + "12h", + "24h", + "2d", + "7d", + "30d" + ] + }, + "timezone": "", + "title": "Istio Performance Dashboard", + "uid": "vu8e0VWZk", + "version": 22 +} +' +--- +apiVersion: v1 +kind: ConfigMap +metadata: + name: istio-grafana-configuration-dashboards-istio-service-dashboard + namespace: istio-system + labels: + app: grafana + chart: grafana + heritage: Tiller + release: istio + istio: grafana +data: + istio-service-dashboard.json: '{ + "annotations": { + "list": [ + { + "builtIn": 1, + "datasource": "-- Grafana --", + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations & Alerts", + "type": "dashboard" + } + ] + }, + "editable": false, + "gnetId": null, + "graphTooltip": 0, + "iteration": 1536442501501, + "links": [], + "panels": [ + { + "content": "
\nSERVICE: $service\n
", + "gridPos": { + "h": 3, + "w": 24, + "x": 0, + "y": 0 + }, + "id": 89, + "links": [], + "mode": "html", + "title": "", + "transparent": true, + "type": "text" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "datasource": "Prometheus", + "format": "ops", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "gridPos": { + "h": 4, + "w": 6, + "x": 0, + "y": 3 + }, + "id": 12, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": true, + "lineColor": "rgb(31, 120, 193)", + "show": true + }, + "tableColumn": "", + "targets": [ + { + "expr": "round(sum(irate(istio_requests_total{reporter=\"source\",destination_service=~\"$service\"}[5m])), 0.001)", + "format": "time_series", + "intervalFactor": 1, + "refId": "A", + "step": 4 + } + ], + "thresholds": "", + "title": "Client Request Volume", + "transparent": false, + "type": "singlestat", + "valueFontSize": "80%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "current" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "rgba(50, 172, 45, 0.97)", + "rgba(237, 129, 40, 0.89)", + "rgba(245, 54, 54, 0.9)" + ], + "datasource": "Prometheus", + "decimals": null, + "format": "percentunit", + "gauge": { + "maxValue": 100, + "minValue": 80, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": false + }, + "gridPos": { + "h": 4, + "w": 6, + "x": 6, + "y": 3 + }, + "id": 14, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": true, + "lineColor": "rgb(31, 120, 193)", + "show": true + }, + "tableColumn": "", + "targets": [ + { + "expr": "sum(irate(istio_requests_total{reporter=\"source\",destination_service=~\"$service\",response_code!~\"5.*\"}[5m])) / sum(irate(istio_requests_total{reporter=\"source\",destination_service=~\"$service\"}[5m]))", + "format": "time_series", + "intervalFactor": 1, + "refId": "B" + } + ], + "thresholds": "95, 99, 99.5", + "title": "Client Success Rate (non-5xx responses)", + "transparent": false, + "type": "singlestat", + "valueFontSize": "80%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "avg" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 4, + "w": 6, + "x": 12, + "y": 3 + }, + "id": 87, + "legend": { + "alignAsTable": false, + "avg": false, + "current": false, + "hideEmpty": false, + "hideZero": false, + "max": false, + "min": false, + "rightSide": true, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "(histogram_quantile(0.50, sum(irate(istio_request_duration_milliseconds_bucket{reporter=\"source\",destination_service=~\"$service\"}[1m])) by (le)) / 1000) or histogram_quantile(0.50, sum(irate(istio_request_duration_seconds_bucket{reporter=\"source\",destination_service=~\"$service\"}[1m])) by (le))", + "format": "time_series", + "interval": "", + "intervalFactor": 1, + "legendFormat": "P50", + "refId": "A" + }, + { + "expr": "(histogram_quantile(0.90, sum(irate(istio_request_duration_milliseconds_bucket{reporter=\"source\",destination_service=~\"$service\"}[1m])) by (le)) / 1000) or histogram_quantile(0.90, sum(irate(istio_request_duration_seconds_bucket{reporter=\"source\",destination_service=~\"$service\"}[1m])) by (le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "P90", + "refId": "B" + }, + { + "expr": "(histogram_quantile(0.99, sum(irate(istio_request_duration_milliseconds_bucket{reporter=\"source\",destination_service=~\"$service\"}[1m])) by (le)) / 1000) or histogram_quantile(0.99, sum(irate(istio_request_duration_seconds_bucket{reporter=\"source\",destination_service=~\"$service\"}[1m])) by (le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "P99", + "refId": "C" + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Client Request Duration", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "s", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "#299c46", + "rgba(237, 129, 40, 0.89)", + "#d44a3a" + ], + "datasource": "Prometheus", + "format": "Bps", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "gridPos": { + "h": 4, + "w": 6, + "x": 18, + "y": 3 + }, + "id": 84, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": true, + "lineColor": "rgb(31, 120, 193)", + "show": true + }, + "tableColumn": "", + "targets": [ + { + "expr": "sum(irate(istio_tcp_received_bytes_total{reporter=\"source\", destination_service=~\"$service\"}[1m]))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "", + "refId": "A" + } + ], + "thresholds": "", + "title": "TCP Received Bytes", + "transparent": false, + "type": "singlestat", + "valueFontSize": "80%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "avg" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "datasource": "Prometheus", + "format": "ops", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "gridPos": { + "h": 4, + "w": 6, + "x": 0, + "y": 7 + }, + "id": 97, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": true, + "lineColor": "rgb(31, 120, 193)", + "show": true + }, + "tableColumn": "", + "targets": [ + { + "expr": "round(sum(irate(istio_requests_total{reporter=\"destination\",destination_service=~\"$service\"}[5m])), 0.001)", + "format": "time_series", + "intervalFactor": 1, + "refId": "A", + "step": 4 + } + ], + "thresholds": "", + "title": "Server Request Volume", + "transparent": false, + "type": "singlestat", + "valueFontSize": "80%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "current" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "rgba(50, 172, 45, 0.97)", + "rgba(237, 129, 40, 0.89)", + "rgba(245, 54, 54, 0.9)" + ], + "datasource": "Prometheus", + "decimals": null, + "format": "percentunit", + "gauge": { + "maxValue": 100, + "minValue": 80, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": false + }, + "gridPos": { + "h": 4, + "w": 6, + "x": 6, + "y": 7 + }, + "id": 98, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": true, + "lineColor": "rgb(31, 120, 193)", + "show": true + }, + "tableColumn": "", + "targets": [ + { + "expr": "sum(irate(istio_requests_total{reporter=\"destination\",destination_service=~\"$service\",response_code!~\"5.*\"}[5m])) / sum(irate(istio_requests_total{reporter=\"destination\",destination_service=~\"$service\"}[5m]))", + "format": "time_series", + "intervalFactor": 1, + "refId": "B" + } + ], + "thresholds": "95, 99, 99.5", + "title": "Server Success Rate (non-5xx responses)", + "transparent": false, + "type": "singlestat", + "valueFontSize": "80%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "avg" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 4, + "w": 6, + "x": 12, + "y": 7 + }, + "id": 99, + "legend": { + "alignAsTable": false, + "avg": false, + "current": false, + "hideEmpty": false, + "hideZero": false, + "max": false, + "min": false, + "rightSide": true, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "(histogram_quantile(0.50, sum(irate(istio_request_duration_milliseconds_bucket{reporter=\"destination\",destination_service=~\"$service\"}[1m])) by (le)) / 1000) or histogram_quantile(0.50, sum(irate(istio_request_duration_seconds_bucket{reporter=\"destination\",destination_service=~\"$service\"}[1m])) by (le))", + "format": "time_series", + "interval": "", + "intervalFactor": 1, + "legendFormat": "P50", + "refId": "A" + }, + { + "expr": "(histogram_quantile(0.90, sum(irate(istio_request_duration_milliseconds_bucket{reporter=\"destination\",destination_service=~\"$service\"}[1m])) by (le)) / 1000) or histogram_quantile(0.90, sum(irate(istio_request_duration_seconds_bucket{reporter=\"destination\",destination_service=~\"$service\"}[1m])) by (le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "P90", + "refId": "B" + }, + { + "expr": "(histogram_quantile(0.99, sum(irate(istio_request_duration_milliseconds_bucket{reporter=\"destination\",destination_service=~\"$service\"}[1m])) by (le)) / 1000) or histogram_quantile(0.99, sum(irate(istio_request_duration_seconds_bucket{reporter=\"destination\",destination_service=~\"$service\"}[1m])) by (le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "P99", + "refId": "C" + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Server Request Duration", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "s", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "#299c46", + "rgba(237, 129, 40, 0.89)", + "#d44a3a" + ], + "datasource": "Prometheus", + "format": "Bps", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "gridPos": { + "h": 4, + "w": 6, + "x": 18, + "y": 7 + }, + "id": 100, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": true, + "lineColor": "rgb(31, 120, 193)", + "show": true + }, + "tableColumn": "", + "targets": [ + { + "expr": "sum(irate(istio_tcp_sent_bytes_total{reporter=\"source\", destination_service=~\"$service\"}[1m])) ", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "", + "refId": "A" + } + ], + "thresholds": "", + "title": "TCP Sent Bytes", + "transparent": false, + "type": "singlestat", + "valueFontSize": "80%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "avg" + }, + { + "content": "
\nCLIENT WORKLOADS\n
", + "gridPos": { + "h": 3, + "w": 24, + "x": 0, + "y": 11 + }, + "id": 45, + "links": [], + "mode": "html", + "title": "", + "transparent": true, + "type": "text" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 0, + "gridPos": { + "h": 6, + "w": 12, + "x": 0, + "y": 14 + }, + "id": 25, + "legend": { + "avg": false, + "current": false, + "hideEmpty": true, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null as zero", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "round(sum(irate(istio_requests_total{connection_security_policy=\"mutual_tls\",destination_service=~\"$service\",reporter=\"source\",source_workload=~\"$srcwl\",source_workload_namespace=~\"$srcns\"}[5m])) by (source_workload, source_workload_namespace, response_code), 0.001)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{ source_workload }}.{{ source_workload_namespace }} : {{ response_code }} (🔐mTLS)", + "refId": "B", + "step": 2 + }, + { + "expr": "round(sum(irate(istio_requests_total{connection_security_policy!=\"mutual_tls\", destination_service=~\"$service\", reporter=\"source\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[5m])) by (source_workload, source_workload_namespace, response_code), 0.001)", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ source_workload }}.{{ source_workload_namespace }} : {{ response_code }}", + "refId": "A", + "step": 2 + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Incoming Requests by Source And Response Code", + "tooltip": { + "shared": false, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [ + "total" + ] + }, + "yaxes": [ + { + "format": "ops", + "label": null, + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 6, + "w": 12, + "x": 12, + "y": 14 + }, + "id": 26, + "legend": { + "avg": false, + "current": false, + "hideEmpty": true, + "hideZero": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(irate(istio_requests_total{reporter=\"source\", connection_security_policy=\"mutual_tls\", destination_service=~\"$service\",response_code!~\"5.*\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[5m])) by (source_workload, source_workload_namespace) / sum(irate(istio_requests_total{reporter=\"source\", connection_security_policy=\"mutual_tls\", destination_service=~\"$service\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[5m])) by (source_workload, source_workload_namespace)", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ source_workload }}.{{ source_workload_namespace }} (🔐mTLS)", + "refId": "A", + "step": 2 + }, + { + "expr": "sum(irate(istio_requests_total{reporter=\"source\", connection_security_policy!=\"mutual_tls\", destination_service=~\"$service\",response_code!~\"5.*\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[5m])) by (source_workload, source_workload_namespace) / sum(irate(istio_requests_total{reporter=\"source\", connection_security_policy!=\"mutual_tls\", destination_service=~\"$service\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[5m])) by (source_workload, source_workload_namespace)", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ source_workload }}.{{ source_workload_namespace }}", + "refId": "B", + "step": 2 + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Incoming Success Rate (non-5xx responses) By Source", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "percentunit", + "label": null, + "logBase": 1, + "max": "1.01", + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "description": "", + "fill": 1, + "gridPos": { + "h": 6, + "w": 8, + "x": 0, + "y": 20 + }, + "id": 27, + "legend": { + "alignAsTable": false, + "avg": false, + "current": false, + "hideEmpty": true, + "hideZero": false, + "max": false, + "min": false, + "rightSide": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "(histogram_quantile(0.50, sum(irate(istio_request_duration_milliseconds_bucket{reporter=\"source\", connection_security_policy=\"mutual_tls\", destination_service=~\"$service\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le)) / 1000) or histogram_quantile(0.50, sum(irate(istio_request_duration_seconds_bucket{reporter=\"source\", connection_security_policy=\"mutual_tls\", destination_service=~\"$service\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{source_workload}}.{{source_workload_namespace}} P50 (🔐mTLS)", + "refId": "D", + "step": 2 + }, + { + "expr": "(histogram_quantile(0.90, sum(irate(istio_request_duration_milliseconds_bucket{reporter=\"source\", connection_security_policy=\"mutual_tls\", destination_service=~\"$service\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le)) / 1000) or histogram_quantile(0.90, sum(irate(istio_request_duration_seconds_bucket{reporter=\"source\", connection_security_policy=\"mutual_tls\", destination_service=~\"$service\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{source_workload}}.{{source_workload_namespace}} P90 (🔐mTLS)", + "refId": "A", + "step": 2 + }, + { + "expr": "(histogram_quantile(0.95, sum(irate(istio_request_duration_milliseconds_bucket{reporter=\"source\", connection_security_policy=\"mutual_tls\", destination_service=~\"$service\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le)) / 1000) or histogram_quantile(0.95, sum(irate(istio_request_duration_seconds_bucket{reporter=\"source\", connection_security_policy=\"mutual_tls\", destination_service=~\"$service\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{source_workload}}.{{source_workload_namespace}} P95 (🔐mTLS)", + "refId": "B", + "step": 2 + }, + { + "expr": "(histogram_quantile(0.99, sum(irate(istio_request_duration_milliseconds_bucket{reporter=\"source\", connection_security_policy=\"mutual_tls\", destination_service=~\"$service\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le)) / 1000) or histogram_quantile(0.99, sum(irate(istio_request_duration_seconds_bucket{reporter=\"source\", connection_security_policy=\"mutual_tls\", destination_service=~\"$service\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{source_workload}}.{{source_workload_namespace}} P99 (🔐mTLS)", + "refId": "C", + "step": 2 + }, + { + "expr": "(histogram_quantile(0.50, sum(irate(istio_request_duration_milliseconds_bucket{reporter=\"source\", connection_security_policy!=\"mutual_tls\", destination_service=~\"$service\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le)) / 1000) or histogram_quantile(0.50, sum(irate(istio_request_duration_seconds_bucket{reporter=\"source\", connection_security_policy!=\"mutual_tls\", destination_service=~\"$service\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{source_workload}}.{{source_workload_namespace}} P50", + "refId": "E", + "step": 2 + }, + { + "expr": "(histogram_quantile(0.90, sum(irate(istio_request_duration_milliseconds_bucket{reporter=\"source\", connection_security_policy!=\"mutual_tls\", destination_service=~\"$service\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le)) / 1000) or histogram_quantile(0.90, sum(irate(istio_request_duration_seconds_bucket{reporter=\"source\", connection_security_policy!=\"mutual_tls\", destination_service=~\"$service\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{source_workload}}.{{source_workload_namespace}} P90", + "refId": "F", + "step": 2 + }, + { + "expr": "(histogram_quantile(0.95, sum(irate(istio_request_duration_milliseconds_bucket{reporter=\"source\", connection_security_policy!=\"mutual_tls\", destination_service=~\"$service\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le)) / 1000) or histogram_quantile(0.95, sum(irate(istio_request_duration_seconds_bucket{reporter=\"source\", connection_security_policy!=\"mutual_tls\", destination_service=~\"$service\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{source_workload}}.{{source_workload_namespace}} P95", + "refId": "G", + "step": 2 + }, + { + "expr": "(histogram_quantile(0.99, sum(irate(istio_request_duration_milliseconds_bucket{reporter=\"source\", connection_security_policy!=\"mutual_tls\", destination_service=~\"$service\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le)) / 1000) or histogram_quantile(0.99, sum(irate(istio_request_duration_seconds_bucket{reporter=\"source\", connection_security_policy!=\"mutual_tls\", destination_service=~\"$service\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{source_workload}}.{{source_workload_namespace}} P99", + "refId": "H", + "step": 2 + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Incoming Request Duration by Source", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "s", + "label": null, + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 6, + "w": 8, + "x": 8, + "y": 20 + }, + "id": 28, + "legend": { + "alignAsTable": false, + "avg": false, + "current": false, + "hideEmpty": true, + "max": false, + "min": false, + "rightSide": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "histogram_quantile(0.50, sum(irate(istio_request_bytes_bucket{reporter=\"source\", connection_security_policy=\"mutual_tls\", destination_service=~\"$service\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{source_workload}}.{{source_workload_namespace}} P50 (🔐mTLS)", + "refId": "D", + "step": 2 + }, + { + "expr": "histogram_quantile(0.90, sum(irate(istio_request_bytes_bucket{reporter=\"source\", connection_security_policy=\"mutual_tls\", destination_service=~\"$service\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{source_workload}}.{{source_workload_namespace}} P90 (🔐mTLS)", + "refId": "A", + "step": 2 + }, + { + "expr": "histogram_quantile(0.95, sum(irate(istio_request_bytes_bucket{reporter=\"source\", connection_security_policy=\"mutual_tls\", destination_service=~\"$service\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{source_workload}}.{{source_workload_namespace}} P95 (🔐mTLS)", + "refId": "B", + "step": 2 + }, + { + "expr": "histogram_quantile(0.99, sum(irate(istio_request_bytes_bucket{reporter=\"source\", connection_security_policy=\"mutual_tls\", destination_service=~\"$service\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{source_workload}}.{{source_workload_namespace}} P99 (🔐mTLS)", + "refId": "C", + "step": 2 + }, + { + "expr": "histogram_quantile(0.50, sum(irate(istio_request_bytes_bucket{reporter=\"source\", connection_security_policy!=\"mutual_tls\", destination_service=~\"$service\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{source_workload}}.{{source_workload_namespace}} P50", + "refId": "E", + "step": 2 + }, + { + "expr": "histogram_quantile(0.90, sum(irate(istio_request_bytes_bucket{reporter=\"source\", connection_security_policy!=\"mutual_tls\", destination_service=~\"$service\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{source_workload}}.{{source_workload_namespace}} P90", + "refId": "F", + "step": 2 + }, + { + "expr": "histogram_quantile(0.95, sum(irate(istio_request_bytes_bucket{reporter=\"source\", connection_security_policy!=\"mutual_tls\", destination_service=~\"$service\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{source_workload}}.{{source_workload_namespace}} P95", + "refId": "G", + "step": 2 + }, + { + "expr": "histogram_quantile(0.99, sum(irate(istio_request_bytes_bucket{reporter=\"source\", connection_security_policy!=\"mutual_tls\", destination_service=~\"$service\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{source_workload}}.{{source_workload_namespace}} P99", + "refId": "H", + "step": 2 + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Incoming Request Size By Source", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "decbytes", + "label": null, + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 6, + "w": 8, + "x": 16, + "y": 20 + }, + "id": 68, + "legend": { + "alignAsTable": false, + "avg": false, + "current": false, + "hideEmpty": true, + "max": false, + "min": false, + "rightSide": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "histogram_quantile(0.50, sum(irate(istio_response_bytes_bucket{reporter=\"source\", connection_security_policy=\"mutual_tls\", destination_service=~\"$service\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{source_workload}}.{{source_workload_namespace}} P50 (🔐mTLS)", + "refId": "D", + "step": 2 + }, + { + "expr": "histogram_quantile(0.90, sum(irate(istio_response_bytes_bucket{reporter=\"source\", connection_security_policy=\"mutual_tls\", destination_service=~\"$service\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{source_workload}}.{{source_workload_namespace}} P90 (🔐mTLS)", + "refId": "A", + "step": 2 + }, + { + "expr": "histogram_quantile(0.95, sum(irate(istio_response_bytes_bucket{reporter=\"source\", connection_security_policy=\"mutual_tls\", destination_service=~\"$service\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{source_workload}}.{{source_workload_namespace}} P95 (🔐mTLS)", + "refId": "B", + "step": 2 + }, + { + "expr": "histogram_quantile(0.99, sum(irate(istio_response_bytes_bucket{reporter=\"source\", connection_security_policy=\"mutual_tls\", destination_service=~\"$service\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{source_workload}}.{{source_workload_namespace}} P99 (🔐mTLS)", + "refId": "C", + "step": 2 + }, + { + "expr": "histogram_quantile(0.50, sum(irate(istio_response_bytes_bucket{reporter=\"source\", connection_security_policy!=\"mutual_tls\", destination_service=~\"$service\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{source_workload}}.{{source_workload_namespace}} P50", + "refId": "E", + "step": 2 + }, + { + "expr": "histogram_quantile(0.90, sum(irate(istio_response_bytes_bucket{reporter=\"source\", connection_security_policy!=\"mutual_tls\", destination_service=~\"$service\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{source_workload}}.{{source_workload_namespace}} P90", + "refId": "F", + "step": 2 + }, + { + "expr": "histogram_quantile(0.95, sum(irate(istio_response_bytes_bucket{reporter=\"source\", connection_security_policy!=\"mutual_tls\", destination_service=~\"$service\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{source_workload}}.{{source_workload_namespace}} P95", + "refId": "G", + "step": 2 + }, + { + "expr": "histogram_quantile(0.99, sum(irate(istio_response_bytes_bucket{reporter=\"source\", connection_security_policy!=\"mutual_tls\", destination_service=~\"$service\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{source_workload}}.{{source_workload_namespace}} P99", + "refId": "H", + "step": 2 + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Response Size By Source", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "decbytes", + "label": null, + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 6, + "w": 12, + "x": 0, + "y": 26 + }, + "id": 80, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "round(sum(irate(istio_tcp_received_bytes_total{reporter=\"source\", connection_security_policy=\"mutual_tls\", destination_service=~\"$service\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace), 0.001)", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ source_workload }}.{{ source_workload_namespace}} (🔐mTLS)", + "refId": "A", + "step": 2 + }, + { + "expr": "round(sum(irate(istio_tcp_received_bytes_total{reporter=\"source\", connection_security_policy!=\"mutual_tls\", destination_service=~\"$service\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace), 0.001)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{ source_workload }}.{{ source_workload_namespace}}", + "refId": "B", + "step": 2 + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Bytes Received from Incoming TCP Connection", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "Bps", + "label": null, + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 6, + "w": 12, + "x": 12, + "y": 26 + }, + "id": 82, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "round(sum(irate(istio_tcp_sent_bytes_total{connection_security_policy=\"mutual_tls\", reporter=\"source\", destination_service=~\"$service\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace), 0.001)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{ source_workload }}.{{ source_workload_namespace}} (🔐mTLS)", + "refId": "A", + "step": 2 + }, + { + "expr": "round(sum(irate(istio_tcp_sent_bytes_total{connection_security_policy!=\"mutual_tls\", reporter=\"source\", destination_service=~\"$service\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace), 0.001)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{ source_workload }}.{{ source_workload_namespace}}", + "refId": "B", + "step": 2 + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Bytes Sent to Incoming TCP Connection", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "Bps", + "label": null, + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "content": "
\nSERVICE WORKLOADS\n
", + "gridPos": { + "h": 3, + "w": 24, + "x": 0, + "y": 32 + }, + "id": 69, + "links": [], + "mode": "html", + "title": "", + "transparent": true, + "type": "text" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 0, + "gridPos": { + "h": 6, + "w": 12, + "x": 0, + "y": 35 + }, + "id": 90, + "legend": { + "avg": false, + "current": false, + "hideEmpty": true, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null as zero", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "round(sum(irate(istio_requests_total{connection_security_policy=\"mutual_tls\",destination_service=~\"$service\",reporter=\"destination\",destination_workload=~\"$dstwl\",destination_workload_namespace=~\"$dstns\"}[5m])) by (destination_workload, destination_workload_namespace, response_code), 0.001)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{ destination_workload }}.{{ destination_workload_namespace }} : {{ response_code }} (🔐mTLS)", + "refId": "B", + "step": 2 + }, + { + "expr": "round(sum(irate(istio_requests_total{connection_security_policy!=\"mutual_tls\", destination_service=~\"$service\", reporter=\"destination\", destination_workload=~\"$dstwl\", destination_workload_namespace=~\"$dstns\"}[5m])) by (destination_workload, destination_workload_namespace, response_code), 0.001)", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_workload }}.{{ destination_workload_namespace }} : {{ response_code }}", + "refId": "A", + "step": 2 + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Incoming Requests by Destination And Response Code", + "tooltip": { + "shared": false, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [ + "total" + ] + }, + "yaxes": [ + { + "format": "ops", + "label": null, + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 6, + "w": 12, + "x": 12, + "y": 35 + }, + "id": 91, + "legend": { + "avg": false, + "current": false, + "hideEmpty": true, + "hideZero": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(irate(istio_requests_total{reporter=\"destination\", connection_security_policy=\"mutual_tls\", destination_service=~\"$service\",response_code!~\"5.*\", destination_workload=~\"$dstwl\", destination_workload_namespace=~\"$dstns\"}[5m])) by (destination_workload, destination_workload_namespace) / sum(irate(istio_requests_total{reporter=\"destination\", connection_security_policy=\"mutual_tls\", destination_service=~\"$service\", destination_workload=~\"$dstwl\", destination_workload_namespace=~\"$dstns\"}[5m])) by (destination_workload, destination_workload_namespace)", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_workload }}.{{ destination_workload_namespace }} (🔐mTLS)", + "refId": "A", + "step": 2 + }, + { + "expr": "sum(irate(istio_requests_total{reporter=\"destination\", connection_security_policy!=\"mutual_tls\", destination_service=~\"$service\",response_code!~\"5.*\", destination_workload=~\"$dstwl\", destination_workload_namespace=~\"$dstns\"}[5m])) by (destination_workload, destination_workload_namespace) / sum(irate(istio_requests_total{reporter=\"destination\", connection_security_policy!=\"mutual_tls\", destination_service=~\"$service\", destination_workload=~\"$dstwl\", destination_workload_namespace=~\"$dstns\"}[5m])) by (destination_workload, destination_workload_namespace)", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_workload }}.{{ destination_workload_namespace }}", + "refId": "B", + "step": 2 + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Incoming Success Rate (non-5xx responses) By Source", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "percentunit", + "label": null, + "logBase": 1, + "max": "1.01", + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "description": "", + "fill": 1, + "gridPos": { + "h": 6, + "w": 8, + "x": 0, + "y": 41 + }, + "id": 94, + "legend": { + "alignAsTable": false, + "avg": false, + "current": false, + "hideEmpty": true, + "hideZero": false, + "max": false, + "min": false, + "rightSide": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "(histogram_quantile(0.50, sum(irate(istio_request_duration_milliseconds_bucket{reporter=\"destination\", connection_security_policy=\"mutual_tls\", destination_service=~\"$service\", destination_workload=~\"$dstwl\", destination_workload_namespace=~\"$dstns\"}[1m])) by (destination_workload, destination_workload_namespace, le)) / 1000) or histogram_quantile(0.50, sum(irate(istio_request_duration_seconds_bucket{reporter=\"destination\", connection_security_policy=\"mutual_tls\", destination_service=~\"$service\", destination_workload=~\"$dstwl\", destination_workload_namespace=~\"$dstns\"}[1m])) by (destination_workload, destination_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_workload }}.{{ destination_workload_namespace }} P50 (🔐mTLS)", + "refId": "D", + "step": 2 + }, + { + "expr": "(histogram_quantile(0.90, sum(irate(istio_request_duration_milliseconds_bucket{reporter=\"destination\", connection_security_policy=\"mutual_tls\", destination_service=~\"$service\", destination_workload=~\"$dstwl\", destination_workload_namespace=~\"$dstns\"}[1m])) by (destination_workload, destination_workload_namespace, le)) / 1000) or histogram_quantile(0.90, sum(irate(istio_request_duration_seconds_bucket{reporter=\"destination\", connection_security_policy=\"mutual_tls\", destination_service=~\"$service\", destination_workload=~\"$dstwl\", destination_workload_namespace=~\"$dstns\"}[1m])) by (destination_workload, destination_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_workload }}.{{ destination_workload_namespace }} P90 (🔐mTLS)", + "refId": "A", + "step": 2 + }, + { + "expr": "(histogram_quantile(0.95, sum(irate(istio_request_duration_milliseconds_bucket{reporter=\"destination\", connection_security_policy=\"mutual_tls\", destination_service=~\"$service\", destination_workload=~\"$dstwl\", destination_workload_namespace=~\"$dstns\"}[1m])) by (destination_workload, destination_workload_namespace, le)) / 1000) or histogram_quantile(0.95, sum(irate(istio_request_duration_seconds_bucket{reporter=\"destination\", connection_security_policy=\"mutual_tls\", destination_service=~\"$service\", destination_workload=~\"$dstwl\", destination_workload_namespace=~\"$dstns\"}[1m])) by (destination_workload, destination_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_workload }}.{{ destination_workload_namespace }} P95 (🔐mTLS)", + "refId": "B", + "step": 2 + }, + { + "expr": "(histogram_quantile(0.99, sum(irate(istio_request_duration_milliseconds_bucket{reporter=\"destination\", connection_security_policy=\"mutual_tls\", destination_service=~\"$service\", destination_workload=~\"$dstwl\", destination_workload_namespace=~\"$dstns\"}[1m])) by (destination_workload, destination_workload_namespace, le)) / 1000) or histogram_quantile(0.99, sum(irate(istio_request_duration_seconds_bucket{reporter=\"destination\", connection_security_policy=\"mutual_tls\", destination_service=~\"$service\", destination_workload=~\"$dstwl\", destination_workload_namespace=~\"$dstns\"}[1m])) by (destination_workload, destination_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_workload }}.{{ destination_workload_namespace }} P99 (🔐mTLS)", + "refId": "C", + "step": 2 + }, + { + "expr": "(histogram_quantile(0.50, sum(irate(istio_request_duration_milliseconds_bucket{reporter=\"destination\", connection_security_policy!=\"mutual_tls\", destination_service=~\"$service\", destination_workload=~\"$dstwl\", destination_workload_namespace=~\"$dstns\"}[1m])) by (destination_workload, destination_workload_namespace, le)) / 1000) or histogram_quantile(0.50, sum(irate(istio_request_duration_seconds_bucket{reporter=\"destination\", connection_security_policy!=\"mutual_tls\", destination_service=~\"$service\", destination_workload=~\"$dstwl\", destination_workload_namespace=~\"$dstns\"}[1m])) by (destination_workload, destination_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_workload }}.{{ destination_workload_namespace }} P50", + "refId": "E", + "step": 2 + }, + { + "expr": "(histogram_quantile(0.90, sum(irate(istio_request_duration_milliseconds_bucket{reporter=\"destination\", connection_security_policy!=\"mutual_tls\", destination_service=~\"$service\", destination_workload=~\"$dstwl\", destination_workload_namespace=~\"$dstns\"}[1m])) by (destination_workload, destination_workload_namespace, le)) / 1000) or histogram_quantile(0.90, sum(irate(istio_request_duration_seconds_bucket{reporter=\"destination\", connection_security_policy!=\"mutual_tls\", destination_service=~\"$service\", destination_workload=~\"$dstwl\", destination_workload_namespace=~\"$dstns\"}[1m])) by (destination_workload, destination_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_workload }}.{{ destination_workload_namespace }} P90", + "refId": "F", + "step": 2 + }, + { + "expr": "(histogram_quantile(0.95, sum(irate(istio_request_duration_milliseconds_bucket{reporter=\"destination\", connection_security_policy!=\"mutual_tls\", destination_service=~\"$service\", destination_workload=~\"$dstwl\", destination_workload_namespace=~\"$dstns\"}[1m])) by (destination_workload, destination_workload_namespace, le)) / 1000) or histogram_quantile(0.95, sum(irate(istio_request_duration_seconds_bucket{reporter=\"destination\", connection_security_policy!=\"mutual_tls\", destination_service=~\"$service\", destination_workload=~\"$dstwl\", destination_workload_namespace=~\"$dstns\"}[1m])) by (destination_workload, destination_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_workload }}.{{ destination_workload_namespace }} P95", + "refId": "G", + "step": 2 + }, + { + "expr": "(histogram_quantile(0.99, sum(irate(istio_request_duration_milliseconds_bucket{reporter=\"destination\", connection_security_policy!=\"mutual_tls\", destination_service=~\"$service\", destination_workload=~\"$dstwl\", destination_workload_namespace=~\"$dstns\"}[1m])) by (destination_workload, destination_workload_namespace, le)) / 1000) or histogram_quantile(0.99, sum(irate(istio_request_duration_seconds_bucket{reporter=\"destination\", connection_security_policy!=\"mutual_tls\", destination_service=~\"$service\", destination_workload=~\"$dstwl\", destination_workload_namespace=~\"$dstns\"}[1m])) by (destination_workload, destination_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_workload }}.{{ destination_workload_namespace }} P99", + "refId": "H", + "step": 2 + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Incoming Request Duration by Source", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "s", + "label": null, + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 6, + "w": 8, + "x": 8, + "y": 41 + }, + "id": 95, + "legend": { + "alignAsTable": false, + "avg": false, + "current": false, + "hideEmpty": true, + "max": false, + "min": false, + "rightSide": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "histogram_quantile(0.50, sum(irate(istio_request_bytes_bucket{reporter=\"destination\", connection_security_policy=\"mutual_tls\", destination_service=~\"$service\", destination_workload=~\"$dstwl\", destination_workload_namespace=~\"$dstns\"}[1m])) by (destination_workload, destination_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_workload }}.{{ destination_workload_namespace }} P50 (🔐mTLS)", + "refId": "D", + "step": 2 + }, + { + "expr": "histogram_quantile(0.90, sum(irate(istio_request_bytes_bucket{reporter=\"destination\", connection_security_policy=\"mutual_tls\", destination_service=~\"$service\", destination_workload=~\"$dstwl\", destination_workload_namespace=~\"$dstns\"}[1m])) by (destination_workload, destination_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_workload }}.{{ destination_workload_namespace }} P90 (🔐mTLS)", + "refId": "A", + "step": 2 + }, + { + "expr": "histogram_quantile(0.95, sum(irate(istio_request_bytes_bucket{reporter=\"destination\", connection_security_policy=\"mutual_tls\", destination_service=~\"$service\", destination_workload=~\"$dstwl\", destination_workload_namespace=~\"$dstns\"}[1m])) by (destination_workload, destination_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_workload }}.{{ destination_workload_namespace }} P95 (🔐mTLS)", + "refId": "B", + "step": 2 + }, + { + "expr": "histogram_quantile(0.99, sum(irate(istio_request_bytes_bucket{reporter=\"destination\", connection_security_policy=\"mutual_tls\", destination_service=~\"$service\", destination_workload=~\"$dstwl\", destination_workload_namespace=~\"$dstns\"}[1m])) by (destination_workload, destination_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_workload }}.{{ destination_workload_namespace }} P99 (🔐mTLS)", + "refId": "C", + "step": 2 + }, + { + "expr": "histogram_quantile(0.50, sum(irate(istio_request_bytes_bucket{reporter=\"destination\", connection_security_policy!=\"mutual_tls\", destination_service=~\"$service\", destination_workload=~\"$dstwl\", destination_workload_namespace=~\"$dstns\"}[1m])) by (destination_workload, destination_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_workload }}.{{ destination_workload_namespace }} P50", + "refId": "E", + "step": 2 + }, + { + "expr": "histogram_quantile(0.90, sum(irate(istio_request_bytes_bucket{reporter=\"destination\", connection_security_policy!=\"mutual_tls\", destination_service=~\"$service\", destination_workload=~\"$dstwl\", destination_workload_namespace=~\"$dstns\"}[1m])) by (destination_workload, destination_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_workload }}.{{ destination_workload_namespace }} P90", + "refId": "F", + "step": 2 + }, + { + "expr": "histogram_quantile(0.95, sum(irate(istio_request_bytes_bucket{reporter=\"destination\", connection_security_policy!=\"mutual_tls\", destination_service=~\"$service\", destination_workload=~\"$dstwl\", destination_workload_namespace=~\"$dstns\"}[1m])) by (destination_workload, destination_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_workload }}.{{ destination_workload_namespace }} P95", + "refId": "G", + "step": 2 + }, + { + "expr": "histogram_quantile(0.99, sum(irate(istio_request_bytes_bucket{reporter=\"destination\", connection_security_policy!=\"mutual_tls\", destination_service=~\"$service\", destination_workload=~\"$dstwl\", destination_workload_namespace=~\"$dstns\"}[1m])) by (destination_workload, destination_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_workload }}.{{ destination_workload_namespace }} P99", + "refId": "H", + "step": 2 + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Incoming Request Size By Source", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "decbytes", + "label": null, + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 6, + "w": 8, + "x": 16, + "y": 41 + }, + "id": 96, + "legend": { + "alignAsTable": false, + "avg": false, + "current": false, + "hideEmpty": true, + "max": false, + "min": false, + "rightSide": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "histogram_quantile(0.50, sum(irate(istio_response_bytes_bucket{reporter=\"destination\", connection_security_policy=\"mutual_tls\", destination_service=~\"$service\", destination_workload=~\"$dstwl\", destination_workload_namespace=~\"$dstns\"}[1m])) by (destination_workload, destination_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_workload }}.{{ destination_workload_namespace }} P50 (🔐mTLS)", + "refId": "D", + "step": 2 + }, + { + "expr": "histogram_quantile(0.90, sum(irate(istio_response_bytes_bucket{reporter=\"destination\", connection_security_policy=\"mutual_tls\", destination_service=~\"$service\", destination_workload=~\"$dstwl\", destination_workload_namespace=~\"$dstns\"}[1m])) by (destination_workload, destination_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_workload }}.{{ destination_workload_namespace }} P90 (🔐mTLS)", + "refId": "A", + "step": 2 + }, + { + "expr": "histogram_quantile(0.95, sum(irate(istio_response_bytes_bucket{reporter=\"destination\", connection_security_policy=\"mutual_tls\", destination_service=~\"$service\", destination_workload=~\"$dstwl\", destination_workload_namespace=~\"$dstns\"}[1m])) by (destination_workload, destination_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_workload }}.{{ destination_workload_namespace }} P95 (🔐mTLS)", + "refId": "B", + "step": 2 + }, + { + "expr": "histogram_quantile(0.99, sum(irate(istio_response_bytes_bucket{reporter=\"destination\", connection_security_policy=\"mutual_tls\", destination_service=~\"$service\", destination_workload=~\"$dstwl\", destination_workload_namespace=~\"$dstns\"}[1m])) by (destination_workload, destination_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_workload }}.{{ destination_workload_namespace }} P99 (🔐mTLS)", + "refId": "C", + "step": 2 + }, + { + "expr": "histogram_quantile(0.50, sum(irate(istio_response_bytes_bucket{reporter=\"destination\", connection_security_policy!=\"mutual_tls\", destination_service=~\"$service\", destination_workload=~\"$dstwl\", destination_workload_namespace=~\"$dstns\"}[1m])) by (destination_workload, destination_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_workload }}.{{ destination_workload_namespace }} P50", + "refId": "E", + "step": 2 + }, + { + "expr": "histogram_quantile(0.90, sum(irate(istio_response_bytes_bucket{reporter=\"destination\", connection_security_policy!=\"mutual_tls\", destination_service=~\"$service\", destination_workload=~\"$dstwl\", destination_workload_namespace=~\"$dstns\"}[1m])) by (destination_workload, destination_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_workload }}.{{ destination_workload_namespace }} P90", + "refId": "F", + "step": 2 + }, + { + "expr": "histogram_quantile(0.95, sum(irate(istio_response_bytes_bucket{reporter=\"destination\", connection_security_policy!=\"mutual_tls\", destination_service=~\"$service\", destination_workload=~\"$dstwl\", destination_workload_namespace=~\"$dstns\"}[1m])) by (destination_workload, destination_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_workload }}.{{ destination_workload_namespace }} P95", + "refId": "G", + "step": 2 + }, + { + "expr": "histogram_quantile(0.99, sum(irate(istio_response_bytes_bucket{reporter=\"destination\", connection_security_policy!=\"mutual_tls\", destination_service=~\"$service\", destination_workload=~\"$dstwl\", destination_workload_namespace=~\"$dstns\"}[1m])) by (destination_workload, destination_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_workload }}.{{ destination_workload_namespace }} P99", + "refId": "H", + "step": 2 + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Response Size By Source", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "decbytes", + "label": null, + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 6, + "w": 12, + "x": 0, + "y": 47 + }, + "id": 92, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "round(sum(irate(istio_tcp_received_bytes_total{reporter=\"source\", connection_security_policy=\"mutual_tls\", destination_service=~\"$service\", destination_workload=~\"$dstwl\", destination_workload_namespace=~\"$dstns\"}[1m])) by (destination_workload, destination_workload_namespace), 0.001)", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_workload }}.{{ destination_workload_namespace}} (🔐mTLS)", + "refId": "A", + "step": 2 + }, + { + "expr": "round(sum(irate(istio_tcp_received_bytes_total{reporter=\"source\", connection_security_policy!=\"mutual_tls\", destination_service=~\"$service\", destination_workload=~\"$dstwl\", destination_workload_namespace=~\"$dstns\"}[1m])) by (destination_workload, destination_workload_namespace), 0.001)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{ destination_workload }}.{{ destination_workload_namespace}}", + "refId": "B", + "step": 2 + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Bytes Received from Incoming TCP Connection", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "Bps", + "label": null, + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 6, + "w": 12, + "x": 12, + "y": 47 + }, + "id": 93, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "round(sum(irate(istio_tcp_sent_bytes_total{connection_security_policy=\"mutual_tls\", reporter=\"source\", destination_service=~\"$service\", destination_workload=~\"$dstwl\", destination_workload_namespace=~\"$dstns\"}[1m])) by (destination_workload, destination_workload_namespace), 0.001)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{ destination_workload }}.{{destination_workload_namespace }} (🔐mTLS)", + "refId": "A", + "step": 2 + }, + { + "expr": "round(sum(irate(istio_tcp_sent_bytes_total{connection_security_policy!=\"mutual_tls\", reporter=\"source\", destination_service=~\"$service\", destination_workload=~\"$dstwl\", destination_workload_namespace=~\"$dstns\"}[1m])) by (destination_workload, destination_workload_namespace), 0.001)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{ destination_workload }}.{{destination_workload_namespace }}", + "refId": "B", + "step": 2 + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Bytes Sent to Incoming TCP Connection", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "Bps", + "label": null, + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + } + ], + "refresh": "10s", + "schemaVersion": 16, + "style": "dark", + "tags": [], + "templating": { + "list": [ + { + "allValue": null, + "datasource": "Prometheus", + "hide": 0, + "includeAll": false, + "label": "Service", + "multi": false, + "name": "service", + "options": [], + "query": "label_values(destination_service)", + "refresh": 1, + "regex": "", + "sort": 0, + "tagValuesQuery": "", + "tags": [], + "tagsQuery": "", + "type": "query", + "useTags": false + }, + { + "allValue": null, + "current": { + "text": "All", + "value": "$__all" + }, + "datasource": "Prometheus", + "hide": 0, + "includeAll": true, + "label": "Client Workload Namespace", + "multi": true, + "name": "srcns", + "options": [], + "query": "query_result( sum(istio_requests_total{reporter=\"destination\", destination_service=\"$service\"}) by (source_workload_namespace) or sum(istio_tcp_sent_bytes_total{reporter=\"destination\", destination_service=~\"$service\"}) by (source_workload_namespace))", + "refresh": 1, + "regex": "/.*namespace=\"([^\"]*).*/", + "sort": 2, + "tagValuesQuery": "", + "tags": [], + "tagsQuery": "", + "type": "query", + "useTags": false + }, + { + "allValue": null, + "current": { + "text": "All", + "value": "$__all" + }, + "datasource": "Prometheus", + "hide": 0, + "includeAll": true, + "label": "Client Workload", + "multi": true, + "name": "srcwl", + "options": [], + "query": "query_result( sum(istio_requests_total{reporter=\"destination\", destination_service=~\"$service\", source_workload_namespace=~\"$srcns\"}) by (source_workload) or sum(istio_tcp_sent_bytes_total{reporter=\"destination\", destination_service=~\"$service\", source_workload_namespace=~\"$srcns\"}) by (source_workload))", + "refresh": 1, + "regex": "/.*workload=\"([^\"]*).*/", + "sort": 3, + "tagValuesQuery": "", + "tags": [], + "tagsQuery": "", + "type": "query", + "useTags": false + }, + { + "allValue": null, + "current": { + "text": "All", + "value": "$__all" + }, + "datasource": "Prometheus", + "hide": 0, + "includeAll": true, + "label": "Service Workload Namespace", + "multi": true, + "name": "dstns", + "options": [], + "query": "query_result( sum(istio_requests_total{reporter=\"destination\", destination_service=\"$service\"}) by (destination_workload_namespace) or sum(istio_tcp_sent_bytes_total{reporter=\"destination\", destination_service=~\"$service\"}) by (destination_workload_namespace))", + "refresh": 1, + "regex": "/.*namespace=\"([^\"]*).*/", + "sort": 2, + "tagValuesQuery": "", + "tags": [], + "tagsQuery": "", + "type": "query", + "useTags": false + }, + { + "allValue": null, + "current": { + "text": "All", + "value": "$__all" + }, + "datasource": "Prometheus", + "hide": 0, + "includeAll": true, + "label": "Service Workload", + "multi": true, + "name": "dstwl", + "options": [], + "query": "query_result( sum(istio_requests_total{reporter=\"destination\", destination_service=~\"$service\", destination_workload_namespace=~\"$dstns\"}) by (destination_workload) or sum(istio_tcp_sent_bytes_total{reporter=\"destination\", destination_service=~\"$service\", destination_workload_namespace=~\"$dstns\"}) by (destination_workload))", + "refresh": 1, + "regex": "/.*workload=\"([^\"]*).*/", + "sort": 3, + "tagValuesQuery": "", + "tags": [], + "tagsQuery": "", + "type": "query", + "useTags": false + } + ] + }, + "time": { + "from": "now-5m", + "to": "now" + }, + "timepicker": { + "refresh_intervals": [ + "5s", + "10s", + "30s", + "1m", + "5m", + "15m", + "30m", + "1h", + "2h", + "1d" + ], + "time_options": [ + "5m", + "15m", + "1h", + "6h", + "12h", + "24h", + "2d", + "7d", + "30d" + ] + }, + "timezone": "", + "title": "Istio Service Dashboard", + "uid": "LJ_uJAvmk", + "version": 1 +} +' +--- +apiVersion: v1 +kind: ConfigMap +metadata: + name: istio-grafana-configuration-dashboards-istio-workload-dashboard + namespace: istio-system + labels: + app: grafana + chart: grafana + heritage: Tiller + release: istio + istio: grafana +data: + istio-workload-dashboard.json: '{ + "__inputs": [ + { + "name": "DS_PROMETHEUS", + "label": "Prometheus", + "description": "", + "type": "datasource", + "pluginId": "prometheus", + "pluginName": "Prometheus" + } + ], + "__requires": [ + { + "type": "grafana", + "id": "grafana", + "name": "Grafana", + "version": "5.0.4" + }, + { + "type": "panel", + "id": "graph", + "name": "Graph", + "version": "5.0.0" + }, + { + "type": "datasource", + "id": "prometheus", + "name": "Prometheus", + "version": "5.0.0" + }, + { + "type": "panel", + "id": "singlestat", + "name": "Singlestat", + "version": "5.0.0" + }, + { + "type": "panel", + "id": "text", + "name": "Text", + "version": "5.0.0" + } + ], + "annotations": { + "list": [ + { + "builtIn": 1, + "datasource": "-- Grafana --", + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations & Alerts", + "type": "dashboard" + } + ] + }, + "editable": false, + "gnetId": null, + "graphTooltip": 0, + "id": null, + "iteration": 1531345461465, + "links": [], + "panels": [ + { + "content": "
\nWORKLOAD: $workload.$namespace\n
", + "gridPos": { + "h": 3, + "w": 24, + "x": 0, + "y": 0 + }, + "id": 89, + "links": [], + "mode": "html", + "title": "", + "transparent": true, + "type": "text" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "datasource": "Prometheus", + "format": "ops", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "gridPos": { + "h": 4, + "w": 8, + "x": 0, + "y": 3 + }, + "id": 12, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": true, + "lineColor": "rgb(31, 120, 193)", + "show": true + }, + "tableColumn": "", + "targets": [ + { + "expr": "round(sum(irate(istio_requests_total{reporter=\"destination\",destination_workload_namespace=~\"$namespace\",destination_workload=~\"$workload\"}[5m])), 0.001)", + "format": "time_series", + "intervalFactor": 1, + "refId": "A", + "step": 4 + } + ], + "thresholds": "", + "title": "Incoming Request Volume", + "transparent": false, + "type": "singlestat", + "valueFontSize": "80%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "current" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "rgba(50, 172, 45, 0.97)", + "rgba(237, 129, 40, 0.89)", + "rgba(245, 54, 54, 0.9)" + ], + "datasource": "Prometheus", + "decimals": null, + "format": "percentunit", + "gauge": { + "maxValue": 100, + "minValue": 80, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": false + }, + "gridPos": { + "h": 4, + "w": 8, + "x": 8, + "y": 3 + }, + "id": 14, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": true, + "lineColor": "rgb(31, 120, 193)", + "show": true + }, + "tableColumn": "", + "targets": [ + { + "expr": "sum(irate(istio_requests_total{reporter=\"destination\",destination_workload_namespace=~\"$namespace\",destination_workload=~\"$workload\",response_code!~\"5.*\"}[5m])) / sum(irate(istio_requests_total{reporter=\"destination\",destination_workload_namespace=~\"$namespace\",destination_workload=~\"$workload\"}[5m]))", + "format": "time_series", + "intervalFactor": 1, + "refId": "B" + } + ], + "thresholds": "95, 99, 99.5", + "title": "Incoming Success Rate (non-5xx responses)", + "transparent": false, + "type": "singlestat", + "valueFontSize": "80%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "avg" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 4, + "w": 8, + "x": 16, + "y": 3 + }, + "id": 87, + "legend": { + "alignAsTable": false, + "avg": false, + "current": false, + "hideEmpty": false, + "hideZero": false, + "max": false, + "min": false, + "rightSide": true, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "(histogram_quantile(0.50, sum(irate(istio_request_duration_milliseconds_bucket{reporter=\"destination\",destination_workload=~\"$workload\", destination_workload_namespace=~\"$namespace\"}[1m])) by (le)) / 1000) or histogram_quantile(0.50, sum(irate(istio_request_duration_seconds_bucket{reporter=\"destination\",destination_workload=~\"$workload\", destination_workload_namespace=~\"$namespace\"}[1m])) by (le))", + "format": "time_series", + "interval": "", + "intervalFactor": 1, + "legendFormat": "P50", + "refId": "A" + }, + { + "expr": "(histogram_quantile(0.50, sum(irate(istio_request_duration_milliseconds_bucket{reporter=\"destination\",destination_workload=~\"$workload\", destination_workload_namespace=~\"$namespace\"}[1m])) by (le)) / 1000) or histogram_quantile(0.90, sum(irate(istio_request_duration_seconds_bucket{reporter=\"destination\",destination_workload=~\"$workload\", destination_workload_namespace=~\"$namespace\"}[1m])) by (le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "P90", + "refId": "B" + }, + { + "expr": "(histogram_quantile(0.50, sum(irate(istio_request_duration_milliseconds_bucket{reporter=\"destination\",destination_workload=~\"$workload\", destination_workload_namespace=~\"$namespace\"}[1m])) by (le)) / 1000) or histogram_quantile(0.99, sum(irate(istio_request_duration_seconds_bucket{reporter=\"destination\",destination_workload=~\"$workload\", destination_workload_namespace=~\"$namespace\"}[1m])) by (le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "P99", + "refId": "C" + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Request Duration", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "s", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ] + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "#299c46", + "rgba(237, 129, 40, 0.89)", + "#d44a3a" + ], + "datasource": "Prometheus", + "format": "Bps", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "gridPos": { + "h": 4, + "w": 12, + "x": 0, + "y": 7 + }, + "id": 84, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": true, + "lineColor": "rgb(31, 120, 193)", + "show": true + }, + "tableColumn": "", + "targets": [ + { + "expr": "sum(irate(istio_tcp_sent_bytes_total{reporter=\"destination\", destination_workload_namespace=~\"$namespace\", destination_workload=~\"$workload\"}[1m])) + sum(irate(istio_tcp_received_bytes_total{reporter=\"destination\", destination_workload_namespace=~\"$namespace\", destination_workload=~\"$workload\"}[1m]))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "", + "refId": "A" + } + ], + "thresholds": "", + "title": "TCP Server Traffic", + "transparent": false, + "type": "singlestat", + "valueFontSize": "80%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "avg" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "#299c46", + "rgba(237, 129, 40, 0.89)", + "#d44a3a" + ], + "datasource": "Prometheus", + "format": "Bps", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "gridPos": { + "h": 4, + "w": 12, + "x": 12, + "y": 7 + }, + "id": 85, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": true, + "lineColor": "rgb(31, 120, 193)", + "show": true + }, + "tableColumn": "", + "targets": [ + { + "expr": "sum(irate(istio_tcp_sent_bytes_total{reporter=\"source\", source_workload_namespace=~\"$namespace\", source_workload=~\"$workload\"}[1m])) + sum(irate(istio_tcp_received_bytes_total{reporter=\"source\", source_workload_namespace=~\"$namespace\", source_workload=~\"$workload\"}[1m]))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "", + "refId": "A" + } + ], + "thresholds": "", + "title": "TCP Client Traffic", + "transparent": false, + "type": "singlestat", + "valueFontSize": "80%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "avg" + }, + { + "content": "
\nINBOUND WORKLOADS\n
", + "gridPos": { + "h": 3, + "w": 24, + "x": 0, + "y": 11 + }, + "id": 45, + "links": [], + "mode": "html", + "title": "", + "transparent": true, + "type": "text" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 0, + "gridPos": { + "h": 6, + "w": 12, + "x": 0, + "y": 14 + }, + "id": 25, + "legend": { + "avg": false, + "current": false, + "hideEmpty": true, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null as zero", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "round(sum(irate(istio_requests_total{connection_security_policy=\"mutual_tls\", destination_workload_namespace=~\"$namespace\", destination_workload=~\"$workload\", reporter=\"destination\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[5m])) by (source_workload, source_workload_namespace, response_code), 0.001)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{ source_workload }}.{{ source_workload_namespace }} : {{ response_code }} (🔐mTLS)", + "refId": "B", + "step": 2 + }, + { + "expr": "round(sum(irate(istio_requests_total{connection_security_policy!=\"mutual_tls\", destination_workload_namespace=~\"$namespace\", destination_workload=~\"$workload\", reporter=\"destination\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[5m])) by (source_workload, source_workload_namespace, response_code), 0.001)", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ source_workload }}.{{ source_workload_namespace }} : {{ response_code }}", + "refId": "A", + "step": 2 + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Incoming Requests by Source And Response Code", + "tooltip": { + "shared": false, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [ + "total" + ] + }, + "yaxes": [ + { + "format": "ops", + "label": null, + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ] + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 6, + "w": 12, + "x": 12, + "y": 14 + }, + "id": 26, + "legend": { + "avg": false, + "current": false, + "hideEmpty": true, + "hideZero": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(irate(istio_requests_total{reporter=\"destination\", connection_security_policy=\"mutual_tls\", destination_workload_namespace=~\"$namespace\", destination_workload=~\"$workload\",response_code!~\"5.*\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[5m])) by (source_workload, source_workload_namespace) / sum(irate(istio_requests_total{reporter=\"destination\", connection_security_policy=\"mutual_tls\", destination_workload_namespace=~\"$namespace\", destination_workload=~\"$workload\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[5m])) by (source_workload, source_workload_namespace)", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ source_workload }}.{{ source_workload_namespace }} (🔐mTLS)", + "refId": "A", + "step": 2 + }, + { + "expr": "sum(irate(istio_requests_total{reporter=\"destination\", connection_security_policy!=\"mutual_tls\", destination_workload_namespace=~\"$namespace\", destination_workload=~\"$workload\",response_code!~\"5.*\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[5m])) by (source_workload, source_workload_namespace) / sum(irate(istio_requests_total{reporter=\"destination\", connection_security_policy!=\"mutual_tls\", destination_workload_namespace=~\"$namespace\", destination_workload=~\"$workload\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[5m])) by (source_workload, source_workload_namespace)", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ source_workload }}.{{ source_workload_namespace }}", + "refId": "B", + "step": 2 + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Incoming Success Rate (non-5xx responses) By Source", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "percentunit", + "label": null, + "logBase": 1, + "max": "1.01", + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ] + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "description": "", + "fill": 1, + "gridPos": { + "h": 6, + "w": 8, + "x": 0, + "y": 20 + }, + "id": 27, + "legend": { + "alignAsTable": false, + "avg": false, + "current": false, + "hideEmpty": true, + "hideZero": false, + "max": false, + "min": false, + "rightSide": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "(histogram_quantile(0.50, sum(irate(istio_request_duration_milliseconds_bucket{reporter=\"destination\", connection_security_policy=\"mutual_tls\", destination_workload=~\"$workload\", destination_workload_namespace=~\"$namespace\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le)) / 1000) or histogram_quantile(0.50, sum(irate(istio_request_duration_seconds_bucket{reporter=\"destination\", connection_security_policy=\"mutual_tls\", destination_workload=~\"$workload\", destination_workload_namespace=~\"$namespace\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{source_workload}}.{{source_workload_namespace}} P50 (🔐mTLS)", + "refId": "D", + "step": 2 + }, + { + "expr": "(histogram_quantile(0.90, sum(irate(istio_request_duration_milliseconds_bucket{reporter=\"destination\", connection_security_policy=\"mutual_tls\", destination_workload=~\"$workload\", destination_workload_namespace=~\"$namespace\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le)) / 1000) or histogram_quantile(0.90, sum(irate(istio_request_duration_seconds_bucket{reporter=\"destination\", connection_security_policy=\"mutual_tls\", destination_workload=~\"$workload\", destination_workload_namespace=~\"$namespace\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{source_workload}}.{{source_workload_namespace}} P90 (🔐mTLS)", + "refId": "A", + "step": 2 + }, + { + "expr": "(histogram_quantile(0.95, sum(irate(istio_request_duration_milliseconds_bucket{reporter=\"destination\", connection_security_policy=\"mutual_tls\", destination_workload=~\"$workload\", destination_workload_namespace=~\"$namespace\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le)) / 1000) or histogram_quantile(0.95, sum(irate(istio_request_duration_seconds_bucket{reporter=\"destination\", connection_security_policy=\"mutual_tls\", destination_workload=~\"$workload\", destination_workload_namespace=~\"$namespace\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{source_workload}}.{{source_workload_namespace}} P95 (🔐mTLS)", + "refId": "B", + "step": 2 + }, + { + "expr": "(histogram_quantile(0.99, sum(irate(istio_request_duration_milliseconds_bucket{reporter=\"destination\", connection_security_policy=\"mutual_tls\", destination_workload=~\"$workload\", destination_workload_namespace=~\"$namespace\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le)) / 1000) or histogram_quantile(0.99, sum(irate(istio_request_duration_seconds_bucket{reporter=\"destination\", connection_security_policy=\"mutual_tls\", destination_workload=~\"$workload\", destination_workload_namespace=~\"$namespace\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{source_workload}}.{{source_workload_namespace}} P99 (🔐mTLS)", + "refId": "C", + "step": 2 + }, + { + "expr": "(histogram_quantile(0.50, sum(irate(istio_request_duration_milliseconds_bucket{reporter=\"destination\", connection_security_policy!=\"mutual_tls\", destination_workload=~\"$workload\", destination_workload_namespace=~\"$namespace\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le)) / 1000) or histogram_quantile(0.50, sum(irate(istio_request_duration_seconds_bucket{reporter=\"destination\", connection_security_policy!=\"mutual_tls\", destination_workload=~\"$workload\", destination_workload_namespace=~\"$namespace\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{source_workload}}.{{source_workload_namespace}} P50", + "refId": "E", + "step": 2 + }, + { + "expr": "(histogram_quantile(0.90, sum(irate(istio_request_duration_milliseconds_bucket{reporter=\"destination\", connection_security_policy!=\"mutual_tls\", destination_workload=~\"$workload\", destination_workload_namespace=~\"$namespace\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le)) / 1000) or histogram_quantile(0.90, sum(irate(istio_request_duration_seconds_bucket{reporter=\"destination\", connection_security_policy!=\"mutual_tls\", destination_workload=~\"$workload\", destination_workload_namespace=~\"$namespace\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{source_workload}}.{{source_workload_namespace}} P90", + "refId": "F", + "step": 2 + }, + { + "expr": "(histogram_quantile(0.95, sum(irate(istio_request_duration_milliseconds_bucket{reporter=\"destination\", connection_security_policy!=\"mutual_tls\", destination_workload=~\"$workload\", destination_workload_namespace=~\"$namespace\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le)) / 1000) or histogram_quantile(0.95, sum(irate(istio_request_duration_seconds_bucket{reporter=\"destination\", connection_security_policy!=\"mutual_tls\", destination_workload=~\"$workload\", destination_workload_namespace=~\"$namespace\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{source_workload}}.{{source_workload_namespace}} P95", + "refId": "G", + "step": 2 + }, + { + "expr": "(histogram_quantile(0.99, sum(irate(istio_request_duration_milliseconds_bucket{reporter=\"destination\", connection_security_policy!=\"mutual_tls\", destination_workload=~\"$workload\", destination_workload_namespace=~\"$namespace\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le)) / 1000) or histogram_quantile(0.99, sum(irate(istio_request_duration_seconds_bucket{reporter=\"destination\", connection_security_policy!=\"mutual_tls\", destination_workload=~\"$workload\", destination_workload_namespace=~\"$namespace\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{source_workload}}.{{source_workload_namespace}} P99", + "refId": "H", + "step": 2 + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Incoming Request Duration by Source", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "s", + "label": null, + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ] + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 6, + "w": 8, + "x": 8, + "y": 20 + }, + "id": 28, + "legend": { + "alignAsTable": false, + "avg": false, + "current": false, + "hideEmpty": true, + "max": false, + "min": false, + "rightSide": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "histogram_quantile(0.50, sum(irate(istio_request_bytes_bucket{reporter=\"destination\", connection_security_policy=\"mutual_tls\", destination_workload=~\"$workload\", destination_workload_namespace=~\"$namespace\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{source_workload}}.{{source_workload_namespace}} P50 (🔐mTLS)", + "refId": "D", + "step": 2 + }, + { + "expr": "histogram_quantile(0.90, sum(irate(istio_request_bytes_bucket{reporter=\"destination\", connection_security_policy=\"mutual_tls\", destination_workload=~\"$workload\", destination_workload_namespace=~\"$namespace\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{source_workload}}.{{source_workload_namespace}} P90 (🔐mTLS)", + "refId": "A", + "step": 2 + }, + { + "expr": "histogram_quantile(0.95, sum(irate(istio_request_bytes_bucket{reporter=\"destination\", connection_security_policy=\"mutual_tls\", destination_workload=~\"$workload\", destination_workload_namespace=~\"$namespace\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{source_workload}}.{{source_workload_namespace}} P95 (🔐mTLS)", + "refId": "B", + "step": 2 + }, + { + "expr": "histogram_quantile(0.99, sum(irate(istio_request_bytes_bucket{reporter=\"destination\", connection_security_policy=\"mutual_tls\", destination_workload=~\"$workload\", destination_workload_namespace=~\"$namespace\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{source_workload}}.{{source_workload_namespace}} P99 (🔐mTLS)", + "refId": "C", + "step": 2 + }, + { + "expr": "histogram_quantile(0.50, sum(irate(istio_request_bytes_bucket{reporter=\"destination\", connection_security_policy!=\"mutual_tls\", destination_workload=~\"$workload\", destination_workload_namespace=~\"$namespace\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{source_workload}}.{{source_workload_namespace}} P50", + "refId": "E", + "step": 2 + }, + { + "expr": "histogram_quantile(0.90, sum(irate(istio_request_bytes_bucket{reporter=\"destination\", connection_security_policy!=\"mutual_tls\", destination_workload=~\"$workload\", destination_workload_namespace=~\"$namespace\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{source_workload}}.{{source_workload_namespace}} P90", + "refId": "F", + "step": 2 + }, + { + "expr": "histogram_quantile(0.95, sum(irate(istio_request_bytes_bucket{reporter=\"destination\", connection_security_policy!=\"mutual_tls\", destination_workload=~\"$workload\", destination_workload_namespace=~\"$namespace\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{source_workload}}.{{source_workload_namespace}} P95", + "refId": "G", + "step": 2 + }, + { + "expr": "histogram_quantile(0.99, sum(irate(istio_request_bytes_bucket{reporter=\"destination\", connection_security_policy!=\"mutual_tls\", destination_workload=~\"$workload\", destination_workload_namespace=~\"$namespace\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{source_workload}}.{{source_workload_namespace}} P99", + "refId": "H", + "step": 2 + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Incoming Request Size By Source", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "decbytes", + "label": null, + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ] + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 6, + "w": 8, + "x": 16, + "y": 20 + }, + "id": 68, + "legend": { + "alignAsTable": false, + "avg": false, + "current": false, + "hideEmpty": true, + "max": false, + "min": false, + "rightSide": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "histogram_quantile(0.50, sum(irate(istio_response_bytes_bucket{reporter=\"destination\", connection_security_policy=\"mutual_tls\", destination_workload=~\"$workload\", destination_workload_namespace=~\"$namespace\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{source_workload}}.{{source_workload_namespace}} P50 (🔐mTLS)", + "refId": "D", + "step": 2 + }, + { + "expr": "histogram_quantile(0.90, sum(irate(istio_response_bytes_bucket{reporter=\"destination\", connection_security_policy=\"mutual_tls\", destination_workload=~\"$workload\", destination_workload_namespace=~\"$namespace\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{source_workload}}.{{source_workload_namespace}} P90 (🔐mTLS)", + "refId": "A", + "step": 2 + }, + { + "expr": "histogram_quantile(0.95, sum(irate(istio_response_bytes_bucket{reporter=\"destination\", connection_security_policy=\"mutual_tls\", destination_workload=~\"$workload\", destination_workload_namespace=~\"$namespace\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{source_workload}}.{{source_workload_namespace}} P95 (🔐mTLS)", + "refId": "B", + "step": 2 + }, + { + "expr": "histogram_quantile(0.99, sum(irate(istio_response_bytes_bucket{reporter=\"destination\", connection_security_policy=\"mutual_tls\", destination_workload=~\"$workload\", destination_workload_namespace=~\"$namespace\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{source_workload}}.{{source_workload_namespace}} P99 (🔐mTLS)", + "refId": "C", + "step": 2 + }, + { + "expr": "histogram_quantile(0.50, sum(irate(istio_response_bytes_bucket{reporter=\"destination\", connection_security_policy!=\"mutual_tls\", destination_workload=~\"$workload\", destination_workload_namespace=~\"$namespace\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{source_workload}}.{{source_workload_namespace}} P50", + "refId": "E", + "step": 2 + }, + { + "expr": "histogram_quantile(0.90, sum(irate(istio_response_bytes_bucket{reporter=\"destination\", connection_security_policy!=\"mutual_tls\", destination_workload=~\"$workload\", destination_workload_namespace=~\"$namespace\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{source_workload}}.{{source_workload_namespace}} P90", + "refId": "F", + "step": 2 + }, + { + "expr": "histogram_quantile(0.95, sum(irate(istio_response_bytes_bucket{reporter=\"destination\", connection_security_policy!=\"mutual_tls\", destination_workload=~\"$workload\", destination_workload_namespace=~\"$namespace\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{source_workload}}.{{source_workload_namespace}} P95", + "refId": "G", + "step": 2 + }, + { + "expr": "histogram_quantile(0.99, sum(irate(istio_response_bytes_bucket{reporter=\"destination\", connection_security_policy!=\"mutual_tls\", destination_workload=~\"$workload\", destination_workload_namespace=~\"$namespace\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{source_workload}}.{{source_workload_namespace}} P99", + "refId": "H", + "step": 2 + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Response Size By Source", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "decbytes", + "label": null, + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ] + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 6, + "w": 12, + "x": 0, + "y": 26 + }, + "id": 80, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "round(sum(irate(istio_tcp_received_bytes_total{reporter=\"destination\", connection_security_policy=\"mutual_tls\", destination_workload_namespace=~\"$namespace\", destination_workload=~\"$workload\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace), 0.001)", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ source_workload }}.{{ source_workload_namespace}} (🔐mTLS)", + "refId": "A", + "step": 2 + }, + { + "expr": "round(sum(irate(istio_tcp_received_bytes_total{reporter=\"destination\", connection_security_policy!=\"mutual_tls\", destination_workload_namespace=~\"$namespace\", destination_workload=~\"$workload\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace), 0.001)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{ source_workload }}.{{ source_workload_namespace}}", + "refId": "B", + "step": 2 + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Bytes Received from Incoming TCP Connection", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "Bps", + "label": null, + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ] + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 6, + "w": 12, + "x": 12, + "y": 26 + }, + "id": 82, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "round(sum(irate(istio_tcp_sent_bytes_total{connection_security_policy=\"mutual_tls\", reporter=\"destination\", destination_workload_namespace=~\"$namespace\", destination_workload=~\"$workload\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace), 0.001)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{ source_workload }}.{{ source_workload_namespace}} (🔐mTLS)", + "refId": "A", + "step": 2 + }, + { + "expr": "round(sum(irate(istio_tcp_sent_bytes_total{connection_security_policy!=\"mutual_tls\", reporter=\"destination\", destination_workload_namespace=~\"$namespace\", destination_workload=~\"$workload\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace), 0.001)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{ source_workload }}.{{ source_workload_namespace}}", + "refId": "B", + "step": 2 + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Bytes Sent to Incoming TCP Connection", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "Bps", + "label": null, + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ] + }, + { + "content": "
\nOUTBOUND SERVICES\n
", + "gridPos": { + "h": 3, + "w": 24, + "x": 0, + "y": 32 + }, + "id": 69, + "links": [], + "mode": "html", + "title": "", + "transparent": true, + "type": "text" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 0, + "gridPos": { + "h": 6, + "w": 12, + "x": 0, + "y": 35 + }, + "id": 70, + "legend": { + "avg": false, + "current": false, + "hideEmpty": true, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null as zero", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "round(sum(irate(istio_requests_total{connection_security_policy=\"mutual_tls\", source_workload_namespace=~\"$namespace\", source_workload=~\"$workload\", reporter=\"source\", destination_service=~\"$dstsvc\"}[5m])) by (destination_service, response_code), 0.001)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{ destination_service }} : {{ response_code }} (🔐mTLS)", + "refId": "B", + "step": 2 + }, + { + "expr": "round(sum(irate(istio_requests_total{connection_security_policy!=\"mutual_tls\", source_workload_namespace=~\"$namespace\", source_workload=~\"$workload\", reporter=\"source\", destination_service=~\"$dstsvc\"}[5m])) by (destination_service, response_code), 0.001)", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_service }} : {{ response_code }}", + "refId": "A", + "step": 2 + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Outgoing Requests by Destination And Response Code", + "tooltip": { + "shared": false, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [ + "total" + ] + }, + "yaxes": [ + { + "format": "ops", + "label": null, + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ] + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 6, + "w": 12, + "x": 12, + "y": 35 + }, + "id": 71, + "legend": { + "avg": false, + "current": false, + "hideEmpty": true, + "hideZero": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(irate(istio_requests_total{reporter=\"source\", connection_security_policy=\"mutual_tls\", source_workload_namespace=~\"$namespace\", source_workload=~\"$workload\",response_code!~\"5.*\", destination_service=~\"$dstsvc\"}[5m])) by (destination_service) / sum(irate(istio_requests_total{reporter=\"source\", connection_security_policy=\"mutual_tls\", source_workload_namespace=~\"$namespace\", source_workload=~\"$workload\", destination_service=~\"$dstsvc\"}[5m])) by (destination_service)", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_service }} (🔐mTLS)", + "refId": "A", + "step": 2 + }, + { + "expr": "sum(irate(istio_requests_total{reporter=\"source\", connection_security_policy!=\"mutual_tls\", source_workload_namespace=~\"$namespace\", source_workload=~\"$workload\",response_code!~\"5.*\", destination_service=~\"$dstsvc\"}[5m])) by (destination_service) / sum(irate(istio_requests_total{reporter=\"source\", connection_security_policy!=\"mutual_tls\", source_workload_namespace=~\"$namespace\", source_workload=~\"$workload\", destination_service=~\"$dstsvc\"}[5m])) by (destination_service)", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{destination_service }}", + "refId": "B", + "step": 2 + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Outgoing Success Rate (non-5xx responses) By Destination", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "percentunit", + "label": null, + "logBase": 1, + "max": "1.01", + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ] + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "description": "", + "fill": 1, + "gridPos": { + "h": 6, + "w": 8, + "x": 0, + "y": 41 + }, + "id": 72, + "legend": { + "alignAsTable": false, + "avg": false, + "current": false, + "hideEmpty": true, + "hideZero": false, + "max": false, + "min": false, + "rightSide": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "(histogram_quantile(0.50, sum(irate(istio_request_duration_milliseconds_bucket{reporter=\"source\", connection_security_policy=\"mutual_tls\", source_workload=~\"$workload\", source_workload_namespace=~\"$namespace\", destination_service=~\"$dstsvc\"}[1m])) by (destination_service, le)) / 1000) or histogram_quantile(0.50, sum(irate(istio_request_duration_seconds_bucket{reporter=\"source\", connection_security_policy=\"mutual_tls\", source_workload=~\"$workload\", source_workload_namespace=~\"$namespace\", destination_service=~\"$dstsvc\"}[1m])) by (destination_service, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_service }} P50 (🔐mTLS)", + "refId": "D", + "step": 2 + }, + { + "expr": "(histogram_quantile(0.90, sum(irate(istio_request_duration_milliseconds_bucket{reporter=\"source\", connection_security_policy=\"mutual_tls\", source_workload=~\"$workload\", source_workload_namespace=~\"$namespace\", destination_service=~\"$dstsvc\"}[1m])) by (destination_service, le)) / 1000) or histogram_quantile(0.90, sum(irate(istio_request_duration_seconds_bucket{reporter=\"source\", connection_security_policy=\"mutual_tls\", source_workload=~\"$workload\", source_workload_namespace=~\"$namespace\", destination_service=~\"$dstsvc\"}[1m])) by (destination_service, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_service }} P90 (🔐mTLS)", + "refId": "A", + "step": 2 + }, + { + "expr": "(histogram_quantile(0.95, sum(irate(istio_request_duration_milliseconds_bucket{reporter=\"source\", connection_security_policy=\"mutual_tls\", source_workload=~\"$workload\", source_workload_namespace=~\"$namespace\", destination_service=~\"$dstsvc\"}[1m])) by (destination_service, le)) / 1000) or histogram_quantile(0.95, sum(irate(istio_request_duration_seconds_bucket{reporter=\"source\", connection_security_policy=\"mutual_tls\", source_workload=~\"$workload\", source_workload_namespace=~\"$namespace\", destination_service=~\"$dstsvc\"}[1m])) by (destination_service, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_service }} P95 (🔐mTLS)", + "refId": "B", + "step": 2 + }, + { + "expr": "(histogram_quantile(0.99, sum(irate(istio_request_duration_milliseconds_bucket{reporter=\"source\", connection_security_policy=\"mutual_tls\", source_workload=~\"$workload\", source_workload_namespace=~\"$namespace\", destination_service=~\"$dstsvc\"}[1m])) by (destination_service, le)) / 1000) or histogram_quantile(0.99, sum(irate(istio_request_duration_seconds_bucket{reporter=\"source\", connection_security_policy=\"mutual_tls\", source_workload=~\"$workload\", source_workload_namespace=~\"$namespace\", destination_service=~\"$dstsvc\"}[1m])) by (destination_service, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_service }} P99 (🔐mTLS)", + "refId": "C", + "step": 2 + }, + { + "expr": "(histogram_quantile(0.50, sum(irate(istio_request_duration_milliseconds_bucket{reporter=\"source\", connection_security_policy!=\"mutual_tls\", source_workload=~\"$workload\", source_workload_namespace=~\"$namespace\", destination_service=~\"$dstsvc\"}[1m])) by (destination_service, le)) / 1000) or histogram_quantile(0.50, sum(irate(istio_request_duration_seconds_bucket{reporter=\"source\", connection_security_policy!=\"mutual_tls\", source_workload=~\"$workload\", source_workload_namespace=~\"$namespace\", destination_service=~\"$dstsvc\"}[1m])) by (destination_service, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_service }} P50", + "refId": "E", + "step": 2 + }, + { + "expr": "(histogram_quantile(0.90, sum(irate(istio_request_duration_milliseconds_bucket{reporter=\"source\", connection_security_policy!=\"mutual_tls\", source_workload=~\"$workload\", source_workload_namespace=~\"$namespace\", destination_service=~\"$dstsvc\"}[1m])) by (destination_service, le)) / 1000) or histogram_quantile(0.90, sum(irate(istio_request_duration_seconds_bucket{reporter=\"source\", connection_security_policy!=\"mutual_tls\", source_workload=~\"$workload\", source_workload_namespace=~\"$namespace\", destination_service=~\"$dstsvc\"}[1m])) by (destination_service, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_service }} P90", + "refId": "F", + "step": 2 + }, + { + "expr": "(histogram_quantile(0.95, sum(irate(istio_request_duration_milliseconds_bucket{reporter=\"source\", connection_security_policy!=\"mutual_tls\", source_workload=~\"$workload\", source_workload_namespace=~\"$namespace\", destination_service=~\"$dstsvc\"}[1m])) by (destination_service, le)) / 1000) or histogram_quantile(0.95, sum(irate(istio_request_duration_seconds_bucket{reporter=\"source\", connection_security_policy!=\"mutual_tls\", source_workload=~\"$workload\", source_workload_namespace=~\"$namespace\", destination_service=~\"$dstsvc\"}[1m])) by (destination_service, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_service }} P95", + "refId": "G", + "step": 2 + }, + { + "expr": "(histogram_quantile(0.99, sum(irate(istio_request_duration_milliseconds_bucket{reporter=\"source\", connection_security_policy!=\"mutual_tls\", source_workload=~\"$workload\", source_workload_namespace=~\"$namespace\", destination_service=~\"$dstsvc\"}[1m])) by (destination_service, le)) / 1000) or histogram_quantile(0.99, sum(irate(istio_request_duration_seconds_bucket{reporter=\"source\", connection_security_policy!=\"mutual_tls\", source_workload=~\"$workload\", source_workload_namespace=~\"$namespace\", destination_service=~\"$dstsvc\"}[1m])) by (destination_service, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_service }} P99", + "refId": "H", + "step": 2 + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Outgoing Request Duration by Destination", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "s", + "label": null, + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ] + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 6, + "w": 8, + "x": 8, + "y": 41 + }, + "id": 73, + "legend": { + "alignAsTable": false, + "avg": false, + "current": false, + "hideEmpty": true, + "max": false, + "min": false, + "rightSide": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "histogram_quantile(0.50, sum(irate(istio_request_bytes_bucket{reporter=\"source\", connection_security_policy=\"mutual_tls\", source_workload=~\"$workload\", source_workload_namespace=~\"$namespace\", destination_service=~\"$dstsvc\"}[1m])) by (destination_service, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_service }} P50 (🔐mTLS)", + "refId": "D", + "step": 2 + }, + { + "expr": "histogram_quantile(0.90, sum(irate(istio_request_bytes_bucket{reporter=\"source\", connection_security_policy=\"mutual_tls\", source_workload=~\"$workload\", source_workload_namespace=~\"$namespace\", destination_service=~\"$dstsvc\"}[1m])) by (destination_service, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_service }} P90 (🔐mTLS)", + "refId": "A", + "step": 2 + }, + { + "expr": "histogram_quantile(0.95, sum(irate(istio_request_bytes_bucket{reporter=\"source\", connection_security_policy=\"mutual_tls\", source_workload=~\"$workload\", source_workload_namespace=~\"$namespace\", destination_service=~\"$dstsvc\"}[1m])) by (destination_service, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_service }} P95 (🔐mTLS)", + "refId": "B", + "step": 2 + }, + { + "expr": "histogram_quantile(0.99, sum(irate(istio_request_bytes_bucket{reporter=\"source\", connection_security_policy=\"mutual_tls\", source_workload=~\"$workload\", source_workload_namespace=~\"$namespace\", destination_service=~\"$dstsvc\"}[1m])) by (destination_service, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_service }} P99 (🔐mTLS)", + "refId": "C", + "step": 2 + }, + { + "expr": "histogram_quantile(0.50, sum(irate(istio_request_bytes_bucket{reporter=\"source\", connection_security_policy!=\"mutual_tls\", source_workload=~\"$workload\", source_workload_namespace=~\"$namespace\", destination_service=~\"$dstsvc\"}[1m])) by (destination_service, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_service }} P50", + "refId": "E", + "step": 2 + }, + { + "expr": "histogram_quantile(0.90, sum(irate(istio_request_bytes_bucket{reporter=\"source\", connection_security_policy!=\"mutual_tls\", source_workload=~\"$workload\", source_workload_namespace=~\"$namespace\", destination_service=~\"$dstsvc\"}[1m])) by (destination_service, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_service }} P90", + "refId": "F", + "step": 2 + }, + { + "expr": "histogram_quantile(0.95, sum(irate(istio_request_bytes_bucket{reporter=\"source\", connection_security_policy!=\"mutual_tls\", source_workload=~\"$workload\", source_workload_namespace=~\"$namespace\", destination_service=~\"$dstsvc\"}[1m])) by (destination_service, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_service }} P95", + "refId": "G", + "step": 2 + }, + { + "expr": "histogram_quantile(0.99, sum(irate(istio_request_bytes_bucket{reporter=\"source\", connection_security_policy!=\"mutual_tls\", source_workload=~\"$workload\", source_workload_namespace=~\"$namespace\", destination_service=~\"$dstsvc\"}[1m])) by (destination_service, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_service }} P99", + "refId": "H", + "step": 2 + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Outgoing Request Size By Destination", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "decbytes", + "label": null, + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ] + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 6, + "w": 8, + "x": 16, + "y": 41 + }, + "id": 74, + "legend": { + "alignAsTable": false, + "avg": false, + "current": false, + "hideEmpty": true, + "max": false, + "min": false, + "rightSide": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "histogram_quantile(0.50, sum(irate(istio_response_bytes_bucket{reporter=\"source\", connection_security_policy=\"mutual_tls\", source_workload=~\"$workload\", source_workload_namespace=~\"$namespace\", destination_service=~\"$dstsvc\"}[1m])) by (destination_service, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_service }} P50 (🔐mTLS)", + "refId": "D", + "step": 2 + }, + { + "expr": "histogram_quantile(0.90, sum(irate(istio_response_bytes_bucket{reporter=\"source\", connection_security_policy=\"mutual_tls\", source_workload=~\"$workload\", source_workload_namespace=~\"$namespace\", destination_service=~\"$dstsvc\"}[1m])) by (destination_service, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_service }} P90 (🔐mTLS)", + "refId": "A", + "step": 2 + }, + { + "expr": "histogram_quantile(0.95, sum(irate(istio_response_bytes_bucket{reporter=\"source\", connection_security_policy=\"mutual_tls\", source_workload=~\"$workload\", source_workload_namespace=~\"$namespace\", destination_service=~\"$dstsvc\"}[1m])) by (destination_service, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_service }} P95 (🔐mTLS)", + "refId": "B", + "step": 2 + }, + { + "expr": "histogram_quantile(0.99, sum(irate(istio_response_bytes_bucket{reporter=\"source\", connection_security_policy=\"mutual_tls\", source_workload=~\"$workload\", source_workload_namespace=~\"$namespace\", destination_service=~\"$dstsvc\"}[1m])) by (destination_service, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_service }} P99 (🔐mTLS)", + "refId": "C", + "step": 2 + }, + { + "expr": "histogram_quantile(0.50, sum(irate(istio_response_bytes_bucket{reporter=\"source\", connection_security_policy!=\"mutual_tls\", source_workload=~\"$workload\", source_workload_namespace=~\"$namespace\", destination_service=~\"$dstsvc\"}[1m])) by (destination_service, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_service }} P50", + "refId": "E", + "step": 2 + }, + { + "expr": "histogram_quantile(0.90, sum(irate(istio_response_bytes_bucket{reporter=\"source\", connection_security_policy!=\"mutual_tls\", source_workload=~\"$workload\", source_workload_namespace=~\"$namespace\", destination_service=~\"$dstsvc\"}[1m])) by (destination_service, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_service }} P90", + "refId": "F", + "step": 2 + }, + { + "expr": "histogram_quantile(0.95, sum(irate(istio_response_bytes_bucket{reporter=\"source\", connection_security_policy!=\"mutual_tls\", source_workload=~\"$workload\", source_workload_namespace=~\"$namespace\", destination_service=~\"$dstsvc\"}[1m])) by (destination_service, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_service }} P95", + "refId": "G", + "step": 2 + }, + { + "expr": "histogram_quantile(0.99, sum(irate(istio_response_bytes_bucket{reporter=\"source\", connection_security_policy!=\"mutual_tls\", source_workload=~\"$workload\", source_workload_namespace=~\"$namespace\", destination_service=~\"$dstsvc\"}[1m])) by (destination_service, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_service }} P99", + "refId": "H", + "step": 2 + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Response Size By Destination", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "decbytes", + "label": null, + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ] + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 6, + "w": 12, + "x": 0, + "y": 47 + }, + "id": 76, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "round(sum(irate(istio_tcp_sent_bytes_total{connection_security_policy=\"mutual_tls\", reporter=\"source\", source_workload_namespace=~\"$namespace\", source_workload=~\"$workload\", destination_service=~\"$dstsvc\"}[1m])) by (destination_service), 0.001)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{ destination_service }} (🔐mTLS)", + "refId": "A", + "step": 2 + }, + { + "expr": "round(sum(irate(istio_tcp_sent_bytes_total{connection_security_policy!=\"mutual_tls\", reporter=\"source\", source_workload_namespace=~\"$namespace\", source_workload=~\"$workload\", destination_service=~\"$dstsvc\"}[1m])) by (destination_service), 0.001)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{ destination_service }}", + "refId": "B", + "step": 2 + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Bytes Sent on Outgoing TCP Connection", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "Bps", + "label": null, + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ] + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 6, + "w": 12, + "x": 12, + "y": 47 + }, + "id": 78, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "round(sum(irate(istio_tcp_received_bytes_total{reporter=\"source\", connection_security_policy=\"mutual_tls\", source_workload_namespace=~\"$namespace\", source_workload=~\"$workload\", destination_service=~\"$dstsvc\"}[1m])) by (destination_service), 0.001)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{ destination_service }} (🔐mTLS)", + "refId": "A", + "step": 2 + }, + { + "expr": "round(sum(irate(istio_tcp_received_bytes_total{reporter=\"source\", connection_security_policy!=\"mutual_tls\", source_workload_namespace=~\"$namespace\", source_workload=~\"$workload\", destination_service=~\"$dstsvc\"}[1m])) by (destination_service), 0.001)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{ destination_service }}", + "refId": "B", + "step": 2 + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Bytes Received from Outgoing TCP Connection", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "Bps", + "label": null, + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ] + } + ], + "refresh": "10s", + "schemaVersion": 16, + "style": "dark", + "tags": [], + "templating": { + "list": [ + { + "allValue": null, + "current": {}, + "datasource": "Prometheus", + "hide": 0, + "includeAll": false, + "label": "Namespace", + "multi": false, + "name": "namespace", + "options": [], + "query": "query_result(sum(istio_requests_total) by (destination_workload_namespace) or sum(istio_tcp_sent_bytes_total) by (destination_workload_namespace))", + "refresh": 1, + "regex": "/.*_namespace=\"([^\"]*).*/", + "sort": 0, + "tagValuesQuery": "", + "tags": [], + "tagsQuery": "", + "type": "query", + "useTags": false + }, + { + "allValue": null, + "current": {}, + "datasource": "Prometheus", + "hide": 0, + "includeAll": false, + "label": "Workload", + "multi": false, + "name": "workload", + "options": [], + "query": "query_result((sum(istio_requests_total{destination_workload_namespace=~\"$namespace\"}) by (destination_workload) or sum(istio_requests_total{source_workload_namespace=~\"$namespace\"}) by (source_workload)) or (sum(istio_tcp_sent_bytes_total{destination_workload_namespace=~\"$namespace\"}) by (destination_workload) or sum(istio_tcp_sent_bytes_total{source_workload_namespace=~\"$namespace\"}) by (source_workload)))", + "refresh": 1, + "regex": "/.*workload=\"([^\"]*).*/", + "sort": 1, + "tagValuesQuery": "", + "tags": [], + "tagsQuery": "", + "type": "query", + "useTags": false + }, + { + "allValue": null, + "current": {}, + "datasource": "Prometheus", + "hide": 0, + "includeAll": true, + "label": "Inbound Workload Namespace", + "multi": true, + "name": "srcns", + "options": [], + "query": "query_result( sum(istio_requests_total{reporter=\"destination\", destination_workload=\"$workload\", destination_workload_namespace=~\"$namespace\"}) by (source_workload_namespace) or sum(istio_tcp_sent_bytes_total{reporter=\"destination\", destination_workload=\"$workload\", destination_workload_namespace=~\"$namespace\"}) by (source_workload_namespace))", + "refresh": 1, + "regex": "/.*namespace=\"([^\"]*).*/", + "sort": 2, + "tagValuesQuery": "", + "tags": [], + "tagsQuery": "", + "type": "query", + "useTags": false + }, + { + "allValue": null, + "current": {}, + "datasource": "Prometheus", + "hide": 0, + "includeAll": true, + "label": "Inbound Workload", + "multi": true, + "name": "srcwl", + "options": [], + "query": "query_result( sum(istio_requests_total{reporter=\"destination\", destination_workload=\"$workload\", destination_workload_namespace=~\"$namespace\", source_workload_namespace=~\"$srcns\"}) by (source_workload) or sum(istio_tcp_sent_bytes_total{reporter=\"destination\", destination_workload=\"$workload\", destination_workload_namespace=~\"$namespace\", source_workload_namespace=~\"$srcns\"}) by (source_workload))", + "refresh": 1, + "regex": "/.*workload=\"([^\"]*).*/", + "sort": 3, + "tagValuesQuery": "", + "tags": [], + "tagsQuery": "", + "type": "query", + "useTags": false + }, + { + "allValue": null, + "current": {}, + "datasource": "Prometheus", + "hide": 0, + "includeAll": true, + "label": "Destination Service", + "multi": true, + "name": "dstsvc", + "options": [], + "query": "query_result( sum(istio_requests_total{reporter=\"source\", source_workload=~\"$workload\", source_workload_namespace=~\"$namespace\"}) by (destination_service) or sum(istio_tcp_sent_bytes_total{reporter=\"source\", source_workload=~\"$workload\", source_workload_namespace=~\"$namespace\"}) by (destination_service))", + "refresh": 1, + "regex": "/.*destination_service=\"([^\"]*).*/", + "sort": 4, + "tagValuesQuery": "", + "tags": [], + "tagsQuery": "", + "type": "query", + "useTags": false + } + ] + }, + "time": { + "from": "now-5m", + "to": "now" + }, + "timepicker": { + "refresh_intervals": [ + "5s", + "10s", + "30s", + "1m", + "5m", + "15m", + "30m", + "1h", + "2h", + "1d" + ], + "time_options": [ + "5m", + "15m", + "1h", + "6h", + "12h", + "24h", + "2d", + "7d", + "30d" + ] + }, + "timezone": "", + "title": "Istio Workload Dashboard", + "uid": "UbsSZTDik", + "version": 1 +} +' +--- +apiVersion: v1 +kind: ConfigMap +metadata: + name: istio-grafana-configuration-dashboards-mixer-dashboard + namespace: istio-system + labels: + app: grafana + chart: grafana + heritage: Tiller + release: istio + istio: grafana +data: + mixer-dashboard.json: '{ + "__inputs": [ + { + "name": "DS_PROMETHEUS", + "label": "Prometheus", + "description": "", + "type": "datasource", + "pluginId": "prometheus", + "pluginName": "Prometheus" + } + ], + "__requires": [ + { + "type": "grafana", + "id": "grafana", + "name": "Grafana", + "version": "5.2.3" + }, + { + "type": "panel", + "id": "graph", + "name": "Graph", + "version": "5.0.0" + }, + { + "type": "datasource", + "id": "prometheus", + "name": "Prometheus", + "version": "5.0.0" + }, + { + "type": "panel", + "id": "text", + "name": "Text", + "version": "5.0.0" + } + ], + "annotations": { + "list": [ + { + "builtIn": 1, + "datasource": "-- Grafana --", + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "limit": 100, + "name": "Annotations & Alerts", + "showIn": 0, + "type": "dashboard" + } + ] + }, + "editable": false, + "gnetId": null, + "graphTooltip": 1, + "id": null, + "iteration": 1543881232533, + "links": [], + "panels": [ + { + "content": "

Deployed Versions

", + "gridPos": { + "h": 3, + "w": 24, + "x": 0, + "y": 0 + }, + "height": "40", + "id": 62, + "links": [], + "mode": "html", + "title": "", + "transparent": true, + "type": "text" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 5, + "w": 24, + "x": 0, + "y": 3 + }, + "id": 64, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(istio_build{component=\"mixer\"}) by (tag)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{ tag }}", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Mixer Versions", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "content": "

Resource Usage

", + "gridPos": { + "h": 3, + "w": 24, + "x": 0, + "y": 8 + }, + "height": "40", + "id": 29, + "links": [], + "mode": "html", + "title": "", + "transparent": true, + "type": "text" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 7, + "w": 6, + "x": 0, + "y": 11 + }, + "id": 5, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(process_virtual_memory_bytes{job=~\"istio-telemetry|istio-policy\"}) by (job)", + "format": "time_series", + "instant": false, + "intervalFactor": 2, + "legendFormat": "Virtual Memory ({{ job }})", + "refId": "I" + }, + { + "expr": "sum(process_resident_memory_bytes{job=~\"istio-telemetry|istio-policy\"}) by (job)", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "Resident Memory ({{ job }})", + "refId": "H" + }, + { + "expr": "sum(go_memstats_heap_sys_bytes{job=~\"istio-telemetry|istio-policy\"}) by (job)", + "format": "time_series", + "hide": true, + "intervalFactor": 2, + "legendFormat": "heap sys ({{ job }})", + "refId": "A" + }, + { + "expr": "sum(go_memstats_heap_alloc_bytes{job=~\"istio-telemetry|istio-policy\"}) by (job)", + "format": "time_series", + "hide": true, + "intervalFactor": 2, + "legendFormat": "heap alloc ({{ job }})", + "refId": "D" + }, + { + "expr": "sum(go_memstats_alloc_bytes{job=~\"istio-telemetry|istio-policy\"}) by (job)", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "Alloc ({{ job }})", + "refId": "F" + }, + { + "expr": "sum(go_memstats_heap_inuse_bytes{job=~\"istio-telemetry|istio-policy\"}) by (job)", + "format": "time_series", + "hide": false, + "intervalFactor": 2, + "legendFormat": "Heap in-use ({{ job }})", + "refId": "E" + }, + { + "expr": "sum(go_memstats_stack_inuse_bytes{job=~\"istio-telemetry|istio-policy\"}) by (job)", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "Stack in-use ({{ job }})", + "refId": "G" + }, + { + "expr": "sum(label_replace(container_memory_usage_bytes{job=\"kubernetes-cadvisor\", container_name=~\"mixer|istio-proxy\", pod_name=~\"istio-telemetry-.*|istio-policy-.*\"}, \"service\", \"$1\" , \"pod_name\", \"(istio-telemetry|istio-policy)-.*\")) by (service)", + "format": "time_series", + "hide": false, + "intervalFactor": 2, + "legendFormat": "{{ service }} total (k8s)", + "refId": "C" + }, + { + "expr": "sum(label_replace(container_memory_usage_bytes{job=\"kubernetes-cadvisor\", container_name=~\"mixer|istio-proxy\", pod_name=~\"istio-telemetry-.*|istio-policy-.*\"}, \"service\", \"$1\" , \"pod_name\", \"(istio-telemetry|istio-policy)-.*\")) by (container_name, service)", + "format": "time_series", + "hide": false, + "intervalFactor": 2, + "legendFormat": "{{ service }} - {{ container_name }} (k8s)", + "refId": "B" + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Memory", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "bytes", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 7, + "w": 6, + "x": 6, + "y": 11 + }, + "id": 6, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "label_replace(sum(rate(container_cpu_usage_seconds_total{job=\"kubernetes-cadvisor\",container_name=~\"mixer|istio-proxy\", pod_name=~\"istio-telemetry-.*|istio-policy-.*\"}[1m])) by (pod_name), \"service\", \"$1\" , \"pod_name\", \"(istio-telemetry|istio-policy)-.*\")", + "format": "time_series", + "hide": false, + "intervalFactor": 2, + "legendFormat": "{{ service }} total (k8s)", + "refId": "A" + }, + { + "expr": "label_replace(sum(rate(container_cpu_usage_seconds_total{job=\"kubernetes-cadvisor\",container_name=~\"mixer|istio-proxy\", pod_name=~\"istio-telemetry-.*|istio-policy-.*\"}[1m])) by (container_name, pod_name), \"service\", \"$1\" , \"pod_name\", \"(istio-telemetry|istio-policy)-.*\")", + "format": "time_series", + "hide": false, + "intervalFactor": 2, + "legendFormat": "{{ service }} - {{ container_name }} (k8s)", + "refId": "B" + }, + { + "expr": "sum(irate(process_cpu_seconds_total{job=~\"istio-telemetry|istio-policy\"}[1m])) by (job)", + "format": "time_series", + "hide": false, + "intervalFactor": 2, + "legendFormat": "{{ job }} (self-reported)", + "refId": "C" + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "CPU", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 7, + "w": 6, + "x": 12, + "y": 11 + }, + "id": 7, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(process_open_fds{job=~\"istio-telemetry|istio-policy\"}) by (job)", + "format": "time_series", + "hide": true, + "instant": false, + "interval": "", + "intervalFactor": 2, + "legendFormat": "Open FDs ({{ job }})", + "refId": "A" + }, + { + "expr": "sum(label_replace(container_fs_usage_bytes{job=\"kubernetes-cadvisor\", container_name=~\"mixer|istio-proxy\", pod_name=~\"istio-telemetry-.*|istio-policy-.*\"}, \"service\", \"$1\" , \"pod_name\", \"(istio-telemetry|istio-policy)-.*\")) by (container_name, service)", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "{{ service }} - {{ container_name }}", + "refId": "B" + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Disk", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "bytes", + "label": "", + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "decimals": null, + "format": "none", + "label": "", + "logBase": 1024, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 7, + "w": 6, + "x": 18, + "y": 11 + }, + "id": 4, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": false, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(go_goroutines{job=~\"istio-telemetry|istio-policy\"}) by (job)", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "Number of Goroutines ({{ job }})", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Goroutines", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": "", + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "content": "

Mixer Overview

", + "gridPos": { + "h": 3, + "w": 24, + "x": 0, + "y": 18 + }, + "height": "40px", + "id": 30, + "links": [], + "mode": "html", + "title": "", + "transparent": true, + "type": "text" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 6, + "w": 6, + "x": 0, + "y": 21 + }, + "id": 9, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(rate(grpc_io_server_completed_rpcs[1m]))", + "format": "time_series", + "hide": false, + "intervalFactor": 2, + "legendFormat": "mixer (Total)", + "refId": "B" + }, + { + "expr": "sum(rate(grpc_io_server_completed_rpcs[1m])) by (grpc_server_method)", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "mixer ({{ grpc_server_method }})", + "refId": "C" + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Incoming Requests", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "ops", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 6, + "w": 6, + "x": 6, + "y": 21 + }, + "id": 8, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [ + { + "alias": "{}", + "yaxis": 1 + } + ], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "histogram_quantile(0.5, sum(rate(grpc_io_server_server_latency_bucket{}[1m])) by (grpc_server_method, le))", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "{{ grpc_server_method }} 0.5", + "refId": "B" + }, + { + "expr": "histogram_quantile(0.9, sum(rate(grpc_io_server_server_latency_bucket{}[1m])) by (grpc_server_method, le))", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "{{ grpc_server_method }} 0.9", + "refId": "C" + }, + { + "expr": "histogram_quantile(0.99, sum(rate(grpc_io_server_server_latency_bucket{}[1m])) by (grpc_server_method, le))", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "{{ grpc_server_method }} 0.99", + "refId": "D" + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Response Durations", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "ms", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 6, + "w": 6, + "x": 12, + "y": 21 + }, + "id": 11, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(rate(grpc_server_handled_total{grpc_code=~\"Unknown|Unimplemented|Internal|DataLoss\"}[1m])) by (grpc_method)", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "Mixer {{ grpc_method }}", + "refId": "B" + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Server Error Rate (5xx responses)", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 6, + "w": 6, + "x": 18, + "y": 21 + }, + "id": 12, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(irate(grpc_server_handled_total{grpc_code!=\"OK\",grpc_service=~\".*Mixer\"}[1m])) by (grpc_method)", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "Mixer {{ grpc_method }}", + "refId": "B" + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Non-successes (4xxs)", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "content": "

Adapters and Config

", + "gridPos": { + "h": 3, + "w": 24, + "x": 0, + "y": 27 + }, + "id": 28, + "links": [], + "mode": "html", + "title": "", + "transparent": true, + "type": "text" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 7, + "w": 12, + "x": 0, + "y": 30 + }, + "id": 13, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(irate(mixer_runtime_dispatches_total{adapter=~\"$adapter\"}[1m])) by (adapter)", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "{{ adapter }}", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Adapter Dispatch Count", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 7, + "w": 12, + "x": 12, + "y": 30 + }, + "id": 14, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "histogram_quantile(0.5, sum(irate(mixer_runtime_dispatch_duration_seconds_bucket{adapter=~\"$adapter\"}[1m])) by (adapter, le))", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "{{ adapter }} - p50", + "refId": "A" + }, + { + "expr": "histogram_quantile(0.9, sum(irate(mixer_runtime_dispatch_duration_seconds_bucket{adapter=~\"$adapter\"}[1m])) by (adapter, le))", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "{{ adapter }} - p90 ", + "refId": "B" + }, + { + "expr": "histogram_quantile(0.99, sum(irate(mixer_runtime_dispatch_duration_seconds_bucket{adapter=~\"$adapter\"}[1m])) by (adapter, le))", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "{{ adapter }} - p99", + "refId": "C" + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Adapter Dispatch Duration", + "tooltip": { + "shared": true, + "sort": 1, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "s", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 7, + "w": 6, + "x": 0, + "y": 37 + }, + "id": 60, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "scalar(topk(1, max(mixer_config_rule_config_count) by (configID)))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Rules", + "refId": "A" + }, + { + "expr": "scalar(topk(1, max(mixer_config_rule_config_error_count) by (configID)))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Config Errors", + "refId": "B" + }, + { + "expr": "scalar(topk(1, max(mixer_config_rule_config_match_error_count) by (configID)))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Match Errors", + "refId": "C" + }, + { + "expr": "scalar(topk(1, max(mixer_config_unsatisfied_action_handler_count) by (configID)))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Unsatisfied Actions", + "refId": "D" + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Rules", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 7, + "w": 6, + "x": 6, + "y": 37 + }, + "id": 56, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "scalar(topk(1, max(mixer_config_instance_config_count) by (configID)))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Instances", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Instances in Latest Config", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 7, + "w": 6, + "x": 12, + "y": 37 + }, + "id": 54, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "scalar(topk(1, max(mixer_config_handler_config_count) by (configID)))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Handlers", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Handlers in Latest Config", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 7, + "w": 6, + "x": 18, + "y": 37 + }, + "id": 58, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "scalar(topk(1, max(mixer_config_attribute_count) by (configID)))", + "format": "time_series", + "instant": false, + "intervalFactor": 1, + "legendFormat": "Attributes", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Attributes in Latest Config", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "content": "

Individual Adapters

", + "gridPos": { + "h": 3, + "w": 24, + "x": 0, + "y": 44 + }, + "id": 23, + "links": [], + "mode": "html", + "title": "", + "transparent": true, + "type": "text" + }, + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 47 + }, + "id": 46, + "panels": [], + "repeat": "adapter", + "title": "$adapter Adapter", + "type": "row" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 7, + "w": 12, + "x": 0, + "y": 48 + }, + "id": 17, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "label_replace(irate(mixer_runtime_dispatches_total{adapter=~\"$adapter\"}[1m]),\"handler\", \"$1 ($3)\", \"handler\", \"(.*)\\\\.(.*)\\\\.(.*)\")", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "{{ handler }} (error: {{ error }})", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Dispatch Count By Handler", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 7, + "w": 12, + "x": 12, + "y": 48 + }, + "id": 18, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "label_replace(histogram_quantile(0.5, sum(rate(mixer_runtime_dispatch_duration_seconds_bucket{adapter=~\"$adapter\"}[1m])) by (handler, error, le)), \"handler_short\", \"$1 ($3)\", \"handler\", \"(.*)\\\\.(.*)\\\\.(.*)\")", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "p50 - {{ handler_short }} (error: {{ error }})", + "refId": "A" + }, + { + "expr": "label_replace(histogram_quantile(0.9, sum(irate(mixer_runtime_dispatch_duration_seconds_bucket{adapter=~\"$adapter\"}[1m])) by (handler, error, le)), \"handler_short\", \"$1 ($3)\", \"handler\", \"(.*)\\\\.(.*)\\\\.(.*)\")", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "p90 - {{ handler_short }} (error: {{ error }})", + "refId": "D" + }, + { + "expr": "label_replace(histogram_quantile(0.99, sum(irate(mixer_runtime_dispatch_duration_seconds_bucket{adapter=~\"$adapter\"}[1m])) by (handler, error, le)), \"handler_short\", \"$1 ($3)\", \"handler\", \"(.*)\\\\.(.*)\\\\.(.*)\")", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "p99 - {{ handler_short }} (error: {{ error }})", + "refId": "E" + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Dispatch Duration By Handler", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "s", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + } + ], + "refresh": "5s", + "schemaVersion": 16, + "style": "dark", + "tags": [], + "templating": { + "list": [ + { + "allValue": null, + "current": {}, + "datasource": "Prometheus", + "hide": 0, + "includeAll": true, + "label": "Adapter", + "multi": true, + "name": "adapter", + "options": [], + "query": "label_values(adapter)", + "refresh": 2, + "regex": "", + "sort": 1, + "tagValuesQuery": "", + "tags": [], + "tagsQuery": "", + "type": "query", + "useTags": false + } + ] + }, + "time": { + "from": "now-5m", + "to": "now" + }, + "timepicker": { + "refresh_intervals": [ + "5s", + "10s", + "30s", + "1m", + "5m", + "15m", + "30m", + "1h", + "2h", + "1d" + ], + "time_options": [ + "5m", + "15m", + "1h", + "6h", + "12h", + "24h", + "2d", + "7d", + "30d" + ] + }, + "timezone": "", + "title": "Istio Mixer Dashboard", + "version": 4 +} +' +--- +apiVersion: v1 +kind: ConfigMap +metadata: + name: istio-grafana-configuration-dashboards-pilot-dashboard + namespace: istio-system + labels: + app: grafana + chart: grafana + heritage: Tiller + release: istio + istio: grafana +data: + pilot-dashboard.json: '{ + "annotations": { + "list": [ + { + "builtIn": 1, + "datasource": "-- Grafana --", + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations & Alerts", + "type": "dashboard" + } + ] + }, + "editable": false, + "gnetId": null, + "graphTooltip": 1, + "id": 11, + "links": [], + "panels": [ + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 0 + }, + "id": 60, + "panels": [], + "title": "Deployed Versions", + "type": "row" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 5, + "w": 24, + "x": 0, + "y": 1 + }, + "id": 56, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(istio_build{component=\"pilot\"}) by (tag)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{ tag }}", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Pilot Versions", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 6 + }, + "id": 62, + "panels": [], + "title": "Resource Usage", + "type": "row" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 7, + "w": 6, + "x": 0, + "y": 7 + }, + "id": 5, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "process_virtual_memory_bytes{job=\"pilot\"}", + "format": "time_series", + "instant": false, + "intervalFactor": 2, + "legendFormat": "Virtual Memory", + "refId": "I", + "step": 2 + }, + { + "expr": "process_resident_memory_bytes{job=\"pilot\"}", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "Resident Memory", + "refId": "H", + "step": 2 + }, + { + "expr": "go_memstats_heap_sys_bytes{job=\"pilot\"}", + "format": "time_series", + "hide": true, + "intervalFactor": 2, + "legendFormat": "heap sys", + "refId": "A" + }, + { + "expr": "go_memstats_heap_alloc_bytes{job=\"pilot\"}", + "format": "time_series", + "hide": true, + "intervalFactor": 2, + "legendFormat": "heap alloc", + "refId": "D" + }, + { + "expr": "go_memstats_alloc_bytes{job=\"pilot\"}", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "Alloc", + "refId": "F", + "step": 2 + }, + { + "expr": "go_memstats_heap_inuse_bytes{job=\"pilot\"}", + "format": "time_series", + "hide": false, + "intervalFactor": 2, + "legendFormat": "Heap in-use", + "refId": "E", + "step": 2 + }, + { + "expr": "go_memstats_stack_inuse_bytes{job=\"pilot\"}", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "Stack in-use", + "refId": "G", + "step": 2 + }, + { + "expr": "container_memory_usage_bytes{job=\"kubernetes-cadvisor\", container_name=~\"discovery\", pod_name=~\"istio-pilot-.*\"}", + "format": "time_series", + "hide": false, + "intervalFactor": 2, + "legendFormat": "Discovery (container)", + "refId": "B", + "step": 2 + }, + { + "expr": "container_memory_usage_bytes{job=\"kubernetes-cadvisor\", container_name=~\"istio-proxy\", pod_name=~\"istio-pilot-.*\"}", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Sidecar (container)", + "refId": "C" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Memory", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "bytes", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 7, + "w": 6, + "x": 6, + "y": 7 + }, + "id": 6, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(irate(container_cpu_usage_seconds_total{job=\"kubernetes-cadvisor\",container_name=\"discovery\", pod_name=~\"istio-pilot-.*\"}[1m]))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Discovery (container)", + "refId": "A" + }, + { + "expr": "irate(process_cpu_seconds_total{job=\"pilot\"}[1m])", + "format": "time_series", + "hide": false, + "intervalFactor": 2, + "legendFormat": "Discovery (process)", + "refId": "C", + "step": 2 + }, + { + "expr": "sum(irate(container_cpu_usage_seconds_total{job=\"kubernetes-cadvisor\",container_name=\"istio-proxy\", pod_name=~\"istio-pilot-.*\"}[1m]))", + "format": "time_series", + "hide": false, + "intervalFactor": 2, + "legendFormat": "Sidecar (container)", + "refId": "B", + "step": 2 + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "CPU", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 7, + "w": 6, + "x": 12, + "y": 7 + }, + "id": 7, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "container_fs_usage_bytes{job=\"kubernetes-cadvisor\", container_name=\"discovery\", pod_name=~\"istio-pilot-.*\"}", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "Discovery", + "refId": "B", + "step": 2 + }, + { + "expr": "container_fs_usage_bytes{job=\"kubernetes-cadvisor\", container_name=\"istio-proxy\", pod_name=~\"istio-pilot-.*\"}", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Sidecar", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Disk", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "bytes", + "label": "", + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "decimals": null, + "format": "none", + "label": "", + "logBase": 1024, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 7, + "w": 6, + "x": 18, + "y": 7 + }, + "id": 4, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": false, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "go_goroutines{job=\"pilot\"}", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "Number of Goroutines", + "refId": "A", + "step": 2 + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Goroutines", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": "", + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 14 + }, + "id": 58, + "panels": [], + "title": "Pilot Push Information", + "type": "row" + }, + { + "aliasColors": {}, + "bars": true, + "dashLength": 10, + "dashes": false, + "description": "Shows the rate of pilot pushes", + "fill": 1, + "gridPos": { + "h": 8, + "w": 8, + "x": 0, + "y": 15 + }, + "id": 622, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": false, + "linewidth": 1, + "links": [], + "nullPointMode": "null as zero", + "paceLength": 10, + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": true, + "steppedLine": false, + "targets": [ + { + "expr": "sum(irate(pilot_xds_pushes{type=\"cds\"}[1m]))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Cluster", + "refId": "C" + }, + { + "expr": "sum(irate(pilot_xds_pushes{type=\"eds\"}[1m]))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Endpoints", + "refId": "D" + }, + { + "expr": "sum(irate(pilot_xds_pushes{type=\"lds\"}[1m]))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Listeners", + "refId": "A" + }, + { + "expr": "sum(irate(pilot_xds_pushes{type=\"rds\"}[1m]))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Routes", + "refId": "E" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Pilot Pushes", + "tooltip": { + "shared": false, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [ + "total" + ] + }, + "yaxes": [ + { + "format": "ops", + "label": null, + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "description": "Captures a variety of pilot errors", + "fill": 1, + "gridPos": { + "h": 8, + "w": 8, + "x": 8, + "y": 15 + }, + "id": 67, + "legend": { + "avg": false, + "current": false, + "hideEmpty": true, + "hideZero": true, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(pilot_xds_cds_reject{job=\"pilot\"}) or (absent(pilot_xds_cds_reject{job=\"pilot\"}) - 1)", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "Rejected CDS Configs", + "refId": "C" + }, + { + "expr": "sum(pilot_xds_eds_reject{job=\"pilot\"}) or (absent(pilot_xds_eds_reject{job=\"pilot\"}) - 1)", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "Rejected EDS Configs", + "refId": "D" + }, + { + "expr": "sum(pilot_xds_rds_reject{job=\"pilot\"}) or (absent(pilot_xds_rds_reject{job=\"pilot\"}) - 1)", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "Rejected RDS Configs", + "refId": "A" + }, + { + "expr": "sum(pilot_xds_lds_reject{job=\"pilot\"}) or (absent(pilot_xds_lds_reject{job=\"pilot\"}) - 1)", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "Rejected LDS Configs", + "refId": "B" + }, + { + "expr": "sum(rate(pilot_xds_write_timeout{job=\"pilot\"}[1m]))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Write Timeouts", + "refId": "F" + }, + { + "expr": "sum(rate(pilot_total_xds_internal_errors{job=\"pilot\"}[1m]))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "Internal Errors", + "refId": "H" + }, + { + "expr": "sum(rate(pilot_total_xds_rejects{job=\"pilot\"}[1m]))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "Config Rejection Rate", + "refId": "E" + }, + { + "expr": "sum(rate(pilot_xds_push_context_errors{job=\"pilot\"}[1m]))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "Push Context Errors", + "refId": "K" + }, + { + "expr": "sum(rate(pilot_xds_pushes{type!~\"lds|cds|rds|eds\"}[1m])) by (type)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Push Errors ({{ type }})", + "refId": "L" + }, + { + "expr": "sum(rate(pilot_xds_push_errors{job=\"pilot\"}[1m])) by (type)", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "Push Errors ({{ type }})", + "refId": "I" + }, + { + "expr": "sum(rate(pilot_xds_push_timeout{job=\"pilot\"}[1m]))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Push Timeouts", + "refId": "G" + }, + { + "expr": "sum(rate(pilot_xds_push_timeout_failures{job=\"pilot\"}[1m]))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Push Timeouts Failures", + "refId": "J" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Pilot Errors", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "description": "Shows the total time it takes to push a config update to a proxy", + "fill": 1, + "gridPos": { + "h": 8, + "w": 8, + "x": 16, + "y": 15 + }, + "id": 624, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "histogram_quantile(0.5, sum(rate(pilot_proxy_convergence_time_bucket[1m])) by (le))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "p50 ", + "refId": "A" + }, + { + "expr": "histogram_quantile(0.9, sum(rate(pilot_proxy_convergence_time_bucket[1m])) by (le))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "p90", + "refId": "B" + }, + { + "expr": "histogram_quantile(0.99, sum(rate(pilot_proxy_convergence_time_bucket[1m])) by (le))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "p99", + "refId": "C" + }, + { + "expr": "histogram_quantile(0.999, sum(rate(pilot_proxy_convergence_time_bucket[1m])) by (le))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "p99.9", + "refId": "D" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Proxy Push Time", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "s", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 8, + "w": 8, + "x": 0, + "y": 23 + }, + "id": 45, + "legend": { + "avg": false, + "current": false, + "hideEmpty": true, + "hideZero": true, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null as zero", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "pilot_conflict_inbound_listener{job=\"pilot\"}", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "Inbound Listeners", + "refId": "B" + }, + { + "expr": "pilot_conflict_outbound_listener_http_over_current_tcp{job=\"pilot\"}", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "Outbound Listeners (http over current tcp)", + "refId": "A" + }, + { + "expr": "pilot_conflict_outbound_listener_tcp_over_current_tcp{job=\"pilot\"}", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "Outbound Listeners (tcp over current tcp)", + "refId": "C" + }, + { + "expr": "pilot_conflict_outbound_listener_tcp_over_current_http{job=\"pilot\"}", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "Outbound Listeners (tcp over current http)", + "refId": "D" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Conflicts", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 8, + "w": 8, + "x": 8, + "y": 23 + }, + "id": 47, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "pilot_virt_services{job=\"pilot\"}", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Virtual Services", + "refId": "A" + }, + { + "expr": "pilot_services{job=\"pilot\"}", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Services", + "refId": "B" + }, + { + "expr": "pilot_xds{job=\"pilot\"}", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Connected Endpoints", + "refId": "E" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "ADS Monitoring", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "columns": [], + "datasource": "Prometheus", + "description": "Clusters in this table do not have any endpoints known to pilot. This could be from referencing subsets that do not have any instances, or pods marked as NotReady", + "fontSize": "100%", + "gridPos": { + "h": 8, + "w": 8, + "x": 16, + "y": 23 + }, + "id": 51, + "links": [], + "pageSize": null, + "scroll": true, + "showHeader": true, + "sort": { + "col": null, + "desc": false + }, + "styles": [ + { + "alias": "Time", + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "pattern": "Time", + "type": "date" + }, + { + "alias": "Clusters", + "colorMode": null, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "decimals": 2, + "pattern": "/.*/", + "thresholds": [], + "type": "number", + "unit": "short" + } + ], + "targets": [ + { + "expr": "sum(pilot_xds_eds_instances{job=\"pilot\", cluster=~\".+\\\\|.+\"}) by (cluster) < 1", + "format": "time_series", + "hide": false, + "instant": true, + "intervalFactor": 1, + "legendFormat": "{{cluster}}", + "refId": "B" + } + ], + "timeFrom": null, + "timeShift": null, + "title": "Clusters with no known endpoints", + "transform": "timeseries_aggregations", + "type": "table" + }, + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 31 + }, + "id": 64, + "panels": [], + "title": "Envoy Information", + "type": "row" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "description": "Shows details about Envoy proxies in the mesh", + "fill": 1, + "gridPos": { + "h": 8, + "w": 8, + "x": 0, + "y": 32 + }, + "id": 40, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(irate(envoy_cluster_upstream_cx_total{cluster_name=\"xds-grpc\"}[1m]))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "XDS Connections", + "refId": "C" + }, + { + "expr": "sum(irate(envoy_cluster_upstream_cx_connect_fail{cluster_name=\"xds-grpc\"}[1m]))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "XDS Connection Failures", + "refId": "A" + }, + { + "expr": "sum(increase(envoy_server_hot_restart_epoch[1m]))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Envoy Restarts", + "refId": "B" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Envoy Details", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "ops", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "ops", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 8, + "w": 8, + "x": 8, + "y": 32 + }, + "id": 41, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(envoy_cluster_upstream_cx_active{cluster_name=\"xds-grpc\"})", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "XDS Active Connections", + "refId": "C", + "step": 2 + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "XDS Active Connections", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "description": "Shows the size of XDS requests and responses", + "fill": 1, + "gridPos": { + "h": 8, + "w": 8, + "x": 16, + "y": 32 + }, + "id": 42, + "legend": { + "avg": false, + "current": false, + "hideEmpty": false, + "hideZero": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "max(rate(envoy_cluster_upstream_cx_rx_bytes_total{cluster_name=\"xds-grpc\"}[1m]))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "XDS Response Bytes Max", + "refId": "D" + }, + { + "expr": "quantile(0.5, rate(envoy_cluster_upstream_cx_rx_bytes_total{cluster_name=\"xds-grpc\"}[1m]))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "XDS Response Bytes Average", + "refId": "B" + }, + { + "expr": "max(rate(envoy_cluster_upstream_cx_tx_bytes_total{cluster_name=\"xds-grpc\"}[1m]))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "XDS Request Bytes Max", + "refId": "A" + }, + { + "expr": "quantile(.5, rate(envoy_cluster_upstream_cx_tx_bytes_total{cluster_name=\"xds-grpc\"}[1m]))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "XDS Request Bytes Average", + "refId": "C" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "XDS Requests Size", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "Bps", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "ops", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + } + ], + "refresh": "5s", + "schemaVersion": 18, + "style": "dark", + "tags": [], + "templating": { + "list": [] + }, + "time": { + "from": "now-5m", + "to": "now" + }, + "timepicker": { + "refresh_intervals": [ + "5s", + "10s", + "30s", + "1m", + "5m", + "15m", + "30m", + "1h", + "2h", + "1d" + ], + "time_options": [ + "5m", + "15m", + "1h", + "6h", + "12h", + "24h", + "2d", + "7d", + "30d" + ] + }, + "timezone": "browser", + "title": "Istio Pilot Dashboard", + "uid": "3--MLVZZk", + "version": 11 +}' +--- + +--- +# Source: istio/charts/grafana/templates/configmap.yaml +apiVersion: v1 +kind: ConfigMap +metadata: + name: istio-grafana + namespace: istio-system + labels: + app: grafana + chart: grafana + heritage: Tiller + release: istio + istio: grafana +data: + datasources.yaml: | + apiVersion: 1 + datasources: + - access: proxy + editable: true + isDefault: true + jsonData: + timeInterval: 5s + name: Prometheus + orgId: 1 + type: prometheus + url: http://prometheus:9090 + + dashboardproviders.yaml: | + apiVersion: 1 + providers: + - disableDeletion: false + folder: istio + name: istio + options: + path: /var/lib/grafana/dashboards/istio + orgId: 1 + type: file + +--- +# Source: istio/charts/kiali/templates/configmap.yaml +apiVersion: v1 +kind: ConfigMap +metadata: + name: kiali + namespace: istio-system + labels: + app: kiali + chart: kiali + heritage: Tiller + release: istio +data: + config.yaml: | + istio_namespace: istio-system + auth: + strategy: login + server: + port: 20001 + web_root: /kiali + external_services: + tracing: + url: + grafana: + url: + prometheus: + url: http://prometheus:9090 + +--- +# Source: istio/charts/prometheus/templates/configmap.yaml +apiVersion: v1 +kind: ConfigMap +metadata: + name: prometheus + namespace: istio-system + labels: + app: prometheus + chart: prometheus + heritage: Tiller + release: istio +data: + prometheus.yml: |- + global: + scrape_interval: 15s + scrape_configs: + + - job_name: 'istio-mesh' + kubernetes_sd_configs: + - role: endpoints + namespaces: + names: + - istio-system + + relabel_configs: + - source_labels: [__meta_kubernetes_service_name, __meta_kubernetes_endpoint_port_name] + action: keep + regex: istio-telemetry;prometheus + + # Scrape config for envoy stats + - job_name: 'envoy-stats' + metrics_path: /stats/prometheus + kubernetes_sd_configs: + - role: pod + + relabel_configs: + - source_labels: [__meta_kubernetes_pod_container_port_name] + action: keep + regex: '.*-envoy-prom' + - source_labels: [__address__, __meta_kubernetes_pod_annotation_prometheus_io_port] + action: replace + regex: ([^:]+)(?::\d+)?;(\d+) + replacement: $1:15090 + target_label: __address__ + - action: labelmap + regex: __meta_kubernetes_pod_label_(.+) + - source_labels: [__meta_kubernetes_namespace] + action: replace + target_label: namespace + - source_labels: [__meta_kubernetes_pod_name] + action: replace + target_label: pod_name + + - job_name: 'istio-policy' + kubernetes_sd_configs: + - role: endpoints + namespaces: + names: + - istio-system + + + relabel_configs: + - source_labels: [__meta_kubernetes_service_name, __meta_kubernetes_endpoint_port_name] + action: keep + regex: istio-policy;http-monitoring + + - job_name: 'istio-telemetry' + kubernetes_sd_configs: + - role: endpoints + namespaces: + names: + - istio-system + + relabel_configs: + - source_labels: [__meta_kubernetes_service_name, __meta_kubernetes_endpoint_port_name] + action: keep + regex: istio-telemetry;http-monitoring + + - job_name: 'pilot' + kubernetes_sd_configs: + - role: endpoints + namespaces: + names: + - istio-system + + relabel_configs: + - source_labels: [__meta_kubernetes_service_name, __meta_kubernetes_endpoint_port_name] + action: keep + regex: istio-pilot;http-monitoring + + - job_name: 'galley' + kubernetes_sd_configs: + - role: endpoints + namespaces: + names: + - istio-system + + relabel_configs: + - source_labels: [__meta_kubernetes_service_name, __meta_kubernetes_endpoint_port_name] + action: keep + regex: istio-galley;http-monitoring + + - job_name: 'citadel' + kubernetes_sd_configs: + - role: endpoints + namespaces: + names: + - istio-system + + relabel_configs: + - source_labels: [__meta_kubernetes_service_name, __meta_kubernetes_endpoint_port_name] + action: keep + regex: istio-citadel;http-monitoring + + # scrape config for API servers + - job_name: 'kubernetes-apiservers' + kubernetes_sd_configs: + - role: endpoints + namespaces: + names: + - default + scheme: https + tls_config: + ca_file: /var/run/secrets/kubernetes.io/serviceaccount/ca.crt + bearer_token_file: /var/run/secrets/kubernetes.io/serviceaccount/token + relabel_configs: + - source_labels: [__meta_kubernetes_service_name, __meta_kubernetes_endpoint_port_name] + action: keep + regex: kubernetes;https + + # scrape config for nodes (kubelet) + - job_name: 'kubernetes-nodes' + scheme: https + tls_config: + ca_file: /var/run/secrets/kubernetes.io/serviceaccount/ca.crt + bearer_token_file: /var/run/secrets/kubernetes.io/serviceaccount/token + kubernetes_sd_configs: + - role: node + relabel_configs: + - action: labelmap + regex: __meta_kubernetes_node_label_(.+) + - target_label: __address__ + replacement: kubernetes.default.svc:443 + - source_labels: [__meta_kubernetes_node_name] + regex: (.+) + target_label: __metrics_path__ + replacement: /api/v1/nodes/${1}/proxy/metrics + + # Scrape config for Kubelet cAdvisor. + # + # This is required for Kubernetes 1.7.3 and later, where cAdvisor metrics + # (those whose names begin with 'container_') have been removed from the + # Kubelet metrics endpoint. This job scrapes the cAdvisor endpoint to + # retrieve those metrics. + # + # In Kubernetes 1.7.0-1.7.2, these metrics are only exposed on the cAdvisor + # HTTP endpoint; use "replacement: /api/v1/nodes/${1}:4194/proxy/metrics" + # in that case (and ensure cAdvisor's HTTP server hasn't been disabled with + # the --cadvisor-port=0 Kubelet flag). + # + # This job is not necessary and should be removed in Kubernetes 1.6 and + # earlier versions, or it will cause the metrics to be scraped twice. + - job_name: 'kubernetes-cadvisor' + scheme: https + tls_config: + ca_file: /var/run/secrets/kubernetes.io/serviceaccount/ca.crt + bearer_token_file: /var/run/secrets/kubernetes.io/serviceaccount/token + kubernetes_sd_configs: + - role: node + relabel_configs: + - action: labelmap + regex: __meta_kubernetes_node_label_(.+) + - target_label: __address__ + replacement: kubernetes.default.svc:443 + - source_labels: [__meta_kubernetes_node_name] + regex: (.+) + target_label: __metrics_path__ + replacement: /api/v1/nodes/${1}/proxy/metrics/cadvisor + + # scrape config for service endpoints. + - job_name: 'kubernetes-service-endpoints' + kubernetes_sd_configs: + - role: endpoints + relabel_configs: + - source_labels: [__meta_kubernetes_service_annotation_prometheus_io_scrape] + action: keep + regex: true + - source_labels: [__meta_kubernetes_service_annotation_prometheus_io_scheme] + action: replace + target_label: __scheme__ + regex: (https?) + - source_labels: [__meta_kubernetes_service_annotation_prometheus_io_path] + action: replace + target_label: __metrics_path__ + regex: (.+) + - source_labels: [__address__, __meta_kubernetes_service_annotation_prometheus_io_port] + action: replace + target_label: __address__ + regex: ([^:]+)(?::\d+)?;(\d+) + replacement: $1:$2 + - action: labelmap + regex: __meta_kubernetes_service_label_(.+) + - source_labels: [__meta_kubernetes_namespace] + action: replace + target_label: kubernetes_namespace + - source_labels: [__meta_kubernetes_service_name] + action: replace + target_label: kubernetes_name + + - job_name: 'kubernetes-pods' + kubernetes_sd_configs: + - role: pod + relabel_configs: # If first two labels are present, pod should be scraped by the istio-secure job. + - source_labels: [__meta_kubernetes_pod_annotation_prometheus_io_scrape] + action: keep + regex: true + # Keep target if there's no sidecar or if prometheus.io/scheme is explicitly set to "http" + - source_labels: [__meta_kubernetes_pod_annotation_sidecar_istio_io_status, __meta_kubernetes_pod_annotation_prometheus_io_scheme] + action: keep + regex: ((;.*)|(.*;http)) + - source_labels: [__meta_kubernetes_pod_annotation_istio_mtls] + action: drop + regex: (true) + - source_labels: [__meta_kubernetes_pod_annotation_prometheus_io_path] + action: replace + target_label: __metrics_path__ + regex: (.+) + - source_labels: [__address__, __meta_kubernetes_pod_annotation_prometheus_io_port] + action: replace + regex: ([^:]+)(?::\d+)?;(\d+) + replacement: $1:$2 + target_label: __address__ + - action: labelmap + regex: __meta_kubernetes_pod_label_(.+) + - source_labels: [__meta_kubernetes_namespace] + action: replace + target_label: namespace + - source_labels: [__meta_kubernetes_pod_name] + action: replace + target_label: pod_name + + - job_name: 'kubernetes-pods-istio-secure' + scheme: https + tls_config: + ca_file: /etc/istio-certs/root-cert.pem + cert_file: /etc/istio-certs/cert-chain.pem + key_file: /etc/istio-certs/key.pem + insecure_skip_verify: true # prometheus does not support secure naming. + kubernetes_sd_configs: + - role: pod + relabel_configs: + - source_labels: [__meta_kubernetes_pod_annotation_prometheus_io_scrape] + action: keep + regex: true + # sidecar status annotation is added by sidecar injector and + # istio_workload_mtls_ability can be specifically placed on a pod to indicate its ability to receive mtls traffic. + - source_labels: [__meta_kubernetes_pod_annotation_sidecar_istio_io_status, __meta_kubernetes_pod_annotation_istio_mtls] + action: keep + regex: (([^;]+);([^;]*))|(([^;]*);(true)) + - source_labels: [__meta_kubernetes_pod_annotation_prometheus_io_scheme] + action: drop + regex: (http) + - source_labels: [__meta_kubernetes_pod_annotation_prometheus_io_path] + action: replace + target_label: __metrics_path__ + regex: (.+) + - source_labels: [__address__] # Only keep address that is host:port + action: keep # otherwise an extra target with ':443' is added for https scheme + regex: ([^:]+):(\d+) + - source_labels: [__address__, __meta_kubernetes_pod_annotation_prometheus_io_port] + action: replace + regex: ([^:]+)(?::\d+)?;(\d+) + replacement: $1:$2 + target_label: __address__ + - action: labelmap + regex: __meta_kubernetes_pod_label_(.+) + - source_labels: [__meta_kubernetes_namespace] + action: replace + target_label: namespace + - source_labels: [__meta_kubernetes_pod_name] + action: replace + target_label: pod_name +--- +# Source: istio/charts/security/templates/configmap.yaml +apiVersion: v1 +kind: ConfigMap +metadata: + name: istio-security-custom-resources + namespace: istio-system + labels: + app: security + chart: security + heritage: Tiller + release: istio + istio: citadel +data: + custom-resources.yaml: |- + # Authentication policy to enable permissive mode for all services (that have sidecar) in the mesh. + apiVersion: "authentication.istio.io/v1alpha1" + kind: "MeshPolicy" + metadata: + name: "default" + labels: + app: security + chart: security + heritage: Tiller + release: istio + spec: + peers: + - mtls: + mode: PERMISSIVE + run.sh: |- + #!/bin/sh + + set -x + + if [ "$#" -ne "1" ]; then + echo "first argument should be path to custom resource yaml" + exit 1 + fi + + pathToResourceYAML=${1} + + kubectl get validatingwebhookconfiguration istio-galley 2>/dev/null + if [ "$?" -eq 0 ]; then + echo "istio-galley validatingwebhookconfiguration found - waiting for istio-galley deployment to be ready" + while true; do + kubectl -n istio-system get deployment istio-galley 2>/dev/null + if [ "$?" -eq 0 ]; then + break + fi + sleep 1 + done + kubectl -n istio-system rollout status deployment istio-galley + if [ "$?" -ne 0 ]; then + echo "istio-galley deployment rollout status check failed" + exit 1 + fi + echo "istio-galley deployment ready for configuration validation" + fi + sleep 5 + kubectl apply -f ${pathToResourceYAML} + + +--- +# Source: istio/templates/configmap.yaml + +apiVersion: v1 +kind: ConfigMap +metadata: + name: istio + namespace: istio-system + labels: + app: istio + chart: istio + heritage: Tiller + release: istio +data: + mesh: |- + # Set the following variable to true to disable policy checks by the Mixer. + # Note that metrics will still be reported to the Mixer. + disablePolicyChecks: false + # reportBatchMaxEntries is the number of requests that are batched before telemetry data is sent to the mixer server + reportBatchMaxEntries: 100 + # reportBatchMaxTime is the max waiting time before the telemetry data of a request is sent to the mixer server + reportBatchMaxTime: 1s + + # Set enableTracing to false to disable request tracing. + enableTracing: true + + # Set accessLogFile to empty string to disable access log. + accessLogFile: "/dev/stdout" + + # If accessLogEncoding is TEXT, value will be used directly as the log format + # example: "[%START_TIME%] %REQ(:METHOD)% %REQ(X-ENVOY-ORIGINAL-PATH?:PATH)% %PROTOCOL%\n" + # If AccessLogEncoding is JSON, value will be parsed as map[string]string + # example: '{"start_time": "%START_TIME%", "req_method": "%REQ(:METHOD)%"}' + # Leave empty to use default log format + accessLogFormat: "" + + # Set accessLogEncoding to JSON or TEXT to configure sidecar access log + accessLogEncoding: 'TEXT' + + enableEnvoyAccessLogService: false + mixerCheckServer: istio-policy.istio-system.svc.cluster.local:9091 + mixerReportServer: istio-telemetry.istio-system.svc.cluster.local:9091 + # policyCheckFailOpen allows traffic in cases when the mixer policy service cannot be reached. + # Default is false which means the traffic is denied when the client is unable to connect to Mixer. + policyCheckFailOpen: false + # Let Pilot give ingresses the public IP of the Istio ingressgateway + ingressService: istio-ingressgateway + + # Default connect timeout for dynamic clusters generated by Pilot and returned via XDS + connectTimeout: 10s + + # Automatic protocol detection uses a set of heuristics to + # determine whether the connection is using TLS or not (on the + # server side), as well as the application protocol being used + # (e.g., http vs tcp). These heuristics rely on the client sending + # the first bits of data. For server first protocols like MySQL, + # MongoDB, etc., Envoy will timeout on the protocol detection after + # the specified period, defaulting to non mTLS plain TCP + # traffic. Set this field to tweak the period that Envoy will wait + # for the client to send the first bits of data. (MUST BE >=1ms) + protocolDetectionTimeout: 100ms + + # DNS refresh rate for Envoy clusters of type STRICT_DNS + dnsRefreshRate: 300s + + # Unix Domain Socket through which envoy communicates with NodeAgent SDS to get + # key/cert for mTLS. Use secret-mount files instead of SDS if set to empty. + sdsUdsPath: "" + + # The trust domain corresponds to the trust root of a system. + # Refer to https://github.com/spiffe/spiffe/blob/master/standards/SPIFFE-ID.md#21-trust-domain + trustDomain: "" + + # Set the default behavior of the sidecar for handling outbound traffic from the application: + # ALLOW_ANY - outbound traffic to unknown destinations will be allowed, in case there are no + # services or ServiceEntries for the destination port + # REGISTRY_ONLY - restrict outbound traffic to services defined in the service registry as well + # as those defined through ServiceEntries + outboundTrafficPolicy: + mode: ALLOW_ANY + localityLbSetting: + enabled: true + # The namespace to treat as the administrative root namespace for istio + # configuration. + rootNamespace: istio-system + configSources: + - address: istio-galley.istio-system.svc:9901 + + defaultConfig: + # + # TCP connection timeout between Envoy & the application, and between Envoys. Used for static clusters + # defined in Envoy's configuration file + connectTimeout: 10s + # + ### ADVANCED SETTINGS ############# + # Where should envoy's configuration be stored in the istio-proxy container + configPath: "/etc/istio/proxy" + binaryPath: "/usr/local/bin/envoy" + # The pseudo service name used for Envoy. + serviceCluster: istio-proxy + # These settings that determine how long an old Envoy + # process should be kept alive after an occasional reload. + drainDuration: 45s + parentShutdownDuration: 1m0s + # + # The mode used to redirect inbound connections to Envoy. This setting + # has no effect on outbound traffic: iptables REDIRECT is always used for + # outbound connections. + # If "REDIRECT", use iptables REDIRECT to NAT and redirect to Envoy. + # The "REDIRECT" mode loses source addresses during redirection. + # If "TPROXY", use iptables TPROXY to redirect to Envoy. + # The "TPROXY" mode preserves both the source and destination IP + # addresses and ports, so that they can be used for advanced filtering + # and manipulation. + # The "TPROXY" mode also configures the sidecar to run with the + # CAP_NET_ADMIN capability, which is required to use TPROXY. + #interceptionMode: REDIRECT + # + # Port where Envoy listens (on local host) for admin commands + # You can exec into the istio-proxy container in a pod and + # curl the admin port (curl http://localhost:15000/) to obtain + # diagnostic information from Envoy. See + # https://lyft.github.io/envoy/docs/operations/admin.html + # for more details + proxyAdminPort: 15000 + # + # Set concurrency to a specific number to control the number of Proxy worker threads. + # If set to 0 (default), then start worker thread for each CPU thread/core. + concurrency: 2 + # + tracing: + zipkin: + # Address of the Zipkin collector + address: zipkin.istio-system:9411 + # + # Mutual TLS authentication between sidecars and istio control plane. + controlPlaneAuthPolicy: NONE + # + # Address where istio Pilot service is running + discoveryAddress: istio-pilot.istio-system:15010 + + # Configuration file for the mesh networks to be used by the Split Horizon EDS. + meshNetworks: |- + networks: {} + +--- +# Source: istio/templates/sidecar-injector-configmap.yaml + +apiVersion: v1 +kind: ConfigMap +metadata: + name: istio-sidecar-injector + namespace: istio-system + labels: + app: istio + chart: istio + heritage: Tiller + release: istio + istio: sidecar-injector +data: + values: |- + {"certmanager":{"enabled":false},"galley":{"enabled":true,"global":{"arch":{"amd64":2,"ppc64le":2,"s390x":2},"configValidation":true,"controlPlaneSecurityEnabled":false,"defaultNodeSelector":{},"defaultPodDisruptionBudget":{"enabled":true},"defaultResources":{"requests":{"cpu":"10m"}},"defaultTolerations":[],"disablePolicyChecks":false,"enableHelmTest":false,"enableTracing":true,"hub":"docker.io/istio","imagePullPolicy":"IfNotPresent","imagePullSecrets":[],"k8sIngress":{"enableHttps":false,"enabled":false,"gatewayName":"ingressgateway"},"localityLbSetting":{"enabled":true},"logging":{"level":"default:info"},"meshExpansion":{"enabled":false,"useILB":false},"meshID":"","meshNetworks":{},"monitoringPort":15014,"mtls":{"enabled":false},"multiCluster":{"clusterName":"","enabled":false},"oneNamespace":false,"outboundTrafficPolicy":{"mode":"ALLOW_ANY"},"policyCheckFailOpen":false,"priorityClassName":"","proxy":{"accessLogEncoding":"TEXT","accessLogFile":"/dev/stdout","accessLogFormat":"","autoInject":"enabled","clusterDomain":"cluster.local","componentLogLevel":"","concurrency":2,"dnsRefreshRate":"300s","enableCoreDump":false,"enableCoreDumpImage":"ubuntu:xenial","envoyAccessLogService":{"enabled":false,"host":null,"port":null,"tcpKeepalive":{"interval":"10s","probes":3,"time":"10s"},"tlsSettings":{"caCertificates":null,"clientCertificate":null,"mode":"DISABLE","privateKey":null,"sni":null,"subjectAltNames":[]}},"envoyMetricsService":{"enabled":false,"host":null,"port":null},"envoyStatsd":{"enabled":false,"host":null,"port":null},"excludeIPRanges":"","excludeInboundPorts":"","excludeOutboundPorts":"","image":"proxyv2","includeIPRanges":"*","includeInboundPorts":"*","init":{"resources":{"limits":{"cpu":"100m","memory":"50Mi"},"requests":{"cpu":"10m","memory":"10Mi"}}},"kubevirtInterfaces":"","logLevel":"","privileged":false,"protocolDetectionTimeout":"100ms","readinessFailureThreshold":30,"readinessInitialDelaySeconds":1,"readinessPeriodSeconds":2,"resources":{"limits":{"cpu":"2000m","memory":"1024Mi"},"requests":{"cpu":"10m","memory":"40Mi"}},"statusPort":15020,"tracer":"zipkin"},"proxy_init":{"image":"proxy_init"},"sds":{"enabled":false,"token":{"aud":"istio-ca"},"udsPath":""},"tag":"1.3.5","tracer":{"datadog":{"address":"$(HOST_IP):8126"},"lightstep":{"accessToken":"","address":"","cacertPath":"","secure":true},"zipkin":{"address":""}},"trustDomain":"","useMCP":true},"image":"galley","nodeSelector":{},"podAntiAffinityLabelSelector":[],"podAntiAffinityTermLabelSelector":[],"replicaCount":1,"rollingMaxSurge":"100%","rollingMaxUnavailable":"25%","tolerations":[]},"gateways":{"enabled":true,"global":{"arch":{"amd64":2,"ppc64le":2,"s390x":2},"configValidation":true,"controlPlaneSecurityEnabled":false,"defaultNodeSelector":{},"defaultPodDisruptionBudget":{"enabled":true},"defaultResources":{"requests":{"cpu":"10m"}},"defaultTolerations":[],"disablePolicyChecks":false,"enableHelmTest":false,"enableTracing":true,"hub":"docker.io/istio","imagePullPolicy":"IfNotPresent","imagePullSecrets":[],"k8sIngress":{"enableHttps":false,"enabled":false,"gatewayName":"ingressgateway"},"localityLbSetting":{"enabled":true},"logging":{"level":"default:info"},"meshExpansion":{"enabled":false,"useILB":false},"meshID":"","meshNetworks":{},"monitoringPort":15014,"mtls":{"enabled":false},"multiCluster":{"clusterName":"","enabled":false},"oneNamespace":false,"outboundTrafficPolicy":{"mode":"ALLOW_ANY"},"policyCheckFailOpen":false,"priorityClassName":"","proxy":{"accessLogEncoding":"TEXT","accessLogFile":"/dev/stdout","accessLogFormat":"","autoInject":"enabled","clusterDomain":"cluster.local","componentLogLevel":"","concurrency":2,"dnsRefreshRate":"300s","enableCoreDump":false,"enableCoreDumpImage":"ubuntu:xenial","envoyAccessLogService":{"enabled":false,"host":null,"port":null,"tcpKeepalive":{"interval":"10s","probes":3,"time":"10s"},"tlsSettings":{"caCertificates":null,"clientCertificate":null,"mode":"DISABLE","privateKey":null,"sni":null,"subjectAltNames":[]}},"envoyMetricsService":{"enabled":false,"host":null,"port":null},"envoyStatsd":{"enabled":false,"host":null,"port":null},"excludeIPRanges":"","excludeInboundPorts":"","excludeOutboundPorts":"","image":"proxyv2","includeIPRanges":"*","includeInboundPorts":"*","init":{"resources":{"limits":{"cpu":"100m","memory":"50Mi"},"requests":{"cpu":"10m","memory":"10Mi"}}},"kubevirtInterfaces":"","logLevel":"","privileged":false,"protocolDetectionTimeout":"100ms","readinessFailureThreshold":30,"readinessInitialDelaySeconds":1,"readinessPeriodSeconds":2,"resources":{"limits":{"cpu":"2000m","memory":"1024Mi"},"requests":{"cpu":"10m","memory":"40Mi"}},"statusPort":15020,"tracer":"zipkin"},"proxy_init":{"image":"proxy_init"},"sds":{"enabled":false,"token":{"aud":"istio-ca"},"udsPath":""},"tag":"1.3.5","tracer":{"datadog":{"address":"$(HOST_IP):8126"},"lightstep":{"accessToken":"","address":"","cacertPath":"","secure":true},"zipkin":{"address":""}},"trustDomain":"","useMCP":true},"istio-egressgateway":{"autoscaleEnabled":false,"autoscaleMax":5,"autoscaleMin":1,"cpu":{"targetAverageUtilization":80},"enabled":true,"env":{"ISTIO_META_ROUTER_MODE":"sni-dnat"},"labels":{"app":"istio-egressgateway","istio":"egressgateway"},"nodeSelector":{},"podAnnotations":{},"podAntiAffinityLabelSelector":[],"podAntiAffinityTermLabelSelector":[],"ports":[{"name":"http2","port":80},{"name":"https","port":443},{"name":"tls","port":15443,"targetPort":15443}],"resources":{"limits":{"cpu":"2000m","memory":"1024Mi"},"requests":{"cpu":"10m","memory":"40Mi"}},"rollingMaxSurge":"100%","rollingMaxUnavailable":"25%","secretVolumes":[{"mountPath":"/etc/istio/egressgateway-certs","name":"egressgateway-certs","secretName":"istio-egressgateway-certs"},{"mountPath":"/etc/istio/egressgateway-ca-certs","name":"egressgateway-ca-certs","secretName":"istio-egressgateway-ca-certs"}],"serviceAnnotations":{},"tolerations":[],"type":"ClusterIP"},"istio-ilbgateway":{"autoscaleEnabled":true,"autoscaleMax":5,"autoscaleMin":1,"cpu":{"targetAverageUtilization":80},"enabled":false,"labels":{"app":"istio-ilbgateway","istio":"ilbgateway"},"loadBalancerIP":"","nodeSelector":{},"podAnnotations":{},"ports":[{"name":"grpc-pilot-mtls","port":15011},{"name":"grpc-pilot","port":15010},{"name":"tcp-citadel-grpc-tls","port":8060,"targetPort":8060},{"name":"tcp-dns","port":5353}],"resources":{"requests":{"cpu":"800m","memory":"512Mi"}},"rollingMaxSurge":"100%","rollingMaxUnavailable":"25%","secretVolumes":[{"mountPath":"/etc/istio/ilbgateway-certs","name":"ilbgateway-certs","secretName":"istio-ilbgateway-certs"},{"mountPath":"/etc/istio/ilbgateway-ca-certs","name":"ilbgateway-ca-certs","secretName":"istio-ilbgateway-ca-certs"}],"serviceAnnotations":{"cloud.google.com/load-balancer-type":"internal"},"tolerations":[],"type":"LoadBalancer"},"istio-ingressgateway":{"applicationPorts":"","autoscaleEnabled":false,"autoscaleMax":5,"autoscaleMin":1,"cpu":{"targetAverageUtilization":80},"enabled":true,"env":{"ISTIO_META_ROUTER_MODE":"sni-dnat"},"externalIPs":[],"labels":{"app":"istio-ingressgateway","istio":"ingressgateway"},"loadBalancerIP":"","loadBalancerSourceRanges":[],"meshExpansionPorts":[{"name":"tcp-pilot-grpc-tls","port":15011,"targetPort":15011},{"name":"tcp-mixer-grpc-tls","port":15004,"targetPort":15004},{"name":"tcp-citadel-grpc-tls","port":8060,"targetPort":8060},{"name":"tcp-dns-tls","port":853,"targetPort":853}],"nodeSelector":{},"podAnnotations":{},"podAntiAffinityLabelSelector":[],"podAntiAffinityTermLabelSelector":[],"ports":[{"name":"status-port","port":15020,"targetPort":15020},{"name":"http2","nodePort":31380,"port":80,"targetPort":80},{"name":"https","nodePort":31390,"port":443},{"name":"tcp","nodePort":31400,"port":31400},{"name":"https-kiali","port":15029,"targetPort":15029},{"name":"https-prometheus","port":15030,"targetPort":15030},{"name":"https-grafana","port":15031,"targetPort":15031},{"name":"https-tracing","port":15032,"targetPort":15032},{"name":"tls","port":15443,"targetPort":15443}],"resources":{"limits":{"cpu":"2000m","memory":"1024Mi"},"requests":{"cpu":"10m","memory":"40Mi"}},"rollingMaxSurge":"100%","rollingMaxUnavailable":"25%","sds":{"enabled":false,"image":"node-agent-k8s","resources":{"limits":{"cpu":"2000m","memory":"1024Mi"},"requests":{"cpu":"100m","memory":"128Mi"}}},"secretVolumes":[{"mountPath":"/etc/istio/ingressgateway-certs","name":"ingressgateway-certs","secretName":"istio-ingressgateway-certs"},{"mountPath":"/etc/istio/ingressgateway-ca-certs","name":"ingressgateway-ca-certs","secretName":"istio-ingressgateway-ca-certs"}],"serviceAnnotations":{},"tolerations":[],"type":"LoadBalancer"}},"global":{"arch":{"amd64":2,"ppc64le":2,"s390x":2},"configValidation":true,"controlPlaneSecurityEnabled":false,"defaultNodeSelector":{},"defaultPodDisruptionBudget":{"enabled":true},"defaultResources":{"requests":{"cpu":"10m"}},"defaultTolerations":[],"disablePolicyChecks":false,"enableHelmTest":false,"enableTracing":true,"hub":"docker.io/istio","imagePullPolicy":"IfNotPresent","imagePullSecrets":[],"k8sIngress":{"enableHttps":false,"enabled":false,"gatewayName":"ingressgateway"},"localityLbSetting":{"enabled":true},"logging":{"level":"default:info"},"meshExpansion":{"enabled":false,"useILB":false},"meshID":"","meshNetworks":{},"monitoringPort":15014,"mtls":{"enabled":false},"multiCluster":{"clusterName":"","enabled":false},"oneNamespace":false,"outboundTrafficPolicy":{"mode":"ALLOW_ANY"},"policyCheckFailOpen":false,"priorityClassName":"","proxy":{"accessLogEncoding":"TEXT","accessLogFile":"/dev/stdout","accessLogFormat":"","autoInject":"enabled","clusterDomain":"cluster.local","componentLogLevel":"","concurrency":2,"dnsRefreshRate":"300s","enableCoreDump":false,"enableCoreDumpImage":"ubuntu:xenial","envoyAccessLogService":{"enabled":false,"host":null,"port":null,"tcpKeepalive":{"interval":"10s","probes":3,"time":"10s"},"tlsSettings":{"caCertificates":null,"clientCertificate":null,"mode":"DISABLE","privateKey":null,"sni":null,"subjectAltNames":[]}},"envoyMetricsService":{"enabled":false,"host":null,"port":null},"envoyStatsd":{"enabled":false,"host":null,"port":null},"excludeIPRanges":"","excludeInboundPorts":"","excludeOutboundPorts":"","image":"proxyv2","includeIPRanges":"*","includeInboundPorts":"*","init":{"resources":{"limits":{"cpu":"100m","memory":"50Mi"},"requests":{"cpu":"10m","memory":"10Mi"}}},"kubevirtInterfaces":"","logLevel":"","privileged":false,"protocolDetectionTimeout":"100ms","readinessFailureThreshold":30,"readinessInitialDelaySeconds":1,"readinessPeriodSeconds":2,"resources":{"limits":{"cpu":"2000m","memory":"1024Mi"},"requests":{"cpu":"10m","memory":"40Mi"}},"statusPort":15020,"tracer":"zipkin"},"proxy_init":{"image":"proxy_init"},"sds":{"enabled":false,"token":{"aud":"istio-ca"},"udsPath":""},"tag":"1.3.5","tracer":{"datadog":{"address":"$(HOST_IP):8126"},"lightstep":{"accessToken":"","address":"","cacertPath":"","secure":true},"zipkin":{"address":""}},"trustDomain":"","useMCP":true},"grafana":{"accessMode":"ReadWriteMany","contextPath":"/grafana","dashboardProviders":{"dashboardproviders.yaml":{"apiVersion":1,"providers":[{"disableDeletion":false,"folder":"istio","name":"istio","options":{"path":"/var/lib/grafana/dashboards/istio"},"orgId":1,"type":"file"}]}},"datasources":{"datasources.yaml":{"apiVersion":1,"datasources":[{"access":"proxy","editable":true,"isDefault":true,"jsonData":{"timeInterval":"5s"},"name":"Prometheus","orgId":1,"type":"prometheus","url":"http://prometheus:9090"}]}},"enabled":true,"env":{},"envSecrets":{},"global":{"arch":{"amd64":2,"ppc64le":2,"s390x":2},"configValidation":true,"controlPlaneSecurityEnabled":false,"defaultNodeSelector":{},"defaultPodDisruptionBudget":{"enabled":true},"defaultResources":{"requests":{"cpu":"10m"}},"defaultTolerations":[],"disablePolicyChecks":false,"enableHelmTest":false,"enableTracing":true,"hub":"docker.io/istio","imagePullPolicy":"IfNotPresent","imagePullSecrets":[],"k8sIngress":{"enableHttps":false,"enabled":false,"gatewayName":"ingressgateway"},"localityLbSetting":{"enabled":true},"logging":{"level":"default:info"},"meshExpansion":{"enabled":false,"useILB":false},"meshID":"","meshNetworks":{},"monitoringPort":15014,"mtls":{"enabled":false},"multiCluster":{"clusterName":"","enabled":false},"oneNamespace":false,"outboundTrafficPolicy":{"mode":"ALLOW_ANY"},"policyCheckFailOpen":false,"priorityClassName":"","proxy":{"accessLogEncoding":"TEXT","accessLogFile":"/dev/stdout","accessLogFormat":"","autoInject":"enabled","clusterDomain":"cluster.local","componentLogLevel":"","concurrency":2,"dnsRefreshRate":"300s","enableCoreDump":false,"enableCoreDumpImage":"ubuntu:xenial","envoyAccessLogService":{"enabled":false,"host":null,"port":null,"tcpKeepalive":{"interval":"10s","probes":3,"time":"10s"},"tlsSettings":{"caCertificates":null,"clientCertificate":null,"mode":"DISABLE","privateKey":null,"sni":null,"subjectAltNames":[]}},"envoyMetricsService":{"enabled":false,"host":null,"port":null},"envoyStatsd":{"enabled":false,"host":null,"port":null},"excludeIPRanges":"","excludeInboundPorts":"","excludeOutboundPorts":"","image":"proxyv2","includeIPRanges":"*","includeInboundPorts":"*","init":{"resources":{"limits":{"cpu":"100m","memory":"50Mi"},"requests":{"cpu":"10m","memory":"10Mi"}}},"kubevirtInterfaces":"","logLevel":"","privileged":false,"protocolDetectionTimeout":"100ms","readinessFailureThreshold":30,"readinessInitialDelaySeconds":1,"readinessPeriodSeconds":2,"resources":{"limits":{"cpu":"2000m","memory":"1024Mi"},"requests":{"cpu":"10m","memory":"40Mi"}},"statusPort":15020,"tracer":"zipkin"},"proxy_init":{"image":"proxy_init"},"sds":{"enabled":false,"token":{"aud":"istio-ca"},"udsPath":""},"tag":"1.3.5","tracer":{"datadog":{"address":"$(HOST_IP):8126"},"lightstep":{"accessToken":"","address":"","cacertPath":"","secure":true},"zipkin":{"address":""}},"trustDomain":"","useMCP":true},"image":{"repository":"grafana/grafana","tag":"6.1.6"},"ingress":{"annotations":null,"enabled":false,"hosts":["grafana.local"],"tls":null},"nodeSelector":{},"persist":false,"podAntiAffinityLabelSelector":[],"podAntiAffinityTermLabelSelector":[],"replicaCount":1,"security":{"enabled":false,"passphraseKey":"passphrase","secretName":"grafana","usernameKey":"username"},"service":{"annotations":{},"externalPort":3000,"loadBalancerIP":null,"loadBalancerSourceRanges":null,"name":"http","type":"ClusterIP"},"storageClassName":"","tolerations":[]},"istio_cni":{"enabled":false},"istiocoredns":{"enabled":false},"kiali":{"contextPath":"/kiali","createDemoSecret":true,"dashboard":{"auth":{"strategy":"login"},"grafanaURL":null,"jaegerURL":null,"secretName":"kiali","viewOnlyMode":false},"enabled":true,"global":{"arch":{"amd64":2,"ppc64le":2,"s390x":2},"configValidation":true,"controlPlaneSecurityEnabled":false,"defaultNodeSelector":{},"defaultPodDisruptionBudget":{"enabled":true},"defaultResources":{"requests":{"cpu":"10m"}},"defaultTolerations":[],"disablePolicyChecks":false,"enableHelmTest":false,"enableTracing":true,"hub":"docker.io/istio","imagePullPolicy":"IfNotPresent","imagePullSecrets":[],"k8sIngress":{"enableHttps":false,"enabled":false,"gatewayName":"ingressgateway"},"localityLbSetting":{"enabled":true},"logging":{"level":"default:info"},"meshExpansion":{"enabled":false,"useILB":false},"meshID":"","meshNetworks":{},"monitoringPort":15014,"mtls":{"enabled":false},"multiCluster":{"clusterName":"","enabled":false},"oneNamespace":false,"outboundTrafficPolicy":{"mode":"ALLOW_ANY"},"policyCheckFailOpen":false,"priorityClassName":"","proxy":{"accessLogEncoding":"TEXT","accessLogFile":"/dev/stdout","accessLogFormat":"","autoInject":"enabled","clusterDomain":"cluster.local","componentLogLevel":"","concurrency":2,"dnsRefreshRate":"300s","enableCoreDump":false,"enableCoreDumpImage":"ubuntu:xenial","envoyAccessLogService":{"enabled":false,"host":null,"port":null,"tcpKeepalive":{"interval":"10s","probes":3,"time":"10s"},"tlsSettings":{"caCertificates":null,"clientCertificate":null,"mode":"DISABLE","privateKey":null,"sni":null,"subjectAltNames":[]}},"envoyMetricsService":{"enabled":false,"host":null,"port":null},"envoyStatsd":{"enabled":false,"host":null,"port":null},"excludeIPRanges":"","excludeInboundPorts":"","excludeOutboundPorts":"","image":"proxyv2","includeIPRanges":"*","includeInboundPorts":"*","init":{"resources":{"limits":{"cpu":"100m","memory":"50Mi"},"requests":{"cpu":"10m","memory":"10Mi"}}},"kubevirtInterfaces":"","logLevel":"","privileged":false,"protocolDetectionTimeout":"100ms","readinessFailureThreshold":30,"readinessInitialDelaySeconds":1,"readinessPeriodSeconds":2,"resources":{"limits":{"cpu":"2000m","memory":"1024Mi"},"requests":{"cpu":"10m","memory":"40Mi"}},"statusPort":15020,"tracer":"zipkin"},"proxy_init":{"image":"proxy_init"},"sds":{"enabled":false,"token":{"aud":"istio-ca"},"udsPath":""},"tag":"1.3.5","tracer":{"datadog":{"address":"$(HOST_IP):8126"},"lightstep":{"accessToken":"","address":"","cacertPath":"","secure":true},"zipkin":{"address":""}},"trustDomain":"","useMCP":true},"hub":"quay.io/kiali","image":"kiali","ingress":{"annotations":null,"enabled":false,"hosts":["kiali.local"],"tls":null},"nodeSelector":{},"podAntiAffinityLabelSelector":[],"podAntiAffinityTermLabelSelector":[],"prometheusAddr":"http://prometheus:9090","replicaCount":1,"security":{"cert_file":"/kiali-cert/cert-chain.pem","enabled":false,"private_key_file":"/kiali-cert/key.pem"},"tag":"v1.4","tolerations":[]},"mixer":{"adapters":{"kubernetesenv":{"enabled":true},"prometheus":{"enabled":true,"metricsExpiryDuration":"10m"},"stdio":{"enabled":true,"outputAsJson":true},"useAdapterCRDs":false},"env":{"GODEBUG":"gctrace=1","GOMAXPROCS":"6"},"global":{"arch":{"amd64":2,"ppc64le":2,"s390x":2},"configValidation":true,"controlPlaneSecurityEnabled":false,"defaultNodeSelector":{},"defaultPodDisruptionBudget":{"enabled":true},"defaultResources":{"requests":{"cpu":"10m"}},"defaultTolerations":[],"disablePolicyChecks":false,"enableHelmTest":false,"enableTracing":true,"hub":"docker.io/istio","imagePullPolicy":"IfNotPresent","imagePullSecrets":[],"k8sIngress":{"enableHttps":false,"enabled":false,"gatewayName":"ingressgateway"},"localityLbSetting":{"enabled":true},"logging":{"level":"default:info"},"meshExpansion":{"enabled":false,"useILB":false},"meshID":"","meshNetworks":{},"monitoringPort":15014,"mtls":{"enabled":false},"multiCluster":{"clusterName":"","enabled":false},"oneNamespace":false,"outboundTrafficPolicy":{"mode":"ALLOW_ANY"},"policyCheckFailOpen":false,"priorityClassName":"","proxy":{"accessLogEncoding":"TEXT","accessLogFile":"/dev/stdout","accessLogFormat":"","autoInject":"enabled","clusterDomain":"cluster.local","componentLogLevel":"","concurrency":2,"dnsRefreshRate":"300s","enableCoreDump":false,"enableCoreDumpImage":"ubuntu:xenial","envoyAccessLogService":{"enabled":false,"host":null,"port":null,"tcpKeepalive":{"interval":"10s","probes":3,"time":"10s"},"tlsSettings":{"caCertificates":null,"clientCertificate":null,"mode":"DISABLE","privateKey":null,"sni":null,"subjectAltNames":[]}},"envoyMetricsService":{"enabled":false,"host":null,"port":null},"envoyStatsd":{"enabled":false,"host":null,"port":null},"excludeIPRanges":"","excludeInboundPorts":"","excludeOutboundPorts":"","image":"proxyv2","includeIPRanges":"*","includeInboundPorts":"*","init":{"resources":{"limits":{"cpu":"100m","memory":"50Mi"},"requests":{"cpu":"10m","memory":"10Mi"}}},"kubevirtInterfaces":"","logLevel":"","privileged":false,"protocolDetectionTimeout":"100ms","readinessFailureThreshold":30,"readinessInitialDelaySeconds":1,"readinessPeriodSeconds":2,"resources":{"limits":{"cpu":"2000m","memory":"1024Mi"},"requests":{"cpu":"10m","memory":"40Mi"}},"statusPort":15020,"tracer":"zipkin"},"proxy_init":{"image":"proxy_init"},"sds":{"enabled":false,"token":{"aud":"istio-ca"},"udsPath":""},"tag":"1.3.5","tracer":{"datadog":{"address":"$(HOST_IP):8126"},"lightstep":{"accessToken":"","address":"","cacertPath":"","secure":true},"zipkin":{"address":""}},"trustDomain":"","useMCP":true},"image":"mixer","nodeSelector":{},"podAnnotations":{},"podAntiAffinityLabelSelector":[],"podAntiAffinityTermLabelSelector":[],"policy":{"autoscaleEnabled":false,"autoscaleMax":5,"autoscaleMin":1,"cpu":{"targetAverageUtilization":80},"enabled":true,"replicaCount":1,"resources":{"requests":{"cpu":"10m","memory":"100Mi"}},"rollingMaxSurge":"100%","rollingMaxUnavailable":"25%"},"telemetry":{"autoscaleEnabled":false,"autoscaleMax":5,"autoscaleMin":1,"cpu":{"targetAverageUtilization":80},"enabled":true,"loadshedding":{"latencyThreshold":"100ms","mode":"enforce"},"replicaCount":1,"reportBatchMaxEntries":100,"reportBatchMaxTime":"1s","resources":{"limits":{"cpu":"4800m","memory":"4G"},"requests":{"cpu":"50m","memory":"100Mi"}},"rollingMaxSurge":"100%","rollingMaxUnavailable":"25%","sessionAffinityEnabled":false},"tolerations":[]},"nodeagent":{"enabled":false},"pilot":{"autoscaleEnabled":false,"autoscaleMax":5,"autoscaleMin":1,"cpu":{"targetAverageUtilization":80},"enableProtocolSniffingForInbound":false,"enableProtocolSniffingForOutbound":true,"enabled":true,"env":{"GODEBUG":"gctrace=1","PILOT_PUSH_THROTTLE":100},"global":{"arch":{"amd64":2,"ppc64le":2,"s390x":2},"configValidation":true,"controlPlaneSecurityEnabled":false,"defaultNodeSelector":{},"defaultPodDisruptionBudget":{"enabled":true},"defaultResources":{"requests":{"cpu":"10m"}},"defaultTolerations":[],"disablePolicyChecks":false,"enableHelmTest":false,"enableTracing":true,"hub":"docker.io/istio","imagePullPolicy":"IfNotPresent","imagePullSecrets":[],"k8sIngress":{"enableHttps":false,"enabled":false,"gatewayName":"ingressgateway"},"localityLbSetting":{"enabled":true},"logging":{"level":"default:info"},"meshExpansion":{"enabled":false,"useILB":false},"meshID":"","meshNetworks":{},"monitoringPort":15014,"mtls":{"enabled":false},"multiCluster":{"clusterName":"","enabled":false},"oneNamespace":false,"outboundTrafficPolicy":{"mode":"ALLOW_ANY"},"policyCheckFailOpen":false,"priorityClassName":"","proxy":{"accessLogEncoding":"TEXT","accessLogFile":"/dev/stdout","accessLogFormat":"","autoInject":"enabled","clusterDomain":"cluster.local","componentLogLevel":"","concurrency":2,"dnsRefreshRate":"300s","enableCoreDump":false,"enableCoreDumpImage":"ubuntu:xenial","envoyAccessLogService":{"enabled":false,"host":null,"port":null,"tcpKeepalive":{"interval":"10s","probes":3,"time":"10s"},"tlsSettings":{"caCertificates":null,"clientCertificate":null,"mode":"DISABLE","privateKey":null,"sni":null,"subjectAltNames":[]}},"envoyMetricsService":{"enabled":false,"host":null,"port":null},"envoyStatsd":{"enabled":false,"host":null,"port":null},"excludeIPRanges":"","excludeInboundPorts":"","excludeOutboundPorts":"","image":"proxyv2","includeIPRanges":"*","includeInboundPorts":"*","init":{"resources":{"limits":{"cpu":"100m","memory":"50Mi"},"requests":{"cpu":"10m","memory":"10Mi"}}},"kubevirtInterfaces":"","logLevel":"","privileged":false,"protocolDetectionTimeout":"100ms","readinessFailureThreshold":30,"readinessInitialDelaySeconds":1,"readinessPeriodSeconds":2,"resources":{"limits":{"cpu":"2000m","memory":"1024Mi"},"requests":{"cpu":"10m","memory":"40Mi"}},"statusPort":15020,"tracer":"zipkin"},"proxy_init":{"image":"proxy_init"},"sds":{"enabled":false,"token":{"aud":"istio-ca"},"udsPath":""},"tag":"1.3.5","tracer":{"datadog":{"address":"$(HOST_IP):8126"},"lightstep":{"accessToken":"","address":"","cacertPath":"","secure":true},"zipkin":{"address":""}},"trustDomain":"","useMCP":true},"image":"pilot","keepaliveMaxServerConnectionAge":"30m","nodeSelector":{},"podAntiAffinityLabelSelector":[],"podAntiAffinityTermLabelSelector":[],"resources":{"requests":{"cpu":"10m","memory":"100Mi"}},"rollingMaxSurge":"100%","rollingMaxUnavailable":"25%","sidecar":true,"tolerations":[],"traceSampling":100},"prometheus":{"contextPath":"/prometheus","enabled":true,"global":{"arch":{"amd64":2,"ppc64le":2,"s390x":2},"configValidation":true,"controlPlaneSecurityEnabled":false,"defaultNodeSelector":{},"defaultPodDisruptionBudget":{"enabled":true},"defaultResources":{"requests":{"cpu":"10m"}},"defaultTolerations":[],"disablePolicyChecks":false,"enableHelmTest":false,"enableTracing":true,"hub":"docker.io/istio","imagePullPolicy":"IfNotPresent","imagePullSecrets":[],"k8sIngress":{"enableHttps":false,"enabled":false,"gatewayName":"ingressgateway"},"localityLbSetting":{"enabled":true},"logging":{"level":"default:info"},"meshExpansion":{"enabled":false,"useILB":false},"meshID":"","meshNetworks":{},"monitoringPort":15014,"mtls":{"enabled":false},"multiCluster":{"clusterName":"","enabled":false},"oneNamespace":false,"outboundTrafficPolicy":{"mode":"ALLOW_ANY"},"policyCheckFailOpen":false,"priorityClassName":"","proxy":{"accessLogEncoding":"TEXT","accessLogFile":"/dev/stdout","accessLogFormat":"","autoInject":"enabled","clusterDomain":"cluster.local","componentLogLevel":"","concurrency":2,"dnsRefreshRate":"300s","enableCoreDump":false,"enableCoreDumpImage":"ubuntu:xenial","envoyAccessLogService":{"enabled":false,"host":null,"port":null,"tcpKeepalive":{"interval":"10s","probes":3,"time":"10s"},"tlsSettings":{"caCertificates":null,"clientCertificate":null,"mode":"DISABLE","privateKey":null,"sni":null,"subjectAltNames":[]}},"envoyMetricsService":{"enabled":false,"host":null,"port":null},"envoyStatsd":{"enabled":false,"host":null,"port":null},"excludeIPRanges":"","excludeInboundPorts":"","excludeOutboundPorts":"","image":"proxyv2","includeIPRanges":"*","includeInboundPorts":"*","init":{"resources":{"limits":{"cpu":"100m","memory":"50Mi"},"requests":{"cpu":"10m","memory":"10Mi"}}},"kubevirtInterfaces":"","logLevel":"","privileged":false,"protocolDetectionTimeout":"100ms","readinessFailureThreshold":30,"readinessInitialDelaySeconds":1,"readinessPeriodSeconds":2,"resources":{"limits":{"cpu":"2000m","memory":"1024Mi"},"requests":{"cpu":"10m","memory":"40Mi"}},"statusPort":15020,"tracer":"zipkin"},"proxy_init":{"image":"proxy_init"},"sds":{"enabled":false,"token":{"aud":"istio-ca"},"udsPath":""},"tag":"1.3.5","tracer":{"datadog":{"address":"$(HOST_IP):8126"},"lightstep":{"accessToken":"","address":"","cacertPath":"","secure":true},"zipkin":{"address":""}},"trustDomain":"","useMCP":true},"hub":"docker.io/prom","image":"prometheus","ingress":{"annotations":null,"enabled":false,"hosts":["prometheus.local"],"tls":null},"nodeSelector":{},"podAntiAffinityLabelSelector":[],"podAntiAffinityTermLabelSelector":[],"replicaCount":1,"retention":"6h","scrapeInterval":"15s","security":{"enabled":true},"service":{"annotations":{},"nodePort":{"enabled":false,"port":32090}},"tag":"v2.8.0","tolerations":[]},"security":{"citadelHealthCheck":false,"createMeshPolicy":true,"enableNamespacesByDefault":true,"enabled":true,"env":{},"global":{"arch":{"amd64":2,"ppc64le":2,"s390x":2},"configValidation":true,"controlPlaneSecurityEnabled":false,"defaultNodeSelector":{},"defaultPodDisruptionBudget":{"enabled":true},"defaultResources":{"requests":{"cpu":"10m"}},"defaultTolerations":[],"disablePolicyChecks":false,"enableHelmTest":false,"enableTracing":true,"hub":"docker.io/istio","imagePullPolicy":"IfNotPresent","imagePullSecrets":[],"k8sIngress":{"enableHttps":false,"enabled":false,"gatewayName":"ingressgateway"},"localityLbSetting":{"enabled":true},"logging":{"level":"default:info"},"meshExpansion":{"enabled":false,"useILB":false},"meshID":"","meshNetworks":{},"monitoringPort":15014,"mtls":{"enabled":false},"multiCluster":{"clusterName":"","enabled":false},"oneNamespace":false,"outboundTrafficPolicy":{"mode":"ALLOW_ANY"},"policyCheckFailOpen":false,"priorityClassName":"","proxy":{"accessLogEncoding":"TEXT","accessLogFile":"/dev/stdout","accessLogFormat":"","autoInject":"enabled","clusterDomain":"cluster.local","componentLogLevel":"","concurrency":2,"dnsRefreshRate":"300s","enableCoreDump":false,"enableCoreDumpImage":"ubuntu:xenial","envoyAccessLogService":{"enabled":false,"host":null,"port":null,"tcpKeepalive":{"interval":"10s","probes":3,"time":"10s"},"tlsSettings":{"caCertificates":null,"clientCertificate":null,"mode":"DISABLE","privateKey":null,"sni":null,"subjectAltNames":[]}},"envoyMetricsService":{"enabled":false,"host":null,"port":null},"envoyStatsd":{"enabled":false,"host":null,"port":null},"excludeIPRanges":"","excludeInboundPorts":"","excludeOutboundPorts":"","image":"proxyv2","includeIPRanges":"*","includeInboundPorts":"*","init":{"resources":{"limits":{"cpu":"100m","memory":"50Mi"},"requests":{"cpu":"10m","memory":"10Mi"}}},"kubevirtInterfaces":"","logLevel":"","privileged":false,"protocolDetectionTimeout":"100ms","readinessFailureThreshold":30,"readinessInitialDelaySeconds":1,"readinessPeriodSeconds":2,"resources":{"limits":{"cpu":"2000m","memory":"1024Mi"},"requests":{"cpu":"10m","memory":"40Mi"}},"statusPort":15020,"tracer":"zipkin"},"proxy_init":{"image":"proxy_init"},"sds":{"enabled":false,"token":{"aud":"istio-ca"},"udsPath":""},"tag":"1.3.5","tracer":{"datadog":{"address":"$(HOST_IP):8126"},"lightstep":{"accessToken":"","address":"","cacertPath":"","secure":true},"zipkin":{"address":""}},"trustDomain":"","useMCP":true},"image":"citadel","nodeSelector":{},"podAntiAffinityLabelSelector":[],"podAntiAffinityTermLabelSelector":[],"replicaCount":1,"rollingMaxSurge":"100%","rollingMaxUnavailable":"25%","selfSigned":true,"tolerations":[],"workloadCertTtl":"2160h"},"sidecarInjectorWebhook":{"alwaysInjectSelector":[],"enableNamespacesByDefault":false,"enabled":true,"global":{"arch":{"amd64":2,"ppc64le":2,"s390x":2},"configValidation":true,"controlPlaneSecurityEnabled":false,"defaultNodeSelector":{},"defaultPodDisruptionBudget":{"enabled":true},"defaultResources":{"requests":{"cpu":"10m"}},"defaultTolerations":[],"disablePolicyChecks":false,"enableHelmTest":false,"enableTracing":true,"hub":"docker.io/istio","imagePullPolicy":"IfNotPresent","imagePullSecrets":[],"k8sIngress":{"enableHttps":false,"enabled":false,"gatewayName":"ingressgateway"},"localityLbSetting":{"enabled":true},"logging":{"level":"default:info"},"meshExpansion":{"enabled":false,"useILB":false},"meshID":"","meshNetworks":{},"monitoringPort":15014,"mtls":{"enabled":false},"multiCluster":{"clusterName":"","enabled":false},"oneNamespace":false,"outboundTrafficPolicy":{"mode":"ALLOW_ANY"},"policyCheckFailOpen":false,"priorityClassName":"","proxy":{"accessLogEncoding":"TEXT","accessLogFile":"/dev/stdout","accessLogFormat":"","autoInject":"enabled","clusterDomain":"cluster.local","componentLogLevel":"","concurrency":2,"dnsRefreshRate":"300s","enableCoreDump":false,"enableCoreDumpImage":"ubuntu:xenial","envoyAccessLogService":{"enabled":false,"host":null,"port":null,"tcpKeepalive":{"interval":"10s","probes":3,"time":"10s"},"tlsSettings":{"caCertificates":null,"clientCertificate":null,"mode":"DISABLE","privateKey":null,"sni":null,"subjectAltNames":[]}},"envoyMetricsService":{"enabled":false,"host":null,"port":null},"envoyStatsd":{"enabled":false,"host":null,"port":null},"excludeIPRanges":"","excludeInboundPorts":"","excludeOutboundPorts":"","image":"proxyv2","includeIPRanges":"*","includeInboundPorts":"*","init":{"resources":{"limits":{"cpu":"100m","memory":"50Mi"},"requests":{"cpu":"10m","memory":"10Mi"}}},"kubevirtInterfaces":"","logLevel":"","privileged":false,"protocolDetectionTimeout":"100ms","readinessFailureThreshold":30,"readinessInitialDelaySeconds":1,"readinessPeriodSeconds":2,"resources":{"limits":{"cpu":"2000m","memory":"1024Mi"},"requests":{"cpu":"10m","memory":"40Mi"}},"statusPort":15020,"tracer":"zipkin"},"proxy_init":{"image":"proxy_init"},"sds":{"enabled":false,"token":{"aud":"istio-ca"},"udsPath":""},"tag":"1.3.5","tracer":{"datadog":{"address":"$(HOST_IP):8126"},"lightstep":{"accessToken":"","address":"","cacertPath":"","secure":true},"zipkin":{"address":""}},"trustDomain":"","useMCP":true},"image":"sidecar_injector","neverInjectSelector":[],"nodeSelector":{},"podAntiAffinityLabelSelector":[],"podAntiAffinityTermLabelSelector":[],"replicaCount":1,"rewriteAppHTTPProbe":false,"rollingMaxSurge":"100%","rollingMaxUnavailable":"25%","tolerations":[]},"tracing":{"enabled":true,"global":{"arch":{"amd64":2,"ppc64le":2,"s390x":2},"configValidation":true,"controlPlaneSecurityEnabled":false,"defaultNodeSelector":{},"defaultPodDisruptionBudget":{"enabled":true},"defaultResources":{"requests":{"cpu":"10m"}},"defaultTolerations":[],"disablePolicyChecks":false,"enableHelmTest":false,"enableTracing":true,"hub":"docker.io/istio","imagePullPolicy":"IfNotPresent","imagePullSecrets":[],"k8sIngress":{"enableHttps":false,"enabled":false,"gatewayName":"ingressgateway"},"localityLbSetting":{"enabled":true},"logging":{"level":"default:info"},"meshExpansion":{"enabled":false,"useILB":false},"meshID":"","meshNetworks":{},"monitoringPort":15014,"mtls":{"enabled":false},"multiCluster":{"clusterName":"","enabled":false},"oneNamespace":false,"outboundTrafficPolicy":{"mode":"ALLOW_ANY"},"policyCheckFailOpen":false,"priorityClassName":"","proxy":{"accessLogEncoding":"TEXT","accessLogFile":"/dev/stdout","accessLogFormat":"","autoInject":"enabled","clusterDomain":"cluster.local","componentLogLevel":"","concurrency":2,"dnsRefreshRate":"300s","enableCoreDump":false,"enableCoreDumpImage":"ubuntu:xenial","envoyAccessLogService":{"enabled":false,"host":null,"port":null,"tcpKeepalive":{"interval":"10s","probes":3,"time":"10s"},"tlsSettings":{"caCertificates":null,"clientCertificate":null,"mode":"DISABLE","privateKey":null,"sni":null,"subjectAltNames":[]}},"envoyMetricsService":{"enabled":false,"host":null,"port":null},"envoyStatsd":{"enabled":false,"host":null,"port":null},"excludeIPRanges":"","excludeInboundPorts":"","excludeOutboundPorts":"","image":"proxyv2","includeIPRanges":"*","includeInboundPorts":"*","init":{"resources":{"limits":{"cpu":"100m","memory":"50Mi"},"requests":{"cpu":"10m","memory":"10Mi"}}},"kubevirtInterfaces":"","logLevel":"","privileged":false,"protocolDetectionTimeout":"100ms","readinessFailureThreshold":30,"readinessInitialDelaySeconds":1,"readinessPeriodSeconds":2,"resources":{"limits":{"cpu":"2000m","memory":"1024Mi"},"requests":{"cpu":"10m","memory":"40Mi"}},"statusPort":15020,"tracer":"zipkin"},"proxy_init":{"image":"proxy_init"},"sds":{"enabled":false,"token":{"aud":"istio-ca"},"udsPath":""},"tag":"1.3.5","tracer":{"datadog":{"address":"$(HOST_IP):8126"},"lightstep":{"accessToken":"","address":"","cacertPath":"","secure":true},"zipkin":{"address":""}},"trustDomain":"","useMCP":true},"ingress":{"annotations":null,"enabled":false,"hosts":null,"tls":null},"jaeger":{"accessMode":"ReadWriteMany","hub":"docker.io/jaegertracing","image":"all-in-one","memory":{"max_traces":50000},"persist":false,"spanStorageType":"badger","storageClassName":"","tag":1.14},"nodeSelector":{},"podAntiAffinityLabelSelector":[],"podAntiAffinityTermLabelSelector":[],"provider":"jaeger","service":{"annotations":{},"externalPort":9411,"name":"http","type":"ClusterIP"},"tolerations":[],"zipkin":{"hub":"docker.io/openzipkin","image":"zipkin","javaOptsHeap":700,"maxSpans":500000,"node":{"cpus":2},"probeStartupDelay":200,"queryPort":9411,"resources":{"limits":{"cpu":"300m","memory":"900Mi"},"requests":{"cpu":"150m","memory":"900Mi"}},"tag":"2.14.2"}}} + + config: |- + policy: enabled + alwaysInjectSelector: + [] + neverInjectSelector: + [] + template: |- + rewriteAppHTTPProbe: {{ valueOrDefault .Values.sidecarInjectorWebhook.rewriteAppHTTPProbe false }} + {{- if or (not .Values.istio_cni.enabled) .Values.global.proxy.enableCoreDump }} + initContainers: + {{ if ne (annotation .ObjectMeta `sidecar.istio.io/interceptionMode` .ProxyConfig.InterceptionMode) `NONE` }} + {{- if not .Values.istio_cni.enabled }} + - name: istio-init + {{- if contains "/" .Values.global.proxy_init.image }} + image: "{{ .Values.global.proxy_init.image }}" + {{- else }} + image: "{{ .Values.global.hub }}/{{ .Values.global.proxy_init.image }}:{{ .Values.global.tag }}" + {{- end }} + args: + - "-p" + - "15001" + - "-z" + - "15006" + - "-u" + - 1337 + - "-m" + - "{{ annotation .ObjectMeta `sidecar.istio.io/interceptionMode` .ProxyConfig.InterceptionMode }}" + - "-i" + - "{{ annotation .ObjectMeta `traffic.sidecar.istio.io/includeOutboundIPRanges` .Values.global.proxy.includeIPRanges }}" + - "-x" + - "{{ annotation .ObjectMeta `traffic.sidecar.istio.io/excludeOutboundIPRanges` .Values.global.proxy.excludeIPRanges }}" + - "-b" + - "{{ annotation .ObjectMeta `traffic.sidecar.istio.io/includeInboundPorts` `*` }}" + - "-d" + - "{{ excludeInboundPort (annotation .ObjectMeta `status.sidecar.istio.io/port` .Values.global.proxy.statusPort) (annotation .ObjectMeta `traffic.sidecar.istio.io/excludeInboundPorts` .Values.global.proxy.excludeInboundPorts) }}" + {{ if or (isset .ObjectMeta.Annotations `traffic.sidecar.istio.io/excludeOutboundPorts`) (ne .Values.global.proxy.excludeOutboundPorts "") -}} + - "-o" + - "{{ annotation .ObjectMeta `traffic.sidecar.istio.io/excludeOutboundPorts` .Values.global.proxy.excludeOutboundPorts }}" + {{ end -}} + {{ if (isset .ObjectMeta.Annotations `traffic.sidecar.istio.io/kubevirtInterfaces`) -}} + - "-k" + - "{{ index .ObjectMeta.Annotations `traffic.sidecar.istio.io/kubevirtInterfaces` }}" + {{ end -}} + imagePullPolicy: "{{ .Values.global.imagePullPolicy }}" + {{- if .Values.global.proxy.init.resources }} + resources: + {{ toYaml .Values.global.proxy.init.resources | indent 4 }} + {{- else }} + resources: {} + {{- end }} + securityContext: + runAsUser: 0 + runAsNonRoot: false + capabilities: + add: + - NET_ADMIN + {{- if .Values.global.proxy.privileged }} + privileged: true + {{- end }} + restartPolicy: Always + {{- end }} + {{ end -}} + {{- if eq .Values.global.proxy.enableCoreDump true }} + - name: enable-core-dump + args: + - -c + - sysctl -w kernel.core_pattern=/var/lib/istio/core.proxy && ulimit -c unlimited + command: + - /bin/sh + image: {{ $.Values.global.proxy.enableCoreDumpImage }} + imagePullPolicy: IfNotPresent + resources: {} + securityContext: + runAsUser: 0 + runAsNonRoot: false + privileged: true + {{ end }} + {{- end }} + containers: + - name: istio-proxy + {{- if contains "/" (annotation .ObjectMeta `sidecar.istio.io/proxyImage` .Values.global.proxy.image) }} + image: "{{ annotation .ObjectMeta `sidecar.istio.io/proxyImage` .Values.global.proxy.image }}" + {{- else }} + image: "{{ annotation .ObjectMeta `sidecar.istio.io/proxyImage` .Values.global.hub }}/{{ .Values.global.proxy.image }}:{{ .Values.global.tag }}" + {{- end }} + ports: + - containerPort: 15090 + protocol: TCP + name: http-envoy-prom + args: + - proxy + - sidecar + - --domain + - $(POD_NAMESPACE).svc.{{ .Values.global.proxy.clusterDomain }} + - --configPath + - "{{ .ProxyConfig.ConfigPath }}" + - --binaryPath + - "{{ .ProxyConfig.BinaryPath }}" + - --serviceCluster + {{ if ne "" (index .ObjectMeta.Labels "app") -}} + - "{{ index .ObjectMeta.Labels `app` }}.$(POD_NAMESPACE)" + {{ else -}} + - "{{ valueOrDefault .DeploymentMeta.Name `istio-proxy` }}.{{ valueOrDefault .DeploymentMeta.Namespace `default` }}" + {{ end -}} + - --drainDuration + - "{{ formatDuration .ProxyConfig.DrainDuration }}" + - --parentShutdownDuration + - "{{ formatDuration .ProxyConfig.ParentShutdownDuration }}" + - --discoveryAddress + - "{{ annotation .ObjectMeta `sidecar.istio.io/discoveryAddress` .ProxyConfig.DiscoveryAddress }}" + {{- if eq .Values.global.proxy.tracer "lightstep" }} + - --lightstepAddress + - "{{ .ProxyConfig.GetTracing.GetLightstep.GetAddress }}" + - --lightstepAccessToken + - "{{ .ProxyConfig.GetTracing.GetLightstep.GetAccessToken }}" + - --lightstepSecure={{ .ProxyConfig.GetTracing.GetLightstep.GetSecure }} + - --lightstepCacertPath + - "{{ .ProxyConfig.GetTracing.GetLightstep.GetCacertPath }}" + {{- else if eq .Values.global.proxy.tracer "zipkin" }} + - --zipkinAddress + - "{{ .ProxyConfig.GetTracing.GetZipkin.GetAddress }}" + {{- else if eq .Values.global.proxy.tracer "datadog" }} + - --datadogAgentAddress + - "{{ .ProxyConfig.GetTracing.GetDatadog.GetAddress }}" + {{- end }} + {{- if .Values.global.proxy.logLevel }} + - --proxyLogLevel={{ .Values.global.proxy.logLevel }} + {{- end}} + {{- if .Values.global.proxy.componentLogLevel }} + - --proxyComponentLogLevel={{ .Values.global.proxy.componentLogLevel }} + {{- end}} + - --dnsRefreshRate + - {{ .Values.global.proxy.dnsRefreshRate }} + - --connectTimeout + - "{{ formatDuration .ProxyConfig.ConnectTimeout }}" + {{- if .Values.global.proxy.envoyStatsd.enabled }} + - --statsdUdpAddress + - "{{ .ProxyConfig.StatsdUdpAddress }}" + {{- end }} + {{- if .Values.global.proxy.envoyMetricsService.enabled }} + - --envoyMetricsServiceAddress + - "{{ .ProxyConfig.GetEnvoyMetricsService.GetAddress }}" + {{- end }} + {{- if .Values.global.proxy.envoyAccessLogService.enabled }} + - --envoyAccessLogService + - '{{ structToJSON .ProxyConfig.EnvoyAccessLogService }}' + {{- end }} + - --proxyAdminPort + - "{{ .ProxyConfig.ProxyAdminPort }}" + {{ if gt .ProxyConfig.Concurrency 0 -}} + - --concurrency + - "{{ .ProxyConfig.Concurrency }}" + {{ end -}} + - --controlPlaneAuthPolicy + - "{{ annotation .ObjectMeta `sidecar.istio.io/controlPlaneAuthPolicy` .ProxyConfig.ControlPlaneAuthPolicy }}" + {{- if (ne (annotation .ObjectMeta "status.sidecar.istio.io/port" .Values.global.proxy.statusPort) "0") }} + - --statusPort + - "{{ annotation .ObjectMeta `status.sidecar.istio.io/port` .Values.global.proxy.statusPort }}" + - --applicationPorts + - "{{ annotation .ObjectMeta `readiness.status.sidecar.istio.io/applicationPorts` (applicationPorts .Spec.Containers) }}" + {{- end }} + {{- if .Values.global.trustDomain }} + - --trust-domain={{ .Values.global.trustDomain }} + {{- end }} + env: + - name: POD_NAME + valueFrom: + fieldRef: + fieldPath: metadata.name + - name: ISTIO_META_POD_PORTS + value: |- + [ + {{- range $index1, $c := .Spec.Containers }} + {{- range $index2, $p := $c.Ports }} + {{if or (ne $index1 0) (ne $index2 0)}},{{end}}{{ structToJSON $p }} + {{- end}} + {{- end}} + ] + - name: ISTIO_META_CLUSTER_ID + value: "{{ valueOrDefault .Values.global.multicluster.clusterName `Kubernetes` }}" + - name: POD_NAMESPACE + valueFrom: + fieldRef: + fieldPath: metadata.namespace + - name: INSTANCE_IP + valueFrom: + fieldRef: + fieldPath: status.podIP + - name: SERVICE_ACCOUNT + valueFrom: + fieldRef: + fieldPath: spec.serviceAccountName + {{- if eq .Values.global.proxy.tracer "datadog" }} + - name: HOST_IP + valueFrom: + fieldRef: + fieldPath: status.hostIP + {{- if isset .ObjectMeta.Annotations `apm.datadoghq.com/env` }} + {{- range $key, $value := fromJSON (index .ObjectMeta.Annotations `apm.datadoghq.com/env`) }} + - name: {{ $key }} + value: "{{ $value }}" + {{- end }} + {{- end }} + {{- end }} + - name: ISTIO_META_POD_NAME + valueFrom: + fieldRef: + fieldPath: metadata.name + - name: ISTIO_META_CONFIG_NAMESPACE + valueFrom: + fieldRef: + fieldPath: metadata.namespace + - name: SDS_ENABLED + value: {{ $.Values.global.sds.enabled }} + - name: ISTIO_META_INTERCEPTION_MODE + value: "{{ or (index .ObjectMeta.Annotations `sidecar.istio.io/interceptionMode`) .ProxyConfig.InterceptionMode.String }}" + - name: ISTIO_META_INCLUDE_INBOUND_PORTS + value: "{{ annotation .ObjectMeta `traffic.sidecar.istio.io/includeInboundPorts` (applicationPorts .Spec.Containers) }}" + {{- if .Values.global.network }} + - name: ISTIO_META_NETWORK + value: "{{ .Values.global.network }}" + {{- end }} + {{ if .ObjectMeta.Annotations }} + - name: ISTIO_METAJSON_ANNOTATIONS + value: | + {{ toJSON .ObjectMeta.Annotations }} + {{ end }} + {{ if .ObjectMeta.Labels }} + - name: ISTIO_METAJSON_LABELS + value: | + {{ toJSON .ObjectMeta.Labels }} + {{ end }} + {{- if .DeploymentMeta.Name }} + - name: ISTIO_META_WORKLOAD_NAME + value: {{ .DeploymentMeta.Name }} + {{ end }} + {{- if and .TypeMeta.APIVersion .DeploymentMeta.Name }} + - name: ISTIO_META_OWNER + value: kubernetes://api/{{ .TypeMeta.APIVersion }}/namespaces/{{ valueOrDefault .DeploymentMeta.Namespace `default` }}/{{ toLower .TypeMeta.Kind}}s/{{ .DeploymentMeta.Name }} + {{- end}} + {{- if (isset .ObjectMeta.Annotations `sidecar.istio.io/bootstrapOverride`) }} + - name: ISTIO_BOOTSTRAP_OVERRIDE + value: "/etc/istio/custom-bootstrap/custom_bootstrap.json" + {{- end }} + {{- if .Values.global.sds.customTokenDirectory }} + - name: ISTIO_META_SDS_TOKEN_PATH + value: "{{ .Values.global.sds.customTokenDirectory -}}/sdstoken" + {{- end }} + {{- if .Values.global.meshID }} + - name: ISTIO_META_MESH_ID + value: "{{ .Values.global.meshID }}" + {{- else if .Values.global.trustDomain }} + - name: ISTIO_META_MESH_ID + value: "{{ .Values.global.trustDomain }}" + {{- end }} + imagePullPolicy: {{ .Values.global.imagePullPolicy }} + {{ if ne (annotation .ObjectMeta `status.sidecar.istio.io/port` .Values.global.proxy.statusPort) `0` }} + readinessProbe: + httpGet: + path: /healthz/ready + port: {{ annotation .ObjectMeta `status.sidecar.istio.io/port` .Values.global.proxy.statusPort }} + initialDelaySeconds: {{ annotation .ObjectMeta `readiness.status.sidecar.istio.io/initialDelaySeconds` .Values.global.proxy.readinessInitialDelaySeconds }} + periodSeconds: {{ annotation .ObjectMeta `readiness.status.sidecar.istio.io/periodSeconds` .Values.global.proxy.readinessPeriodSeconds }} + failureThreshold: {{ annotation .ObjectMeta `readiness.status.sidecar.istio.io/failureThreshold` .Values.global.proxy.readinessFailureThreshold }} + {{ end -}} + securityContext: + {{- if .Values.global.proxy.privileged }} + privileged: true + {{- end }} + {{- if ne .Values.global.proxy.enableCoreDump true }} + readOnlyRootFilesystem: true + {{- end }} + {{ if eq (annotation .ObjectMeta `sidecar.istio.io/interceptionMode` .ProxyConfig.InterceptionMode) `TPROXY` -}} + capabilities: + add: + - NET_ADMIN + runAsGroup: 1337 + {{ else -}} + {{ if .Values.global.sds.enabled }} + runAsGroup: 1337 + {{- end }} + runAsUser: 1337 + {{- end }} + resources: + {{ if or (isset .ObjectMeta.Annotations `sidecar.istio.io/proxyCPU`) (isset .ObjectMeta.Annotations `sidecar.istio.io/proxyMemory`) -}} + requests: + {{ if (isset .ObjectMeta.Annotations `sidecar.istio.io/proxyCPU`) -}} + cpu: "{{ index .ObjectMeta.Annotations `sidecar.istio.io/proxyCPU` }}" + {{ end}} + {{ if (isset .ObjectMeta.Annotations `sidecar.istio.io/proxyMemory`) -}} + memory: "{{ index .ObjectMeta.Annotations `sidecar.istio.io/proxyMemory` }}" + {{ end }} + {{ else -}} + {{- if .Values.global.proxy.resources }} + {{ toYaml .Values.global.proxy.resources | indent 4 }} + {{- end }} + {{ end -}} + volumeMounts: + {{ if (isset .ObjectMeta.Annotations `sidecar.istio.io/bootstrapOverride`) }} + - mountPath: /etc/istio/custom-bootstrap + name: custom-bootstrap-volume + {{- end }} + - mountPath: /etc/istio/proxy + name: istio-envoy + {{- if .Values.global.sds.enabled }} + - mountPath: /var/run/sds + name: sds-uds-path + readOnly: true + - mountPath: /var/run/secrets/tokens + name: istio-token + {{- if .Values.global.sds.customTokenDirectory }} + - mountPath: "{{ .Values.global.sds.customTokenDirectory -}}" + name: custom-sds-token + readOnly: true + {{- end }} + {{- else }} + - mountPath: /etc/certs/ + name: istio-certs + readOnly: true + {{- end }} + {{- if and (eq .Values.global.proxy.tracer "lightstep") .Values.global.tracer.lightstep.cacertPath }} + - mountPath: {{ directory .ProxyConfig.GetTracing.GetLightstep.GetCacertPath }} + name: lightstep-certs + readOnly: true + {{- end }} + {{- if isset .ObjectMeta.Annotations `sidecar.istio.io/userVolumeMount` }} + {{ range $index, $value := fromJSON (index .ObjectMeta.Annotations `sidecar.istio.io/userVolumeMount`) }} + - name: "{{ $index }}" + {{ toYaml $value | indent 4 }} + {{ end }} + {{- end }} + volumes: + {{- if (isset .ObjectMeta.Annotations `sidecar.istio.io/bootstrapOverride`) }} + - name: custom-bootstrap-volume + configMap: + name: {{ annotation .ObjectMeta `sidecar.istio.io/bootstrapOverride` "" }} + {{- end }} + - emptyDir: + medium: Memory + name: istio-envoy + {{- if .Values.global.sds.enabled }} + - name: sds-uds-path + hostPath: + path: /var/run/sds + - name: istio-token + projected: + sources: + - serviceAccountToken: + path: istio-token + expirationSeconds: 43200 + audience: {{ .Values.global.sds.token.aud }} + {{- if .Values.global.sds.customTokenDirectory }} + - name: custom-sds-token + secret: + secretName: sdstokensecret + {{- end }} + {{- else }} + - name: istio-certs + secret: + optional: true + {{ if eq .Spec.ServiceAccountName "" }} + secretName: istio.default + {{ else -}} + secretName: {{ printf "istio.%s" .Spec.ServiceAccountName }} + {{ end -}} + {{- if isset .ObjectMeta.Annotations `sidecar.istio.io/userVolume` }} + {{range $index, $value := fromJSON (index .ObjectMeta.Annotations `sidecar.istio.io/userVolume`) }} + - name: "{{ $index }}" + {{ toYaml $value | indent 2 }} + {{ end }} + {{ end }} + {{- end }} + {{- if and (eq .Values.global.proxy.tracer "lightstep") .Values.global.tracer.lightstep.cacertPath }} + - name: lightstep-certs + secret: + optional: true + secretName: lightstep.cacert + {{- end }} + {{- if .Values.global.podDNSSearchNamespaces }} + dnsConfig: + searches: + {{- range .Values.global.podDNSSearchNamespaces }} + - {{ render . }} + {{- end }} + {{- end }} + podRedirectAnnot: + sidecar.istio.io/interceptionMode: "{{ annotation .ObjectMeta `sidecar.istio.io/interceptionMode` .ProxyConfig.InterceptionMode }}" + traffic.sidecar.istio.io/includeOutboundIPRanges: "{{ annotation .ObjectMeta `traffic.sidecar.istio.io/includeOutboundIPRanges` .Values.global.proxy.includeIPRanges }}" + traffic.sidecar.istio.io/excludeOutboundIPRanges: "{{ annotation .ObjectMeta `traffic.sidecar.istio.io/excludeOutboundIPRanges` .Values.global.proxy.excludeIPRanges }}" + traffic.sidecar.istio.io/includeInboundPorts: "{{ annotation .ObjectMeta `traffic.sidecar.istio.io/includeInboundPorts` (includeInboundPorts .Spec.Containers) }}" + traffic.sidecar.istio.io/excludeInboundPorts: "{{ excludeInboundPort (annotation .ObjectMeta `status.sidecar.istio.io/port` .Values.global.proxy.statusPort) (annotation .ObjectMeta `traffic.sidecar.istio.io/excludeInboundPorts` .Values.global.proxy.excludeInboundPorts) }}" + {{ if or (isset .ObjectMeta.Annotations `traffic.sidecar.istio.io/excludeOutboundPorts`) (ne .Values.global.proxy.excludeOutboundPorts "") }} + traffic.sidecar.istio.io/excludeOutboundPorts: "{{ annotation .ObjectMeta `traffic.sidecar.istio.io/excludeOutboundPorts` .Values.global.proxy.excludeOutboundPorts }}" + {{- end }} + traffic.sidecar.istio.io/kubevirtInterfaces: "{{ index .ObjectMeta.Annotations `traffic.sidecar.istio.io/kubevirtInterfaces` }}" + +--- +# Source: istio/charts/galley/templates/serviceaccount.yaml +apiVersion: v1 +kind: ServiceAccount +metadata: + name: istio-galley-service-account + namespace: istio-system + labels: + app: galley + chart: galley + heritage: Tiller + release: istio + +--- +# Source: istio/charts/gateways/templates/serviceaccount.yaml + +apiVersion: v1 +kind: ServiceAccount +metadata: + name: istio-egressgateway-service-account + namespace: istio-system + labels: + app: istio-egressgateway + chart: gateways + heritage: Tiller + release: istio +--- +apiVersion: v1 +kind: ServiceAccount +metadata: + name: istio-ingressgateway-service-account + namespace: istio-system + labels: + app: istio-ingressgateway + chart: gateways + heritage: Tiller + release: istio +--- + + +--- +# Source: istio/charts/grafana/templates/create-custom-resources-job.yaml +apiVersion: v1 +kind: ServiceAccount +metadata: + name: istio-grafana-post-install-account + namespace: istio-system + labels: + app: grafana + chart: grafana + heritage: Tiller + release: istio +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: istio-grafana-post-install-istio-system + labels: + app: grafana + chart: grafana + heritage: Tiller + release: istio +rules: +- apiGroups: ["authentication.istio.io"] # needed to create default authn policy + resources: ["*"] + verbs: ["*"] +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: istio-grafana-post-install-role-binding-istio-system + labels: + app: grafana + chart: grafana + heritage: Tiller + release: istio +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: istio-grafana-post-install-istio-system +subjects: + - kind: ServiceAccount + name: istio-grafana-post-install-account + namespace: istio-system +--- +apiVersion: batch/v1 +kind: Job +metadata: + name: istio-grafana-post-install-1.3.5 + namespace: istio-system + annotations: + "helm.sh/hook": post-install + "helm.sh/hook-delete-policy": hook-succeeded + labels: + app: grafana + chart: grafana + heritage: Tiller + release: istio +spec: + template: + metadata: + name: istio-grafana-post-install + labels: + app: istio-grafana + chart: grafana + heritage: Tiller + release: istio + spec: + serviceAccountName: istio-grafana-post-install-account + containers: + - name: kubectl + image: "docker.io/istio/kubectl:1.3.5" + command: [ "/bin/bash", "/tmp/grafana/run.sh", "/tmp/grafana/custom-resources.yaml" ] + volumeMounts: + - mountPath: "/tmp/grafana" + name: tmp-configmap-grafana + volumes: + - name: tmp-configmap-grafana + configMap: + name: istio-grafana-custom-resources + restartPolicy: OnFailure + affinity: + nodeAffinity: + requiredDuringSchedulingIgnoredDuringExecution: + nodeSelectorTerms: + - matchExpressions: + - key: beta.kubernetes.io/arch + operator: In + values: + - "amd64" + - "ppc64le" + - "s390x" + preferredDuringSchedulingIgnoredDuringExecution: + - weight: 2 + preference: + matchExpressions: + - key: beta.kubernetes.io/arch + operator: In + values: + - "amd64" + - weight: 2 + preference: + matchExpressions: + - key: beta.kubernetes.io/arch + operator: In + values: + - "ppc64le" + - weight: 2 + preference: + matchExpressions: + - key: beta.kubernetes.io/arch + operator: In + values: + - "s390x" + +--- +# Source: istio/charts/kiali/templates/serviceaccount.yaml +apiVersion: v1 +kind: ServiceAccount +metadata: + name: kiali-service-account + namespace: istio-system + labels: + app: kiali + chart: kiali + heritage: Tiller + release: istio + +--- +# Source: istio/charts/mixer/templates/serviceaccount.yaml + +apiVersion: v1 +kind: ServiceAccount +metadata: + name: istio-mixer-service-account + namespace: istio-system + labels: + app: mixer + chart: mixer + heritage: Tiller + release: istio + +--- +# Source: istio/charts/pilot/templates/serviceaccount.yaml +apiVersion: v1 +kind: ServiceAccount +metadata: + name: istio-pilot-service-account + namespace: istio-system + labels: + app: pilot + chart: pilot + heritage: Tiller + release: istio + +--- +# Source: istio/charts/prometheus/templates/serviceaccount.yaml +apiVersion: v1 +kind: ServiceAccount +metadata: + name: prometheus + namespace: istio-system + labels: + app: prometheus + chart: prometheus + heritage: Tiller + release: istio + +--- +# Source: istio/charts/security/templates/create-custom-resources-job.yaml + +apiVersion: v1 +kind: ServiceAccount +metadata: + name: istio-security-post-install-account + namespace: istio-system + labels: + app: security + chart: security + heritage: Tiller + release: istio +--- +apiVersion: rbac.authorization.k8s.io/v1beta1 +kind: ClusterRole +metadata: + name: istio-security-post-install-istio-system + labels: + app: security + chart: security + heritage: Tiller + release: istio +rules: +- apiGroups: ["authentication.istio.io"] # needed to create default authn policy + resources: ["*"] + verbs: ["*"] +- apiGroups: ["networking.istio.io"] # needed to create security destination rules + resources: ["*"] + verbs: ["*"] +- apiGroups: ["admissionregistration.k8s.io"] + resources: ["validatingwebhookconfigurations"] + verbs: ["get"] +- apiGroups: ["extensions", "apps"] + resources: ["deployments", "replicasets"] + verbs: ["get", "list", "watch"] +--- +apiVersion: rbac.authorization.k8s.io/v1beta1 +kind: ClusterRoleBinding +metadata: + name: istio-security-post-install-role-binding-istio-system + labels: + app: security + chart: security + heritage: Tiller + release: istio +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: istio-security-post-install-istio-system +subjects: + - kind: ServiceAccount + name: istio-security-post-install-account + namespace: istio-system +--- +apiVersion: batch/v1 +kind: Job +metadata: + name: istio-security-post-install-1.3.5 + namespace: istio-system + annotations: + "helm.sh/hook": post-install,post-upgrade + "helm.sh/hook-delete-policy": hook-succeeded + labels: + app: security + chart: security + heritage: Tiller + release: istio +spec: + template: + metadata: + name: istio-security-post-install + labels: + app: security + chart: security + heritage: Tiller + release: istio + spec: + serviceAccountName: istio-security-post-install-account + containers: + - name: kubectl + image: "docker.io/istio/kubectl:1.3.5" + imagePullPolicy: IfNotPresent + command: [ "/bin/bash", "/tmp/security/run.sh", "/tmp/security/custom-resources.yaml" ] + volumeMounts: + - mountPath: "/tmp/security" + name: tmp-configmap-security + volumes: + - name: tmp-configmap-security + configMap: + name: istio-security-custom-resources + restartPolicy: OnFailure + affinity: + nodeAffinity: + requiredDuringSchedulingIgnoredDuringExecution: + nodeSelectorTerms: + - matchExpressions: + - key: beta.kubernetes.io/arch + operator: In + values: + - "amd64" + - "ppc64le" + - "s390x" + preferredDuringSchedulingIgnoredDuringExecution: + - weight: 2 + preference: + matchExpressions: + - key: beta.kubernetes.io/arch + operator: In + values: + - "amd64" + - weight: 2 + preference: + matchExpressions: + - key: beta.kubernetes.io/arch + operator: In + values: + - "ppc64le" + - weight: 2 + preference: + matchExpressions: + - key: beta.kubernetes.io/arch + operator: In + values: + - "s390x" + +--- +# Source: istio/charts/security/templates/serviceaccount.yaml +apiVersion: v1 +kind: ServiceAccount +metadata: + name: istio-citadel-service-account + namespace: istio-system + labels: + app: security + chart: security + heritage: Tiller + release: istio + +--- +# Source: istio/charts/sidecarInjectorWebhook/templates/serviceaccount.yaml +apiVersion: v1 +kind: ServiceAccount +metadata: + name: istio-sidecar-injector-service-account + namespace: istio-system + labels: + app: sidecarInjectorWebhook + chart: sidecarInjectorWebhook + heritage: Tiller + release: istio + istio: sidecar-injector + +--- +# Source: istio/templates/serviceaccount.yaml +apiVersion: v1 +kind: ServiceAccount +metadata: + name: istio-multi + namespace: istio-system + +--- +# Source: istio/charts/galley/templates/clusterrole.yaml +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: istio-galley-istio-system + labels: + app: galley + chart: galley + heritage: Tiller + release: istio +rules: +- apiGroups: ["admissionregistration.k8s.io"] + resources: ["validatingwebhookconfigurations"] + verbs: ["*"] +- apiGroups: ["config.istio.io"] # istio mixer CRD watcher + resources: ["*"] + verbs: ["get", "list", "watch"] +- apiGroups: ["networking.istio.io"] + resources: ["*"] + verbs: ["get", "list", "watch"] +- apiGroups: ["authentication.istio.io"] + resources: ["*"] + verbs: ["get", "list", "watch"] +- apiGroups: ["rbac.istio.io"] + resources: ["*"] + verbs: ["get", "list", "watch"] +- apiGroups: ["extensions","apps"] + resources: ["deployments"] + resourceNames: ["istio-galley"] + verbs: ["get"] +- apiGroups: [""] + resources: ["pods", "nodes", "services", "endpoints", "namespaces"] + verbs: ["get", "list", "watch"] +- apiGroups: ["extensions"] + resources: ["ingresses"] + verbs: ["get", "list", "watch"] +- apiGroups: ["extensions"] + resources: ["deployments/finalizers"] + resourceNames: ["istio-galley"] + verbs: ["update"] +- apiGroups: ["apiextensions.k8s.io"] + resources: ["customresourcedefinitions"] + verbs: ["get", "list", "watch"] + +--- +# Source: istio/charts/kiali/templates/clusterrole.yaml +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: kiali + labels: + app: kiali + chart: kiali + heritage: Tiller + release: istio +rules: +- apiGroups: [""] + resources: + - configmaps + - endpoints + - namespaces + - nodes + - pods + - pods/log + - replicationcontrollers + - services + verbs: + - get + - list + - watch +- apiGroups: ["extensions", "apps"] + resources: + - deployments + - replicasets + - statefulsets + verbs: + - get + - list + - watch +- apiGroups: ["autoscaling"] + resources: + - horizontalpodautoscalers + verbs: + - get + - list + - watch +- apiGroups: ["batch"] + resources: + - cronjobs + - jobs + verbs: + - get + - list + - watch +- apiGroups: ["config.istio.io"] + resources: + - adapters + - apikeys + - bypasses + - authorizations + - checknothings + - circonuses + - cloudwatches + - deniers + - dogstatsds + - edges + - fluentds + - handlers + - instances + - kubernetesenvs + - kuberneteses + - listcheckers + - listentries + - logentries + - memquotas + - metrics + - noops + - opas + - prometheuses + - quotas + - quotaspecbindings + - quotaspecs + - rbacs + - redisquotas + - reportnothings + - rules + - signalfxs + - solarwindses + - stackdrivers + - statsds + - stdios + - templates + - tracespans + - zipkins + verbs: + - create + - delete + - get + - list + - patch + - watch +- apiGroups: ["networking.istio.io"] + resources: + - destinationrules + - gateways + - serviceentries + - sidecars + - virtualservices + verbs: + - create + - delete + - get + - list + - patch + - watch +- apiGroups: ["authentication.istio.io"] + resources: + - meshpolicies + - policies + verbs: + - create + - delete + - get + - list + - patch + - watch +- apiGroups: ["rbac.istio.io"] + resources: + - clusterrbacconfigs + - rbacconfigs + - servicerolebindings + - serviceroles + verbs: + - create + - delete + - get + - list + - patch + - watch +- apiGroups: ["monitoring.kiali.io"] + resources: + - monitoringdashboards + verbs: + - get + - list +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: kiali-viewer + labels: + app: kiali + chart: kiali + heritage: Tiller + release: istio +rules: +- apiGroups: [""] + resources: + - configmaps + - endpoints + - namespaces + - nodes + - pods + - pods/log + - replicationcontrollers + - services + verbs: + - get + - list + - watch +- apiGroups: ["extensions", "apps"] + resources: + - deployments + - replicasets + - statefulsets + verbs: + - get + - list + - watch +- apiGroups: ["autoscaling"] + resources: + - horizontalpodautoscalers + verbs: + - get + - list + - watch +- apiGroups: ["batch"] + resources: + - cronjobs + - jobs + verbs: + - get + - list + - watch +- apiGroups: ["config.istio.io"] + resources: + - adapters + - apikeys + - bypasses + - authorizations + - checknothings + - circonuses + - cloudwatches + - deniers + - dogstatsds + - edges + - fluentds + - handlers + - instances + - kubernetesenvs + - kuberneteses + - listcheckers + - listentries + - logentries + - memquotas + - metrics + - noops + - opas + - prometheuses + - quotas + - quotaspecbindings + - quotaspecs + - rbacs + - redisquotas + - reportnothings + - rules + - signalfxs + - solarwindses + - stackdrivers + - statsds + - stdios + - templates + - tracespans + - zipkins + verbs: + - get + - list + - watch +- apiGroups: ["networking.istio.io"] + resources: + - destinationrules + - gateways + - serviceentries + - sidecars + - virtualservices + verbs: + - get + - list + - watch +- apiGroups: ["authentication.istio.io"] + resources: + - meshpolicies + - policies + verbs: + - get + - list + - watch +- apiGroups: ["rbac.istio.io"] + resources: + - clusterrbacconfigs + - rbacconfigs + - servicerolebindings + - serviceroles + verbs: + - get + - list + - watch +- apiGroups: ["monitoring.kiali.io"] + resources: + - monitoringdashboards + verbs: + - get + - list + +--- +# Source: istio/charts/mixer/templates/clusterrole.yaml + +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: istio-mixer-istio-system + labels: + app: mixer + chart: mixer + heritage: Tiller + release: istio +rules: +- apiGroups: ["config.istio.io"] # istio CRD watcher + resources: ["*"] + verbs: ["create", "get", "list", "watch", "patch"] +- apiGroups: ["apiextensions.k8s.io"] + resources: ["customresourcedefinitions"] + verbs: ["get", "list", "watch"] +- apiGroups: [""] + resources: ["configmaps", "endpoints", "pods", "services", "namespaces", "secrets", "replicationcontrollers"] + verbs: ["get", "list", "watch"] +- apiGroups: ["extensions", "apps"] + resources: ["replicasets"] + verbs: ["get", "list", "watch"] + +--- +# Source: istio/charts/pilot/templates/clusterrole.yaml +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: istio-pilot-istio-system + labels: + app: pilot + chart: pilot + heritage: Tiller + release: istio +rules: +- apiGroups: ["config.istio.io"] + resources: ["*"] + verbs: ["*"] +- apiGroups: ["rbac.istio.io"] + resources: ["*"] + verbs: ["get", "watch", "list"] +- apiGroups: ["networking.istio.io"] + resources: ["*"] + verbs: ["*"] +- apiGroups: ["authentication.istio.io"] + resources: ["*"] + verbs: ["*"] +- apiGroups: ["apiextensions.k8s.io"] + resources: ["customresourcedefinitions"] + verbs: ["*"] +- apiGroups: ["extensions"] + resources: ["ingresses", "ingresses/status"] + verbs: ["*"] +- apiGroups: [""] + resources: ["configmaps"] + verbs: ["create", "get", "list", "watch", "update"] +- apiGroups: [""] + resources: ["endpoints", "pods", "services", "namespaces", "nodes", "secrets"] + verbs: ["get", "list", "watch"] + +--- +# Source: istio/charts/prometheus/templates/clusterrole.yaml +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: prometheus-istio-system + labels: + app: prometheus + chart: prometheus + heritage: Tiller + release: istio +rules: +- apiGroups: [""] + resources: + - nodes + - services + - endpoints + - pods + - nodes/proxy + verbs: ["get", "list", "watch"] +- apiGroups: [""] + resources: + - configmaps + verbs: ["get"] +- nonResourceURLs: ["/metrics"] + verbs: ["get"] + +--- +# Source: istio/charts/security/templates/clusterrole.yaml +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: istio-citadel-istio-system + labels: + app: security + chart: security + heritage: Tiller + release: istio +rules: +- apiGroups: [""] + resources: ["configmaps"] + verbs: ["create", "get", "update"] +- apiGroups: [""] + resources: ["secrets"] + verbs: ["create", "get", "watch", "list", "update", "delete"] +- apiGroups: [""] + resources: ["serviceaccounts", "services", "namespaces"] + verbs: ["get", "watch", "list"] +- apiGroups: ["authentication.k8s.io"] + resources: ["tokenreviews"] + verbs: ["create"] + +--- +# Source: istio/charts/sidecarInjectorWebhook/templates/clusterrole.yaml +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: istio-sidecar-injector-istio-system + labels: + app: sidecarInjectorWebhook + chart: sidecarInjectorWebhook + heritage: Tiller + release: istio + istio: sidecar-injector +rules: +- apiGroups: [""] + resources: ["configmaps"] + verbs: ["get", "list", "watch"] +- apiGroups: ["admissionregistration.k8s.io"] + resources: ["mutatingwebhookconfigurations"] + verbs: ["get", "list", "watch", "patch"] + +--- +# Source: istio/templates/clusterrole.yaml +kind: ClusterRole +apiVersion: rbac.authorization.k8s.io/v1 +metadata: + name: istio-reader +rules: + - apiGroups: [''] + resources: ['nodes', 'pods', 'services', 'endpoints', "replicationcontrollers"] + verbs: ['get', 'watch', 'list'] + - apiGroups: ["extensions", "apps"] + resources: ["replicasets"] + verbs: ["get", "list", "watch"] + +--- +# Source: istio/charts/galley/templates/clusterrolebinding.yaml +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: istio-galley-admin-role-binding-istio-system + labels: + app: galley + chart: galley + heritage: Tiller + release: istio +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: istio-galley-istio-system +subjects: + - kind: ServiceAccount + name: istio-galley-service-account + namespace: istio-system + +--- +# Source: istio/charts/kiali/templates/clusterrolebinding.yaml + +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: istio-kiali-admin-role-binding-istio-system + labels: + app: kiali + chart: kiali + heritage: Tiller + release: istio +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: kiali +subjects: +- kind: ServiceAccount + name: kiali-service-account + namespace: istio-system + +--- +# Source: istio/charts/mixer/templates/clusterrolebinding.yaml + +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: istio-mixer-admin-role-binding-istio-system + labels: + app: mixer + chart: mixer + heritage: Tiller + release: istio +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: istio-mixer-istio-system +subjects: + - kind: ServiceAccount + name: istio-mixer-service-account + namespace: istio-system + +--- +# Source: istio/charts/pilot/templates/clusterrolebinding.yaml +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: istio-pilot-istio-system + labels: + app: pilot + chart: pilot + heritage: Tiller + release: istio +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: istio-pilot-istio-system +subjects: + - kind: ServiceAccount + name: istio-pilot-service-account + namespace: istio-system + +--- +# Source: istio/charts/prometheus/templates/clusterrolebindings.yaml +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: prometheus-istio-system + labels: + app: prometheus + chart: prometheus + heritage: Tiller + release: istio +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: prometheus-istio-system +subjects: +- kind: ServiceAccount + name: prometheus + namespace: istio-system + +--- +# Source: istio/charts/security/templates/clusterrolebinding.yaml +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: istio-citadel-istio-system + labels: + app: security + chart: security + heritage: Tiller + release: istio +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: istio-citadel-istio-system +subjects: + - kind: ServiceAccount + name: istio-citadel-service-account + namespace: istio-system + +--- +# Source: istio/charts/sidecarInjectorWebhook/templates/clusterrolebinding.yaml +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: istio-sidecar-injector-admin-role-binding-istio-system + labels: + app: sidecarInjectorWebhook + chart: sidecarInjectorWebhook + heritage: Tiller + release: istio + istio: sidecar-injector +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: istio-sidecar-injector-istio-system +subjects: + - kind: ServiceAccount + name: istio-sidecar-injector-service-account + namespace: istio-system + +--- +# Source: istio/templates/clusterrolebinding.yaml +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: istio-multi + labels: + chart: istio-1.1.0 +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: istio-reader +subjects: +- kind: ServiceAccount + name: istio-multi + namespace: istio-system + +--- +# Source: istio/charts/gateways/templates/role.yaml + +apiVersion: rbac.authorization.k8s.io/v1 +kind: Role +metadata: + name: istio-ingressgateway-sds + namespace: istio-system +rules: +- apiGroups: [""] + resources: ["secrets"] + verbs: ["get", "watch", "list"] +--- + +--- +# Source: istio/charts/gateways/templates/rolebindings.yaml + +apiVersion: rbac.authorization.k8s.io/v1 +kind: RoleBinding +metadata: + name: istio-ingressgateway-sds + namespace: istio-system +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: Role + name: istio-ingressgateway-sds +subjects: +- kind: ServiceAccount + name: istio-ingressgateway-service-account +--- + +--- +# Source: istio/charts/galley/templates/service.yaml +apiVersion: v1 +kind: Service +metadata: + name: istio-galley + namespace: istio-system + labels: + app: galley + chart: galley + heritage: Tiller + release: istio + istio: galley +spec: + ports: + - port: 443 + name: https-validation + - port: 15014 + name: http-monitoring + - port: 9901 + name: grpc-mcp + selector: + istio: galley + +--- +# Source: istio/charts/gateways/templates/service.yaml + +apiVersion: v1 +kind: Service +metadata: + name: istio-egressgateway + namespace: istio-system + annotations: + labels: + chart: gateways + heritage: Tiller + release: istio + app: istio-egressgateway + istio: egressgateway +spec: + type: ClusterIP + selector: + release: istio + app: istio-egressgateway + istio: egressgateway + ports: + - + name: http2 + port: 80 + - + name: https + port: 443 + - + name: tls + port: 15443 + targetPort: 15443 +--- +apiVersion: v1 +kind: Service +metadata: + name: istio-ingressgateway + namespace: istio-system + annotations: + labels: + chart: gateways + heritage: Tiller + release: istio + app: istio-ingressgateway + istio: ingressgateway +spec: + type: LoadBalancer + selector: + release: istio + app: istio-ingressgateway + istio: ingressgateway + ports: + - + name: status-port + port: 15020 + targetPort: 15020 + - + name: http2 + nodePort: 31380 + port: 80 + targetPort: 80 + - + name: https + nodePort: 31390 + port: 443 + - + name: tcp + nodePort: 31400 + port: 31400 + - + name: https-kiali + port: 15029 + targetPort: 15029 + - + name: https-prometheus + port: 15030 + targetPort: 15030 + - + name: https-grafana + port: 15031 + targetPort: 15031 + - + name: https-tracing + port: 15032 + targetPort: 15032 + - + name: tls + port: 15443 + targetPort: 15443 +--- + +--- +# Source: istio/charts/grafana/templates/service.yaml +apiVersion: v1 +kind: Service +metadata: + name: grafana + namespace: istio-system + annotations: + labels: + app: grafana + chart: grafana + heritage: Tiller + release: istio +spec: + type: ClusterIP + ports: + - port: 3000 + targetPort: 3000 + protocol: TCP + name: http + selector: + app: grafana + +--- +# Source: istio/charts/kiali/templates/service.yaml +apiVersion: v1 +kind: Service +metadata: + name: kiali + namespace: istio-system + labels: + app: kiali + chart: kiali + heritage: Tiller + release: istio +spec: + ports: + - name: http-kiali + protocol: TCP + port: 20001 + selector: + app: kiali + +--- +# Source: istio/charts/mixer/templates/service.yaml + +apiVersion: v1 +kind: Service +metadata: + name: istio-policy + namespace: istio-system + annotations: + networking.istio.io/exportTo: "*" + labels: + app: mixer + chart: mixer + heritage: Tiller + release: istio + istio: mixer +spec: + ports: + - name: grpc-mixer + port: 9091 + - name: grpc-mixer-mtls + port: 15004 + - name: http-monitoring + port: 15014 + selector: + istio: mixer + istio-mixer-type: policy +--- +apiVersion: v1 +kind: Service +metadata: + name: istio-telemetry + namespace: istio-system + annotations: + networking.istio.io/exportTo: "*" + labels: + app: mixer + chart: mixer + heritage: Tiller + release: istio + istio: mixer +spec: + ports: + - name: grpc-mixer + port: 9091 + - name: grpc-mixer-mtls + port: 15004 + - name: http-monitoring + port: 15014 + - name: prometheus + port: 42422 + selector: + istio: mixer + istio-mixer-type: telemetry +--- + + +--- +# Source: istio/charts/pilot/templates/service.yaml +apiVersion: v1 +kind: Service +metadata: + name: istio-pilot + namespace: istio-system + labels: + app: pilot + chart: pilot + heritage: Tiller + release: istio + istio: pilot +spec: + ports: + - port: 15010 + name: grpc-xds # direct + - port: 15011 + name: https-xds # mTLS + - port: 8080 + name: http-legacy-discovery # direct + - port: 15014 + name: http-monitoring + selector: + istio: pilot + +--- +# Source: istio/charts/prometheus/templates/service.yaml +apiVersion: v1 +kind: Service +metadata: + name: prometheus + namespace: istio-system + annotations: + prometheus.io/scrape: 'true' + labels: + app: prometheus + chart: prometheus + heritage: Tiller + release: istio +spec: + selector: + app: prometheus + ports: + - name: http-prometheus + protocol: TCP + port: 9090 + +--- +# Source: istio/charts/security/templates/service.yaml +apiVersion: v1 +kind: Service +metadata: + # we use the normal name here (e.g. 'prometheus') + # as grafana is configured to use this as a data source + name: istio-citadel + namespace: istio-system + labels: + app: security + chart: security + heritage: Tiller + release: istio + istio: citadel +spec: + ports: + - name: grpc-citadel + port: 8060 + targetPort: 8060 + protocol: TCP + - name: http-monitoring + port: 15014 + selector: + istio: citadel + +--- +# Source: istio/charts/sidecarInjectorWebhook/templates/service.yaml +apiVersion: v1 +kind: Service +metadata: + name: istio-sidecar-injector + namespace: istio-system + labels: + app: sidecarInjectorWebhook + chart: sidecarInjectorWebhook + heritage: Tiller + release: istio + istio: sidecar-injector +spec: + ports: + - port: 443 + name: https-inject + - port: 15014 + name: http-monitoring + selector: + istio: sidecar-injector + +--- +# Source: istio/charts/galley/templates/deployment.yaml +apiVersion: apps/v1 +kind: Deployment +metadata: + name: istio-galley + namespace: istio-system + labels: + app: galley + chart: galley + heritage: Tiller + release: istio + istio: galley +spec: + replicas: 1 + selector: + matchLabels: + istio: galley + strategy: + rollingUpdate: + maxSurge: 100% + maxUnavailable: 25% + template: + metadata: + labels: + app: galley + chart: galley + heritage: Tiller + release: istio + istio: galley + annotations: + sidecar.istio.io/inject: "false" + spec: + serviceAccountName: istio-galley-service-account + containers: + - name: galley + image: "docker.io/istio/galley:1.3.5" + imagePullPolicy: IfNotPresent + ports: + - containerPort: 443 + - containerPort: 15014 + - containerPort: 9901 + command: + - /usr/local/bin/galley + - server + - --meshConfigFile=/etc/mesh-config/mesh + - --livenessProbeInterval=1s + - --livenessProbePath=/healthliveness + - --readinessProbePath=/healthready + - --readinessProbeInterval=1s + - --deployment-namespace=istio-system + - --insecure=true + - --validation-webhook-config-file + - /etc/config/validatingwebhookconfiguration.yaml + - --monitoringPort=15014 + - --log_output_level=default:info + volumeMounts: + - name: certs + mountPath: /etc/certs + readOnly: true + - name: config + mountPath: /etc/config + readOnly: true + - name: mesh-config + mountPath: /etc/mesh-config + readOnly: true + livenessProbe: + exec: + command: + - /usr/local/bin/galley + - probe + - --probe-path=/healthliveness + - --interval=10s + initialDelaySeconds: 5 + periodSeconds: 5 + readinessProbe: + exec: + command: + - /usr/local/bin/galley + - probe + - --probe-path=/healthready + - --interval=10s + initialDelaySeconds: 5 + periodSeconds: 5 + resources: + requests: + cpu: 10m + + volumes: + - name: certs + secret: + secretName: istio.istio-galley-service-account + - name: config + configMap: + name: istio-galley-configuration + - name: mesh-config + configMap: + name: istio + affinity: + nodeAffinity: + requiredDuringSchedulingIgnoredDuringExecution: + nodeSelectorTerms: + - matchExpressions: + - key: beta.kubernetes.io/arch + operator: In + values: + - "amd64" + - "ppc64le" + - "s390x" + preferredDuringSchedulingIgnoredDuringExecution: + - weight: 2 + preference: + matchExpressions: + - key: beta.kubernetes.io/arch + operator: In + values: + - "amd64" + - weight: 2 + preference: + matchExpressions: + - key: beta.kubernetes.io/arch + operator: In + values: + - "ppc64le" + - weight: 2 + preference: + matchExpressions: + - key: beta.kubernetes.io/arch + operator: In + values: + - "s390x" + +--- +# Source: istio/charts/gateways/templates/deployment.yaml + +apiVersion: apps/v1 +kind: Deployment +metadata: + name: istio-egressgateway + namespace: istio-system + labels: + chart: gateways + heritage: Tiller + release: istio + app: istio-egressgateway + istio: egressgateway +spec: + replicas: 1 + selector: + matchLabels: + app: istio-egressgateway + istio: egressgateway + strategy: + rollingUpdate: + maxSurge: 100% + maxUnavailable: 25% + template: + metadata: + labels: + chart: gateways + heritage: Tiller + release: istio + app: istio-egressgateway + istio: egressgateway + annotations: + sidecar.istio.io/inject: "false" + spec: + serviceAccountName: istio-egressgateway-service-account + containers: + - name: istio-proxy + image: "docker.io/istio/proxyv2:1.3.5" + imagePullPolicy: IfNotPresent + ports: + - containerPort: 80 + - containerPort: 443 + - containerPort: 15443 + - containerPort: 15090 + protocol: TCP + name: http-envoy-prom + args: + - proxy + - router + - --domain + - $(POD_NAMESPACE).svc.cluster.local + - --log_output_level=default:info + - --drainDuration + - '45s' #drainDuration + - --parentShutdownDuration + - '1m0s' #parentShutdownDuration + - --connectTimeout + - '10s' #connectTimeout + - --serviceCluster + - istio-egressgateway + - --zipkinAddress + - zipkin:9411 + - --proxyAdminPort + - "15000" + - --statusPort + - "15020" + - --controlPlaneAuthPolicy + - NONE + - --discoveryAddress + - istio-pilot:15010 + readinessProbe: + failureThreshold: 30 + httpGet: + path: /healthz/ready + port: 15020 + scheme: HTTP + initialDelaySeconds: 1 + periodSeconds: 2 + successThreshold: 1 + timeoutSeconds: 1 + resources: + limits: + cpu: 2000m + memory: 1024Mi + requests: + cpu: 10m + memory: 40Mi + + env: + - name: NODE_NAME + valueFrom: + fieldRef: + apiVersion: v1 + fieldPath: spec.nodeName + - name: POD_NAME + valueFrom: + fieldRef: + apiVersion: v1 + fieldPath: metadata.name + - name: POD_NAMESPACE + valueFrom: + fieldRef: + apiVersion: v1 + fieldPath: metadata.namespace + - name: INSTANCE_IP + valueFrom: + fieldRef: + apiVersion: v1 + fieldPath: status.podIP + - name: HOST_IP + valueFrom: + fieldRef: + apiVersion: v1 + fieldPath: status.hostIP + - name: SERVICE_ACCOUNT + valueFrom: + fieldRef: + fieldPath: spec.serviceAccountName + - name: ISTIO_META_POD_NAME + valueFrom: + fieldRef: + apiVersion: v1 + fieldPath: metadata.name + - name: ISTIO_META_CONFIG_NAMESPACE + valueFrom: + fieldRef: + fieldPath: metadata.namespace + - name: SDS_ENABLED + value: "false" + - name: ISTIO_META_WORKLOAD_NAME + value: istio-egressgateway + - name: ISTIO_META_OWNER + value: kubernetes://api/apps/v1/namespaces/istio-system/deployments/istio-egressgateway + - name: ISTIO_META_ROUTER_MODE + value: sni-dnat + volumeMounts: + - name: istio-certs + mountPath: /etc/certs + readOnly: true + - name: egressgateway-certs + mountPath: "/etc/istio/egressgateway-certs" + readOnly: true + - name: egressgateway-ca-certs + mountPath: "/etc/istio/egressgateway-ca-certs" + readOnly: true + volumes: + - name: istio-certs + secret: + secretName: istio.istio-egressgateway-service-account + optional: true + - name: egressgateway-certs + secret: + secretName: "istio-egressgateway-certs" + optional: true + - name: egressgateway-ca-certs + secret: + secretName: "istio-egressgateway-ca-certs" + optional: true + affinity: + nodeAffinity: + requiredDuringSchedulingIgnoredDuringExecution: + nodeSelectorTerms: + - matchExpressions: + - key: beta.kubernetes.io/arch + operator: In + values: + - "amd64" + - "ppc64le" + - "s390x" + preferredDuringSchedulingIgnoredDuringExecution: + - weight: 2 + preference: + matchExpressions: + - key: beta.kubernetes.io/arch + operator: In + values: + - "amd64" + - weight: 2 + preference: + matchExpressions: + - key: beta.kubernetes.io/arch + operator: In + values: + - "ppc64le" + - weight: 2 + preference: + matchExpressions: + - key: beta.kubernetes.io/arch + operator: In + values: + - "s390x" +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: istio-ingressgateway + namespace: istio-system + labels: + chart: gateways + heritage: Tiller + release: istio + app: istio-ingressgateway + istio: ingressgateway +spec: + replicas: 1 + selector: + matchLabels: + app: istio-ingressgateway + istio: ingressgateway + strategy: + rollingUpdate: + maxSurge: 100% + maxUnavailable: 25% + template: + metadata: + labels: + chart: gateways + heritage: Tiller + release: istio + app: istio-ingressgateway + istio: ingressgateway + annotations: + sidecar.istio.io/inject: "false" + spec: + serviceAccountName: istio-ingressgateway-service-account + containers: + - name: istio-proxy + image: "docker.io/istio/proxyv2:1.3.5" + imagePullPolicy: IfNotPresent + ports: + - containerPort: 15020 + - containerPort: 80 + - containerPort: 443 + - containerPort: 31400 + - containerPort: 15029 + - containerPort: 15030 + - containerPort: 15031 + - containerPort: 15032 + - containerPort: 15443 + - containerPort: 15090 + protocol: TCP + name: http-envoy-prom + args: + - proxy + - router + - --domain + - $(POD_NAMESPACE).svc.cluster.local + - --log_output_level=default:info + - --drainDuration + - '45s' #drainDuration + - --parentShutdownDuration + - '1m0s' #parentShutdownDuration + - --connectTimeout + - '10s' #connectTimeout + - --serviceCluster + - istio-ingressgateway + - --zipkinAddress + - zipkin:9411 + - --proxyAdminPort + - "15000" + - --statusPort + - "15020" + - --controlPlaneAuthPolicy + - NONE + - --discoveryAddress + - istio-pilot:15010 + readinessProbe: + failureThreshold: 30 + httpGet: + path: /healthz/ready + port: 15020 + scheme: HTTP + initialDelaySeconds: 1 + periodSeconds: 2 + successThreshold: 1 + timeoutSeconds: 1 + resources: + limits: + cpu: 2000m + memory: 1024Mi + requests: + cpu: 10m + memory: 40Mi + + env: + - name: NODE_NAME + valueFrom: + fieldRef: + apiVersion: v1 + fieldPath: spec.nodeName + - name: POD_NAME + valueFrom: + fieldRef: + apiVersion: v1 + fieldPath: metadata.name + - name: POD_NAMESPACE + valueFrom: + fieldRef: + apiVersion: v1 + fieldPath: metadata.namespace + - name: INSTANCE_IP + valueFrom: + fieldRef: + apiVersion: v1 + fieldPath: status.podIP + - name: HOST_IP + valueFrom: + fieldRef: + apiVersion: v1 + fieldPath: status.hostIP + - name: SERVICE_ACCOUNT + valueFrom: + fieldRef: + fieldPath: spec.serviceAccountName + - name: ISTIO_META_POD_NAME + valueFrom: + fieldRef: + apiVersion: v1 + fieldPath: metadata.name + - name: ISTIO_META_CONFIG_NAMESPACE + valueFrom: + fieldRef: + fieldPath: metadata.namespace + - name: SDS_ENABLED + value: "false" + - name: ISTIO_META_WORKLOAD_NAME + value: istio-ingressgateway + - name: ISTIO_META_OWNER + value: kubernetes://api/apps/v1/namespaces/istio-system/deployments/istio-ingressgateway + - name: ISTIO_META_ROUTER_MODE + value: sni-dnat + volumeMounts: + - name: istio-certs + mountPath: /etc/certs + readOnly: true + - name: ingressgateway-certs + mountPath: "/etc/istio/ingressgateway-certs" + readOnly: true + - name: ingressgateway-ca-certs + mountPath: "/etc/istio/ingressgateway-ca-certs" + readOnly: true + volumes: + - name: istio-certs + secret: + secretName: istio.istio-ingressgateway-service-account + optional: true + - name: ingressgateway-certs + secret: + secretName: "istio-ingressgateway-certs" + optional: true + - name: ingressgateway-ca-certs + secret: + secretName: "istio-ingressgateway-ca-certs" + optional: true + affinity: + nodeAffinity: + requiredDuringSchedulingIgnoredDuringExecution: + nodeSelectorTerms: + - matchExpressions: + - key: beta.kubernetes.io/arch + operator: In + values: + - "amd64" + - "ppc64le" + - "s390x" + preferredDuringSchedulingIgnoredDuringExecution: + - weight: 2 + preference: + matchExpressions: + - key: beta.kubernetes.io/arch + operator: In + values: + - "amd64" + - weight: 2 + preference: + matchExpressions: + - key: beta.kubernetes.io/arch + operator: In + values: + - "ppc64le" + - weight: 2 + preference: + matchExpressions: + - key: beta.kubernetes.io/arch + operator: In + values: + - "s390x" +--- + +--- +# Source: istio/charts/grafana/templates/deployment.yaml +apiVersion: apps/v1 +kind: Deployment +metadata: + name: grafana + namespace: istio-system + labels: + app: grafana + chart: grafana + heritage: Tiller + release: istio +spec: + replicas: 1 + selector: + matchLabels: + app: grafana + template: + metadata: + labels: + app: grafana + chart: grafana + heritage: Tiller + release: istio + annotations: + sidecar.istio.io/inject: "false" + prometheus.io/scrape: "true" + spec: + securityContext: + runAsUser: 472 + fsGroup: 472 + containers: + - name: grafana + image: "grafana/grafana:6.1.6" + imagePullPolicy: IfNotPresent + ports: + - containerPort: 3000 + readinessProbe: + httpGet: + path: /api/health + port: 3000 + env: + - name: GRAFANA_PORT + value: "3000" + - name: GF_AUTH_BASIC_ENABLED + value: "false" + - name: GF_AUTH_ANONYMOUS_ENABLED + value: "true" + - name: GF_AUTH_ANONYMOUS_ORG_ROLE + value: Admin + - name: GF_PATHS_DATA + value: /data/grafana + resources: + requests: + cpu: 10m + + volumeMounts: + - name: data + mountPath: /data/grafana + - name: dashboards-istio-citadel-dashboard + mountPath: "/var/lib/grafana/dashboards/istio/citadel-dashboard.json" + subPath: citadel-dashboard.json + readOnly: true + - name: dashboards-istio-galley-dashboard + mountPath: "/var/lib/grafana/dashboards/istio/galley-dashboard.json" + subPath: galley-dashboard.json + readOnly: true + - name: dashboards-istio-istio-mesh-dashboard + mountPath: "/var/lib/grafana/dashboards/istio/istio-mesh-dashboard.json" + subPath: istio-mesh-dashboard.json + readOnly: true + - name: dashboards-istio-istio-performance-dashboard + mountPath: "/var/lib/grafana/dashboards/istio/istio-performance-dashboard.json" + subPath: istio-performance-dashboard.json + readOnly: true + - name: dashboards-istio-istio-service-dashboard + mountPath: "/var/lib/grafana/dashboards/istio/istio-service-dashboard.json" + subPath: istio-service-dashboard.json + readOnly: true + - name: dashboards-istio-istio-workload-dashboard + mountPath: "/var/lib/grafana/dashboards/istio/istio-workload-dashboard.json" + subPath: istio-workload-dashboard.json + readOnly: true + - name: dashboards-istio-mixer-dashboard + mountPath: "/var/lib/grafana/dashboards/istio/mixer-dashboard.json" + subPath: mixer-dashboard.json + readOnly: true + - name: dashboards-istio-pilot-dashboard + mountPath: "/var/lib/grafana/dashboards/istio/pilot-dashboard.json" + subPath: pilot-dashboard.json + readOnly: true + - name: config + mountPath: "/etc/grafana/provisioning/datasources/datasources.yaml" + subPath: datasources.yaml + - name: config + mountPath: "/etc/grafana/provisioning/dashboards/dashboardproviders.yaml" + subPath: dashboardproviders.yaml + affinity: + nodeAffinity: + requiredDuringSchedulingIgnoredDuringExecution: + nodeSelectorTerms: + - matchExpressions: + - key: beta.kubernetes.io/arch + operator: In + values: + - "amd64" + - "ppc64le" + - "s390x" + preferredDuringSchedulingIgnoredDuringExecution: + - weight: 2 + preference: + matchExpressions: + - key: beta.kubernetes.io/arch + operator: In + values: + - "amd64" + - weight: 2 + preference: + matchExpressions: + - key: beta.kubernetes.io/arch + operator: In + values: + - "ppc64le" + - weight: 2 + preference: + matchExpressions: + - key: beta.kubernetes.io/arch + operator: In + values: + - "s390x" + volumes: + - name: config + configMap: + name: istio-grafana + - name: data + emptyDir: {} + - name: dashboards-istio-citadel-dashboard + configMap: + name: istio-grafana-configuration-dashboards-citadel-dashboard + - name: dashboards-istio-galley-dashboard + configMap: + name: istio-grafana-configuration-dashboards-galley-dashboard + - name: dashboards-istio-istio-mesh-dashboard + configMap: + name: istio-grafana-configuration-dashboards-istio-mesh-dashboard + - name: dashboards-istio-istio-performance-dashboard + configMap: + name: istio-grafana-configuration-dashboards-istio-performance-dashboard + - name: dashboards-istio-istio-service-dashboard + configMap: + name: istio-grafana-configuration-dashboards-istio-service-dashboard + - name: dashboards-istio-istio-workload-dashboard + configMap: + name: istio-grafana-configuration-dashboards-istio-workload-dashboard + - name: dashboards-istio-mixer-dashboard + configMap: + name: istio-grafana-configuration-dashboards-mixer-dashboard + - name: dashboards-istio-pilot-dashboard + configMap: + name: istio-grafana-configuration-dashboards-pilot-dashboard + +--- +# Source: istio/charts/kiali/templates/deployment.yaml +apiVersion: apps/v1 +kind: Deployment +metadata: + name: kiali + namespace: istio-system + labels: + app: kiali + chart: kiali + heritage: Tiller + release: istio +spec: + replicas: 1 + selector: + matchLabels: + app: kiali + template: + metadata: + name: kiali + labels: + app: kiali + chart: kiali + heritage: Tiller + release: istio + annotations: + sidecar.istio.io/inject: "false" + scheduler.alpha.kubernetes.io/critical-pod: "" + prometheus.io/scrape: "true" + prometheus.io/port: "9090" + kiali.io/runtimes: go,kiali + spec: + serviceAccountName: kiali-service-account + containers: + - image: "quay.io/kiali/kiali:v1.4" + imagePullPolicy: IfNotPresent + name: kiali + command: + - "/opt/kiali/kiali" + - "-config" + - "/kiali-configuration/config.yaml" + - "-v" + - "3" + readinessProbe: + httpGet: + path: /kiali/healthz + port: 20001 + scheme: 'HTTP' + initialDelaySeconds: 5 + periodSeconds: 30 + livenessProbe: + httpGet: + path: /kiali/healthz + port: 20001 + scheme: 'HTTP' + initialDelaySeconds: 5 + periodSeconds: 30 + env: + - name: ACTIVE_NAMESPACE + valueFrom: + fieldRef: + fieldPath: metadata.namespace + volumeMounts: + - name: kiali-configuration + mountPath: "/kiali-configuration" + - name: kiali-cert + mountPath: "/kiali-cert" + - name: kiali-secret + mountPath: "/kiali-secret" + resources: + requests: + cpu: 10m + + volumes: + - name: kiali-configuration + configMap: + name: kiali + - name: kiali-cert + secret: + secretName: istio.kiali-service-account + optional: true + - name: kiali-secret + secret: + secretName: kiali + optional: true + affinity: + nodeAffinity: + requiredDuringSchedulingIgnoredDuringExecution: + nodeSelectorTerms: + - matchExpressions: + - key: beta.kubernetes.io/arch + operator: In + values: + - "amd64" + - "ppc64le" + - "s390x" + preferredDuringSchedulingIgnoredDuringExecution: + - weight: 2 + preference: + matchExpressions: + - key: beta.kubernetes.io/arch + operator: In + values: + - "amd64" + - weight: 2 + preference: + matchExpressions: + - key: beta.kubernetes.io/arch + operator: In + values: + - "ppc64le" + - weight: 2 + preference: + matchExpressions: + - key: beta.kubernetes.io/arch + operator: In + values: + - "s390x" + +--- +# Source: istio/charts/mixer/templates/deployment.yaml + +apiVersion: apps/v1 +kind: Deployment +metadata: + name: istio-policy + namespace: istio-system + labels: + app: istio-mixer + chart: mixer + heritage: Tiller + release: istio + istio: mixer +spec: + replicas: 1 + strategy: + rollingUpdate: + maxSurge: 100% + maxUnavailable: 25% + selector: + matchLabels: + istio: mixer + istio-mixer-type: policy + template: + metadata: + labels: + app: policy + chart: mixer + heritage: Tiller + release: istio + istio: mixer + istio-mixer-type: policy + annotations: + sidecar.istio.io/inject: "false" + spec: + serviceAccountName: istio-mixer-service-account + volumes: + - name: istio-certs + secret: + secretName: istio.istio-mixer-service-account + optional: true + - name: uds-socket + emptyDir: {} + - name: policy-adapter-secret + secret: + secretName: policy-adapter-secret + optional: true + affinity: + nodeAffinity: + requiredDuringSchedulingIgnoredDuringExecution: + nodeSelectorTerms: + - matchExpressions: + - key: beta.kubernetes.io/arch + operator: In + values: + - "amd64" + - "ppc64le" + - "s390x" + preferredDuringSchedulingIgnoredDuringExecution: + - weight: 2 + preference: + matchExpressions: + - key: beta.kubernetes.io/arch + operator: In + values: + - "amd64" + - weight: 2 + preference: + matchExpressions: + - key: beta.kubernetes.io/arch + operator: In + values: + - "ppc64le" + - weight: 2 + preference: + matchExpressions: + - key: beta.kubernetes.io/arch + operator: In + values: + - "s390x" + containers: + - name: mixer + image: "docker.io/istio/mixer:1.3.5" + imagePullPolicy: IfNotPresent + ports: + - containerPort: 15014 + - containerPort: 42422 + args: + - --monitoringPort=15014 + - --address + - unix:///sock/mixer.socket + - --log_output_level=default:info + - --configStoreURL=mcp://istio-galley.istio-system.svc:9901 + - --configDefaultNamespace=istio-system + - --useAdapterCRDs=false + - --useTemplateCRDs=false + - --trace_zipkin_url=http://zipkin.istio-system:9411/api/v1/spans + env: + - name: GODEBUG + value: "gctrace=1" + - name: GOMAXPROCS + value: "6" + resources: + requests: + cpu: 10m + memory: 100Mi + + volumeMounts: + - name: istio-certs + mountPath: /etc/certs + readOnly: true + - name: uds-socket + mountPath: /sock + livenessProbe: + httpGet: + path: /version + port: 15014 + initialDelaySeconds: 5 + periodSeconds: 5 + - name: istio-proxy + image: "docker.io/istio/proxyv2:1.3.5" + imagePullPolicy: IfNotPresent + ports: + - containerPort: 9091 + - containerPort: 15004 + - containerPort: 15090 + protocol: TCP + name: http-envoy-prom + args: + - proxy + - --domain + - $(POD_NAMESPACE).svc.cluster.local + - --serviceCluster + - istio-policy + - --templateFile + - /etc/istio/proxy/envoy_policy.yaml.tmpl + - --controlPlaneAuthPolicy + - NONE + env: + - name: POD_NAME + valueFrom: + fieldRef: + apiVersion: v1 + fieldPath: metadata.name + - name: POD_NAMESPACE + valueFrom: + fieldRef: + apiVersion: v1 + fieldPath: metadata.namespace + - name: INSTANCE_IP + valueFrom: + fieldRef: + apiVersion: v1 + fieldPath: status.podIP + - name: SDS_ENABLED + value: "false" + resources: + limits: + cpu: 2000m + memory: 1024Mi + requests: + cpu: 10m + memory: 40Mi + + volumeMounts: + - name: istio-certs + mountPath: /etc/certs + readOnly: true + - name: uds-socket + mountPath: /sock + - name: policy-adapter-secret + mountPath: /var/run/secrets/istio.io/policy/adapter + readOnly: true + +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: istio-telemetry + namespace: istio-system + labels: + app: istio-mixer + chart: mixer + heritage: Tiller + release: istio + istio: mixer +spec: + replicas: 1 + strategy: + rollingUpdate: + maxSurge: 100% + maxUnavailable: 25% + selector: + matchLabels: + istio: mixer + istio-mixer-type: telemetry + template: + metadata: + labels: + app: telemetry + chart: mixer + heritage: Tiller + release: istio + istio: mixer + istio-mixer-type: telemetry + annotations: + sidecar.istio.io/inject: "false" + spec: + serviceAccountName: istio-mixer-service-account + volumes: + - name: istio-certs + secret: + secretName: istio.istio-mixer-service-account + optional: true + - name: uds-socket + emptyDir: {} + - name: telemetry-adapter-secret + secret: + secretName: telemetry-adapter-secret + optional: true + affinity: + nodeAffinity: + requiredDuringSchedulingIgnoredDuringExecution: + nodeSelectorTerms: + - matchExpressions: + - key: beta.kubernetes.io/arch + operator: In + values: + - "amd64" + - "ppc64le" + - "s390x" + preferredDuringSchedulingIgnoredDuringExecution: + - weight: 2 + preference: + matchExpressions: + - key: beta.kubernetes.io/arch + operator: In + values: + - "amd64" + - weight: 2 + preference: + matchExpressions: + - key: beta.kubernetes.io/arch + operator: In + values: + - "ppc64le" + - weight: 2 + preference: + matchExpressions: + - key: beta.kubernetes.io/arch + operator: In + values: + - "s390x" + containers: + - name: mixer + image: "docker.io/istio/mixer:1.3.5" + imagePullPolicy: IfNotPresent + ports: + - containerPort: 15014 + - containerPort: 42422 + args: + - --monitoringPort=15014 + - --address + - unix:///sock/mixer.socket + - --log_output_level=default:info + - --configStoreURL=mcp://istio-galley.istio-system.svc:9901 + - --configDefaultNamespace=istio-system + - --useAdapterCRDs=false + - --trace_zipkin_url=http://zipkin.istio-system:9411/api/v1/spans + - --averageLatencyThreshold + - 100ms + - --loadsheddingMode + - enforce + env: + - name: GODEBUG + value: "gctrace=1" + - name: GOMAXPROCS + value: "6" + resources: + limits: + cpu: 4800m + memory: 4G + requests: + cpu: 50m + memory: 100Mi + + volumeMounts: + - name: istio-certs + mountPath: /etc/certs + readOnly: true + - name: telemetry-adapter-secret + mountPath: /var/run/secrets/istio.io/telemetry/adapter + readOnly: true + - name: uds-socket + mountPath: /sock + livenessProbe: + httpGet: + path: /version + port: 15014 + initialDelaySeconds: 5 + periodSeconds: 5 + - name: istio-proxy + image: "docker.io/istio/proxyv2:1.3.5" + imagePullPolicy: IfNotPresent + ports: + - containerPort: 9091 + - containerPort: 15004 + - containerPort: 15090 + protocol: TCP + name: http-envoy-prom + args: + - proxy + - --domain + - $(POD_NAMESPACE).svc.cluster.local + - --serviceCluster + - istio-telemetry + - --templateFile + - /etc/istio/proxy/envoy_telemetry.yaml.tmpl + - --controlPlaneAuthPolicy + - NONE + env: + - name: POD_NAME + valueFrom: + fieldRef: + apiVersion: v1 + fieldPath: metadata.name + - name: POD_NAMESPACE + valueFrom: + fieldRef: + apiVersion: v1 + fieldPath: metadata.namespace + - name: INSTANCE_IP + valueFrom: + fieldRef: + apiVersion: v1 + fieldPath: status.podIP + - name: SDS_ENABLED + value: "false" + resources: + limits: + cpu: 2000m + memory: 1024Mi + requests: + cpu: 10m + memory: 40Mi + + volumeMounts: + - name: istio-certs + mountPath: /etc/certs + readOnly: true + - name: uds-socket + mountPath: /sock + +--- + +--- +# Source: istio/charts/pilot/templates/deployment.yaml +apiVersion: apps/v1 +kind: Deployment +metadata: + name: istio-pilot + namespace: istio-system + # TODO: default template doesn't have this, which one is right ? + labels: + app: pilot + chart: pilot + heritage: Tiller + release: istio + istio: pilot + annotations: + checksum/config-volume: f8da08b6b8c170dde721efd680270b2901e750d4aa186ebb6c22bef5b78a43f9 +spec: + replicas: 1 + strategy: + rollingUpdate: + maxSurge: 100% + maxUnavailable: 25% + selector: + matchLabels: + istio: pilot + template: + metadata: + labels: + app: pilot + chart: pilot + heritage: Tiller + release: istio + istio: pilot + annotations: + sidecar.istio.io/inject: "false" + spec: + serviceAccountName: istio-pilot-service-account + containers: + - name: discovery + image: "docker.io/istio/pilot:1.3.5" + imagePullPolicy: IfNotPresent + args: + - "discovery" + - --monitoringAddr=:15014 + - --log_output_level=default:info + - --domain + - cluster.local + - --secureGrpcAddr + - "" + - --keepaliveMaxServerConnectionAge + - "30m" + ports: + - containerPort: 8080 + - containerPort: 15010 + readinessProbe: + httpGet: + path: /ready + port: 8080 + initialDelaySeconds: 5 + periodSeconds: 30 + timeoutSeconds: 5 + env: + - name: POD_NAME + valueFrom: + fieldRef: + apiVersion: v1 + fieldPath: metadata.name + - name: POD_NAMESPACE + valueFrom: + fieldRef: + apiVersion: v1 + fieldPath: metadata.namespace + - name: GODEBUG + value: "gctrace=1" + - name: PILOT_PUSH_THROTTLE + value: "100" + - name: PILOT_TRACE_SAMPLING + value: "100" + - name: PILOT_ENABLE_PROTOCOL_SNIFFING_FOR_OUTBOUND + value: "true" + - name: PILOT_ENABLE_PROTOCOL_SNIFFING_FOR_INBOUND + value: "false" + resources: + requests: + cpu: 10m + memory: 100Mi + + volumeMounts: + - name: config-volume + mountPath: /etc/istio/config + - name: istio-certs + mountPath: /etc/certs + readOnly: true + - name: istio-proxy + image: "docker.io/istio/proxyv2:1.3.5" + imagePullPolicy: IfNotPresent + ports: + - containerPort: 15003 + - containerPort: 15005 + - containerPort: 15007 + - containerPort: 15011 + args: + - proxy + - --domain + - $(POD_NAMESPACE).svc.cluster.local + - --serviceCluster + - istio-pilot + - --templateFile + - /etc/istio/proxy/envoy_pilot.yaml.tmpl + - --controlPlaneAuthPolicy + - NONE + env: + - name: POD_NAME + valueFrom: + fieldRef: + apiVersion: v1 + fieldPath: metadata.name + - name: POD_NAMESPACE + valueFrom: + fieldRef: + apiVersion: v1 + fieldPath: metadata.namespace + - name: INSTANCE_IP + valueFrom: + fieldRef: + apiVersion: v1 + fieldPath: status.podIP + - name: SDS_ENABLED + value: "false" + resources: + limits: + cpu: 2000m + memory: 1024Mi + requests: + cpu: 10m + memory: 40Mi + + volumeMounts: + - name: istio-certs + mountPath: /etc/certs + readOnly: true + volumes: + - name: config-volume + configMap: + name: istio + - name: istio-certs + secret: + secretName: istio.istio-pilot-service-account + optional: true + affinity: + nodeAffinity: + requiredDuringSchedulingIgnoredDuringExecution: + nodeSelectorTerms: + - matchExpressions: + - key: beta.kubernetes.io/arch + operator: In + values: + - "amd64" + - "ppc64le" + - "s390x" + preferredDuringSchedulingIgnoredDuringExecution: + - weight: 2 + preference: + matchExpressions: + - key: beta.kubernetes.io/arch + operator: In + values: + - "amd64" + - weight: 2 + preference: + matchExpressions: + - key: beta.kubernetes.io/arch + operator: In + values: + - "ppc64le" + - weight: 2 + preference: + matchExpressions: + - key: beta.kubernetes.io/arch + operator: In + values: + - "s390x" + +--- +# Source: istio/charts/prometheus/templates/deployment.yaml +# TODO: the original template has service account, roles, etc +apiVersion: apps/v1 +kind: Deployment +metadata: + name: prometheus + namespace: istio-system + labels: + app: prometheus + chart: prometheus + heritage: Tiller + release: istio +spec: + replicas: 1 + selector: + matchLabels: + app: prometheus + template: + metadata: + labels: + app: prometheus + chart: prometheus + heritage: Tiller + release: istio + annotations: + sidecar.istio.io/inject: "false" + spec: + serviceAccountName: prometheus + containers: + - name: prometheus + image: "docker.io/prom/prometheus:v2.8.0" + imagePullPolicy: IfNotPresent + args: + - '--storage.tsdb.retention=6h' + - '--config.file=/etc/prometheus/prometheus.yml' + ports: + - containerPort: 9090 + name: http + livenessProbe: + httpGet: + path: /-/healthy + port: 9090 + readinessProbe: + httpGet: + path: /-/ready + port: 9090 + resources: + requests: + cpu: 10m + + volumeMounts: + - name: config-volume + mountPath: /etc/prometheus + - mountPath: /etc/istio-certs + name: istio-certs + volumes: + - name: config-volume + configMap: + name: prometheus + - name: istio-certs + secret: + defaultMode: 420 + secretName: istio.default + affinity: + nodeAffinity: + requiredDuringSchedulingIgnoredDuringExecution: + nodeSelectorTerms: + - matchExpressions: + - key: beta.kubernetes.io/arch + operator: In + values: + - "amd64" + - "ppc64le" + - "s390x" + preferredDuringSchedulingIgnoredDuringExecution: + - weight: 2 + preference: + matchExpressions: + - key: beta.kubernetes.io/arch + operator: In + values: + - "amd64" + - weight: 2 + preference: + matchExpressions: + - key: beta.kubernetes.io/arch + operator: In + values: + - "ppc64le" + - weight: 2 + preference: + matchExpressions: + - key: beta.kubernetes.io/arch + operator: In + values: + - "s390x" + +--- +# Source: istio/charts/security/templates/deployment.yaml +# istio CA watching all namespaces +apiVersion: apps/v1 +kind: Deployment +metadata: + name: istio-citadel + namespace: istio-system + labels: + app: security + chart: security + heritage: Tiller + release: istio + istio: citadel +spec: + replicas: 1 + selector: + matchLabels: + istio: citadel + strategy: + rollingUpdate: + maxSurge: 100% + maxUnavailable: 25% + template: + metadata: + labels: + app: security + chart: security + heritage: Tiller + release: istio + istio: citadel + annotations: + sidecar.istio.io/inject: "false" + spec: + serviceAccountName: istio-citadel-service-account + containers: + - name: citadel + image: "docker.io/istio/citadel:1.3.5" + imagePullPolicy: IfNotPresent + args: + - --append-dns-names=true + - --grpc-port=8060 + - --citadel-storage-namespace=istio-system + - --custom-dns-names=istio-pilot-service-account.istio-system:istio-pilot.istio-system + - --monitoring-port=15014 + - --self-signed-ca=true + - --workload-cert-ttl=2160h + env: + - name: CITADEL_ENABLE_NAMESPACES_BY_DEFAULT + value: "true" + resources: + requests: + cpu: 10m + + affinity: + nodeAffinity: + requiredDuringSchedulingIgnoredDuringExecution: + nodeSelectorTerms: + - matchExpressions: + - key: beta.kubernetes.io/arch + operator: In + values: + - "amd64" + - "ppc64le" + - "s390x" + preferredDuringSchedulingIgnoredDuringExecution: + - weight: 2 + preference: + matchExpressions: + - key: beta.kubernetes.io/arch + operator: In + values: + - "amd64" + - weight: 2 + preference: + matchExpressions: + - key: beta.kubernetes.io/arch + operator: In + values: + - "ppc64le" + - weight: 2 + preference: + matchExpressions: + - key: beta.kubernetes.io/arch + operator: In + values: + - "s390x" + +--- +# Source: istio/charts/sidecarInjectorWebhook/templates/deployment.yaml +apiVersion: apps/v1 +kind: Deployment +metadata: + name: istio-sidecar-injector + namespace: istio-system + labels: + app: sidecarInjectorWebhook + chart: sidecarInjectorWebhook + heritage: Tiller + release: istio + istio: sidecar-injector +spec: + replicas: 1 + selector: + matchLabels: + istio: sidecar-injector + strategy: + rollingUpdate: + maxSurge: 100% + maxUnavailable: 25% + template: + metadata: + labels: + app: sidecarInjectorWebhook + chart: sidecarInjectorWebhook + heritage: Tiller + release: istio + istio: sidecar-injector + annotations: + sidecar.istio.io/inject: "false" + spec: + serviceAccountName: istio-sidecar-injector-service-account + containers: + - name: sidecar-injector-webhook + image: "docker.io/istio/sidecar_injector:1.3.5" + imagePullPolicy: IfNotPresent + args: + - --caCertFile=/etc/istio/certs/root-cert.pem + - --tlsCertFile=/etc/istio/certs/cert-chain.pem + - --tlsKeyFile=/etc/istio/certs/key.pem + - --injectConfig=/etc/istio/inject/config + - --meshConfig=/etc/istio/config/mesh + - --healthCheckInterval=2s + - --healthCheckFile=/health + volumeMounts: + - name: config-volume + mountPath: /etc/istio/config + readOnly: true + - name: certs + mountPath: /etc/istio/certs + readOnly: true + - name: inject-config + mountPath: /etc/istio/inject + readOnly: true + livenessProbe: + exec: + command: + - /usr/local/bin/sidecar-injector + - probe + - --probe-path=/health + - --interval=4s + initialDelaySeconds: 4 + periodSeconds: 4 + readinessProbe: + exec: + command: + - /usr/local/bin/sidecar-injector + - probe + - --probe-path=/health + - --interval=4s + initialDelaySeconds: 4 + periodSeconds: 4 + resources: + requests: + cpu: 10m + + volumes: + - name: config-volume + configMap: + name: istio + - name: certs + secret: + secretName: istio.istio-sidecar-injector-service-account + - name: inject-config + configMap: + name: istio-sidecar-injector + items: + - key: config + path: config + - key: values + path: values + affinity: + nodeAffinity: + requiredDuringSchedulingIgnoredDuringExecution: + nodeSelectorTerms: + - matchExpressions: + - key: beta.kubernetes.io/arch + operator: In + values: + - "amd64" + - "ppc64le" + - "s390x" + preferredDuringSchedulingIgnoredDuringExecution: + - weight: 2 + preference: + matchExpressions: + - key: beta.kubernetes.io/arch + operator: In + values: + - "amd64" + - weight: 2 + preference: + matchExpressions: + - key: beta.kubernetes.io/arch + operator: In + values: + - "ppc64le" + - weight: 2 + preference: + matchExpressions: + - key: beta.kubernetes.io/arch + operator: In + values: + - "s390x" + +--- +# Source: istio/charts/tracing/templates/deployment-jaeger.yaml + + +apiVersion: apps/v1 +kind: Deployment +metadata: + name: istio-tracing + namespace: istio-system + labels: + app: jaeger + chart: tracing + heritage: Tiller + release: istio +spec: + selector: + matchLabels: + app: jaeger + template: + metadata: + labels: + app: jaeger + chart: tracing + heritage: Tiller + release: istio + annotations: + sidecar.istio.io/inject: "false" + prometheus.io/scrape: "true" + prometheus.io/port: "14269" + spec: + containers: + - name: jaeger + image: "docker.io/jaegertracing/all-in-one:1.14" + imagePullPolicy: IfNotPresent + ports: + - containerPort: 9411 + - containerPort: 16686 + - containerPort: 14250 + - containerPort: 14267 + - containerPort: 14268 + - containerPort: 14269 + - containerPort: 5775 + protocol: UDP + - containerPort: 6831 + protocol: UDP + - containerPort: 6832 + protocol: UDP + env: + - name: POD_NAMESPACE + valueFrom: + fieldRef: + apiVersion: v1 + fieldPath: metadata.namespace + - name: BADGER_EPHEMERAL + value: "false" + - name: SPAN_STORAGE_TYPE + value: "badger" + - name: BADGER_DIRECTORY_VALUE + value: "/badger/data" + - name: BADGER_DIRECTORY_KEY + value: "/badger/key" + - name: COLLECTOR_ZIPKIN_HTTP_PORT + value: "9411" + - name: MEMORY_MAX_TRACES + value: "50000" + - name: QUERY_BASE_PATH + value: /jaeger + livenessProbe: + httpGet: + path: / + port: 14269 + readinessProbe: + httpGet: + path: / + port: 14269 + volumeMounts: + - name: data + mountPath: /badger + resources: + requests: + cpu: 10m + + affinity: + nodeAffinity: + requiredDuringSchedulingIgnoredDuringExecution: + nodeSelectorTerms: + - matchExpressions: + - key: beta.kubernetes.io/arch + operator: In + values: + - "amd64" + - "ppc64le" + - "s390x" + preferredDuringSchedulingIgnoredDuringExecution: + - weight: 2 + preference: + matchExpressions: + - key: beta.kubernetes.io/arch + operator: In + values: + - "amd64" + - weight: 2 + preference: + matchExpressions: + - key: beta.kubernetes.io/arch + operator: In + values: + - "ppc64le" + - weight: 2 + preference: + matchExpressions: + - key: beta.kubernetes.io/arch + operator: In + values: + - "s390x" + volumes: + - name: data + emptyDir: {} + + +--- +# Source: istio/charts/tracing/templates/service-jaeger.yaml + + +apiVersion: v1 +kind: List +metadata: + name: jaeger-services + namespace: istio-system + labels: + app: jaeger + chart: tracing + heritage: Tiller + release: istio +items: +- apiVersion: v1 + kind: Service + metadata: + name: jaeger-query + namespace: istio-system + annotations: + labels: + app: jaeger + jaeger-infra: jaeger-service + chart: tracing + heritage: Tiller + release: istio + spec: + ports: + - name: query-http + port: 16686 + protocol: TCP + targetPort: 16686 + selector: + app: jaeger +- apiVersion: v1 + kind: Service + metadata: + name: jaeger-collector + namespace: istio-system + labels: + app: jaeger + jaeger-infra: collector-service + chart: tracing + heritage: Tiller + release: istio + spec: + ports: + - name: jaeger-collector-tchannel + port: 14267 + protocol: TCP + targetPort: 14267 + - name: jaeger-collector-http + port: 14268 + targetPort: 14268 + protocol: TCP + - name: jaeger-collector-grpc + port: 14250 + targetPort: 14250 + protocol: TCP + selector: + app: jaeger + type: ClusterIP +- apiVersion: v1 + kind: Service + metadata: + name: jaeger-agent + namespace: istio-system + labels: + app: jaeger + jaeger-infra: agent-service + chart: tracing + heritage: Tiller + release: istio + spec: + ports: + - name: agent-zipkin-thrift + port: 5775 + protocol: UDP + targetPort: 5775 + - name: agent-compact + port: 6831 + protocol: UDP + targetPort: 6831 + - name: agent-binary + port: 6832 + protocol: UDP + targetPort: 6832 + clusterIP: None + selector: + app: jaeger + + + +--- +# Source: istio/charts/tracing/templates/service.yaml +apiVersion: v1 +kind: List +metadata: + name: tracing-services + namespace: istio-system + labels: + app: jaeger + chart: tracing + heritage: Tiller + release: istio +items: +- apiVersion: v1 + kind: Service + metadata: + name: zipkin + namespace: istio-system + labels: + app: jaeger + chart: tracing + heritage: Tiller + release: istio + spec: + type: ClusterIP + ports: + - port: 9411 + targetPort: 9411 + protocol: TCP + name: http + selector: + app: jaeger +- apiVersion: v1 + kind: Service + metadata: + name: tracing + namespace: istio-system + annotations: + labels: + app: jaeger + chart: tracing + heritage: Tiller + release: istio + spec: + ports: + - name: http-query + port: 80 + protocol: TCP + + targetPort: 16686 + + selector: + app: jaeger + +--- +# Source: istio/charts/sidecarInjectorWebhook/templates/mutatingwebhook.yaml +apiVersion: admissionregistration.k8s.io/v1beta1 +kind: MutatingWebhookConfiguration +metadata: + name: istio-sidecar-injector + labels: + app: sidecarInjectorWebhook + chart: sidecarInjectorWebhook + heritage: Tiller + release: istio +webhooks: + - name: sidecar-injector.istio.io + clientConfig: + service: + name: istio-sidecar-injector + namespace: istio-system + path: "/inject" + caBundle: "" + rules: + - operations: [ "CREATE" ] + apiGroups: [""] + apiVersions: ["v1"] + resources: ["pods"] + failurePolicy: Fail + namespaceSelector: + matchLabels: + istio-injection: enabled + + +--- +# Source: istio/charts/galley/templates/poddisruptionbudget.yaml + +apiVersion: policy/v1beta1 +kind: PodDisruptionBudget +metadata: + name: istio-galley + namespace: istio-system + labels: + app: galley + chart: galley + heritage: Tiller + release: istio + istio: galley +spec: + + minAvailable: 1 + selector: + matchLabels: + app: galley + release: istio + istio: galley + +--- +# Source: istio/charts/gateways/templates/poddisruptionbudget.yaml + +apiVersion: policy/v1beta1 +kind: PodDisruptionBudget +metadata: + name: istio-egressgateway + namespace: istio-system + labels: + chart: gateways + heritage: Tiller + release: istio + app: istio-egressgateway + istio: egressgateway +spec: + + minAvailable: 1 + selector: + matchLabels: + release: istio + app: istio-egressgateway + istio: egressgateway +--- +apiVersion: policy/v1beta1 +kind: PodDisruptionBudget +metadata: + name: istio-ingressgateway + namespace: istio-system + labels: + chart: gateways + heritage: Tiller + release: istio + app: istio-ingressgateway + istio: ingressgateway +spec: + + minAvailable: 1 + selector: + matchLabels: + release: istio + app: istio-ingressgateway + istio: ingressgateway +--- + +--- +# Source: istio/charts/mixer/templates/poddisruptionbudget.yaml + +apiVersion: policy/v1beta1 +kind: PodDisruptionBudget +metadata: + name: istio-policy + namespace: istio-system + labels: + app: policy + chart: mixer + heritage: Tiller + release: istio + version: 1.1.0 + istio: mixer + istio-mixer-type: policy +spec: + + minAvailable: 1 + selector: + matchLabels: + app: policy + release: istio + istio: mixer + istio-mixer-type: policy +--- +apiVersion: policy/v1beta1 +kind: PodDisruptionBudget +metadata: + name: istio-telemetry + namespace: istio-system + labels: + app: telemetry + chart: mixer + heritage: Tiller + release: istio + version: 1.1.0 + istio: mixer + istio-mixer-type: telemetry +spec: + + minAvailable: 1 + selector: + matchLabels: + app: telemetry + release: istio + istio: mixer + istio-mixer-type: telemetry +--- + +--- +# Source: istio/charts/pilot/templates/poddisruptionbudget.yaml + +apiVersion: policy/v1beta1 +kind: PodDisruptionBudget +metadata: + name: istio-pilot + namespace: istio-system + labels: + app: pilot + chart: pilot + heritage: Tiller + release: istio + istio: pilot +spec: + + minAvailable: 1 + selector: + matchLabels: + app: pilot + release: istio + istio: pilot + +--- +# Source: istio/charts/sidecarInjectorWebhook/templates/poddisruptionbudget.yaml + +apiVersion: policy/v1beta1 +kind: PodDisruptionBudget +metadata: + name: istio-sidecar-injector + namespace: istio-system + labels: + app: sidecarInjectorWebhook + release: istio + istio: sidecar-injector +spec: + + minAvailable: 1 + selector: + matchLabels: + app: sidecarInjectorWebhook + release: istio + istio: sidecar-injector +--- +# Source: istio/charts/galley/templates/validatingwebhookconfiguration.yaml.tpl + + +--- +# Source: istio/charts/gateways/templates/autoscale.yaml + + +--- +# Source: istio/charts/gateways/templates/preconfigured.yaml + + +--- +# Source: istio/charts/grafana/templates/grafana-ports-mtls.yaml + + +--- +# Source: istio/charts/grafana/templates/ingress.yaml + +--- +# Source: istio/charts/grafana/templates/pvc.yaml + + +--- +# Source: istio/charts/grafana/templates/tests/test-grafana-connection.yaml + + +--- +# Source: istio/charts/kiali/templates/ingress.yaml + +--- +# Source: istio/charts/kiali/templates/tests/test-kiali-connection.yaml + + +--- +# Source: istio/charts/mixer/templates/autoscale.yaml + + +--- +# Source: istio/charts/pilot/templates/autoscale.yaml + + +--- +# Source: istio/charts/pilot/templates/meshexpansion.yaml + + + +--- +# Source: istio/charts/prometheus/templates/ingress.yaml + +--- +# Source: istio/charts/prometheus/templates/tests/test-prometheus-connection.yaml + + +--- +# Source: istio/charts/security/templates/enable-mesh-mtls.yaml + + +--- +# Source: istio/charts/security/templates/enable-mesh-permissive.yaml + + +--- +# Source: istio/charts/security/templates/meshexpansion.yaml + + +--- +# Source: istio/charts/security/templates/tests/test-citadel-connection.yaml + + +--- +# Source: istio/charts/tracing/templates/deployment-zipkin.yaml + + +--- +# Source: istio/charts/tracing/templates/ingress.yaml + +--- +# Source: istio/charts/tracing/templates/pvc.yaml + + +--- +# Source: istio/charts/tracing/templates/tests/test-tracing-connection.yaml + + +--- +# Source: istio/templates/endpoints.yaml + + +--- +# Source: istio/templates/install-custom-resources.sh.tpl + + +--- +# Source: istio/templates/service.yaml + + +--- +# Source: istio/charts/mixer/templates/config.yaml + +apiVersion: "config.istio.io/v1alpha2" +kind: attributemanifest +metadata: + name: istioproxy + namespace: istio-system + labels: + app: mixer + chart: mixer + heritage: Tiller + release: istio +spec: + attributes: + origin.ip: + valueType: IP_ADDRESS + origin.uid: + valueType: STRING + origin.user: + valueType: STRING + request.headers: + valueType: STRING_MAP + request.id: + valueType: STRING + request.host: + valueType: STRING + request.method: + valueType: STRING + request.path: + valueType: STRING + request.url_path: + valueType: STRING + request.query_params: + valueType: STRING_MAP + request.reason: + valueType: STRING + request.referer: + valueType: STRING + request.scheme: + valueType: STRING + request.total_size: + valueType: INT64 + request.size: + valueType: INT64 + request.time: + valueType: TIMESTAMP + request.useragent: + valueType: STRING + response.code: + valueType: INT64 + response.duration: + valueType: DURATION + response.headers: + valueType: STRING_MAP + response.total_size: + valueType: INT64 + response.size: + valueType: INT64 + response.time: + valueType: TIMESTAMP + response.grpc_status: + valueType: STRING + response.grpc_message: + valueType: STRING + source.uid: + valueType: STRING + source.user: # DEPRECATED + valueType: STRING + source.principal: + valueType: STRING + destination.uid: + valueType: STRING + destination.principal: + valueType: STRING + destination.port: + valueType: INT64 + connection.event: + valueType: STRING + connection.id: + valueType: STRING + connection.received.bytes: + valueType: INT64 + connection.received.bytes_total: + valueType: INT64 + connection.sent.bytes: + valueType: INT64 + connection.sent.bytes_total: + valueType: INT64 + connection.duration: + valueType: DURATION + connection.mtls: + valueType: BOOL + connection.requested_server_name: + valueType: STRING + context.protocol: + valueType: STRING + context.proxy_error_code: + valueType: STRING + context.timestamp: + valueType: TIMESTAMP + context.time: + valueType: TIMESTAMP + # Deprecated, kept for compatibility + context.reporter.local: + valueType: BOOL + context.reporter.kind: + valueType: STRING + context.reporter.uid: + valueType: STRING + api.service: + valueType: STRING + api.version: + valueType: STRING + api.operation: + valueType: STRING + api.protocol: + valueType: STRING + request.auth.principal: + valueType: STRING + request.auth.audiences: + valueType: STRING + request.auth.presenter: + valueType: STRING + request.auth.claims: + valueType: STRING_MAP + request.auth.raw_claims: + valueType: STRING + request.api_key: + valueType: STRING + rbac.permissive.response_code: + valueType: STRING + rbac.permissive.effective_policy_id: + valueType: STRING + check.error_code: + valueType: INT64 + check.error_message: + valueType: STRING + check.cache_hit: + valueType: BOOL + quota.cache_hit: + valueType: BOOL + context.proxy_version: + valueType: STRING + +--- +apiVersion: "config.istio.io/v1alpha2" +kind: attributemanifest +metadata: + name: kubernetes + namespace: istio-system + labels: + app: mixer + chart: mixer + heritage: Tiller + release: istio +spec: + attributes: + source.ip: + valueType: IP_ADDRESS + source.labels: + valueType: STRING_MAP + source.metadata: + valueType: STRING_MAP + source.name: + valueType: STRING + source.namespace: + valueType: STRING + source.owner: + valueType: STRING + source.serviceAccount: + valueType: STRING + source.services: + valueType: STRING + source.workload.uid: + valueType: STRING + source.workload.name: + valueType: STRING + source.workload.namespace: + valueType: STRING + destination.ip: + valueType: IP_ADDRESS + destination.labels: + valueType: STRING_MAP + destination.metadata: + valueType: STRING_MAP + destination.owner: + valueType: STRING + destination.name: + valueType: STRING + destination.container.name: + valueType: STRING + destination.namespace: + valueType: STRING + destination.service.uid: + valueType: STRING + destination.service.name: + valueType: STRING + destination.service.namespace: + valueType: STRING + destination.service.host: + valueType: STRING + destination.serviceAccount: + valueType: STRING + destination.workload.uid: + valueType: STRING + destination.workload.name: + valueType: STRING + destination.workload.namespace: + valueType: STRING +--- +apiVersion: "config.istio.io/v1alpha2" +kind: handler +metadata: + name: stdio + namespace: istio-system + labels: + app: mixer + chart: mixer + heritage: Tiller + release: istio +spec: + compiledAdapter: stdio + params: + outputAsJson: true +--- +apiVersion: "config.istio.io/v1alpha2" +kind: instance +metadata: + name: accesslog + namespace: istio-system + labels: + app: mixer + chart: mixer + heritage: Tiller + release: istio +spec: + compiledTemplate: logentry + params: + severity: '"Info"' + timestamp: request.time + variables: + sourceIp: source.ip | ip("0.0.0.0") + sourceApp: source.labels["app"] | "" + sourcePrincipal: source.principal | "" + sourceName: source.name | "" + sourceWorkload: source.workload.name | "" + sourceNamespace: source.namespace | "" + sourceOwner: source.owner | "" + destinationApp: destination.labels["app"] | "" + destinationIp: destination.ip | ip("0.0.0.0") + destinationServiceHost: destination.service.host | request.host | "" + destinationWorkload: destination.workload.name | "" + destinationName: destination.name | "" + destinationNamespace: destination.namespace | "" + destinationOwner: destination.owner | "" + destinationPrincipal: destination.principal | "" + apiClaims: request.auth.raw_claims | "" + apiKey: request.api_key | request.headers["x-api-key"] | "" + protocol: request.scheme | context.protocol | "http" + method: request.method | "" + url: request.path | "" + responseCode: response.code | 0 + responseFlags: context.proxy_error_code | "" + responseSize: response.size | 0 + permissiveResponseCode: rbac.permissive.response_code | "none" + permissiveResponsePolicyID: rbac.permissive.effective_policy_id | "none" + requestSize: request.size | 0 + requestId: request.headers["x-request-id"] | "" + clientTraceId: request.headers["x-client-trace-id"] | "" + latency: response.duration | "0ms" + connection_security_policy: conditional((context.reporter.kind | "inbound") == "outbound", "unknown", conditional(connection.mtls | false, "mutual_tls", "none")) + requestedServerName: connection.requested_server_name | "" + userAgent: request.useragent | "" + responseTimestamp: response.time + receivedBytes: request.total_size | 0 + sentBytes: response.total_size | 0 + referer: request.referer | "" + httpAuthority: request.headers[":authority"] | request.host | "" + xForwardedFor: request.headers["x-forwarded-for"] | "0.0.0.0" + reporter: conditional((context.reporter.kind | "inbound") == "outbound", "source", "destination") + grpcStatus: response.grpc_status | "" + grpcMessage: response.grpc_message | "" + monitored_resource_type: '"global"' +--- +apiVersion: "config.istio.io/v1alpha2" +kind: instance +metadata: + name: tcpaccesslog + namespace: istio-system + labels: + app: mixer + chart: mixer + heritage: Tiller + release: istio +spec: + compiledTemplate: logentry + params: + severity: '"Info"' + timestamp: context.time | timestamp("2017-01-01T00:00:00Z") + variables: + connectionEvent: connection.event | "" + sourceIp: source.ip | ip("0.0.0.0") + sourceApp: source.labels["app"] | "" + sourcePrincipal: source.principal | "" + sourceName: source.name | "" + sourceWorkload: source.workload.name | "" + sourceNamespace: source.namespace | "" + sourceOwner: source.owner | "" + destinationApp: destination.labels["app"] | "" + destinationIp: destination.ip | ip("0.0.0.0") + destinationServiceHost: destination.service.host | "" + destinationWorkload: destination.workload.name | "" + destinationName: destination.name | "" + destinationNamespace: destination.namespace | "" + destinationOwner: destination.owner | "" + destinationPrincipal: destination.principal | "" + protocol: context.protocol | "tcp" + connectionDuration: connection.duration | "0ms" + connection_security_policy: conditional((context.reporter.kind | "inbound") == "outbound", "unknown", conditional(connection.mtls | false, "mutual_tls", "none")) + requestedServerName: connection.requested_server_name | "" + receivedBytes: connection.received.bytes | 0 + sentBytes: connection.sent.bytes | 0 + totalReceivedBytes: connection.received.bytes_total | 0 + totalSentBytes: connection.sent.bytes_total | 0 + reporter: conditional((context.reporter.kind | "inbound") == "outbound", "source", "destination") + responseFlags: context.proxy_error_code | "" + monitored_resource_type: '"global"' +--- +apiVersion: "config.istio.io/v1alpha2" +kind: rule +metadata: + name: stdio + namespace: istio-system + labels: + app: mixer + chart: mixer + heritage: Tiller + release: istio +spec: + match: context.protocol == "http" || context.protocol == "grpc" + actions: + - handler: stdio + instances: + - accesslog +--- +apiVersion: "config.istio.io/v1alpha2" +kind: rule +metadata: + name: stdiotcp + namespace: istio-system + labels: + app: mixer + chart: mixer + heritage: Tiller + release: istio +spec: + match: context.protocol == "tcp" + actions: + - handler: stdio + instances: + - tcpaccesslog +--- +apiVersion: "config.istio.io/v1alpha2" +kind: instance +metadata: + name: requestcount + namespace: istio-system + labels: + app: mixer + chart: mixer + heritage: Tiller + release: istio +spec: + compiledTemplate: metric + params: + value: "1" + dimensions: + reporter: conditional((context.reporter.kind | "inbound") == "outbound", "source", "destination") + source_workload: source.workload.name | "unknown" + source_workload_namespace: source.workload.namespace | "unknown" + source_principal: source.principal | "unknown" + source_app: source.labels["app"] | "unknown" + source_version: source.labels["version"] | "unknown" + destination_workload: destination.workload.name | "unknown" + destination_workload_namespace: destination.workload.namespace | "unknown" + destination_principal: destination.principal | "unknown" + destination_app: destination.labels["app"] | "unknown" + destination_version: destination.labels["version"] | "unknown" + destination_service: destination.service.host | request.host | "unknown" + destination_service_name: destination.service.name | "unknown" + destination_service_namespace: destination.service.namespace | "unknown" + request_protocol: api.protocol | context.protocol | "unknown" + response_code: response.code | 200 + response_flags: context.proxy_error_code | "-" + permissive_response_code: rbac.permissive.response_code | "none" + permissive_response_policyid: rbac.permissive.effective_policy_id | "none" + connection_security_policy: conditional((context.reporter.kind | "inbound") == "outbound", "unknown", conditional(connection.mtls | false, "mutual_tls", "none")) + monitored_resource_type: '"UNSPECIFIED"' +--- +apiVersion: "config.istio.io/v1alpha2" +kind: instance +metadata: + name: requestduration + namespace: istio-system + labels: + app: mixer + chart: mixer + heritage: Tiller + release: istio +spec: + compiledTemplate: metric + params: + value: response.duration | "0ms" + dimensions: + reporter: conditional((context.reporter.kind | "inbound") == "outbound", "source", "destination") + source_workload: source.workload.name | "unknown" + source_workload_namespace: source.workload.namespace | "unknown" + source_principal: source.principal | "unknown" + source_app: source.labels["app"] | "unknown" + source_version: source.labels["version"] | "unknown" + destination_workload: destination.workload.name | "unknown" + destination_workload_namespace: destination.workload.namespace | "unknown" + destination_principal: destination.principal | "unknown" + destination_app: destination.labels["app"] | "unknown" + destination_version: destination.labels["version"] | "unknown" + destination_service: destination.service.host | request.host | "unknown" + destination_service_name: destination.service.name | "unknown" + destination_service_namespace: destination.service.namespace | "unknown" + request_protocol: api.protocol | context.protocol | "unknown" + response_code: response.code | 200 + response_flags: context.proxy_error_code | "-" + permissive_response_code: rbac.permissive.response_code | "none" + permissive_response_policyid: rbac.permissive.effective_policy_id | "none" + connection_security_policy: conditional((context.reporter.kind | "inbound") == "outbound", "unknown", conditional(connection.mtls | false, "mutual_tls", "none")) + monitored_resource_type: '"UNSPECIFIED"' +--- +apiVersion: "config.istio.io/v1alpha2" +kind: instance +metadata: + name: requestsize + namespace: istio-system + labels: + app: mixer + chart: mixer + heritage: Tiller + release: istio +spec: + compiledTemplate: metric + params: + value: request.size | 0 + dimensions: + reporter: conditional((context.reporter.kind | "inbound") == "outbound", "source", "destination") + source_workload: source.workload.name | "unknown" + source_workload_namespace: source.workload.namespace | "unknown" + source_principal: source.principal | "unknown" + source_app: source.labels["app"] | "unknown" + source_version: source.labels["version"] | "unknown" + destination_workload: destination.workload.name | "unknown" + destination_workload_namespace: destination.workload.namespace | "unknown" + destination_principal: destination.principal | "unknown" + destination_app: destination.labels["app"] | "unknown" + destination_version: destination.labels["version"] | "unknown" + destination_service: destination.service.host | request.host | "unknown" + destination_service_name: destination.service.name | "unknown" + destination_service_namespace: destination.service.namespace | "unknown" + request_protocol: api.protocol | context.protocol | "unknown" + response_code: response.code | 200 + response_flags: context.proxy_error_code | "-" + permissive_response_code: rbac.permissive.response_code | "none" + permissive_response_policyid: rbac.permissive.effective_policy_id | "none" + connection_security_policy: conditional((context.reporter.kind | "inbound") == "outbound", "unknown", conditional(connection.mtls | false, "mutual_tls", "none")) + monitored_resource_type: '"UNSPECIFIED"' +--- +apiVersion: "config.istio.io/v1alpha2" +kind: instance +metadata: + name: responsesize + namespace: istio-system + labels: + app: mixer + chart: mixer + heritage: Tiller + release: istio +spec: + compiledTemplate: metric + params: + value: response.size | 0 + dimensions: + reporter: conditional((context.reporter.kind | "inbound") == "outbound", "source", "destination") + source_workload: source.workload.name | "unknown" + source_workload_namespace: source.workload.namespace | "unknown" + source_principal: source.principal | "unknown" + source_app: source.labels["app"] | "unknown" + source_version: source.labels["version"] | "unknown" + destination_workload: destination.workload.name | "unknown" + destination_workload_namespace: destination.workload.namespace | "unknown" + destination_principal: destination.principal | "unknown" + destination_app: destination.labels["app"] | "unknown" + destination_version: destination.labels["version"] | "unknown" + destination_service: destination.service.host | request.host | "unknown" + destination_service_name: destination.service.name | "unknown" + destination_service_namespace: destination.service.namespace | "unknown" + request_protocol: api.protocol | context.protocol | "unknown" + response_code: response.code | 200 + response_flags: context.proxy_error_code | "-" + permissive_response_code: rbac.permissive.response_code | "none" + permissive_response_policyid: rbac.permissive.effective_policy_id | "none" + connection_security_policy: conditional((context.reporter.kind | "inbound") == "outbound", "unknown", conditional(connection.mtls | false, "mutual_tls", "none")) + monitored_resource_type: '"UNSPECIFIED"' +--- +apiVersion: "config.istio.io/v1alpha2" +kind: instance +metadata: + name: tcpbytesent + namespace: istio-system + labels: + app: mixer + chart: mixer + heritage: Tiller + release: istio +spec: + compiledTemplate: metric + params: + value: connection.sent.bytes | 0 + dimensions: + reporter: conditional((context.reporter.kind | "inbound") == "outbound", "source", "destination") + source_workload: source.workload.name | "unknown" + source_workload_namespace: source.workload.namespace | "unknown" + source_principal: source.principal | "unknown" + source_app: source.labels["app"] | "unknown" + source_version: source.labels["version"] | "unknown" + destination_workload: destination.workload.name | "unknown" + destination_workload_namespace: destination.workload.namespace | "unknown" + destination_principal: destination.principal | "unknown" + destination_app: destination.labels["app"] | "unknown" + destination_version: destination.labels["version"] | "unknown" + destination_service: destination.service.host | "unknown" + destination_service_name: destination.service.name | "unknown" + destination_service_namespace: destination.service.namespace | "unknown" + connection_security_policy: conditional((context.reporter.kind | "inbound") == "outbound", "unknown", conditional(connection.mtls | false, "mutual_tls", "none")) + response_flags: context.proxy_error_code | "-" + monitored_resource_type: '"UNSPECIFIED"' +--- +apiVersion: "config.istio.io/v1alpha2" +kind: instance +metadata: + name: tcpbytereceived + namespace: istio-system + labels: + app: mixer + chart: mixer + heritage: Tiller + release: istio +spec: + compiledTemplate: metric + params: + value: connection.received.bytes | 0 + dimensions: + reporter: conditional((context.reporter.kind | "inbound") == "outbound", "source", "destination") + source_workload: source.workload.name | "unknown" + source_workload_namespace: source.workload.namespace | "unknown" + source_principal: source.principal | "unknown" + source_app: source.labels["app"] | "unknown" + source_version: source.labels["version"] | "unknown" + destination_workload: destination.workload.name | "unknown" + destination_workload_namespace: destination.workload.namespace | "unknown" + destination_principal: destination.principal | "unknown" + destination_app: destination.labels["app"] | "unknown" + destination_version: destination.labels["version"] | "unknown" + destination_service: destination.service.host | "unknown" + destination_service_name: destination.service.name | "unknown" + destination_service_namespace: destination.service.namespace | "unknown" + connection_security_policy: conditional((context.reporter.kind | "inbound") == "outbound", "unknown", conditional(connection.mtls | false, "mutual_tls", "none")) + response_flags: context.proxy_error_code | "-" + monitored_resource_type: '"UNSPECIFIED"' +--- +apiVersion: "config.istio.io/v1alpha2" +kind: instance +metadata: + name: tcpconnectionsopened + namespace: istio-system + labels: + app: mixer + chart: mixer + heritage: Tiller + release: istio +spec: + compiledTemplate: metric + params: + value: "1" + dimensions: + reporter: conditional((context.reporter.kind | "inbound") == "outbound", "source", "destination") + source_workload: source.workload.name | "unknown" + source_workload_namespace: source.workload.namespace | "unknown" + source_principal: source.principal | "unknown" + source_app: source.labels["app"] | "unknown" + source_version: source.labels["version"] | "unknown" + destination_workload: destination.workload.name | "unknown" + destination_workload_namespace: destination.workload.namespace | "unknown" + destination_principal: destination.principal | "unknown" + destination_app: destination.labels["app"] | "unknown" + destination_version: destination.labels["version"] | "unknown" + destination_service: destination.service.host | "unknown" + destination_service_name: destination.service.name | "unknown" + destination_service_namespace: destination.service.namespace | "unknown" + connection_security_policy: conditional((context.reporter.kind | "inbound") == "outbound", "unknown", conditional(connection.mtls | false, "mutual_tls", "none")) + response_flags: context.proxy_error_code | "-" + monitored_resource_type: '"UNSPECIFIED"' +--- +apiVersion: "config.istio.io/v1alpha2" +kind: instance +metadata: + name: tcpconnectionsclosed + namespace: istio-system + labels: + app: mixer + chart: mixer + heritage: Tiller + release: istio +spec: + compiledTemplate: metric + params: + value: "1" + dimensions: + reporter: conditional((context.reporter.kind | "inbound") == "outbound", "source", "destination") + source_workload: source.workload.name | "unknown" + source_workload_namespace: source.workload.namespace | "unknown" + source_principal: source.principal | "unknown" + source_app: source.labels["app"] | "unknown" + source_version: source.labels["version"] | "unknown" + destination_workload: destination.workload.name | "unknown" + destination_workload_namespace: destination.workload.namespace | "unknown" + destination_principal: destination.principal | "unknown" + destination_app: destination.labels["app"] | "unknown" + destination_version: destination.labels["version"] | "unknown" + destination_service: destination.service.host | "unknown" + destination_service_name: destination.service.name | "unknown" + destination_service_namespace: destination.service.namespace | "unknown" + connection_security_policy: conditional((context.reporter.kind | "inbound") == "outbound", "unknown", conditional(connection.mtls | false, "mutual_tls", "none")) + response_flags: context.proxy_error_code | "-" + monitored_resource_type: '"UNSPECIFIED"' +--- +apiVersion: "config.istio.io/v1alpha2" +kind: handler +metadata: + name: prometheus + namespace: istio-system + labels: + app: mixer + chart: mixer + heritage: Tiller + release: istio +spec: + compiledAdapter: prometheus + params: + metricsExpirationPolicy: + metricsExpiryDuration: "10m" + metrics: + - name: requests_total + instance_name: requestcount.instance.istio-system + kind: COUNTER + label_names: + - reporter + - source_app + - source_principal + - source_workload + - source_workload_namespace + - source_version + - destination_app + - destination_principal + - destination_workload + - destination_workload_namespace + - destination_version + - destination_service + - destination_service_name + - destination_service_namespace + - request_protocol + - response_code + - response_flags + - permissive_response_code + - permissive_response_policyid + - connection_security_policy + - name: request_duration_seconds + instance_name: requestduration.instance.istio-system + kind: DISTRIBUTION + label_names: + - reporter + - source_app + - source_principal + - source_workload + - source_workload_namespace + - source_version + - destination_app + - destination_principal + - destination_workload + - destination_workload_namespace + - destination_version + - destination_service + - destination_service_name + - destination_service_namespace + - request_protocol + - response_code + - response_flags + - permissive_response_code + - permissive_response_policyid + - connection_security_policy + buckets: + explicit_buckets: + bounds: [0.005, 0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 1, 2.5, 5, 10] + - name: request_bytes + instance_name: requestsize.instance.istio-system + kind: DISTRIBUTION + label_names: + - reporter + - source_app + - source_principal + - source_workload + - source_workload_namespace + - source_version + - destination_app + - destination_principal + - destination_workload + - destination_workload_namespace + - destination_version + - destination_service + - destination_service_name + - destination_service_namespace + - request_protocol + - response_code + - response_flags + - permissive_response_code + - permissive_response_policyid + - connection_security_policy + buckets: + exponentialBuckets: + numFiniteBuckets: 8 + scale: 1 + growthFactor: 10 + - name: response_bytes + instance_name: responsesize.instance.istio-system + kind: DISTRIBUTION + label_names: + - reporter + - source_app + - source_principal + - source_workload + - source_workload_namespace + - source_version + - destination_app + - destination_principal + - destination_workload + - destination_workload_namespace + - destination_version + - destination_service + - destination_service_name + - destination_service_namespace + - request_protocol + - response_code + - response_flags + - permissive_response_code + - permissive_response_policyid + - connection_security_policy + buckets: + exponentialBuckets: + numFiniteBuckets: 8 + scale: 1 + growthFactor: 10 + - name: tcp_sent_bytes_total + instance_name: tcpbytesent.instance.istio-system + kind: COUNTER + label_names: + - reporter + - source_app + - source_principal + - source_workload + - source_workload_namespace + - source_version + - destination_app + - destination_principal + - destination_workload + - destination_workload_namespace + - destination_version + - destination_service + - destination_service_name + - destination_service_namespace + - connection_security_policy + - response_flags + - name: tcp_received_bytes_total + instance_name: tcpbytereceived.instance.istio-system + kind: COUNTER + label_names: + - reporter + - source_app + - source_principal + - source_workload + - source_workload_namespace + - source_version + - destination_app + - destination_principal + - destination_workload + - destination_workload_namespace + - destination_version + - destination_service + - destination_service_name + - destination_service_namespace + - connection_security_policy + - response_flags + - name: tcp_connections_opened_total + instance_name: tcpconnectionsopened.instance.istio-system + kind: COUNTER + label_names: + - reporter + - source_app + - source_principal + - source_workload + - source_workload_namespace + - source_version + - destination_app + - destination_principal + - destination_workload + - destination_workload_namespace + - destination_version + - destination_service + - destination_service_name + - destination_service_namespace + - connection_security_policy + - response_flags + - name: tcp_connections_closed_total + instance_name: tcpconnectionsclosed.instance.istio-system + kind: COUNTER + label_names: + - reporter + - source_app + - source_principal + - source_workload + - source_workload_namespace + - source_version + - destination_app + - destination_principal + - destination_workload + - destination_workload_namespace + - destination_version + - destination_service + - destination_service_name + - destination_service_namespace + - connection_security_policy + - response_flags +--- +apiVersion: "config.istio.io/v1alpha2" +kind: rule +metadata: + name: promhttp + namespace: istio-system + labels: + app: mixer + chart: mixer + heritage: Tiller + release: istio +spec: + match: (context.protocol == "http" || context.protocol == "grpc") && (match((request.useragent | "-"), "kube-probe*") == false) && (match((request.useragent | "-"), "Prometheus*") == false) + actions: + - handler: prometheus + instances: + - requestcount + - requestduration + - requestsize + - responsesize +--- +apiVersion: "config.istio.io/v1alpha2" +kind: rule +metadata: + name: promtcp + namespace: istio-system + labels: + app: mixer + chart: mixer + heritage: Tiller + release: istio +spec: + match: context.protocol == "tcp" + actions: + - handler: prometheus + instances: + - tcpbytesent + - tcpbytereceived +--- +apiVersion: "config.istio.io/v1alpha2" +kind: rule +metadata: + name: promtcpconnectionopen + namespace: istio-system + labels: + app: mixer + chart: mixer + heritage: Tiller + release: istio +spec: + match: context.protocol == "tcp" && ((connection.event | "na") == "open") + actions: + - handler: prometheus + instances: + - tcpconnectionsopened +--- +apiVersion: "config.istio.io/v1alpha2" +kind: rule +metadata: + name: promtcpconnectionclosed + namespace: istio-system + labels: + app: mixer + chart: mixer + heritage: Tiller + release: istio +spec: + match: context.protocol == "tcp" && ((connection.event | "na") == "close") + actions: + - handler: prometheus + instances: + - tcpconnectionsclosed +--- +apiVersion: "config.istio.io/v1alpha2" +kind: handler +metadata: + name: kubernetesenv + namespace: istio-system + labels: + app: mixer + chart: mixer + heritage: Tiller + release: istio +spec: + compiledAdapter: kubernetesenv + params: + # when running from mixer root, use the following config after adding a + # symbolic link to a kubernetes config file via: + # + # $ ln -s ~/.kube/config mixer/adapter/kubernetes/kubeconfig + # + # kubeconfig_path: "mixer/adapter/kubernetes/kubeconfig" + +--- +apiVersion: "config.istio.io/v1alpha2" +kind: rule +metadata: + name: kubeattrgenrulerule + namespace: istio-system + labels: + app: mixer + chart: mixer + heritage: Tiller + release: istio +spec: + actions: + - handler: kubernetesenv + instances: + - attributes +--- +apiVersion: "config.istio.io/v1alpha2" +kind: rule +metadata: + name: tcpkubeattrgenrulerule + namespace: istio-system + labels: + app: mixer + chart: mixer + heritage: Tiller + release: istio +spec: + match: context.protocol == "tcp" + actions: + - handler: kubernetesenv + instances: + - attributes +--- +apiVersion: "config.istio.io/v1alpha2" +kind: instance +metadata: + name: attributes + namespace: istio-system + labels: + app: mixer + chart: mixer + heritage: Tiller + release: istio +spec: + compiledTemplate: kubernetes + params: + # Pass the required attribute data to the adapter + source_uid: source.uid | "" + source_ip: source.ip | ip("0.0.0.0") # default to unspecified ip addr + destination_uid: destination.uid | "" + destination_port: destination.port | 0 + attributeBindings: + # Fill the new attributes from the adapter produced output. + # $out refers to an instance of OutputTemplate message + source.ip: $out.source_pod_ip | ip("0.0.0.0") + source.uid: $out.source_pod_uid | "unknown" + source.labels: $out.source_labels | emptyStringMap() + source.name: $out.source_pod_name | "unknown" + source.namespace: $out.source_namespace | "default" + source.owner: $out.source_owner | "unknown" + source.serviceAccount: $out.source_service_account_name | "unknown" + source.workload.uid: $out.source_workload_uid | "unknown" + source.workload.name: $out.source_workload_name | "unknown" + source.workload.namespace: $out.source_workload_namespace | "unknown" + destination.ip: $out.destination_pod_ip | ip("0.0.0.0") + destination.uid: $out.destination_pod_uid | "unknown" + destination.labels: $out.destination_labels | emptyStringMap() + destination.name: $out.destination_pod_name | "unknown" + destination.container.name: $out.destination_container_name | "unknown" + destination.namespace: $out.destination_namespace | "default" + destination.owner: $out.destination_owner | "unknown" + destination.serviceAccount: $out.destination_service_account_name | "unknown" + destination.workload.uid: $out.destination_workload_uid | "unknown" + destination.workload.name: $out.destination_workload_name | "unknown" + destination.workload.namespace: $out.destination_workload_namespace | "unknown" +--- +# Configuration needed by Mixer. +# Mixer cluster is delivered via CDS +# Specify mixer cluster settings +apiVersion: networking.istio.io/v1alpha3 +kind: DestinationRule +metadata: + name: istio-policy + namespace: istio-system + labels: + app: mixer + chart: mixer + heritage: Tiller + release: istio +spec: + host: istio-policy.istio-system.svc.cluster.local + trafficPolicy: + connectionPool: + http: + http2MaxRequests: 10000 + maxRequestsPerConnection: 10000 +--- +apiVersion: networking.istio.io/v1alpha3 +kind: DestinationRule +metadata: + name: istio-telemetry + namespace: istio-system + labels: + app: mixer + chart: mixer + heritage: Tiller + release: istio +spec: + host: istio-telemetry.istio-system.svc.cluster.local + trafficPolicy: + connectionPool: + http: + http2MaxRequests: 10000 + maxRequestsPerConnection: 10000 +--- + diff --git a/istio-1.3.5/install/kubernetes/mesh-expansion.yaml b/istio-1.3.5/install/kubernetes/mesh-expansion.yaml new file mode 100644 index 0000000..16b95b4 --- /dev/null +++ b/istio-1.3.5/install/kubernetes/mesh-expansion.yaml @@ -0,0 +1,86 @@ +# Currently specific to GKE. Annotations specific to other providers should be added +# after they get tested. +apiVersion: v1 +kind: Service +metadata: + name: istio-pilot-ilb + namespace: istio-system + annotations: + cloud.google.com/load-balancer-type: "internal" + labels: + istio: pilot +spec: + type: LoadBalancer + ports: + - name: https-pilot + port: 15005 + protocol: TCP + - port: 8080 + name: http-pilot + protocol: TCP + - port: 15010 + name: grpc-pilot + protocol: TCP + - port: 15011 + name: tls-grpc-pilot + protocol: TCP + selector: + istio: pilot +--- +apiVersion: v1 +kind: Service +metadata: + name: dns-ilb + namespace: kube-system + annotations: + cloud.google.com/load-balancer-type: "internal" + labels: + k8s-app: kube-dns +spec: + type: LoadBalancer + ports: + - port: 53 + protocol: UDP + selector: + k8s-app: kube-dns + +--- + +apiVersion: v1 +kind: Service +metadata: + name: mixer-ilb + namespace: istio-system + annotations: + cloud.google.com/load-balancer-type: "internal" + labels: + istio: mixer +spec: + type: LoadBalancer + ports: + - port: 15004 + protocol: TCP + selector: + istio: mixer + istio-mixer-type: telemetry + +# This points to istio-telemetry until we are able to support both +# istio-policy and istio-telemetry as separate services for mesh expansion. + +--- +apiVersion: v1 +kind: Service +metadata: + name: citadel-ilb + namespace: istio-system + annotations: + cloud.google.com/load-balancer-type: "internal" + labels: + istio: citadel +spec: + type: LoadBalancer + ports: + - port: 8060 + protocol: TCP + selector: + istio: citadel diff --git a/istio-1.3.5/install/kubernetes/namespace.yaml b/istio-1.3.5/install/kubernetes/namespace.yaml new file mode 100644 index 0000000..96fb18e --- /dev/null +++ b/istio-1.3.5/install/kubernetes/namespace.yaml @@ -0,0 +1,7 @@ +apiVersion: v1 +kind: Namespace +metadata: + name: istio-system + labels: + istio-injection: disabled +--- diff --git a/istio-1.3.5/install/kubernetes/operator/charts/crds/Chart.yaml b/istio-1.3.5/install/kubernetes/operator/charts/crds/Chart.yaml new file mode 100644 index 0000000..190b372 --- /dev/null +++ b/istio-1.3.5/install/kubernetes/operator/charts/crds/Chart.yaml @@ -0,0 +1,11 @@ +apiVersion: v1 +name: istio-crds +version: 1.1.0 +tillerVersion: ">=2.7.2" +description: Helm chart for deploying Istio CRDs +keywords: + - istio +sources: + - http://github.com/istio/istio +engine: gotpl +icon: https://istio.io/favicons/android-192x192.png diff --git a/istio-1.3.5/install/kubernetes/operator/charts/crds/files/crd-10.yaml b/istio-1.3.5/install/kubernetes/operator/charts/crds/files/crd-10.yaml new file mode 100644 index 0000000..b44dbfb --- /dev/null +++ b/istio-1.3.5/install/kubernetes/operator/charts/crds/files/crd-10.yaml @@ -0,0 +1,594 @@ +apiVersion: apiextensions.k8s.io/v1beta1 +kind: CustomResourceDefinition +metadata: + name: virtualservices.networking.istio.io + labels: + app: istio-pilot + chart: istio + heritage: Tiller + release: istio +spec: + group: networking.istio.io + names: + kind: VirtualService + listKind: VirtualServiceList + plural: virtualservices + singular: virtualservice + shortNames: + - vs + categories: + - istio-io + - networking-istio-io + scope: Namespaced + versions: + - name: v1alpha3 + served: true + storage: true + additionalPrinterColumns: + - JSONPath: .spec.gateways + description: The names of gateways and sidecars that should apply these routes + name: Gateways + type: string + - JSONPath: .spec.hosts + description: The destination hosts to which traffic is being sent + name: Hosts + type: string + - JSONPath: .metadata.creationTimestamp + description: |- + CreationTimestamp is a timestamp representing the server time when this object was created. It is not guaranteed to be set in happens-before order across separate operations. Clients may not set this value. It is represented in RFC3339 form and is in UTC. + + Populated by the system. Read-only. Null for lists. More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#metadata + name: Age + type: date +--- +apiVersion: apiextensions.k8s.io/v1beta1 +kind: CustomResourceDefinition +metadata: + name: destinationrules.networking.istio.io + labels: + app: istio-pilot + chart: istio + heritage: Tiller + release: istio +spec: + group: networking.istio.io + names: + kind: DestinationRule + listKind: DestinationRuleList + plural: destinationrules + singular: destinationrule + shortNames: + - dr + categories: + - istio-io + - networking-istio-io + scope: Namespaced + versions: + - name: v1alpha3 + served: true + storage: true + additionalPrinterColumns: + - JSONPath: .spec.host + description: The name of a service from the service registry + name: Host + type: string + - JSONPath: .metadata.creationTimestamp + description: |- + CreationTimestamp is a timestamp representing the server time when this object was created. It is not guaranteed to be set in happens-before order across separate operations. Clients may not set this value. It is represented in RFC3339 form and is in UTC. + + Populated by the system. Read-only. Null for lists. More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#metadata + name: Age + type: date +--- +apiVersion: apiextensions.k8s.io/v1beta1 +kind: CustomResourceDefinition +metadata: + name: serviceentries.networking.istio.io + labels: + app: istio-pilot + chart: istio + heritage: Tiller + release: istio +spec: + group: networking.istio.io + names: + kind: ServiceEntry + listKind: ServiceEntryList + plural: serviceentries + singular: serviceentry + shortNames: + - se + categories: + - istio-io + - networking-istio-io + scope: Namespaced + versions: + - name: v1alpha3 + served: true + storage: true + additionalPrinterColumns: + - JSONPath: .spec.hosts + description: The hosts associated with the ServiceEntry + name: Hosts + type: string + - JSONPath: .spec.location + description: Whether the service is external to the mesh or part of the mesh (MESH_EXTERNAL or MESH_INTERNAL) + name: Location + type: string + - JSONPath: .spec.resolution + description: Service discovery mode for the hosts (NONE, STATIC, or DNS) + name: Resolution + type: string + - JSONPath: .metadata.creationTimestamp + description: |- + CreationTimestamp is a timestamp representing the server time when this object was created. It is not guaranteed to be set in happens-before order across separate operations. Clients may not set this value. It is represented in RFC3339 form and is in UTC. + + Populated by the system. Read-only. Null for lists. More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#metadata + name: Age + type: date +--- +apiVersion: apiextensions.k8s.io/v1beta1 +kind: CustomResourceDefinition +metadata: + name: gateways.networking.istio.io + labels: + app: istio-pilot + chart: istio + heritage: Tiller + release: istio +spec: + group: networking.istio.io + names: + kind: Gateway + plural: gateways + singular: gateway + shortNames: + - gw + categories: + - istio-io + - networking-istio-io + scope: Namespaced + versions: + - name: v1alpha3 + served: true + storage: true +--- +apiVersion: apiextensions.k8s.io/v1beta1 +kind: CustomResourceDefinition +metadata: + name: envoyfilters.networking.istio.io + labels: + app: istio-pilot + chart: istio + heritage: Tiller + release: istio +spec: + group: networking.istio.io + names: + kind: EnvoyFilter + plural: envoyfilters + singular: envoyfilter + categories: + - istio-io + - networking-istio-io + scope: Namespaced + versions: + - name: v1alpha3 + served: true + storage: true +--- +kind: CustomResourceDefinition +apiVersion: apiextensions.k8s.io/v1beta1 +metadata: + name: clusterrbacconfigs.rbac.istio.io + labels: + app: istio-pilot + istio: rbac + heritage: Tiller + release: istio +spec: + group: rbac.istio.io + names: + kind: ClusterRbacConfig + plural: clusterrbacconfigs + singular: clusterrbacconfig + categories: + - istio-io + - rbac-istio-io + scope: Cluster + versions: + - name: v1alpha1 + served: true + storage: true +--- +kind: CustomResourceDefinition +apiVersion: apiextensions.k8s.io/v1beta1 +metadata: + name: policies.authentication.istio.io + labels: + app: istio-citadel + chart: istio + heritage: Tiller + release: istio +spec: + group: authentication.istio.io + names: + kind: Policy + plural: policies + singular: policy + categories: + - istio-io + - authentication-istio-io + scope: Namespaced + versions: + - name: v1alpha1 + served: true + storage: true +--- +kind: CustomResourceDefinition +apiVersion: apiextensions.k8s.io/v1beta1 +metadata: + name: meshpolicies.authentication.istio.io + labels: + app: istio-citadel + chart: istio + heritage: Tiller + release: istio +spec: + group: authentication.istio.io + names: + kind: MeshPolicy + listKind: MeshPolicyList + plural: meshpolicies + singular: meshpolicy + categories: + - istio-io + - authentication-istio-io + scope: Cluster + versions: + - name: v1alpha1 + served: true + storage: true +--- +kind: CustomResourceDefinition +apiVersion: apiextensions.k8s.io/v1beta1 +metadata: + name: httpapispecbindings.config.istio.io + labels: + app: istio-mixer + chart: istio + heritage: Tiller + release: istio +spec: + group: config.istio.io + names: + kind: HTTPAPISpecBinding + plural: httpapispecbindings + singular: httpapispecbinding + categories: + - istio-io + - apim-istio-io + scope: Namespaced + versions: + - name: v1alpha2 + served: true + storage: true +--- +kind: CustomResourceDefinition +apiVersion: apiextensions.k8s.io/v1beta1 +metadata: + name: httpapispecs.config.istio.io + labels: + app: istio-mixer + chart: istio + heritage: Tiller + release: istio +spec: + group: config.istio.io + names: + kind: HTTPAPISpec + plural: httpapispecs + singular: httpapispec + categories: + - istio-io + - apim-istio-io + scope: Namespaced + versions: + - name: v1alpha2 + served: true + storage: true +--- +kind: CustomResourceDefinition +apiVersion: apiextensions.k8s.io/v1beta1 +metadata: + name: quotaspecbindings.config.istio.io + labels: + app: istio-mixer + chart: istio + heritage: Tiller + release: istio +spec: + group: config.istio.io + names: + kind: QuotaSpecBinding + plural: quotaspecbindings + singular: quotaspecbinding + categories: + - istio-io + - apim-istio-io + scope: Namespaced + versions: + - name: v1alpha2 + served: true + storage: true +--- +kind: CustomResourceDefinition +apiVersion: apiextensions.k8s.io/v1beta1 +metadata: + name: quotaspecs.config.istio.io + labels: + app: istio-mixer + chart: istio + heritage: Tiller + release: istio +spec: + group: config.istio.io + names: + kind: QuotaSpec + plural: quotaspecs + singular: quotaspec + categories: + - istio-io + - apim-istio-io + scope: Namespaced + versions: + - name: v1alpha2 + served: true + storage: true +--- +kind: CustomResourceDefinition +apiVersion: apiextensions.k8s.io/v1beta1 +metadata: + name: rules.config.istio.io + labels: + app: mixer + package: istio.io.mixer + istio: core + chart: istio + heritage: Tiller + release: istio +spec: + group: config.istio.io + names: + kind: rule + plural: rules + singular: rule + categories: + - istio-io + - policy-istio-io + scope: Namespaced + versions: + - name: v1alpha2 + served: true + storage: true +--- +kind: CustomResourceDefinition +apiVersion: apiextensions.k8s.io/v1beta1 +metadata: + name: attributemanifests.config.istio.io + labels: + app: mixer + package: istio.io.mixer + istio: core + chart: istio + heritage: Tiller + release: istio +spec: + group: config.istio.io + names: + kind: attributemanifest + plural: attributemanifests + singular: attributemanifest + categories: + - istio-io + - policy-istio-io + scope: Namespaced + versions: + - name: v1alpha2 + served: true + storage: true +--- +kind: CustomResourceDefinition +apiVersion: apiextensions.k8s.io/v1beta1 +metadata: + name: rbacconfigs.rbac.istio.io + labels: + app: mixer + package: istio.io.mixer + istio: rbac + chart: istio + heritage: Tiller + release: istio +spec: + group: rbac.istio.io + names: + kind: RbacConfig + plural: rbacconfigs + singular: rbacconfig + categories: + - istio-io + - rbac-istio-io + scope: Namespaced + versions: + - name: v1alpha1 + served: true + storage: true +--- +kind: CustomResourceDefinition +apiVersion: apiextensions.k8s.io/v1beta1 +metadata: + name: serviceroles.rbac.istio.io + labels: + app: mixer + package: istio.io.mixer + istio: rbac + chart: istio + heritage: Tiller + release: istio +spec: + group: rbac.istio.io + names: + kind: ServiceRole + plural: serviceroles + singular: servicerole + categories: + - istio-io + - rbac-istio-io + scope: Namespaced + versions: + - name: v1alpha1 + served: true + storage: true +--- +kind: CustomResourceDefinition +apiVersion: apiextensions.k8s.io/v1beta1 +metadata: + name: servicerolebindings.rbac.istio.io + labels: + app: mixer + package: istio.io.mixer + istio: rbac + chart: istio + heritage: Tiller + release: istio +spec: + group: rbac.istio.io + names: + kind: ServiceRoleBinding + plural: servicerolebindings + singular: servicerolebinding + categories: + - istio-io + - rbac-istio-io + scope: Namespaced + versions: + - name: v1alpha1 + served: true + storage: true + additionalPrinterColumns: + - JSONPath: .spec.roleRef.name + description: The name of the ServiceRole object being referenced + name: Reference + type: string + - JSONPath: .metadata.creationTimestamp + description: |- + CreationTimestamp is a timestamp representing the server time when this object was created. It is not guaranteed to be set in happens-before order across separate operations. Clients may not set this value. It is represented in RFC3339 form and is in UTC. + + Populated by the system. Read-only. Null for lists. More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#metadata + name: Age + type: date +--- +kind: CustomResourceDefinition +apiVersion: apiextensions.k8s.io/v1beta1 +metadata: + name: adapters.config.istio.io + labels: + app: mixer + package: adapter + istio: mixer-adapter + chart: istio + heritage: Tiller + release: istio +spec: + group: config.istio.io + names: + kind: adapter + plural: adapters + singular: adapter + categories: + - istio-io + - policy-istio-io + scope: Namespaced + versions: + - name: v1alpha2 + served: true + storage: true +--- +kind: CustomResourceDefinition +apiVersion: apiextensions.k8s.io/v1beta1 +metadata: + name: instances.config.istio.io + labels: + app: mixer + package: instance + istio: mixer-instance + chart: istio + heritage: Tiller + release: istio +spec: + group: config.istio.io + names: + kind: instance + plural: instances + singular: instance + categories: + - istio-io + - policy-istio-io + scope: Namespaced + versions: + - name: v1alpha2 + served: true + storage: true +--- +kind: CustomResourceDefinition +apiVersion: apiextensions.k8s.io/v1beta1 +metadata: + name: templates.config.istio.io + labels: + app: mixer + package: template + istio: mixer-template + chart: istio + heritage: Tiller + release: istio +spec: + group: config.istio.io + names: + kind: template + plural: templates + singular: template + categories: + - istio-io + - policy-istio-io + scope: Namespaced + versions: + - name: v1alpha2 + served: true + storage: true +--- +kind: CustomResourceDefinition +apiVersion: apiextensions.k8s.io/v1beta1 +metadata: + name: handlers.config.istio.io + labels: + app: mixer + package: handler + istio: mixer-handler + chart: istio + heritage: Tiller + release: istio +spec: + group: config.istio.io + names: + kind: handler + plural: handlers + singular: handler + categories: + - istio-io + - policy-istio-io + scope: Namespaced + versions: + - name: v1alpha2 + served: true + storage: true +--- diff --git a/istio-1.3.5/install/kubernetes/operator/charts/crds/files/crd-11.yaml b/istio-1.3.5/install/kubernetes/operator/charts/crds/files/crd-11.yaml new file mode 100644 index 0000000..40008fb --- /dev/null +++ b/istio-1.3.5/install/kubernetes/operator/charts/crds/files/crd-11.yaml @@ -0,0 +1,24 @@ +apiVersion: apiextensions.k8s.io/v1beta1 +kind: CustomResourceDefinition +metadata: + name: sidecars.networking.istio.io + labels: + app: istio-pilot + chart: istio + heritage: Tiller + release: istio +spec: + group: networking.istio.io + names: + kind: Sidecar + plural: sidecars + singular: sidecar + categories: + - istio-io + - networking-istio-io + scope: Namespaced + versions: + - name: v1alpha3 + served: true + storage: true +--- diff --git a/istio-1.3.5/install/kubernetes/operator/charts/crds/files/crd-12.yaml b/istio-1.3.5/install/kubernetes/operator/charts/crds/files/crd-12.yaml new file mode 100644 index 0000000..d9b3372 --- /dev/null +++ b/istio-1.3.5/install/kubernetes/operator/charts/crds/files/crd-12.yaml @@ -0,0 +1,24 @@ +kind: CustomResourceDefinition +apiVersion: apiextensions.k8s.io/v1beta1 +metadata: + name: authorizationpolicies.rbac.istio.io + labels: + app: istio-pilot + istio: rbac + heritage: Tiller + release: istio +spec: + group: rbac.istio.io + names: + kind: AuthorizationPolicy + plural: authorizationpolicies + singular: authorizationpolicy + categories: + - istio-io + - rbac-istio-io + scope: Namespaced + versions: + - name: v1alpha1 + served: true + storage: true +--- diff --git a/istio-1.3.5/install/kubernetes/operator/charts/crds/files/crd-certmanager-10.yaml b/istio-1.3.5/install/kubernetes/operator/charts/crds/files/crd-certmanager-10.yaml new file mode 100644 index 0000000..b4fdf1d --- /dev/null +++ b/istio-1.3.5/install/kubernetes/operator/charts/crds/files/crd-certmanager-10.yaml @@ -0,0 +1,85 @@ +apiVersion: apiextensions.k8s.io/v1beta1 +kind: CustomResourceDefinition +metadata: + name: clusterissuers.certmanager.k8s.io + labels: + app: certmanager + chart: certmanager + heritage: Tiller + release: istio +spec: + group: certmanager.k8s.io + versions: + - name: v1alpha1 + served: true + storage: true + names: + kind: ClusterIssuer + plural: clusterissuers + scope: Cluster +--- +apiVersion: apiextensions.k8s.io/v1beta1 +kind: CustomResourceDefinition +metadata: + name: issuers.certmanager.k8s.io + labels: + app: certmanager + chart: certmanager + heritage: Tiller + release: istio +spec: + group: certmanager.k8s.io + versions: + - name: v1alpha1 + served: true + storage: true + names: + kind: Issuer + plural: issuers + scope: Namespaced +--- +apiVersion: apiextensions.k8s.io/v1beta1 +kind: CustomResourceDefinition +metadata: + name: certificates.certmanager.k8s.io + labels: + app: certmanager + chart: certmanager + heritage: Tiller + release: istio +spec: + additionalPrinterColumns: + - JSONPath: .status.conditions[?(@.type=="Ready")].status + name: Ready + type: string + - JSONPath: .spec.secretName + name: Secret + type: string + - JSONPath: .spec.issuerRef.name + name: Issuer + type: string + priority: 1 + - JSONPath: .status.conditions[?(@.type=="Ready")].message + name: Status + type: string + priority: 1 + - JSONPath: .metadata.creationTimestamp + description: |- + CreationTimestamp is a timestamp representing the server time when this object was created. It is not guaranteed to be set in happens-before order across separate operations. Clients may not set this value. It is represented in RFC3339 form and is in UTC. + + Populated by the system. Read-only. Null for lists. More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#metadata + name: Age + type: date + group: certmanager.k8s.io + versions: + - name: v1alpha1 + served: true + storage: true + scope: Namespaced + names: + kind: Certificate + plural: certificates + shortNames: + - cert + - certs +--- diff --git a/istio-1.3.5/install/kubernetes/operator/charts/crds/files/crd-certmanager-11.yaml b/istio-1.3.5/install/kubernetes/operator/charts/crds/files/crd-certmanager-11.yaml new file mode 100644 index 0000000..2d7438d --- /dev/null +++ b/istio-1.3.5/install/kubernetes/operator/charts/crds/files/crd-certmanager-11.yaml @@ -0,0 +1,76 @@ +apiVersion: apiextensions.k8s.io/v1beta1 +kind: CustomResourceDefinition +metadata: + name: orders.certmanager.k8s.io + labels: + app: certmanager + chart: certmanager + heritage: Tiller + release: istio +spec: + additionalPrinterColumns: + - JSONPath: .status.state + name: State + type: string + - JSONPath: .spec.issuerRef.name + name: Issuer + type: string + priority: 1 + - JSONPath: .status.reason + name: Reason + type: string + priority: 1 + - JSONPath: .metadata.creationTimestamp + description: |- + CreationTimestamp is a timestamp representing the server time when this object was created. It is not guaranteed to be set in happens-before order across separate operations. Clients may not set this value. It is represented in RFC3339 form and is in UTC. + + Populated by the system. Read-only. Null for lists. More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#metadata + name: Age + type: date + group: certmanager.k8s.io + versions: + - name: v1alpha1 + served: true + storage: true + names: + kind: Order + plural: orders + scope: Namespaced +--- +apiVersion: apiextensions.k8s.io/v1beta1 +kind: CustomResourceDefinition +metadata: + name: challenges.certmanager.k8s.io + labels: + app: certmanager + chart: certmanager + heritage: Tiller + release: istio +spec: + additionalPrinterColumns: + - JSONPath: .status.state + name: State + type: string + - JSONPath: .spec.dnsName + name: Domain + type: string + - JSONPath: .status.reason + name: Reason + type: string + - JSONPath: .metadata.creationTimestamp + description: |- + CreationTimestamp is a timestamp representing the server time when this object was created. It is not guaranteed to be set in happens-before order across separate operations. Clients may not set this value. It is represented in RFC3339 form and is in UTC. + + Populated by the system. Read-only. Null for lists. More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#metadata + name: Age + type: date + group: certmanager.k8s.io + versions: + - name: v1alpha1 + served: true + storage: true + names: + kind: Challenge + plural: challenges + scope: Namespaced +--- diff --git a/istio-1.3.5/install/kubernetes/operator/charts/crds/kustomization.yaml b/istio-1.3.5/install/kubernetes/operator/charts/crds/kustomization.yaml new file mode 100644 index 0000000..608171c --- /dev/null +++ b/istio-1.3.5/install/kubernetes/operator/charts/crds/kustomization.yaml @@ -0,0 +1,9 @@ +apiVersion: kustomize.config.k8s.io/v1beta1 +kind: Kustomization + +resources: + - files/crd-10.yaml + - files/crd-11.yaml + - files/crd-12.yaml + - files/crd-certmanager-10.yaml + - files/crd-certmanager-11.yaml diff --git a/istio-1.3.5/install/kubernetes/operator/charts/crds/templates/crds.yaml b/istio-1.3.5/install/kubernetes/operator/charts/crds/templates/crds.yaml new file mode 100644 index 0000000..c715e68 --- /dev/null +++ b/istio-1.3.5/install/kubernetes/operator/charts/crds/templates/crds.yaml @@ -0,0 +1,9 @@ +{{ .Files.Get "files/crd-10.yaml" }} +{{ .Files.Get "files/crd-11.yaml" }} +{{ .Files.Get "files/crd-12.yaml" }} +{{- if .Values.certmanager }} +{{- if .Values.certmanager.enabled }} +{{ .Files.Get "files/crd-certmanager-10.yaml" }} +{{ .Files.Get "files/crd-certmanager-11.yaml" }} +{{- end }} +{{- end }} diff --git a/istio-1.3.5/install/kubernetes/operator/charts/crds/templates/namespaces.yaml b/istio-1.3.5/install/kubernetes/operator/charts/crds/templates/namespaces.yaml new file mode 100644 index 0000000..65759a6 --- /dev/null +++ b/istio-1.3.5/install/kubernetes/operator/charts/crds/templates/namespaces.yaml @@ -0,0 +1,64 @@ +# To prevent accidental injection into istio control plane namespaces. +apiVersion: v1 +kind: Namespace +metadata: + name: {{ .Release.Namespace }} + labels: + istio-operator-managed: Reconcile + istio-injection: disabled +--- + +{{- if ne .Values.global.istioNamespace .Release.Namespace }} +apiVersion: v1 +kind: Namespace +metadata: + name: {{ .Values.global.istioNamespace }} + labels: + istio-operator-managed: Reconcile + istio-injection: disabled +--- +{{- end }} + +{{- if and (ne .Values.global.configNamespace .Release.Namespace) (ne .Values.global.configNamespace .Values.global.istioNamespace) }} +apiVersion: v1 +kind: Namespace +metadata: + name: {{ .Values.global.configNamespace }} + labels: + istio-operator-managed: Reconcile + istio-injection: disabled +--- +{{- end }} + +{{- if ne .Values.global.telemetryNamespace .Release.Namespace }} +apiVersion: v1 +kind: Namespace +metadata: + name: {{ .Values.global.telemetryNamespace }} + labels: + istio-operator-managed: Reconcile + istio-injection: disabled +--- +{{- end }} + +{{- if and (ne .Values.global.prometheusNamespace .Release.Namespace) (ne .Values.global.prometheusNamespace .Values.global.telemetryNamespace) }} +apiVersion: v1 +kind: Namespace +metadata: + name: {{ .Values.global.prometheusNamespace }} + labels: + istio-operator-managed: Reconcile + istio-injection: disabled +--- +{{- end }} + +{{- if ne .Values.global.policyNamespace .Release.Namespace }} +apiVersion: v1 +kind: Namespace +metadata: + name: {{ .Values.global.policyNamespace }} + labels: + istio-operator-managed: Reconcile + istio-injection: disabled +--- +{{- end }} diff --git a/istio-1.3.5/install/kubernetes/operator/charts/gateways/istio-egress/Chart.yaml b/istio-1.3.5/install/kubernetes/operator/charts/gateways/istio-egress/Chart.yaml new file mode 100644 index 0000000..f6c62e5 --- /dev/null +++ b/istio-1.3.5/install/kubernetes/operator/charts/gateways/istio-egress/Chart.yaml @@ -0,0 +1,13 @@ +apiVersion: v1 +name: istio-egress +version: 1.1.0 +tillerVersion: ">=2.7.2" +description: Helm chart for deploying Istio gateways +keywords: + - istio + - egressgateway + - gateways +sources: + - http://github.com/istio/istio +engine: gotpl +icon: https://istio.io/favicons/android-192x192.png diff --git a/istio-1.3.5/install/kubernetes/operator/charts/gateways/istio-egress/NOTES.txt b/istio-1.3.5/install/kubernetes/operator/charts/gateways/istio-egress/NOTES.txt new file mode 100644 index 0000000..9baacc0 --- /dev/null +++ b/istio-1.3.5/install/kubernetes/operator/charts/gateways/istio-egress/NOTES.txt @@ -0,0 +1,45 @@ + +Changes: +- separate namespace allows: +-- easier reconfig of just the gateway +-- TLS secrets and domain name management is isolated, for better security +-- simplified configuration +-- multiple versions of the ingress can be used, to minize upgrade risks + +- the new chart uses the default namespace service account, and doesn't require +additional RBAC permissions. + +- simplified label structure. Label change is not supported on upgrade. + +- for 'internal load balancer' you should deploy a separate gateway, in a different +namespace. + +All ingress gateway have a "app:ingressgateway" label, used to identify it as an +ingress, and an "istio: ingressgateway$SUFFIX" label of Gateway selection. + +The Gateways use "istio: ingressgateway$SUFFIX" selectors. + + +# Multiple gateway versions + + + +# Using different pilot versions + + + +# Migration from istio-system + +Istio 1.0 includes the gateways in istio-system. Since the external IP is associated +with the Service and bound to the namespace, it is recommended to: + +1. Install the new gateway in a new namespace. +2. Copy any TLS certificate to the new namespace, and configure the domains. +3. Checking the new gateway work - for example by overriding the IP in /etc/hosts +4. Modify the DNS server to add the A record of the new namespace +5. Check traffic +6. Delete the A record corresponding to the gateway in istio-system +7. Upgrade istio-system, disabling the ingressgateway +8. Delete the domain TLS certs from istio-system. + +If using certmanager, all Certificate and associated configs must be moved as well. diff --git a/istio-1.3.5/install/kubernetes/operator/charts/gateways/istio-egress/templates/_affinity.tpl b/istio-1.3.5/install/kubernetes/operator/charts/gateways/istio-egress/templates/_affinity.tpl new file mode 100644 index 0000000..ce8bac0 --- /dev/null +++ b/istio-1.3.5/install/kubernetes/operator/charts/gateways/istio-egress/templates/_affinity.tpl @@ -0,0 +1,93 @@ +{{/* affinity - https://kubernetes.io/docs/concepts/configuration/assign-pod-node/ */}} + +{{- define "nodeaffinity" }} + nodeAffinity: + requiredDuringSchedulingIgnoredDuringExecution: + {{- include "nodeAffinityRequiredDuringScheduling" . }} + preferredDuringSchedulingIgnoredDuringExecution: + {{- include "nodeAffinityPreferredDuringScheduling" . }} +{{- end }} + +{{- define "nodeAffinityRequiredDuringScheduling" }} + nodeSelectorTerms: + - matchExpressions: + - key: beta.kubernetes.io/arch + operator: In + values: + {{- range $key, $val := .global.arch }} + {{- if gt ($val | int) 0 }} + - {{ $key }} + {{- end }} + {{- end }} + {{- $nodeSelector := default .global.defaultNodeSelector .nodeSelector -}} + {{- range $key, $val := $nodeSelector }} + - key: {{ $key }} + operator: In + values: + - {{ $val }} + {{- end }} +{{- end }} + +{{- define "nodeAffinityPreferredDuringScheduling" }} + {{- range $key, $val := .global.arch }} + {{- if gt ($val | int) 0 }} + - weight: {{ $val | int }} + preference: + matchExpressions: + - key: beta.kubernetes.io/arch + operator: In + values: + - {{ $key }} + {{- end }} + {{- end }} +{{- end }} + +{{- define "podAntiAffinity" }} +{{- if or .podAntiAffinityLabelSelector .podAntiAffinityTermLabelSelector}} + podAntiAffinity: + {{- if .podAntiAffinityLabelSelector }} + requiredDuringSchedulingIgnoredDuringExecution: + {{- include "podAntiAffinityRequiredDuringScheduling" . }} + {{- end }} + {{- if .podAntiAffinityTermLabelSelector }} + preferredDuringSchedulingIgnoredDuringExecution: + {{- include "podAntiAffinityPreferredDuringScheduling" . }} + {{- end }} +{{- end }} +{{- end }} + +{{- define "podAntiAffinityRequiredDuringScheduling" }} + {{- range $index, $item := .podAntiAffinityLabelSelector }} + - labelSelector: + matchExpressions: + - key: {{ $item.key }} + operator: {{ $item.operator }} + {{- if $item.values }} + values: + {{- $vals := split "," $item.values }} + {{- range $i, $v := $vals }} + - {{ $v }} + {{- end }} + {{- end }} + topologyKey: {{ $item.topologyKey }} + {{- end }} +{{- end }} + +{{- define "podAntiAffinityPreferredDuringScheduling" }} + {{- range $index, $item := .podAntiAffinityTermLabelSelector }} + - podAffinityTerm: + labelSelector: + matchExpressions: + - key: {{ $item.key }} + operator: {{ $item.operator }} + {{- if $item.values }} + values: + {{- $vals := split "," $item.values }} + {{- range $i, $v := $vals }} + - {{ $v }} + {{- end }} + {{- end }} + topologyKey: {{ $item.topologyKey }} + weight: 100 + {{- end }} +{{- end }} diff --git a/istio-1.3.5/install/kubernetes/operator/charts/gateways/istio-egress/templates/_helpers.tpl b/istio-1.3.5/install/kubernetes/operator/charts/gateways/istio-egress/templates/_helpers.tpl new file mode 100644 index 0000000..54735a2 --- /dev/null +++ b/istio-1.3.5/install/kubernetes/operator/charts/gateways/istio-egress/templates/_helpers.tpl @@ -0,0 +1,34 @@ +{{/* vim: set filetype=mustache: */}} +{{/* +Expand the name of the chart. +*/}} +{{- define "gateway.name" -}} +{{ $gateway := index .Values "gateways" "istio-egressgateway" }} +{{- default .Chart.Name $gateway.nameOverride | trunc 63 | trimSuffix "-" -}} +{{- end -}} + +{{/* +Create a default fully qualified app name. +We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). +If release name contains chart name it will be used as a full name. +*/}} +{{- define "gateway.fullname" -}} +{{ $gateway := index .Values "gateways" "istio-egressgateway" }} +{{- if $gateway.fullnameOverride -}} +{{- $gateway.fullnameOverride | trunc 63 | trimSuffix "-" -}} +{{- else -}} +{{- $name := default .Chart.Name $gateway.nameOverride -}} +{{- if contains $name .Release.Name -}} +{{- .Release.Name | trunc 63 | trimSuffix "-" -}} +{{- else -}} +{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" -}} +{{- end -}} +{{- end -}} +{{- end -}} + +{{/* +Create chart name and version as used by the chart label. +*/}} +{{- define "gateway.chart" -}} +{{- .Chart.Name | trunc 63 | trimSuffix "-" -}} +{{- end -}} diff --git a/istio-1.3.5/install/kubernetes/operator/charts/gateways/istio-egress/templates/autoscale.yaml b/istio-1.3.5/install/kubernetes/operator/charts/gateways/istio-egress/templates/autoscale.yaml new file mode 100644 index 0000000..caf9793 --- /dev/null +++ b/istio-1.3.5/install/kubernetes/operator/charts/gateways/istio-egress/templates/autoscale.yaml @@ -0,0 +1,24 @@ +{{ $gateway := index .Values "gateways" "istio-egressgateway" }} +{{- if and $gateway.autoscaleEnabled $gateway.autoscaleMin $gateway.autoscaleMax }} +apiVersion: autoscaling/v2beta1 +kind: HorizontalPodAutoscaler +metadata: + name: egressgateway + namespace: {{ .Release.Namespace }} + labels: + app: istio-egressgateway + release: {{ .Release.Name }} +spec: + maxReplicas: {{ $gateway.autoscaleMax }} + minReplicas: {{ $gateway.autoscaleMin }} + scaleTargetRef: + apiVersion: apps/v1 + kind: Deployment + name: istio-egressgateway + metrics: + - type: Resource + resource: + name: cpu + targetAverageUtilization: {{ $gateway.cpu.targetAverageUtilization }} +--- +{{- end }} diff --git a/istio-1.3.5/install/kubernetes/operator/charts/gateways/istio-egress/templates/deployment.yaml b/istio-1.3.5/install/kubernetes/operator/charts/gateways/istio-egress/templates/deployment.yaml new file mode 100644 index 0000000..3388144 --- /dev/null +++ b/istio-1.3.5/install/kubernetes/operator/charts/gateways/istio-egress/templates/deployment.yaml @@ -0,0 +1,275 @@ +{{ $gateway := index .Values "gateways" "istio-egressgateway" }} +apiVersion: apps/v1 +kind: Deployment +metadata: + name: istio-egressgateway + namespace: {{ .Release.Namespace }} + labels: + app: istio-egressgateway + istio: egressgateway + release: {{ .Release.Name }} +spec: +{{- if not $gateway.autoscaleEnabled }} +{{- if $gateway.replicaCount }} + replicas: {{ $gateway.replicaCount }} +{{- else }} + replicas: 1 +{{- end }} +{{- end }} + selector: + matchLabels: + app: istio-egressgateway + istio: egressgateway + strategy: + rollingUpdate: + maxSurge: {{ $gateway.rollingMaxSurge }} + maxUnavailable: {{ $gateway.rollingMaxUnavailable }} + template: + metadata: + labels: + app: istio-egressgateway + istio: egressgateway +{{- if eq .Release.Namespace "istio-system"}} + heritage: Tiller + release: istio + chart: gateways +{{- end }} + annotations: + sidecar.istio.io/inject: "false" +{{- if $gateway.podAnnotations }} +{{ toYaml $gateway.podAnnotations | indent 8 }} +{{ end }} + spec: +{{- if .Values.global.priorityClassName }} + priorityClassName: "{{ .Values.global.priorityClassName }}" +{{- end }} +{{- if .Values.global.proxy.enableCoreDump }} + initContainers: + - name: enable-core-dump +{{- if contains "/" .Values.global.proxy_init.image }} + image: "{{ .Values.global.proxy_init.image }}" +{{- else }} + image: "{{ .Values.global.hub }}/{{ .Values.global.proxy_init.image | default "proxy_init" }}:{{ .Values.global.tag }}" +{{- end }} + imagePullPolicy: {{ .Values.global.imagePullPolicy | default "Always" }} + command: + - /bin/sh + args: + - -c + - sysctl -w kernel.core_pattern=/var/lib/istio/core.proxy && ulimit -c unlimited + securityContext: + privileged: true +{{- end }} + containers: + - name: istio-proxy +{{- if contains "/" .Values.global.proxy.image }} + image: "{{ .Values.global.proxy.image }}" +{{- else }} + image: "{{ .Values.global.hub }}/{{ .Values.global.proxy.image }}:{{ .Values.global.tag }}" +{{- end }} + imagePullPolicy: {{ .Values.global.imagePullPolicy | default "Always" }} + ports: + {{- range $key, $val := $gateway.ports }} + - containerPort: {{ $val.port }} + {{- end }} + {{- range $key, $val := $gateway.meshExpansionPorts }} + - containerPort: {{ $val.port }} + {{- end }} + - containerPort: 15090 + protocol: TCP + name: http-envoy-prom + args: + - proxy + - router + - --domain + - $(POD_NAMESPACE).svc.{{ .Values.global.proxy.clusterDomain }} + {{- if .Values.global.proxy.logLevel }} + - --proxyLogLevel={{ .Values.global.proxy.logLevel }} + {{- end}} + {{- if .Values.global.proxy.componentLogLevel }} + - --proxyComponentLogLevel={{ .Values.global.proxy.componentLogLevel }} + {{- end}} + {{- if .Values.global.logging.level }} + - --log_output_level={{ .Values.global.logging.level }} + {{- end}} + {{- if .Values.global.logAsJson }} + - --log_as_json + {{- end }} + - --drainDuration + - '45s' #drainDuration + - --parentShutdownDuration + - '1m0s' #parentShutdownDuration + - --connectTimeout + - '10s' #connectTimeout + - --serviceCluster + - istio-egressgateway + - --zipkinAddress + {{- if .Values.global.tracer.zipkin.address }} + - {{ .Values.global.tracer.zipkin.address }} + {{- else if .Values.global.telemetryNamespace }} + - zipkin.{{ .Values.global.telemetryNamespace }}:9411 + {{- else }} + - zipkin:9411 + {{- end }} + - --proxyAdminPort + - "15000" + - --statusPort + - "15020" + {{- if .Values.global.controlPlaneSecurityEnabled }} + - --controlPlaneAuthPolicy + - MUTUAL_TLS + - --discoveryAddress + {{- if .Values.global.istioNamespace }} + - istio-pilot.{{ .Values.global.istioNamespace }}:15011 + {{- else }} + - istio-pilot:15011 + {{- end }} + {{- else }} + - --controlPlaneAuthPolicy + - NONE + - --discoveryAddress + {{- if .Values.global.istioNamespace }} + - istio-pilot.{{ .Values.global.istioNamespace }}:15010 + {{- else }} + - istio-pilot:15010 + {{- end }} + {{- end }} + {{- if .Values.global.trustDomain }} + - --trust-domain={{ .Values.global.trustDomain }} + {{- end }} + readinessProbe: + failureThreshold: 30 + httpGet: + path: /healthz/ready + port: 15020 + scheme: HTTP + initialDelaySeconds: 1 + periodSeconds: 2 + successThreshold: 1 + timeoutSeconds: 1 + resources: +{{- if $gateway.resources }} +{{ toYaml $gateway.resources | indent 12 }} +{{- else }} +{{ toYaml .Values.global.defaultResources | indent 12 }} +{{- end }} + env: + - name: NODE_NAME + valueFrom: + fieldRef: + apiVersion: v1 + fieldPath: spec.nodeName + - name: POD_NAME + valueFrom: + fieldRef: + apiVersion: v1 + fieldPath: metadata.name + - name: POD_NAMESPACE + valueFrom: + fieldRef: + apiVersion: v1 + fieldPath: metadata.namespace + - name: INSTANCE_IP + valueFrom: + fieldRef: + apiVersion: v1 + fieldPath: status.podIP + - name: HOST_IP + valueFrom: + fieldRef: + apiVersion: v1 + fieldPath: status.hostIP + - name: SERVICE_ACCOUNT + valueFrom: + fieldRef: + fieldPath: spec.serviceAccountName + - name: ISTIO_META_WORKLOAD_NAME + value: istio-egressgateway + - name: ISTIO_META_OWNER + value: kubernetes://api/apps/v1/namespaces/{{ .Release.Namespace }}/deployments/istio-egressgateway + - name: ISTIO_META_POD_NAME + valueFrom: + fieldRef: + apiVersion: v1 + fieldPath: metadata.name + - name: ISTIO_META_CONFIG_NAMESPACE + valueFrom: + fieldRef: + fieldPath: metadata.namespace + {{- if $gateway.sds }} + {{- if $gateway.sds.enabled }} + - name: ISTIO_META_USER_SDS + value: "true" + {{- end }} + {{- end }} + {{- if $gateway.env }} + {{- range $key, $val := $gateway.env }} + - name: {{ $key }} + value: {{ $val }} + {{- end }} + {{ end }} +{{- if $gateway.podAnnotations }} + - name: "ISTIO_METAJSON_ANNOTATIONS" + value: | +{{ toJson $gateway.podAnnotations | indent 16}} +{{ end }} + volumeMounts: + {{ if .Values.global.sds.enabled }} + - name: sdsudspath + mountPath: /var/run/sds + readOnly: true + - name: istio-token + mountPath: /var/run/secrets/tokens + {{- end }} + - name: istio-certs + mountPath: /etc/certs + readOnly: true + {{- range $gateway.secretVolumes }} + - name: {{ .name }} + mountPath: {{ .mountPath | quote }} + readOnly: true + {{- end }} +{{- if $gateway.additionalContainers }} +{{ toYaml $gateway.additionalContainers | indent 8 }} +{{- end }} + volumes: + {{- if .Values.global.sds.enabled }} + - name: sdsudspath + hostPath: + path: /var/run/sds + - name: istio-token + projected: + sources: + - serviceAccountToken: + path: istio-token + expirationSeconds: 43200 + audience: {{ .Values.global.trustDomain }} + {{- end }} + {{ if .Values.global.sds.enabled }} + - name: sdsudspath + hostPath: + path: /var/run/sds + {{- end }} + - name: istio-certs + secret: + secretName: istio.default + optional: true + {{- range $gateway.secretVolumes }} + - name: {{ .name }} + secret: + secretName: {{ .secretName | quote }} + optional: true + {{- end }} + {{- range $gateway.configVolumes }} + - name: {{ .name }} + configMap: + name: {{ .configMapName | quote }} + optional: true + {{- end }} + affinity: + {{- include "nodeaffinity" (dict "global" .Values.global "nodeSelector" $gateway.nodeSelector) | indent 6 }} + {{- include "podAntiAffinity" $gateway | indent 6 }} +{{- if $gateway.tolerations }} + tolerations: +{{ toYaml $gateway.tolerations | indent 6 }} +{{- end }} diff --git a/istio-1.3.5/install/kubernetes/operator/charts/gateways/istio-egress/templates/poddisruptionbudget.yaml b/istio-1.3.5/install/kubernetes/operator/charts/gateways/istio-egress/templates/poddisruptionbudget.yaml new file mode 100644 index 0000000..d2a8c14 --- /dev/null +++ b/istio-1.3.5/install/kubernetes/operator/charts/gateways/istio-egress/templates/poddisruptionbudget.yaml @@ -0,0 +1,19 @@ +{{ $gateway := index .Values "gateways" "istio-egressgateway" }} +{{- if .Values.global.defaultPodDisruptionBudget.enabled }} +apiVersion: policy/v1beta1 +kind: PodDisruptionBudget +metadata: + name: istio-egressgateway + namespace: {{ .Release.Namespace }} + labels: + app: istio-egressgateway + istio: egressgateway + release: {{ .Release.Name }} +spec: + minAvailable: 1 + selector: + matchLabels: + app: istio-egressgateway + istio: egressgateway + release: {{ .Release.Name }} +{{- end }} diff --git a/istio-1.3.5/install/kubernetes/operator/charts/gateways/istio-egress/templates/preconfigured.yaml b/istio-1.3.5/install/kubernetes/operator/charts/gateways/istio-egress/templates/preconfigured.yaml new file mode 100644 index 0000000..b8c776c --- /dev/null +++ b/istio-1.3.5/install/kubernetes/operator/charts/gateways/istio-egress/templates/preconfigured.yaml @@ -0,0 +1,82 @@ +{{ $gateway := index .Values "gateways" "istio-egressgateway" }} +{{- if $gateway.zvpn.enabled }} +apiVersion: networking.istio.io/v1alpha3 +kind: Gateway +metadata: + name: istio-multicluster-egressgateway + namespace: {{ .Release.Namespace }} + labels: + app: istio-egressgateway + release: {{ .Release.Name }} +spec: + selector: + istio: egressgateway + servers: + - hosts: + - "*.{{ $gateway.zvpn.suffix }}" + port: + name: tls + number: 15443 + protocol: TLS + tls: {} +--- +apiVersion: networking.istio.io/v1alpha3 +kind: VirtualService +metadata: + name: istio-multicluster-egressgateway + namespace: {{ .Release.Namespace }} + labels: + app: istio-egressgateway + release: {{ .Release.Name }} +spec: + gateways: + - istio-multicluster-egressgateway + hosts: + - "*.{{ $gateway.zvpn.suffix }}" + tls: + - match: + - port: 15443 + sniHosts: + - "*.{{ $gateway.zvpn.suffix }}" + route: + - destination: + host: non.existent.cluster + port: + number: 15443 + weight: 100 +--- +apiVersion: networking.istio.io/v1alpha3 +kind: EnvoyFilter +metadata: + name: istio-multicluster-egressgateway + namespace: {{ .Release.Namespace }} + labels: + app: istio-egressgateway + release: {{ .Release.Name }} +spec: + workloadLabels: + istio: egressgateway + filters: + - listenerMatch: + portNumber: 15443 + listenerType: GATEWAY + filterName: envoy.filters.network.sni_cluster + filterType: NETWORK + filterConfig: {} +--- +## To ensure all traffic to *.global is using mTLS +apiVersion: networking.istio.io/v1alpha3 +kind: DestinationRule +metadata: + name: istio-multicluster-destinationrule + namespace: {{ .Release.Namespace }} + labels: + app: istio-egressgateway + release: {{ .Release.Name }} +spec: + host: "*.{{ $gateway.zvpn.suffix }}" + trafficPolicy: + tls: + mode: ISTIO_MUTUAL +--- +{{- end }} diff --git a/istio-1.3.5/install/kubernetes/operator/charts/gateways/istio-egress/templates/service.yaml b/istio-1.3.5/install/kubernetes/operator/charts/gateways/istio-egress/templates/service.yaml new file mode 100644 index 0000000..f7bc76b --- /dev/null +++ b/istio-1.3.5/install/kubernetes/operator/charts/gateways/istio-egress/templates/service.yaml @@ -0,0 +1,25 @@ +{{ $gateway := index .Values "gateways" "istio-egressgateway" }} +apiVersion: v1 +kind: Service +metadata: + name: istio-egressgateway + namespace: {{ .Release.Namespace }} + annotations: + {{- range $key, $val := $gateway.serviceAnnotations }} + {{ $key }}: {{ $val | quote }} + {{- end }} + labels: + app: istio-egressgateway + release: {{ .Release.Name }} +spec: + type: ClusterIP + selector: + app: istio-egressgateway + ports: + {{- range $key, $val := $gateway.ports }} + - + {{- range $pkey, $pval := $val }} + {{ $pkey}}: {{ $pval }} + {{- end }} + {{- end }} +--- diff --git a/istio-1.3.5/install/kubernetes/operator/charts/gateways/istio-egress/templates/serviceaccount.yaml b/istio-1.3.5/install/kubernetes/operator/charts/gateways/istio-egress/templates/serviceaccount.yaml new file mode 100644 index 0000000..1a6c259 --- /dev/null +++ b/istio-1.3.5/install/kubernetes/operator/charts/gateways/istio-egress/templates/serviceaccount.yaml @@ -0,0 +1,40 @@ +{{ $gateway := index .Values "gateways" "istio-egressgateway" }} +{{ if ($gateway.sds) and ($gateway.sds.enabled) }} +apiVersion: rbac.authorization.k8s.io/v1 +kind: Role +metadata: + name: istio-egressgateway-sds + namespace: {{ .Release.Namespace }} +rules: +- apiGroups: [""] + resources: ["secrets"] + verbs: ["get", "watch", "list"] +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: RoleBinding +metadata: + name: istio-egressgateway-sds + namespace: {{ .Release.Namespace }} +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: Role + name: istio-egressgateway-sds +subjects: +- kind: ServiceAccount + name: istio-egressgateway-service-account +--- +apiVersion: v1 +kind: ServiceAccount +{{- if .Values.global.imagePullSecrets }} +imagePullSecrets: +{{- range .Values.global.imagePullSecrets }} + - name: {{ . }} +{{- end }} +{{- end }} +metadata: + name: istio-egressgateway-service-account + namespace: {{ .Release.Namespace }} + labels: + app: istio-egressgateway + release: {{ .Release.Name }} +{{ end }} \ No newline at end of file diff --git a/istio-1.3.5/install/kubernetes/operator/charts/gateways/istio-egress/values.yaml b/istio-1.3.5/install/kubernetes/operator/charts/gateways/istio-egress/values.yaml new file mode 100644 index 0000000..db8bc44 --- /dev/null +++ b/istio-1.3.5/install/kubernetes/operator/charts/gateways/istio-egress/values.yaml @@ -0,0 +1,98 @@ +# Standalone istio egress gateway. +# Should be installed in a separate namespace, to minimize access to config +gateways: + istio-egressgateway: + ports: + - port: 80 + name: http2 + - port: 443 + name: https + # This is the port where sni routing happens + - port: 15443 + targetPort: 15443 + name: tls + + # Enable cross-cluster access using SNI matching. + # Make sure you set suffix if deploying multiple egress gateways. + zvpn: + # Must be different for each egress namespace. + # Used to control the domain name suffix for zero vpn routing. + # Domain names ending with this suffix will be routed to this egress gateway + # automatically. + # This can be a real domain name ( istio.example.com ) + suffix: global + enabled: true + + + # Scalability tunning + # replicaCount: 1 + rollingMaxSurge: 100% + rollingMaxUnavailable: 25% + autoscaleEnabled: true + autoscaleMin: 1 + autoscaleMax: 5 + resources: + requests: + cpu: 100m + memory: 128Mi + limits: + cpu: 2000m + memory: 256Mi + cpu: + targetAverageUtilization: 80 + + drainDuration: 45s + connectTimeout: 10s + + serviceAnnotations: {} + podAnnotations: {} + type: ClusterIP # change to NodePort or LoadBalancer if need be + + secretVolumes: + - name: egressgateway-certs + secretName: istio-egressgateway-certs + mountPath: /etc/istio/egressgateway-certs + - name: egressgateway-ca-certs + secretName: istio-egressgateway-ca-certs + mountPath: /etc/istio/egressgateway-ca-certs + + + ### Advanced options ############ + # TODO: convert to real options, env should not be exposed + env: + # Set this to "external" if and only if you want the egress gateway to + # act as a transparent SNI gateway that routes mTLS/TLS traffic to + # external services defined using service entries, where the service + # entry has resolution set to DNS, has one or more endpoints with + # network field set to "external". By default its set to "" so that + # the egress gateway sees the same set of endpoints as the sidecars + # preserving backward compatibility + # ISTIO_META_REQUESTED_NETWORK_VIEW: "" + # A gateway with this mode ensures that pilot generates an additional + # set of clusters for internal services but without Istio mTLS, to + # enable cross cluster routing. + ISTIO_META_ROUTER_MODE: "sni-dnat" + + nodeSelector: {} + tolerations: [] + + # Specify the pod anti-affinity that allows you to constrain which nodes + # your pod is eligible to be scheduled based on labels on pods that are + # already running on the node rather than based on labels on nodes. + # There are currently two types of anti-affinity: + # "requiredDuringSchedulingIgnoredDuringExecution" + # "preferredDuringSchedulingIgnoredDuringExecution" + # which denote "hard" vs. "soft" requirements, you can define your values + # in "podAntiAffinityLabelSelector" and "podAntiAffinityTermLabelSelector" + # correspondingly. + # For example: + # podAntiAffinityLabelSelector: + # - key: security + # operator: In + # values: S1,S2 + # topologyKey: "kubernetes.io/hostname" + # This pod anti-affinity rule says that the pod requires not to be scheduled + # onto a node if that node is already running a pod with label having key + # "security" and value "S1". + podAntiAffinityLabelSelector: [] + podAntiAffinityTermLabelSelector: [] diff --git a/istio-1.3.5/install/kubernetes/operator/charts/gateways/istio-ingress/Chart.yaml b/istio-1.3.5/install/kubernetes/operator/charts/gateways/istio-ingress/Chart.yaml new file mode 100644 index 0000000..3ef0d25 --- /dev/null +++ b/istio-1.3.5/install/kubernetes/operator/charts/gateways/istio-ingress/Chart.yaml @@ -0,0 +1,13 @@ +apiVersion: v1 +name: istio-ingress +version: 1.1.0 +tillerVersion: ">=2.7.2" +description: Helm chart for deploying Istio gateways +keywords: + - istio + - ingressgateway + - gateways +sources: + - http://github.com/istio/istio +engine: gotpl +icon: https://istio.io/favicons/android-192x192.png diff --git a/istio-1.3.5/install/kubernetes/operator/charts/gateways/istio-ingress/NOTES.txt b/istio-1.3.5/install/kubernetes/operator/charts/gateways/istio-ingress/NOTES.txt new file mode 100644 index 0000000..221ee56 --- /dev/null +++ b/istio-1.3.5/install/kubernetes/operator/charts/gateways/istio-ingress/NOTES.txt @@ -0,0 +1,43 @@ + +Changes: +- separate namespace allows: +-- easier reconfig of just the gateway +-- TLS secrets and domain name management is isolated, for better security +-- simplified configuration +-- multiple versions of the ingress can be used, to minimize upgrade risks + +- the new chart uses the default namespace service account, and doesn't require +additional RBAC permissions. + +- simplified label and chart structure. +- ability to run a pilot dedicated for the gateway, isolated from the main pilot. This is more robust, safer on upgrades +and allows a bit more flexibility. +- the dedicated pilot-per-ingress is required if the gateway needs to support k8s-style ingress. + +# Port and basic host configuration + +In order to configure the Service object, the install/upgrade needs to provide a list of all ports. +In the past, this was done when installing/upgrading full istio, and involved some duplication - ports configured +both in upgrade, Gateway and VirtualService. + +The new Ingress chart uses a 'values.yaml' (see user-example-ingress), which auto-generates Service ports, +Gateways and basic VirtualService. It is still possible to only configure the ports in Service, and do manual +config for the rest. + +All internal services ( telemetry, pilot debug ports, mesh expansion ) can now be configured via the new mechanism. + +# Migration from istio-system + +Istio 1.0 includes the gateways in istio-system. Since the external IP is associated +with the Service and bound to the namespace, it is recommended to: + +1. Install the new gateway in a new namespace. +2. Copy any TLS certificate to the new namespace, and configure the domains. +3. Checking the new gateway work - for example by overriding the IP in /etc/hosts +4. Modify the DNS server to add the A record of the new namespace +5. Check traffic +6. Delete the A record corresponding to the gateway in istio-system +7. Upgrade istio-system, disabling the ingressgateway +8. Delete the domain TLS certs from istio-system. + +If using certmanager, all Certificate and associated configs must be moved as well. diff --git a/istio-1.3.5/install/kubernetes/operator/charts/gateways/istio-ingress/templates/_affinity.tpl b/istio-1.3.5/install/kubernetes/operator/charts/gateways/istio-ingress/templates/_affinity.tpl new file mode 100644 index 0000000..ce8bac0 --- /dev/null +++ b/istio-1.3.5/install/kubernetes/operator/charts/gateways/istio-ingress/templates/_affinity.tpl @@ -0,0 +1,93 @@ +{{/* affinity - https://kubernetes.io/docs/concepts/configuration/assign-pod-node/ */}} + +{{- define "nodeaffinity" }} + nodeAffinity: + requiredDuringSchedulingIgnoredDuringExecution: + {{- include "nodeAffinityRequiredDuringScheduling" . }} + preferredDuringSchedulingIgnoredDuringExecution: + {{- include "nodeAffinityPreferredDuringScheduling" . }} +{{- end }} + +{{- define "nodeAffinityRequiredDuringScheduling" }} + nodeSelectorTerms: + - matchExpressions: + - key: beta.kubernetes.io/arch + operator: In + values: + {{- range $key, $val := .global.arch }} + {{- if gt ($val | int) 0 }} + - {{ $key }} + {{- end }} + {{- end }} + {{- $nodeSelector := default .global.defaultNodeSelector .nodeSelector -}} + {{- range $key, $val := $nodeSelector }} + - key: {{ $key }} + operator: In + values: + - {{ $val }} + {{- end }} +{{- end }} + +{{- define "nodeAffinityPreferredDuringScheduling" }} + {{- range $key, $val := .global.arch }} + {{- if gt ($val | int) 0 }} + - weight: {{ $val | int }} + preference: + matchExpressions: + - key: beta.kubernetes.io/arch + operator: In + values: + - {{ $key }} + {{- end }} + {{- end }} +{{- end }} + +{{- define "podAntiAffinity" }} +{{- if or .podAntiAffinityLabelSelector .podAntiAffinityTermLabelSelector}} + podAntiAffinity: + {{- if .podAntiAffinityLabelSelector }} + requiredDuringSchedulingIgnoredDuringExecution: + {{- include "podAntiAffinityRequiredDuringScheduling" . }} + {{- end }} + {{- if .podAntiAffinityTermLabelSelector }} + preferredDuringSchedulingIgnoredDuringExecution: + {{- include "podAntiAffinityPreferredDuringScheduling" . }} + {{- end }} +{{- end }} +{{- end }} + +{{- define "podAntiAffinityRequiredDuringScheduling" }} + {{- range $index, $item := .podAntiAffinityLabelSelector }} + - labelSelector: + matchExpressions: + - key: {{ $item.key }} + operator: {{ $item.operator }} + {{- if $item.values }} + values: + {{- $vals := split "," $item.values }} + {{- range $i, $v := $vals }} + - {{ $v }} + {{- end }} + {{- end }} + topologyKey: {{ $item.topologyKey }} + {{- end }} +{{- end }} + +{{- define "podAntiAffinityPreferredDuringScheduling" }} + {{- range $index, $item := .podAntiAffinityTermLabelSelector }} + - podAffinityTerm: + labelSelector: + matchExpressions: + - key: {{ $item.key }} + operator: {{ $item.operator }} + {{- if $item.values }} + values: + {{- $vals := split "," $item.values }} + {{- range $i, $v := $vals }} + - {{ $v }} + {{- end }} + {{- end }} + topologyKey: {{ $item.topologyKey }} + weight: 100 + {{- end }} +{{- end }} diff --git a/istio-1.3.5/install/kubernetes/operator/charts/gateways/istio-ingress/templates/addongateway.yaml b/istio-1.3.5/install/kubernetes/operator/charts/gateways/istio-ingress/templates/addongateway.yaml new file mode 100644 index 0000000..5b49beb --- /dev/null +++ b/istio-1.3.5/install/kubernetes/operator/charts/gateways/istio-ingress/templates/addongateway.yaml @@ -0,0 +1,65 @@ +# Template for telemetry addon gateways +{{ $gateway := index .Values "gateways" "istio-ingressgateway" }} +{{ range $addon := $gateway.telemetry_addon_gateways }} +{{ if $addon.enabled }} +apiVersion: networking.istio.io/v1alpha3 +kind: Gateway +metadata: + name: istio-{{ $addon.name }}-gateway + namespace: {{ $.Release.Namespace }} + labels: + app: {{ $addon.name }} + release: {{ $.Release.Name }} +spec: + selector: + istio: ingressgateway + servers: + - port: + number: {{ $addon.port }} + name: https-{{ $addon.name }} + protocol: HTTPS + tls: + mode: SIMPLE + serverCertificate: /etc/istio/ingressgateway-certs/tls.crt + privateKey: /etc/istio/ingressgateway-certs/tls.key + hosts: + - "*" +--- +apiVersion: networking.istio.io/v1alpha3 +kind: VirtualService +metadata: + name: {{ $addon.name }}-virtual-service + namespace: {{ $.Release.Namespace }} + labels: + app: {{ $addon.name }} + release: {{ $.Release.Name }} +spec: + hosts: + - "*" + gateways: + - istio-{{ $addon.name }}-gateway + http: + - match: + - port: {{ $addon.port }} + route: + - destination: + host: {{ $addon.name }}.{{ $.Release.Namespace }}.svc.{{ $.Values.global.proxy.clusterDomain }} + port: + number: {{ $addon.desPort }} +--- +apiVersion: networking.istio.io/v1alpha3 +kind: DestinationRule +metadata: + name: {{ $addon.name }} + namespace: {{ $.Release.Namespace }} + labels: + app: {{ $addon.name }} + release: {{ $.Release.Name }} +spec: + host: {{ $addon.name }}.{{ $.Release.Namespace }}.svc.{{ $.Values.global.proxy.clusterDomain }} + trafficPolicy: + tls: + mode: DISABLE +--- +{{- end }} +{{- end }} diff --git a/istio-1.3.5/install/kubernetes/operator/charts/gateways/istio-ingress/templates/autoscale.yaml b/istio-1.3.5/install/kubernetes/operator/charts/gateways/istio-ingress/templates/autoscale.yaml new file mode 100644 index 0000000..5974a5e --- /dev/null +++ b/istio-1.3.5/install/kubernetes/operator/charts/gateways/istio-ingress/templates/autoscale.yaml @@ -0,0 +1,24 @@ +{{ $gateway := index .Values "gateways" "istio-ingressgateway" }} +{{- if and $gateway.autoscaleEnabled $gateway.autoscaleMin $gateway.autoscaleMax }} +apiVersion: autoscaling/v2beta1 +kind: HorizontalPodAutoscaler +metadata: + name: istio-ingressgateway + namespace: {{ .Release.Namespace }} + labels: + app: istio-ingressgateway + release: {{ .Release.Name }} +spec: + maxReplicas: {{ $gateway.autoscaleMax }} + minReplicas: {{ $gateway.autoscaleMin }} + scaleTargetRef: + apiVersion: apps/v1 + kind: Deployment + name: istio-ingressgateway + metrics: + - type: Resource + resource: + name: cpu + targetAverageUtilization: {{ $gateway.cpu.targetAverageUtilization }} +--- +{{- end }} diff --git a/istio-1.3.5/install/kubernetes/operator/charts/gateways/istio-ingress/templates/certificate.yaml b/istio-1.3.5/install/kubernetes/operator/charts/gateways/istio-ingress/templates/certificate.yaml new file mode 100644 index 0000000..b66611b --- /dev/null +++ b/istio-1.3.5/install/kubernetes/operator/charts/gateways/istio-ingress/templates/certificate.yaml @@ -0,0 +1,45 @@ +{{ $gateway := index .Values "gateways" "istio-ingressgateway" }} +{{ if $gateway.certificates }} +--- +# Auto-generate Certmanager Issuer and certificate requests. +# Requires 'email' to be set, for Let's Encrypt use. + +apiVersion: certmanager.k8s.io/v1alpha1 +kind: Issuer +metadata: + name: letsencrypt + namespace: {{ .Release.Namespace }} +spec: + acme: + server: https://acme-v02.api.letsencrypt.org/directory + email: {{ $gateway.email }} + privateKeySecretRef: + name: letsencrypt + http01: {} +--- + +apiVersion: certmanager.k8s.io/v1alpha1 +kind: Certificate +metadata: + name: istio-ingressgateway-certs + namespace: {{ .Release.Namespace }} +spec: + secretName: istio-ingressgateway-certs + issuerRef: + name: letsencrypt + kind: ClusterIssuer + commonName: {{ $gateway.commonName }} + dnsNames: +{{- range $key := $gateway.certificates }} + - {{ $key }} +{{- end }} + acme: + config: + - http01: + ingressClass: istio + domains: +{{- range $key := $gateway.certificates }} + - {{ $key }} +{{- end }} +{{- end }} + diff --git a/istio-1.3.5/install/kubernetes/operator/charts/gateways/istio-ingress/templates/deployment.yaml b/istio-1.3.5/install/kubernetes/operator/charts/gateways/istio-ingress/templates/deployment.yaml new file mode 100644 index 0000000..7a7a5fe --- /dev/null +++ b/istio-1.3.5/install/kubernetes/operator/charts/gateways/istio-ingress/templates/deployment.yaml @@ -0,0 +1,317 @@ +{{ $gateway := index .Values "gateways" "istio-ingressgateway" }} +apiVersion: apps/v1 +kind: Deployment +metadata: + name: istio-ingressgateway + namespace: {{ .Release.Namespace }} + labels: + app: istio-ingressgateway + istio: ingressgateway + release: {{ .Release.Name }} +spec: +{{- if not $gateway.autoscaleEnabled }} +{{- if $gateway.replicaCount }} + replicas: {{ $gateway.replicaCount }} +{{- else }} + replicas: 1 +{{- end }} +{{- end }} + selector: + matchLabels: + app: istio-ingressgateway + istio: ingressgateway + strategy: + rollingUpdate: + maxSurge: {{ $gateway.rollingMaxSurge }} + maxUnavailable: {{ $gateway.rollingMaxUnavailable }} + template: + metadata: + labels: + app: istio-ingressgateway + istio: ingressgateway +{{- if eq .Release.Namespace "istio-system"}} + heritage: Tiller + release: istio + chart: gateways +{{- end }} + annotations: + sidecar.istio.io/inject: "false" +{{- if $gateway.podAnnotations }} +{{ toYaml $gateway.podAnnotations | indent 8 }} +{{ end }} + spec: + serviceAccountName: istio-ingressgateway-service-account +{{- if .Values.global.priorityClassName }} + priorityClassName: "{{ .Values.global.priorityClassName }}" +{{- end }} +{{- if .Values.global.proxy.enableCoreDump }} + initContainers: + - name: enable-core-dump +{{- if contains "/" .Values.global.proxy.image }} + image: "{{ .Values.global.proxy.image }}" +{{- else }} + image: "{{ .Values.global.hub }}/{{ .Values.global.proxy.image | default "proxyv2" }}:{{ .Values.global.tag }}" +{{- end }} + imagePullPolicy: {{ .Values.global.imagePullPolicy | default "Always" }} + command: + - /bin/sh + args: + - -c + - sysctl -w kernel.core_pattern=/var/lib/istio/core.proxy && ulimit -c unlimited + securityContext: + privileged: true +{{- end }} + containers: +{{- if $gateway.sds.enabled }} + - name: ingress-sds +{{- if contains "/" $gateway.sds.image }} + image: "{{ $gateway.sds.image }}" +{{- else }} + image: "{{ .Values.global.hub }}/{{ $gateway.sds.image }}:{{ .Values.global.tag }}" +{{- end }} + imagePullPolicy: {{ .Values.global.imagePullPolicy | default "Always" }} + resources: +{{- if $gateway.sds.resources }} +{{ toYaml $gateway.sds.resources | indent 12 }} +{{- else }} +{{ toYaml .Values.global.defaultResources | indent 12 }} +{{- end }} + env: + - name: "ENABLE_WORKLOAD_SDS" + value: "false" + - name: "ENABLE_INGRESS_GATEWAY_SDS" + value: "true" + - name: "INGRESS_GATEWAY_NAMESPACE" + valueFrom: + fieldRef: + apiVersion: v1 + fieldPath: metadata.namespace + volumeMounts: + - name: ingressgatewaysdsudspath + mountPath: /var/run/ingress_gateway +{{- end }} + - name: istio-proxy +{{- if contains "/" .Values.global.proxy.image }} + image: "{{ .Values.global.proxy.image }}" +{{- else }} + image: "{{ .Values.global.hub }}/{{ .Values.global.proxy.image | default "proxyv2" }}:{{ .Values.global.tag }}" +{{- end }} + imagePullPolicy: {{ .Values.global.imagePullPolicy | default "Always" }} + ports: + {{- range $key, $val := $gateway.ports }} + - containerPort: {{ $val.port }} + {{- end }} + {{- range $key, $val := $gateway.meshExpansionPorts }} + - containerPort: {{ $val.port }} + {{- end }} + - containerPort: 15090 + protocol: TCP + name: http-envoy-prom + args: + - proxy + - router + - --domain + - $(POD_NAMESPACE).svc.{{ .Values.global.proxy.clusterDomain }} + {{- if .Values.global.proxy.logLevel }} + - --proxyLogLevel={{ .Values.global.proxy.logLevel }} + {{- end}} + {{- if .Values.global.proxy.componentLogLevel }} + - --proxyComponentLogLevel={{ .Values.global.proxy.componentLogLevel }} + {{- end}} + {{- if .Values.global.logging.level }} + - --log_output_level={{ .Values.global.logging.level }} + {{- end}} + {{- if .Values.global.logAsJson }} + - --log_as_json + {{- end }} + - --drainDuration + - '45s' #drainDuration + - --parentShutdownDuration + - '1m0s' #parentShutdownDuration + - --connectTimeout + - '10s' #connectTimeout + - --serviceCluster + - istio-ingressgateway + - --zipkinAddress + {{- if .Values.global.tracer.zipkin.address }} + - {{ .Values.global.tracer.zipkin.address }} + {{- else if .Values.global.telemetryNamespace }} + - zipkin.{{ .Values.global.telemetryNamespace }}:9411 + {{- else }} + - zipkin:9411 + {{- end }} + {{- if $gateway.envoyMetricsService }} + - --envoyMetricsServiceAddress + - {{ $gateway.envoyMetricsService.host }}:{{ $gateway.envoyMetricsService.port }} + {{- end }} + {{- if .Values.global.proxy.envoyAccessLogService.enabled }} + - --envoyAccessLogServiceAddress + - {{ .Values.global.proxy.envoyAccessLogService.host }}:{{ .Values.global.proxy.envoyAccessLogService.port }} + {{- end }} + {{- if $gateway.applicationPorts }} + - --applicationPorts + - "{{ $gateway.applicationPorts }}" + {{- end }} + - --proxyAdminPort + - "15000" + - --statusPort + - "15020" + {{- if .Values.global.controlPlaneSecurityEnabled }} + - --controlPlaneAuthPolicy + - MUTUAL_TLS + - --discoveryAddress + {{- if .Values.global.istioNamespace }} + - istio-pilot.{{ .Values.global.istioNamespace }}:15011 + {{- else }} + - istio-pilot:15011 + {{- end }} + {{- else }} + - --controlPlaneAuthPolicy + - NONE + - --discoveryAddress + {{- if .Values.global.istioNamespace }} + - istio-pilot.{{ .Values.global.istioNamespace }}:15010 + {{- else }} + - istio-pilot:15010 + {{- end }} + {{- end }} + {{- if .Values.global.trustDomain }} + - --trust-domain={{ .Values.global.trustDomain }} + {{- end }} + readinessProbe: + failureThreshold: 30 + httpGet: + path: /healthz/ready + port: 15020 + scheme: HTTP + initialDelaySeconds: 1 + periodSeconds: 2 + successThreshold: 1 + timeoutSeconds: 1 + resources: +{{- if $gateway.resources }} +{{ toYaml $gateway.resources | indent 12 }} +{{- else }} +{{ toYaml .Values.global.defaultResources | indent 12 }} +{{- end }} + env: + - name: NODE_NAME + valueFrom: + fieldRef: + apiVersion: v1 + fieldPath: spec.nodeName + - name: POD_NAME + valueFrom: + fieldRef: + apiVersion: v1 + fieldPath: metadata.name + - name: POD_NAMESPACE + valueFrom: + fieldRef: + apiVersion: v1 + fieldPath: metadata.namespace + - name: INSTANCE_IP + valueFrom: + fieldRef: + apiVersion: v1 + fieldPath: status.podIP + - name: HOST_IP + valueFrom: + fieldRef: + apiVersion: v1 + fieldPath: status.hostIP + - name: SERVICE_ACCOUNT + valueFrom: + fieldRef: + fieldPath: spec.serviceAccountName + - name: ISTIO_META_WORKLOAD_NAME + value: istio-ingressgateway + - name: ISTIO_META_OWNER + value: kubernetes://api/apps/v1/namespaces/{{ .Release.Namespace }}/deployments/istio-ingressgateway + - name: ISTIO_META_POD_NAME + valueFrom: + fieldRef: + apiVersion: v1 + fieldPath: metadata.name + - name: ISTIO_META_CONFIG_NAMESPACE + valueFrom: + fieldRef: + fieldPath: metadata.namespace + {{- if $gateway.sds.enabled }} + - name: ISTIO_META_USER_SDS + value: "true" + {{- end }} + {{- if $gateway.env }} + {{- range $key, $val := $gateway.env }} + - name: {{ $key }} + value: {{ $val }} + {{- end }} + {{- end }} +{{- if $gateway.podAnnotations }} + - name: "ISTIO_METAJSON_ANNOTATIONS" + value: | +{{ toJson $gateway.podAnnotations | indent 16}} +{{ end }} + volumeMounts: + {{ if .Values.global.sds.enabled }} + - name: sdsudspath + mountPath: /var/run/sds + readOnly: true + - name: istio-token + mountPath: /var/run/secrets/tokens + {{- end }} + {{- if $gateway.sds.enabled }} + - name: ingressgatewaysdsudspath + mountPath: /var/run/ingress_gateway + {{- end }} + - name: istio-certs + mountPath: /etc/certs + readOnly: true + {{- range $gateway.secretVolumes }} + - name: {{ .name }} + mountPath: {{ .mountPath | quote }} + readOnly: true + {{- end }} +{{- if $gateway.additionalContainers }} +{{ toYaml $gateway.additionalContainers | indent 8 }} +{{- end }} + volumes: + {{- if $gateway.sds.enabled }} + - name: ingressgatewaysdsudspath + emptyDir: {} + {{- end }} + {{- if .Values.global.sds.enabled }} + - name: sdsudspath + hostPath: + path: /var/run/sds + - name: istio-token + projected: + sources: + - serviceAccountToken: + path: istio-token + expirationSeconds: 43200 + audience: {{ .Values.global.trustDomain }} + {{- end }} + - name: istio-certs + secret: + secretName: istio.istio-ingressgateway-service-account + optional: true + {{- range $gateway.secretVolumes }} + - name: {{ .name }} + secret: + secretName: {{ .secretName | quote }} + optional: true + {{- end }} + {{- range $gateway.configVolumes }} + - name: {{ .name }} + configMap: + name: {{ .configMapName | quote }} + optional: true + {{- end }} + affinity: + {{- include "nodeaffinity" (dict "global" .Values.global "nodeSelector" $gateway.nodeSelector) | indent 6 }} + {{- include "podAntiAffinity" $gateway | indent 6 }} +{{- if $gateway.tolerations }} + tolerations: +{{ toYaml $gateway.tolerations | indent 6 }} +{{- end }} diff --git a/istio-1.3.5/install/kubernetes/operator/charts/gateways/istio-ingress/templates/gateway.yaml b/istio-1.3.5/install/kubernetes/operator/charts/gateways/istio-ingress/templates/gateway.yaml new file mode 100644 index 0000000..3cc0de8 --- /dev/null +++ b/istio-1.3.5/install/kubernetes/operator/charts/gateways/istio-ingress/templates/gateway.yaml @@ -0,0 +1,40 @@ +{{ $gateway := index .Values "gateways" "istio-ingressgateway" }} +# Main Gateway. Apps must bind to NAMESPACE/ingressgateway +apiVersion: networking.istio.io/v1alpha3 +kind: Gateway +metadata: + name: ingressgateway + namespace: {{ .Release.Namespace }} + labels: + release: {{ .Release.Name }} +spec: + selector: + istio: ingressgateway + servers: +{{- if $gateway.tls }} + - port: + number: 443 + name: https-default + protocol: HTTPS + tls: + mode: SIMPLE + serverCertificate: /etc/istio/ingressgateway-certs/tls.crt + privateKey: /etc/istio/ingressgateway-certs/tls.key + hosts: + - "*" + {{- end }} + - port: + number: 80 + name: http + protocol: HTTP + hosts: + - "*" + # Additional ports in gateaway for the ingressPorts - apps using dedicated port instead of hostname +{{ range $app := $gateway.ingressPorts }} + - port: + number: {{ $app.port }} + name: {{ $app.name }} + protocol: HTTP2 + hosts: + - "*" +{{- end }} diff --git a/istio-1.3.5/install/kubernetes/operator/charts/gateways/istio-ingress/templates/hosts.yaml b/istio-1.3.5/install/kubernetes/operator/charts/gateways/istio-ingress/templates/hosts.yaml new file mode 100644 index 0000000..90f5f7d --- /dev/null +++ b/istio-1.3.5/install/kubernetes/operator/charts/gateways/istio-ingress/templates/hosts.yaml @@ -0,0 +1,50 @@ +{{ $gateway := index .Values "gateways" "istio-ingressgateway" }} + +# TODO: range TCP ports, add ports +# {{ $gateway.domain }} +{{ range $app := $gateway.hosts }} +--- +apiVersion: networking.istio.io/v1alpha3 +kind: VirtualService +metadata: + name: {{ $app.name }} + namespace: {{ $.Release.Namespace }} + labels: + release: {{ $.Release.Name }} +spec: + hosts: + - "{{ $app.name }}.{{ $gateway.domain }}" + gateways: + - ingressgateway + http: + - route: + - destination: + host: {{ $app.dest }} + port: + number: {{ $app.destPort }} +{{- end }} + +{{ range $app := $gateway.ingressPorts }} +--- +apiVersion: networking.istio.io/v1alpha3 +kind: VirtualService +metadata: + name: {{ $app.name }} + namespace: {{ $.Release.Namespace }} + labels: + release: {{ $.Release.Name }} +spec: + hosts: + - "*" + gateways: + - ingressgateway + http: + - + match: + - port: {{ $app.port }} + route: + - destination: + host: {{ $app.dest }} + port: + number: {{ $app.destPort }} +{{- end }} diff --git a/istio-1.3.5/install/kubernetes/operator/charts/gateways/istio-ingress/templates/meshexpansion.yaml b/istio-1.3.5/install/kubernetes/operator/charts/gateways/istio-ingress/templates/meshexpansion.yaml new file mode 100644 index 0000000..2b69fb2 --- /dev/null +++ b/istio-1.3.5/install/kubernetes/operator/charts/gateways/istio-ingress/templates/meshexpansion.yaml @@ -0,0 +1,97 @@ +{{ $gateway := index .Values "gateways" "istio-ingressgateway" }} +{{- if .Values.global.meshExpansion.enabled }} +apiVersion: networking.istio.io/v1alpha3 +kind: Gateway +metadata: + name: meshexpansion-gateway + namespace: {{ .Release.Namespace }} + labels: + release: {{ .Release.Name }} +spec: + selector: + istio: ingressgateway + servers: + - port: + number: 15011 + protocol: TCP + name: tcp-pilot + hosts: + - "*" + - port: + number: 8060 + protocol: TCP + name: tcp-citadel + hosts: + - "*" +--- + +apiVersion: networking.istio.io/v1alpha3 +kind: VirtualService +metadata: + name: meshexpansion-vs-pilot1 + namespace: {{ .Release.Namespace }} + labels: + release: {{ .Release.Name }} +spec: + hosts: + - istio-pilot.{{ .Values.global.istioNamespace }}.svc.cluster.local + gateways: + - meshexpansion-gateway + tcp: + - match: + - port: {{ $gateway.externalPort }} + route: + - destination: + host: istio-pilot.{{ .Values.global.istioNamespace }}.svc.cluster.local + port: + number: 15011 + # - match: + # - port: 53 + # route: + # - destination: + # host: kube-dns.kube-system.svc.cluster.local + # port: + # number: 53 +--- + +apiVersion: networking.istio.io/v1alpha3 +kind: DestinationRule +metadata: + name: meshexpansion-dr-pilot9 + namespace: {{ .Release.Namespace }} + labels: + release: {{ .Release.Name }} +spec: + host: istio-pilot.{{ .Release.Namespace }}.svc.cluster.local + trafficPolicy: + portLevelSettings: + - port: + number: 15011 + tls: + mode: DISABLE +--- + + +apiVersion: networking.istio.io/v1alpha3 +kind: VirtualService +metadata: + name: meshexpansion-vs-citadel + namespace: {{ .Release.Namespace }} + labels: + release: {{ .Release.Name }} +spec: + hosts: + - istio-citadel.{{ $.Release.Namespace }}.svc.cluster.local + gateways: + - meshexpansion-gateway + tcp: + - match: + - port: 8060 + route: + - destination: + host: istio-citadel.{{ $.Release.Namespace }}.svc.cluster.local + port: + number: 8060 + +{{- end }} + diff --git a/istio-1.3.5/install/kubernetes/operator/charts/gateways/istio-ingress/templates/poddisruptionbudget.yaml b/istio-1.3.5/install/kubernetes/operator/charts/gateways/istio-ingress/templates/poddisruptionbudget.yaml new file mode 100644 index 0000000..a900c83 --- /dev/null +++ b/istio-1.3.5/install/kubernetes/operator/charts/gateways/istio-ingress/templates/poddisruptionbudget.yaml @@ -0,0 +1,18 @@ +{{- if .Values.global.defaultPodDisruptionBudget.enabled }} +apiVersion: policy/v1beta1 +kind: PodDisruptionBudget +metadata: + name: ingressgateway + namespace: {{ .Release.Namespace }} + labels: + app: istio-ingressgateway + release: {{ .Release.Name }} + istio: ingressgateway +spec: + minAvailable: 1 + selector: + matchLabels: + app: istio-ingressgateway + release: {{ .Release.Name }} + istio: ingressgateway +{{- end }} diff --git a/istio-1.3.5/install/kubernetes/operator/charts/gateways/istio-ingress/templates/preconfigured.yaml b/istio-1.3.5/install/kubernetes/operator/charts/gateways/istio-ingress/templates/preconfigured.yaml new file mode 100644 index 0000000..9fd400b --- /dev/null +++ b/istio-1.3.5/install/kubernetes/operator/charts/gateways/istio-ingress/templates/preconfigured.yaml @@ -0,0 +1,102 @@ +{{ $gateway := index .Values "gateways" "istio-ingressgateway" }} +{{- if .Values.global.k8sIngress.enabled }} +apiVersion: networking.istio.io/v1alpha3 +kind: Gateway +metadata: + name: istio-autogenerated-k8s-ingress + namespace: {{ .Release.Namespace }} + labels: + app: istio-ingressgateway + release: {{ .Release.Name }} +spec: + selector: + istio: {{ .Values.global.k8sIngress.gatewayName }} + servers: + - port: + number: 80 + protocol: HTTP2 + name: http + hosts: + - "*" +{{ if .Values.global.k8sIngress.enableHttps }} + - port: + number: 443 + protocol: HTTPS + name: https-default + tls: + mode: SIMPLE + serverCertificate: /etc/istio/ingress-certs/tls.crt + privateKey: /etc/istio/ingress-certs/tls.key + hosts: + - "*" +{{ end }} +--- +{{ end }} + + +{{- if .Values.global.multiCluster.enabled }} +apiVersion: networking.istio.io/v1alpha3 +kind: Gateway +metadata: + name: istio-multicluster-ingressgateway + namespace: {{ .Release.Namespace }} + labels: + app: istio-ingressgateway + release: {{ .Release.Name }} +spec: + selector: + istio: ingressgateway + servers: + - hosts: + - "*.global" + port: + name: tls + number: 15443 + protocol: TLS + tls: + mode: AUTO_PASSTHROUGH +--- +apiVersion: networking.istio.io/v1alpha3 +kind: EnvoyFilter +metadata: + name: istio-multicluster-ingressgateway + namespace: {{ .Release.Namespace }} + labels: + app: istio-ingressgateway + release: {{ .Release.Name }} +spec: + workloadLabels: + istio: ingressgateway + filters: + - listenerMatch: + portNumber: 15443 + listenerType: GATEWAY + insertPosition: + index: AFTER + relativeTo: envoy.filters.network.sni_cluster + filterName: envoy.filters.network.tcp_cluster_rewrite + filterType: NETWORK + filterConfig: + cluster_pattern: "\\.global$" + cluster_replacement: ".svc.{{ .Values.global.proxy.clusterDomain }}" +--- +## To ensure all traffic to *.global is using mTLS +apiVersion: networking.istio.io/v1alpha3 +kind: DestinationRule +metadata: + name: istio-multicluster-destinationrule + namespace: {{ .Release.Namespace }} + labels: + app: istio-ingressgateway + release: {{ .Release.Name }} +spec: + host: "*.global" + {{- if .Values.global.defaultConfigVisibilitySettings }} + exportTo: + - '*' + {{- end }} + trafficPolicy: + tls: + mode: ISTIO_MUTUAL +--- +{{- end }} diff --git a/istio-1.3.5/install/kubernetes/operator/charts/gateways/istio-ingress/templates/role.yaml b/istio-1.3.5/install/kubernetes/operator/charts/gateways/istio-ingress/templates/role.yaml new file mode 100644 index 0000000..0d36e93 --- /dev/null +++ b/istio-1.3.5/install/kubernetes/operator/charts/gateways/istio-ingress/templates/role.yaml @@ -0,0 +1,15 @@ +{{ $gateway := index .Values "gateways" "istio-ingressgateway" }} +{{- if $gateway.sds.enabled }} +apiVersion: rbac.authorization.k8s.io/v1beta1 +kind: Role +metadata: + name: istio-ingressgateway-sds + namespace: {{ .Release.Namespace }} + labels: + release: {{ .Release.Name }} +rules: +- apiGroups: [""] + resources: ["secrets"] + verbs: ["get", "watch", "list"] +--- +{{- end }} diff --git a/istio-1.3.5/install/kubernetes/operator/charts/gateways/istio-ingress/templates/rolebindings.yaml b/istio-1.3.5/install/kubernetes/operator/charts/gateways/istio-ingress/templates/rolebindings.yaml new file mode 100644 index 0000000..b3d0488 --- /dev/null +++ b/istio-1.3.5/install/kubernetes/operator/charts/gateways/istio-ingress/templates/rolebindings.yaml @@ -0,0 +1,18 @@ +{{ $gateway := index .Values "gateways" "istio-ingressgateway" }} +{{- if $gateway.sds.enabled }} +apiVersion: rbac.authorization.k8s.io/v1 +kind: RoleBinding +metadata: + name: istio-ingressgateway-sds + namespace: {{ .Release.Namespace }} + labels: + release: {{ .Release.Name }} +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: Role + name: istio-ingressgateway-sds +subjects: +- kind: ServiceAccount + name: istio-ingressgateway-service-account +--- +{{- end }} diff --git a/istio-1.3.5/install/kubernetes/operator/charts/gateways/istio-ingress/templates/service.yaml b/istio-1.3.5/install/kubernetes/operator/charts/gateways/istio-ingress/templates/service.yaml new file mode 100644 index 0000000..d223f93 --- /dev/null +++ b/istio-1.3.5/install/kubernetes/operator/charts/gateways/istio-ingress/templates/service.yaml @@ -0,0 +1,52 @@ +{{ $gateway := index .Values "gateways" "istio-ingressgateway" }} +{{- if not $gateway.customService }} +apiVersion: v1 +kind: Service +metadata: + name: istio-ingressgateway + namespace: {{ .Release.Namespace }} + annotations: + {{- range $key, $val := $gateway.serviceAnnotations }} + {{ $key }}: {{ $val | quote }} + {{- end }} + labels: + app: istio-ingressgateway + release: {{ .Release.Name }} +spec: +{{- if $gateway.loadBalancerIP }} + loadBalancerIP: "{{ $gateway.loadBalancerIP }}" +{{- end }} +{{- if $gateway.loadBalancerSourceRanges }} + loadBalancerSourceRanges: +{{ toYaml $gateway.loadBalancerSourceRanges | indent 4 }} +{{- end }} +{{- if $gateway.externalTrafficPolicy }} + externalTrafficPolicy: {{$gateway.externalTrafficPolicy }} +{{- end }} + type: {{ $gateway.type }} + selector: + app: istio-ingressgateway + ports: + + {{- range $key, $val := $gateway.ports }} + - + {{- range $pkey, $pval := $val }} + {{ $pkey}}: {{ $pval }} + {{- end }} + {{- end }} + + {{- if $.Values.global.meshExpansion.enabled }} + {{- range $key, $val := $gateway.meshExpansionPorts }} + - + {{- range $pkey, $pval := $val }} + {{ $pkey}}: {{ $pval }} + {{- end }} + {{- end }} + {{- end }} + {{ range $app := $gateway.ingressPorts }} + - + port: {{ $app.port }} + name: {{ $app.name }} + {{- end }} +--- +{{ end }} diff --git a/istio-1.3.5/install/kubernetes/operator/charts/gateways/istio-ingress/templates/serviceaccount.yaml b/istio-1.3.5/install/kubernetes/operator/charts/gateways/istio-ingress/templates/serviceaccount.yaml new file mode 100644 index 0000000..30f8fa4 --- /dev/null +++ b/istio-1.3.5/install/kubernetes/operator/charts/gateways/istio-ingress/templates/serviceaccount.yaml @@ -0,0 +1,14 @@ +apiVersion: v1 +kind: ServiceAccount +{{- if .Values.global.imagePullSecrets }} +imagePullSecrets: +{{- range .Values.global.imagePullSecrets }} + - name: {{ . }} +{{- end }} +{{- end }} +metadata: + name: istio-ingressgateway-service-account + namespace: {{ .Release.Namespace }} + labels: + app: istio-ingressgateway + release: {{ .Release.Name }} \ No newline at end of file diff --git a/istio-1.3.5/install/kubernetes/operator/charts/gateways/istio-ingress/templates/sidecar.yaml b/istio-1.3.5/install/kubernetes/operator/charts/gateways/istio-ingress/templates/sidecar.yaml new file mode 100644 index 0000000..d03af8c --- /dev/null +++ b/istio-1.3.5/install/kubernetes/operator/charts/gateways/istio-ingress/templates/sidecar.yaml @@ -0,0 +1,11 @@ +apiVersion: networking.istio.io/v1alpha3 +kind: Sidecar +metadata: + name: default + namespace: {{ .Release.Namespace }} + labels: + release: {{ .Release.Name }} +spec: + egress: + - hosts: + - "*/*" diff --git a/istio-1.3.5/install/kubernetes/operator/charts/gateways/istio-ingress/values.yaml b/istio-1.3.5/install/kubernetes/operator/charts/gateways/istio-ingress/values.yaml new file mode 100644 index 0000000..63b1253 --- /dev/null +++ b/istio-1.3.5/install/kubernetes/operator/charts/gateways/istio-ingress/values.yaml @@ -0,0 +1,192 @@ +# A-la-carte istio ingress gateway. +# Must be installed in a separate namespace, to minimize access to secrets. + +gateways: + istio-ingressgateway: + # + # Secret Discovery Service (SDS) configuration for ingress gateway. + # + sds: + # If true, ingress gateway fetches credentials from SDS server to handle TLS connections. + enabled: false + # SDS server that watches kubernetes secrets and provisions credentials to ingress gateway. + # This server runs in the same pod as ingress gateway. + image: node-agent-k8s + resources: + requests: + cpu: 100m + memory: 128Mi + limits: + cpu: 2000m + memory: 1024Mi + ports: + ## You can add custom gateway ports in user values overrides, but it must include those ports since helm replaces. + # Note that AWS ELB will by default perform health checks on the first port + # on this list. Setting this to the health check port will ensure that health + # checks always work. https://github.com/istio/istio/issues/12503 + - port: 15020 + targetPort: 15020 + name: status-port + - port: 80 + targetPort: 80 + name: http2 + - port: 443 + name: https + - port: 15029 + targetPort: 15029 + name: kiali + - port: 15030 + targetPort: 15030 + name: prometheus + - port: 15031 + targetPort: 15031 + name: grafana + - port: 15032 + targetPort: 15032 + name: tracing + # This is the port where sni routing happens + - port: 15443 + targetPort: 15443 + name: tls + + # Scalability tunning + # replicaCount: 1 + rollingMaxSurge: 100% + rollingMaxUnavailable: 25% + autoscaleEnabled: true + autoscaleMin: 1 + autoscaleMax: 5 + + cpu: + targetAverageUtilization: 80 + + resources: + requests: + cpu: 100m + memory: 128Mi + limits: + cpu: 2000m + memory: 1024Mi + + # Debug level for envoy. Can be set to 'debug' + debug: info + + loadBalancerIP: "" + loadBalancerSourceRanges: [] + externalIPs: [] + serviceAnnotations: {} + + domain: "" + + # Enable cross-cluster access using SNI matching + zvpn: + enabled: true + suffix: global + + # To generate an internal load balancer: + # --set serviceAnnotations.cloud.google.com/load-balancer-type=internal + #serviceAnnotations: + # cloud.google.com/load-balancer-type: "internal" + + podAnnotations: {} + type: LoadBalancer #change to NodePort, ClusterIP or LoadBalancer if need be + + #### MESH EXPANSION PORTS ######## + # Pilot and Citadel MTLS ports are enabled in gateway - but will only redirect + # to pilot/citadel if global.meshExpansion settings are enabled. + # Delete these ports if mesh expansion is not enabled, to avoid + # exposing unnecessary ports on the web. + # You can remove these ports if you are not using mesh expansion + meshExpansionPorts: + - port: 15011 + targetPort: 15011 + name: tcp-pilot-grpc-tls + - port: 8060 + targetPort: 8060 + name: tcp-citadel-grpc-tls + - port: 853 + targetPort: 853 + name: tcp-dns-tls + ####### end MESH EXPANSION PORTS ###### + + ############## + secretVolumes: + - name: ingressgateway-certs + secretName: istio-ingressgateway-certs + mountPath: /etc/istio/ingressgateway-certs + - name: ingressgateway-ca-certs + secretName: istio-ingressgateway-ca-certs + mountPath: /etc/istio/ingressgateway-ca-certs + + # Domain name for telemetry addons + telemetry_domain_name: "" + + # Ports to explicitly check for readiness. If configured, the readiness check will expect a + # listener on these ports. A comma separated list is expected, such as "80,443". + # + # Warning: If you do not have a gateway configured for the ports provided, this check will always + # fail. This is intended for use cases where you always expect to have a listener on the port, + # such as 80 or 443 in typical setups. + applicationPorts: "" + + # Telemetry addon gateways example config + telemetry_addon_gateways: + tracing_gateway: + name: tracing + port: 15032 + desPort: 80 + enabled: false + tls: false + kiali_gateway: + name: kiali + port: 15029 + desPort: 20001 + enabled: false + tls: false + grafana_gateway: + name: grafana + port: 15031 + desPort: 3000 + enabled: false + tls: false + prometheus_gateway: + name: prometheus + port: 15030 + desPort: 9090 + enabled: false + tls: false + + # For Certmanager Issuer and Certificate generation + # certificates: {} + # email: "" + + ### Advanced options ############ + env: + # A gateway with this mode ensures that pilot generates an additional + # set of clusters for internal services but without Istio mTLS, to + # enable cross cluster routing. + ISTIO_META_ROUTER_MODE: "sni-dnat" + + nodeSelector: {} + tolerations: [] + + # Specify the pod anti-affinity that allows you to constrain which nodes + # your pod is eligible to be scheduled based on labels on pods that are + # already running on the node rather than based on labels on nodes. + # There are currently two types of anti-affinity: + # "requiredDuringSchedulingIgnoredDuringExecution" + # "preferredDuringSchedulingIgnoredDuringExecution" + # which denote "hard" vs. "soft" requirements, you can define your values + # in "podAntiAffinityLabelSelector" and "podAntiAffinityTermLabelSelector" + # correspondingly. + # For example: + # podAntiAffinityLabelSelector: + # - key: security + # operator: In + # values: S1,S2 + # topologyKey: "kubernetes.io/hostname" + # This pod anti-affinity rule says that the pod requires not to be scheduled + # onto a node if that node is already running a pod with label having key + # "security" and value "S1". + podAntiAffinityLabelSelector: [] + podAntiAffinityTermLabelSelector: [] diff --git a/istio-1.3.5/install/kubernetes/operator/charts/istio-cni/Chart.yaml b/istio-1.3.5/install/kubernetes/operator/charts/istio-cni/Chart.yaml new file mode 100644 index 0000000..3d0f182 --- /dev/null +++ b/istio-1.3.5/install/kubernetes/operator/charts/istio-cni/Chart.yaml @@ -0,0 +1,13 @@ +apiVersion: v1 +name: istio-cni +version: 0.2.0 +appVersion: 0.2.0 +tillerVersion: ">=2.7.2-0" +description: Helm chart for istio-cni components +keywords: + - istio + - cni +sources: + - http://github.com/istio/cni +engine: gotpl +icon: https://istio.io/favicons/android-192x192.png diff --git a/istio-1.3.5/install/kubernetes/operator/charts/istio-cni/templates/clusterrole.yaml b/istio-1.3.5/install/kubernetes/operator/charts/istio-cni/templates/clusterrole.yaml new file mode 100644 index 0000000..8595fef --- /dev/null +++ b/istio-1.3.5/install/kubernetes/operator/charts/istio-cni/templates/clusterrole.yaml @@ -0,0 +1,14 @@ +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: istio-cni + labels: + app: istio-cni + release: {{ .Release.Name }} +rules: +- apiGroups: [""] + resources: + - pods + - nodes + verbs: + - get diff --git a/istio-1.3.5/install/kubernetes/operator/charts/istio-cni/templates/clusterrolebinding.yaml b/istio-1.3.5/install/kubernetes/operator/charts/istio-cni/templates/clusterrolebinding.yaml new file mode 100644 index 0000000..27adfdc --- /dev/null +++ b/istio-1.3.5/install/kubernetes/operator/charts/istio-cni/templates/clusterrolebinding.yaml @@ -0,0 +1,15 @@ +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: istio-cni + labels: + app: istio-cni + release: {{ .Release.Name }} +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: istio-cni +subjects: +- kind: ServiceAccount + name: istio-cni + namespace: {{ .Release.Namespace }} diff --git a/istio-1.3.5/install/kubernetes/operator/charts/istio-cni/templates/configmap-cni.yaml b/istio-1.3.5/install/kubernetes/operator/charts/istio-cni/templates/configmap-cni.yaml new file mode 100644 index 0000000..f5c4590 --- /dev/null +++ b/istio-1.3.5/install/kubernetes/operator/charts/istio-cni/templates/configmap-cni.yaml @@ -0,0 +1,21 @@ +kind: ConfigMap +apiVersion: v1 +metadata: + name: istio-cni-config + namespace: {{ .Release.Namespace }} + labels: + app: istio-cni + release: {{ .Release.Name }} +data: + # The CNI network configuration to add to the plugin chain on each node. The special + # values in this config will be automatically populated. + cni_network_config: |- + { + "type": "istio-cni", + "log_level": {{ quote .Values.cni.logLevel }}, + "kubernetes": { + "kubeconfig": "__KUBECONFIG_FILEPATH__", + "cni_bin_dir": {{ quote .Values.cni.cniBinDir }}, + "exclude_namespaces": [ {{ range $idx, $ns := .Values.cni.excludeNamespaces }}{{ if $idx }}, {{ end }}{{ quote $ns }}{{ end }} ] + } + } diff --git a/istio-1.3.5/install/kubernetes/operator/charts/istio-cni/templates/daemonset.yaml b/istio-1.3.5/install/kubernetes/operator/charts/istio-cni/templates/daemonset.yaml new file mode 100644 index 0000000..450683e --- /dev/null +++ b/istio-1.3.5/install/kubernetes/operator/charts/istio-cni/templates/daemonset.yaml @@ -0,0 +1,78 @@ +# This manifest installs the Istio install-cni container, as well +# as the Istio CNI plugin and config on +# each master and worker node in a Kubernetes cluster. +kind: DaemonSet +apiVersion: extensions/v1beta1 +metadata: + name: istio-cni-node + namespace: {{ .Release.Namespace }} + labels: + k8s-app: istio-cni-node + release: {{ .Release.Name }} +spec: + selector: + matchLabels: + k8s-app: istio-cni-node + updateStrategy: + type: RollingUpdate + rollingUpdate: + maxUnavailable: 1 + template: + metadata: + labels: + k8s-app: istio-cni-node + annotations: + # This, along with the CriticalAddonsOnly toleration below, + # marks the pod as a critical add-on, ensuring it gets + # priority scheduling and that its resources are reserved + # if it ever gets evicted. + scheduler.alpha.kubernetes.io/critical-pod: '' + spec: + nodeSelector: + beta.kubernetes.io/os: linux + hostNetwork: true + tolerations: + # Make sure istio-cni-node gets scheduled on all nodes. + - effect: NoSchedule + operator: Exists + # Mark the pod as a critical add-on for rescheduling. + - key: CriticalAddonsOnly + operator: Exists + - effect: NoExecute + operator: Exists + serviceAccountName: istio-cni + # Minimize downtime during a rolling upgrade or deletion; tell Kubernetes to do a "force + # deletion": https://kubernetes.io/docs/concepts/workloads/pods/pod/#termination-of-pods. + terminationGracePeriodSeconds: 5 + containers: + # This container installs the Istio CNI binaries + # and CNI network config file on each node. + - name: install-cni + image: {{ .Values.cni.hub }}/install-cni:{{ .Values.cni.tag }} + imagePullPolicy: {{ .Values.cni.pullPolicy | default .Values.global.imagePullPolicy }} + command: ["/install-cni.sh"] + env: +{{- if .Values.cni.cniConfFileName }} + # Name of the CNI config file to create. + - name: CNI_CONF_NAME + value: "{{ .Values.cni.cniConfFileName }}" +{{- end }} + # The CNI network config to install on each node. + - name: CNI_NETWORK_CONFIG + valueFrom: + configMapKeyRef: + name: istio-cni-config + key: cni_network_config + volumeMounts: + - mountPath: /host/opt/cni/bin + name: cni-bin-dir + - mountPath: /host/etc/cni/net.d + name: cni-net-dir + volumes: + # Used to install CNI. + - name: cni-bin-dir + hostPath: + path: {{ default "/opt/cni/bin" .Values.cni.cniBinDir }} + - name: cni-net-dir + hostPath: + path: {{ default "/etc/cni/net.d" .Values.cni.cniConfDir }} diff --git a/istio-1.3.5/install/kubernetes/operator/charts/istio-cni/templates/serviceaccount.yaml b/istio-1.3.5/install/kubernetes/operator/charts/istio-cni/templates/serviceaccount.yaml new file mode 100644 index 0000000..7a8aa71 --- /dev/null +++ b/istio-1.3.5/install/kubernetes/operator/charts/istio-cni/templates/serviceaccount.yaml @@ -0,0 +1,14 @@ +apiVersion: v1 +kind: ServiceAccount +{{- if .Values.global.imagePullSecrets }} +imagePullSecrets: +{{- range .Values.global.imagePullSecrets }} + - name: {{ . }} +{{- end }} +{{- end }} +metadata: + name: istio-cni + namespace: {{ .Release.Namespace }} + labels: + app: istio-cni + release: {{ .Release.Name }} diff --git a/istio-1.3.5/install/kubernetes/operator/charts/istio-cni/values.yaml b/istio-1.3.5/install/kubernetes/operator/charts/istio-cni/values.yaml new file mode 100644 index 0000000..70b41e5 --- /dev/null +++ b/istio-1.3.5/install/kubernetes/operator/charts/istio-cni/values.yaml @@ -0,0 +1,19 @@ +cni: + hub: gcr.io/istio-release + tag: release-1.3-latest-daily + pullPolicy: Always + + logLevel: info + + # Configuration file to insert istio-cni plugin configuration + # by default this will be the first file found in the cni-conf-dir + # Example + # cniConfFileName: 10-calico.conflist + + # CNI bin and conf dir override settings + # defaults: + cniBinDir: /opt/cni/bin + cniConfDir: /etc/cni/net.d + + excludeNamespaces: + - istio-system diff --git a/istio-1.3.5/install/kubernetes/operator/charts/istio-cni/values_gke.yaml b/istio-1.3.5/install/kubernetes/operator/charts/istio-cni/values_gke.yaml new file mode 100644 index 0000000..e03721b --- /dev/null +++ b/istio-1.3.5/install/kubernetes/operator/charts/istio-cni/values_gke.yaml @@ -0,0 +1,19 @@ +cni: + hub: docker.io/tiswanso + tag: v0.1-dev + pullPolicy: Always + + logLevel: info + + # Configuration file to insert istio-cni plugin configuration + # by default this will be the first file found in the cni-conf-dir + # Example + # cniConfFileName: 10-calico.conflist + + # CNI bin and conf dir override settings + # defaults: + cniBinDir: /home/kubernetes/bin + cniConfDir: /etc/cni/net.d + + excludeNamespaces: + - istio-system diff --git a/istio-1.3.5/install/kubernetes/operator/charts/istio-control/istio-autoinject/Chart.yaml b/istio-1.3.5/install/kubernetes/operator/charts/istio-control/istio-autoinject/Chart.yaml new file mode 100644 index 0000000..ecd466a --- /dev/null +++ b/istio-1.3.5/install/kubernetes/operator/charts/istio-control/istio-autoinject/Chart.yaml @@ -0,0 +1,14 @@ +apiVersion: v1 +name: istio-autoinject +version: 1.1.0 +appVersion: 1.1.0 +tillerVersion: ">=2.7.2" +description: Helm chart for sidecar injector webhook deployment +keywords: + - istio + - sidecarInjectorWebhook + - autoinject +sources: + - http://github.com/istio/istio +engine: gotpl +icon: https://istio.io/favicons/android-192x192.png diff --git a/istio-1.3.5/install/kubernetes/operator/charts/istio-control/istio-autoinject/NOTES.txt b/istio-1.3.5/install/kubernetes/operator/charts/istio-control/istio-autoinject/NOTES.txt new file mode 100644 index 0000000..8d77938 --- /dev/null +++ b/istio-1.3.5/install/kubernetes/operator/charts/istio-control/istio-autoinject/NOTES.txt @@ -0,0 +1,33 @@ +Sidecar injector (optional): if disabled, manual injection or other tools need to be used. + +Sidecar injection in each profile can be selected by labeling the namespace with the appropriate profile. + +The new label is 'istio-env' and the value is the namespace where the injector is installed. + +Note that it is possible to install a profile with only the injector app - using remote Pilot and MCP. + +``` + # New style, using the istio-pilot11 profile + kubectl create ns fortio + kubectl label ns fortio istio-env=istio-control + + # Second pilot profile + kubectl create ns fortio-test + kubectl label ns fortio istio-env=istio-master + + # Old-style, using istio-system and Istio 1.0 or 1.1 default installations. + kubectl create ns fortio-istio-system + kubectl label ns fortio istio-injection=enabled +``` + +# Uninstall + +After uninstalling, you should cleanup the global CRD using: + +```bash + + kubectl delete MutatingWebhookConfiguration istio-sidecar-injector-istio-control + +``` + +Any app using the uninstalled istio-env label will no longer be auto-injected once the config is deleted. diff --git a/istio-1.3.5/install/kubernetes/operator/charts/istio-control/istio-autoinject/files/injection-template.yaml b/istio-1.3.5/install/kubernetes/operator/charts/istio-control/istio-autoinject/files/injection-template.yaml new file mode 100644 index 0000000..6b4432c --- /dev/null +++ b/istio-1.3.5/install/kubernetes/operator/charts/istio-control/istio-autoinject/files/injection-template.yaml @@ -0,0 +1,374 @@ +template: | + rewriteAppHTTPProbe: {{ valueOrDefault .Values.sidecarInjectorWebhook.rewriteAppHTTPProbe false }} + {{- if or (not .Values.istio_cni.enabled) .Values.global.proxy.enableCoreDump }} + initContainers: + {{ if ne (annotation .ObjectMeta `sidecar.istio.io/interceptionMode` .ProxyConfig.InterceptionMode) `NONE` }} + {{- if not .Values.istio_cni.enabled }} + - name: istio-init + {{- if contains "/" .Values.global.proxy_init.image }} + image: "{{ .Values.global.proxy_init.image }}" + {{- else }} + image: "{{ .Values.global.hub }}/{{ .Values.global.proxy_init.image }}:{{ .Values.global.tag }}" + {{- end }} + command: + - "/usr/local/bin/istio-iptables.sh" + - "-p" + - 15001 + - "-z" + - "15006" + - "-u" + - 1337 + - "-m" + - "{{ annotation .ObjectMeta `sidecar.istio.io/interceptionMode` .ProxyConfig.InterceptionMode }}" + - "-i" + - "{{ annotation .ObjectMeta `traffic.sidecar.istio.io/includeOutboundIPRanges` .Values.global.proxy.includeIPRanges }}" + - "-x" + - "{{ annotation .ObjectMeta `traffic.sidecar.istio.io/excludeOutboundIPRanges` .Values.global.proxy.excludeIPRanges }}" + - "-b" + - "{{ annotation .ObjectMeta `traffic.sidecar.istio.io/includeInboundPorts` `*` }}" + - "-d" + - "{{ excludeInboundPort (annotation .ObjectMeta `status.sidecar.istio.io/port` .Values.global.proxy.statusPort) (annotation .ObjectMeta `traffic.sidecar.istio.io/excludeInboundPorts` .Values.global.proxy.excludeInboundPorts) }}" + {{ if or (isset .ObjectMeta.Annotations `traffic.sidecar.istio.io/excludeOutboundPorts`) (ne (valueOrDefault .Values.global.proxy.excludeOutboundPorts "") "") -}} + - "-o" + - "{{ annotation .ObjectMeta `traffic.sidecar.istio.io/excludeOutboundPorts` .Values.global.proxy.excludeOutboundPorts }}" + {{ end -}} + {{ if (isset .ObjectMeta.Annotations `traffic.sidecar.istio.io/kubevirtInterfaces`) -}} + - "-k" + - "{{ index .ObjectMeta.Annotations `traffic.sidecar.istio.io/kubevirtInterfaces` }}" + {{ end -}} + imagePullPolicy: "{{ valueOrDefault .Values.global.imagePullPolicy `Always` }}" + {{- if .Values.global.proxy_init.resources }} + resources: + {{ toYaml .Values.global.proxy_init.resources | indent 4 }} + {{- else }} + resources: {} + {{- end }} + securityContext: + runAsUser: 0 + runAsNonRoot: false + capabilities: + add: + - NET_ADMIN + {{- if .Values.global.proxy.privileged }} + privileged: true + {{- end }} + restartPolicy: Always + {{- end }} + {{ end -}} + {{- if eq .Values.global.proxy.enableCoreDump true }} + - name: enable-core-dump + args: + - -c + - sysctl -w kernel.core_pattern=/var/lib/istio/core.proxy && ulimit -c unlimited + command: + - /bin/sh + {{- if contains "/" .Values.global.proxy_init.image }} + image: "{{ .Values.global.proxy_init.image }}" + {{- else }} + image: "{{ .Values.global.hub }}/{{ .Values.global.proxy_init.image }}:{{ .Values.global.tag }}" + {{- end }} + imagePullPolicy: "{{ valueOrDefault .Values.global.imagePullPolicy `Always` }}" + resources: {} + securityContext: + runAsUser: 0 + runAsNonRoot: false + privileged: true + {{ end }} + {{- end }} + containers: + - name: istio-proxy + {{- if contains "/" (annotation .ObjectMeta `sidecar.istio.io/proxyImage` .Values.global.proxy.image) }} + image: "{{ annotation .ObjectMeta `sidecar.istio.io/proxyImage` .Values.global.proxy.image }}" + {{- else }} + image: "{{ .Values.global.hub }}/{{ .Values.global.proxy.image }}:{{ .Values.global.tag }}" + {{- end }} + ports: + - containerPort: 15090 + protocol: TCP + name: http-envoy-prom + args: + - proxy + - sidecar + - --domain + - $(POD_NAMESPACE).svc.{{ .Values.global.proxy.clusterDomain }} + - --configPath + - "/etc/istio/proxy" + - --binaryPath + - "/usr/local/bin/envoy" + - --serviceCluster + {{ if ne "" (index .ObjectMeta.Labels "app") -}} + - "{{ index .ObjectMeta.Labels `app` }}.$(POD_NAMESPACE)" + {{ else -}} + - "{{ valueOrDefault .DeploymentMeta.Name `istio-proxy` }}.{{ valueOrDefault .DeploymentMeta.Namespace `default` }}" + {{ end -}} + - --drainDuration + - "{{ formatDuration .ProxyConfig.DrainDuration }}" + - --parentShutdownDuration + - "{{ formatDuration .ProxyConfig.ParentShutdownDuration }}" + - --discoveryAddress + - "{{ annotation .ObjectMeta `sidecar.istio.io/discoveryAddress` .ProxyConfig.DiscoveryAddress }}" + {{- if eq .Values.global.proxy.tracer "lightstep" }} + - --lightstepAddress + - "{{ .ProxyConfig.GetTracing.GetLightstep.GetAddress }}" + - --lightstepAccessToken + - "{{ .ProxyConfig.GetTracing.GetLightstep.GetAccessToken }}" + - --lightstepSecure={{ .ProxyConfig.GetTracing.GetLightstep.GetSecure }} + - --lightstepCacertPath + - "{{ .ProxyConfig.GetTracing.GetLightstep.GetCacertPath }}" + {{- else if eq .Values.global.proxy.tracer "zipkin" }} + - --zipkinAddress + - "{{ .ProxyConfig.GetTracing.GetZipkin.GetAddress }}" + {{- else if eq .Values.global.proxy.tracer "datadog" }} + - --datadogAgentAddress + - "{{ .ProxyConfig.GetTracing.GetDatadog.GetAddress }}" + {{- end }} + - --proxyLogLevel={{ annotation .ObjectMeta `sidecar.istio.io/logLevel` .Values.global.proxy.logLevel}} + - --proxyComponentLogLevel={{ annotation .ObjectMeta `sidecar.istio.io/componentLogLevel` .Values.global.proxy.componentLogLevel}} + - --connectTimeout + - "{{ formatDuration .ProxyConfig.ConnectTimeout }}" + {{- if .Values.global.proxy.envoyStatsd.enabled }} + - --statsdUdpAddress + - "{{ .ProxyConfig.StatsdUdpAddress }}" + {{- end }} + {{- if .Values.global.proxy.envoyMetricsService.enabled }} + - --envoyMetricsServiceAddress + - "{{ .ProxyConfig.GetEnvoyMetricsService.GetAddress }}" + {{- end }} + {{- if .Values.global.proxy.envoyAccessLogService.enabled }} + - --envoyAccessLogServiceAddress + - "{{ .ProxyConfig.GetEnvoyAccessLogService.GetAddress }}" + {{- end }} + - --proxyAdminPort + - "{{ .ProxyConfig.ProxyAdminPort }}" + {{ if gt .ProxyConfig.Concurrency 0 -}} + - --concurrency + - "{{ .ProxyConfig.Concurrency }}" + {{ end -}} + {{- if .Values.global.controlPlaneSecurityEnabled }} + - --controlPlaneAuthPolicy + - MUTUAL_TLS + {{- else }} + - --controlPlaneAuthPolicy + - NONE + {{- end }} + - --dnsRefreshRate + - {{ valueOrDefault .Values.global.proxy.dnsRefreshRate "300s" }} + {{- if (ne (annotation .ObjectMeta "status.sidecar.istio.io/port" .Values.global.proxy.statusPort) "0") }} + - --statusPort + - "{{ annotation .ObjectMeta `status.sidecar.istio.io/port` .Values.global.proxy.statusPort }}" + - --applicationPorts + - "{{ annotation .ObjectMeta `readiness.status.sidecar.istio.io/applicationPorts` (applicationPorts .Spec.Containers) }}" + {{- end }} + {{- if .Values.global.trustDomain }} + - --trust-domain={{ .Values.global.trustDomain }} + {{- end }} + {{- if .Values.global.logAsJson }} + - --log_as_json + {{- end }} + - --controlPlaneBootstrap=false + {{- if (isset .ObjectMeta.Annotations `sidecar.istio.io/bootstrapOverride`) }} + - --templateFile=/etc/istio/custom-bootstrap/envoy_bootstrap.json + {{- end }} + env: + - name: POD_NAME + valueFrom: + fieldRef: + fieldPath: metadata.name + - name: POD_NAMESPACE + valueFrom: + fieldRef: + fieldPath: metadata.namespace + - name: INSTANCE_IP + valueFrom: + fieldRef: + fieldPath: status.podIP + - name: SERVICE_ACCOUNT + valueFrom: + fieldRef: + fieldPath: spec.serviceAccountName + - name: HOST_IP + valueFrom: + fieldRef: + fieldPath: status.hostIP + - name: ISTIO_META_POD_NAME + valueFrom: + fieldRef: + fieldPath: metadata.name + - name: ISTIO_META_CONFIG_NAMESPACE + valueFrom: + fieldRef: + fieldPath: metadata.namespace + - name: ISTIO_META_INTERCEPTION_MODE + value: "{{ or (index .ObjectMeta.Annotations `sidecar.istio.io/interceptionMode`) .ProxyConfig.InterceptionMode.String }}" + - name: ISTIO_META_INCLUDE_INBOUND_PORTS + value: "{{ annotation .ObjectMeta `traffic.sidecar.istio.io/includeInboundPorts` (applicationPorts .Spec.Containers) }}" + {{- if .Values.global.network }} + - name: ISTIO_META_NETWORK + value: "{{ .Values.global.network }}" + {{- end }} + {{ if .ObjectMeta.Annotations }} + - name: ISTIO_METAJSON_ANNOTATIONS + value: | + {{ toJSON .ObjectMeta.Annotations }} + {{ end }} + {{ if .ObjectMeta.Labels }} + - name: ISTIO_METAJSON_LABELS + value: | + {{ toJSON .ObjectMeta.Labels }} + {{ end }} + {{- if .DeploymentMeta.Name }} + - name: ISTIO_META_WORKLOAD_NAME + value: {{ .DeploymentMeta.Name }} + {{ end }} + {{- if and .TypeMeta.APIVersion .DeploymentMeta.Name }} + - name: ISTIO_META_OWNER + value: kubernetes://api/{{ .TypeMeta.APIVersion }}/namespaces/{{ valueOrDefault .DeploymentMeta.Namespace `default` }}/{{ toLower .TypeMeta.Kind}}s/{{ .DeploymentMeta.Name }} + {{- end}} + {{- if (isset .ObjectMeta.Annotations `sidecar.istio.io/bootstrapOverride`) }} + - name: ISTIO_BOOTSTRAP_OVERRIDE + value: "/etc/istio/custom-bootstrap/custom_bootstrap.json" + {{- end }} + {{- if .Values.global.sds.customTokenDirectory }} + - name: ISTIO_META_SDS_TOKEN_PATH + value: "{{ .Values.global.sds.customTokenDirectory -}}/sdstoken" + {{- end }} + {{- if .Values.global.meshID }} + - name: ISTIO_META_MESH_ID + value: "{{ .Values.global.meshID }}" + {{- else if .Values.global.trustDomain }} + - name: ISTIO_META_MESH_ID + value: "{{ .Values.global.trustDomain }}" + {{- end }} + {{- if and (eq .Values.global.proxy.tracer "datadog") (isset .ObjectMeta.Annotations `apm.datadoghq.com/env`) }} + {{- range $key, $value := fromJSON (index .ObjectMeta.Annotations `apm.datadoghq.com/env`) }} + - name: {{ $key }} + value: "{{ $value }}" + {{- end }} + {{- end }} + imagePullPolicy: "{{ valueOrDefault .Values.global.imagePullPolicy `Always` }}" + {{ if ne (annotation .ObjectMeta `status.sidecar.istio.io/port` .Values.global.proxy.statusPort) `0` }} + readinessProbe: + httpGet: + path: /healthz/ready + port: {{ annotation .ObjectMeta `status.sidecar.istio.io/port` .Values.global.proxy.statusPort }} + initialDelaySeconds: {{ annotation .ObjectMeta `readiness.status.sidecar.istio.io/initialDelaySeconds` .Values.global.proxy.readinessInitialDelaySeconds }} + periodSeconds: {{ annotation .ObjectMeta `readiness.status.sidecar.istio.io/periodSeconds` .Values.global.proxy.readinessPeriodSeconds }} + failureThreshold: {{ annotation .ObjectMeta `readiness.status.sidecar.istio.io/failureThreshold` .Values.global.proxy.readinessFailureThreshold }} + {{ end -}} + securityContext: + {{- if .Values.global.proxy.privileged }} + privileged: true + {{- end }} + {{- if ne .Values.global.proxy.enableCoreDump true }} + readOnlyRootFilesystem: true + {{- end }} + {{ if eq (annotation .ObjectMeta `sidecar.istio.io/interceptionMode` .ProxyConfig.InterceptionMode) `TPROXY` -}} + capabilities: + add: + - NET_ADMIN + {{ else -}} + runAsUser: 1337 + {{- end }} + runAsGroup: 1337 + resources: + {{ if or (isset .ObjectMeta.Annotations `sidecar.istio.io/proxyCPU`) (isset .ObjectMeta.Annotations `sidecar.istio.io/proxyMemory`) -}} + requests: + {{ if (isset .ObjectMeta.Annotations `sidecar.istio.io/proxyCPU`) -}} + cpu: "{{ index .ObjectMeta.Annotations `sidecar.istio.io/proxyCPU` }}" + {{ end}} + {{ if (isset .ObjectMeta.Annotations `sidecar.istio.io/proxyMemory`) -}} + memory: "{{ index .ObjectMeta.Annotations `sidecar.istio.io/proxyMemory` }}" + {{ end }} + {{ else -}} + {{- if .Values.global.proxy.resources }} + {{ toYaml .Values.global.proxy.resources | indent 4 }} + {{- end }} + {{ end -}} + volumeMounts: + {{ if (isset .ObjectMeta.Annotations `sidecar.istio.io/bootstrapOverride`) }} + - mountPath: /etc/istio/custom-bootstrap + name: custom-bootstrap-volume + {{- end }} + - mountPath: /etc/istio/proxy + name: istio-envoy + {{- if .Values.global.sds.enabled }} + - mountPath: /var/run/sds + name: sds-uds-path + readOnly: true + - mountPath: /var/run/secrets/tokens + name: istio-token + {{- if .Values.global.sds.customTokenDirectory }} + - mountPath: "{{ .Values.global.sds.customTokenDirectory -}}" + name: custom-sds-token + readOnly: true + {{- end }} + {{- else }} + - mountPath: /etc/certs/ + name: istio-certs + readOnly: true + {{- end }} + {{- if and (eq .Values.global.proxy.tracer "lightstep") .Values.global.tracer.lightstep.cacertPath }} + - mountPath: {{ directory .ProxyConfig.GetTracing.GetLightstep.GetCacertPath }} + name: lightstep-certs + readOnly: true + {{- end }} + {{- if isset .ObjectMeta.Annotations `sidecar.istio.io/userVolumeMount` }} + {{ range $index, $value := fromJSON (index .ObjectMeta.Annotations `sidecar.istio.io/userVolumeMount`) }} + - name: "{{ $index }}" + {{ toYaml $value | indent 4 }} + {{ end }} + {{- end }} + volumes: + {{- if (isset .ObjectMeta.Annotations `sidecar.istio.io/bootstrapOverride`) }} + - name: custom-bootstrap-volume + configMap: + name: {{ annotation .ObjectMeta `sidecar.istio.io/bootstrapOverride` "" }} + {{- end }} + - emptyDir: + medium: Memory + name: istio-envoy + {{- if .Values.global.sds.enabled }} + - name: sds-uds-path + hostPath: + path: /var/run/sds + - name: istio-token + projected: + sources: + - serviceAccountToken: + path: istio-token + expirationSeconds: 43200 + audience: {{ .Values.global.trustDomain }} + {{- if .Values.global.sds.customTokenDirectory }} + - name: custom-sds-token + secret: + secretName: sdstokensecret + {{- end }} + {{- else }} + - name: istio-certs + secret: + optional: true + {{ if eq .Spec.ServiceAccountName "" }} + secretName: istio.default + {{ else -}} + secretName: {{ printf "istio.%s" .Spec.ServiceAccountName }} + {{ end -}} + {{- if isset .ObjectMeta.Annotations `sidecar.istio.io/userVolume` }} + {{range $index, $value := fromJSON (index .ObjectMeta.Annotations `sidecar.istio.io/userVolume`) }} + - name: "{{ $index }}" + {{ toYaml $value | indent 2 }} + {{ end }} + {{ end }} + {{- end }} + {{- if and (eq .Values.global.proxy.tracer "lightstep") .Values.global.tracer.lightstep.cacertPath }} + - name: lightstep-certs + secret: + optional: true + secretName: lightstep.cacert + {{- end }} + {{- if .Values.global.podDNSSearchNamespaces }} + dnsConfig: + searches: + {{- range .Values.global.podDNSSearchNamespaces }} + - {{ render . }} + {{- end }} + {{- end }} diff --git a/istio-1.3.5/install/kubernetes/operator/charts/istio-control/istio-autoinject/templates/_affinity.tpl b/istio-1.3.5/install/kubernetes/operator/charts/istio-control/istio-autoinject/templates/_affinity.tpl new file mode 100644 index 0000000..230ed1e --- /dev/null +++ b/istio-1.3.5/install/kubernetes/operator/charts/istio-control/istio-autoinject/templates/_affinity.tpl @@ -0,0 +1,93 @@ +{{/* affinity - https://kubernetes.io/docs/concepts/configuration/assign-pod-node/ */}} + +{{- define "nodeaffinity" }} + nodeAffinity: + requiredDuringSchedulingIgnoredDuringExecution: + {{- include "nodeAffinityRequiredDuringScheduling" . }} + preferredDuringSchedulingIgnoredDuringExecution: + {{- include "nodeAffinityPreferredDuringScheduling" . }} +{{- end }} + +{{- define "nodeAffinityRequiredDuringScheduling" }} + nodeSelectorTerms: + - matchExpressions: + - key: beta.kubernetes.io/arch + operator: In + values: + {{- range $key, $val := .Values.global.arch }} + {{- if gt ($val | int) 0 }} + - {{ $key }} + {{- end }} + {{- end }} + {{- $nodeSelector := default .Values.global.defaultNodeSelector .Values.sidecarInjectorWebhook.nodeSelector -}} + {{- range $key, $val := $nodeSelector }} + - key: {{ $key }} + operator: In + values: + - {{ $val }} + {{- end }} +{{- end }} + +{{- define "nodeAffinityPreferredDuringScheduling" }} + {{- range $key, $val := .Values.global.arch }} + {{- if gt ($val | int) 0 }} + - weight: {{ $val | int }} + preference: + matchExpressions: + - key: beta.kubernetes.io/arch + operator: In + values: + - {{ $key }} + {{- end }} + {{- end }} +{{- end }} + +{{- define "podAntiAffinity" }} +{{- if or .Values.sidecarInjectorWebhook.podAntiAffinityLabelSelector .Values.sidecarInjectorWebhook.podAntiAffinityTermLabelSelector}} + podAntiAffinity: + {{- if .Values.sidecarInjectorWebhook.podAntiAffinityLabelSelector }} + requiredDuringSchedulingIgnoredDuringExecution: + {{- include "podAntiAffinityRequiredDuringScheduling" . }} + {{- end }} + {{- if .Values.sidecarInjectorWebhook.podAntiAffinityTermLabelSelector }} + preferredDuringSchedulingIgnoredDuringExecution: + {{- include "podAntiAffinityPreferredDuringScheduling" . }} + {{- end }} +{{- end }} +{{- end }} + +{{- define "podAntiAffinityRequiredDuringScheduling" }} + {{- range $index, $item := .Values.sidecarInjectorWebhook.podAntiAffinityLabelSelector }} + - labelSelector: + matchExpressions: + - key: {{ $item.key }} + operator: {{ $item.operator }} + {{- if $item.values }} + values: + {{- $vals := split "," $item.values }} + {{- range $i, $v := $vals }} + - {{ $v }} + {{- end }} + {{- end }} + topologyKey: {{ $item.topologyKey }} + {{- end }} +{{- end }} + +{{- define "podAntiAffinityPreferredDuringScheduling" }} + {{- range $index, $item := .Values.sidecarInjectorWebhook.podAntiAffinityTermLabelSelector }} + - podAffinityTerm: + labelSelector: + matchExpressions: + - key: {{ $item.key }} + operator: {{ $item.operator }} + {{- if $item.values }} + values: + {{- $vals := split "," $item.values }} + {{- range $i, $v := $vals }} + - {{ $v }} + {{- end }} + {{- end }} + topologyKey: {{ $item.topologyKey }} + weight: 100 + {{- end }} +{{- end }} diff --git a/istio-1.3.5/install/kubernetes/operator/charts/istio-control/istio-autoinject/templates/_helpers.tpl b/istio-1.3.5/install/kubernetes/operator/charts/istio-control/istio-autoinject/templates/_helpers.tpl new file mode 100644 index 0000000..df59a7c --- /dev/null +++ b/istio-1.3.5/install/kubernetes/operator/charts/istio-control/istio-autoinject/templates/_helpers.tpl @@ -0,0 +1,32 @@ +{{/* vim: set filetype=mustache: */}} +{{/* +Expand the name of the chart. +*/}} +{{- define "sidecar-injector.name" -}} +{{- default .Chart.Name .Values.sidecarInjectorWebhook.nameOverride | trunc 63 | trimSuffix "-" -}} +{{- end -}} + +{{/* +Create a default fully qualified app name. +We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). +If release name contains chart name it will be used as a full name. +*/}} +{{- define "sidecar-injector.fullname" -}} +{{- if .Values.sidecarInjectorWebhook.fullnameOverride -}} +{{- .Values.sidecarInjectorWebhook.fullnameOverride | trunc 63 | trimSuffix "-" -}} +{{- else -}} +{{- $name := default .Chart.Name .Values.sidecarInjectorWebhook.nameOverride -}} +{{- if contains $name .Release.Name -}} +{{- .Release.Name | trunc 63 | trimSuffix "-" -}} +{{- else -}} +{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" -}} +{{- end -}} +{{- end -}} +{{- end -}} + +{{/* +Create chart name and version as used by the chart label. +*/}} +{{- define "sidecar-injector.chart" -}} +{{- .Chart.Name | trunc 63 | trimSuffix "-" -}} +{{- end -}} diff --git a/istio-1.3.5/install/kubernetes/operator/charts/istio-control/istio-autoinject/templates/clusterrole.yaml b/istio-1.3.5/install/kubernetes/operator/charts/istio-control/istio-autoinject/templates/clusterrole.yaml new file mode 100644 index 0000000..93d42d8 --- /dev/null +++ b/istio-1.3.5/install/kubernetes/operator/charts/istio-control/istio-autoinject/templates/clusterrole.yaml @@ -0,0 +1,17 @@ +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: istio-sidecar-injector-{{ .Release.Namespace }} + labels: + app: sidecar-injector + release: {{ .Release.Name }} + istio: sidecar-injector +rules: +- apiGroups: [""] + resources: ["configmaps"] + resourceNames: ["istio-sidecar-injector"] + verbs: ["get", "list", "watch"] +- apiGroups: ["admissionregistration.k8s.io"] + resources: ["mutatingwebhookconfigurations"] + resourceNames: ["istio-sidecar-injector", "istio-sidecar-injector-{{.Release.Namespace}}"] + verbs: ["get", "list", "watch", "patch"] diff --git a/istio-1.3.5/install/kubernetes/operator/charts/istio-control/istio-autoinject/templates/clusterrolebinding.yaml b/istio-1.3.5/install/kubernetes/operator/charts/istio-control/istio-autoinject/templates/clusterrolebinding.yaml new file mode 100644 index 0000000..338467e --- /dev/null +++ b/istio-1.3.5/install/kubernetes/operator/charts/istio-control/istio-autoinject/templates/clusterrolebinding.yaml @@ -0,0 +1,16 @@ +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: istio-sidecar-injector-admin-role-binding-{{ .Release.Namespace }} + labels: + app: sidecar-injector + release: {{ .Release.Name }} + istio: sidecar-injector +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: istio-sidecar-injector-{{ .Release.Namespace }} +subjects: + - kind: ServiceAccount + name: istio-sidecar-injector-service-account + namespace: {{ .Release.Namespace }} diff --git a/istio-1.3.5/install/kubernetes/operator/charts/istio-control/istio-autoinject/templates/configmap.yaml b/istio-1.3.5/install/kubernetes/operator/charts/istio-control/istio-autoinject/templates/configmap.yaml new file mode 100644 index 0000000..bcf50ab --- /dev/null +++ b/istio-1.3.5/install/kubernetes/operator/charts/istio-control/istio-autoinject/templates/configmap.yaml @@ -0,0 +1,83 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: injector-mesh + namespace: {{ .Release.Namespace }} + labels: + release: {{ .Release.Name }} +data: + # This is the 'mesh' config, loaded by the sidecar injector. + # It is a different configmap from pilot to allow a-la-carte install of the injector and follow the model + # of reducing blast-radius of config changes and avoiding globals. + + # Note that injector uses a subset of the mesh config only - for clarity this is only generating the + # required config, i.e. the defaultConfig section. See injection-template .ProxyConfig settings. + + + mesh: |- + + defaultConfig: + # + # TCP connection timeout between Envoy & the application, and between Envoys. + connectTimeout: 10s + # + ### ADVANCED SETTINGS ############# + # Where should envoy's configuration be stored in the istio-proxy container + configPath: "/etc/istio/proxy" + # The pseudo service name used for Envoy. + serviceCluster: istio-proxy + # These settings that determine how long an old Envoy + # process should be kept alive after an occasional reload. + drainDuration: 45s + parentShutdownDuration: 1m0s + # + # Port where Envoy listens (on local host) for admin commands + # You can exec into the istio-proxy container in a pod and + # curl the admin port (curl http://localhost:15000/) to obtain + # diagnostic information from Envoy. See + # https://lyft.github.io/envoy/docs/operations/admin.html + # for more details + proxyAdminPort: 15000 + # + # Set concurrency to a specific number to control the number of Proxy worker threads. + # If set to 0 (default), then start worker thread for each CPU thread/core. + concurrency: {{ .Values.global.proxy.concurrency }} + # + {{- if eq .Values.global.proxy.tracer "lightstep" }} + tracing: + lightstep: + # Address of the LightStep Satellite pool + address: {{ .Values.global.tracer.lightstep.address }} + # Access Token used to communicate with the Satellite pool + accessToken: {{ .Values.global.tracer.lightstep.accessToken }} + # Whether communication with the Satellite pool should be secure + secure: {{ .Values.global.tracer.lightstep.secure }} + # Path to the file containing the cacert to use when verifying TLS + cacertPath: {{ .Values.global.tracer.lightstep.cacertPath }} + {{- else if eq .Values.global.proxy.tracer "zipkin" }} + tracing: + zipkin: + # Address of the Zipkin collector + {{- if .Values.global.tracer.zipkin.address }} + address: {{ .Values.global.tracer.zipkin.address }} + {{- else }} + address: zipkin.{{ .Values.global.telemetryNamespace }}:9411 + {{- end }} + {{- end }} + + {{- if .Values.global.controlPlaneSecurityEnabled }} + # + # Mutual TLS authentication between sidecars and istio control plane. + controlPlaneAuthPolicy: MUTUAL_TLS + # + # Address where istio Pilot service is running + discoveryAddress: istio-pilot{{ .Values.version }}.{{ .Release.Namespace }}:15011 + {{- else }} + # + # Mutual TLS authentication between sidecars and istio control plane. + controlPlaneAuthPolicy: NONE + # + # Address where istio Pilot service is running + discoveryAddress: istio-pilot{{ .Values.version }}.{{ .Release.Namespace }}:15010 + {{- end }} +--- diff --git a/istio-1.3.5/install/kubernetes/operator/charts/istio-control/istio-autoinject/templates/deployment.yaml b/istio-1.3.5/install/kubernetes/operator/charts/istio-control/istio-autoinject/templates/deployment.yaml new file mode 100644 index 0000000..caaba80 --- /dev/null +++ b/istio-1.3.5/install/kubernetes/operator/charts/istio-control/istio-autoinject/templates/deployment.yaml @@ -0,0 +1,125 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: istio-sidecar-injector + namespace: {{ .Release.Namespace }} + labels: + app: sidecar-injector + release: {{ .Release.Name }} + istio: sidecar-injector +spec: + replicas: {{ .Values.sidecarInjectorWebhook.replicaCount }} + selector: + matchLabels: + istio: sidecar-injector + strategy: + rollingUpdate: + maxSurge: {{ .Values.sidecarInjectorWebhook.rollingMaxSurge }} + maxUnavailable: {{ .Values.sidecarInjectorWebhook.rollingMaxUnavailable }} + template: + metadata: + labels: + app: sidecarInjectorWebhook + istio: sidecar-injector +{{- if eq .Release.Namespace "istio-system"}} + heritage: Tiller + release: istio + chart: sidecarInjectorWebhook +{{- end }} + annotations: + sidecar.istio.io/inject: "false" + checksum/config-volume: {{ .Files.Get "files/injection-template.yaml" | sha256sum }} + spec: + serviceAccountName: istio-sidecar-injector-service-account +{{- if .Values.global.priorityClassName }} + priorityClassName: "{{ .Values.global.priorityClassName }}" +{{- end }} + containers: + - name: sidecar-injector-webhook +{{- if contains "/" .Values.sidecarInjectorWebhook.image }} + image: "{{ .Values.sidecarInjectorWebhook.image }}" +{{- else }} + image: "{{ .Values.global.hub }}/{{ .Values.sidecarInjectorWebhook.image | default "sidecar_injector" }}:{{ .Values.global.tag }}" +{{- end }} + imagePullPolicy: {{ .Values.global.imagePullPolicy | default "Always" }} + args: + - --caCertFile=/etc/istio/certs/root-cert.pem + - --tlsCertFile=/etc/istio/certs/cert-chain.pem + - --tlsKeyFile=/etc/istio/certs/key.pem + - --injectConfig=/etc/istio/inject/config + - --meshConfig=/etc/istio/config/mesh + - --port=9443 + - --healthCheckInterval=2s + - --healthCheckFile=/health + {{- if eq .Release.Namespace "istio-system"}} + - --webhookConfigName=istio-sidecar-injector + {{ else }} + - --webhookConfigName=istio-sidecar-injector-{{ .Release.Namespace }} + {{- end }} + - --log_output_level=debug + {{- if .Values.global.logAsJson }} + - --log_as_json + {{- end }} + {{/*securityContext:*/}} + {{/*runAsUser: 1337*/}} + {{/*runAsGroup: 1337*/}} + volumeMounts: + - name: config-volume + mountPath: /etc/istio/config + readOnly: true + - name: certs + mountPath: /etc/istio/certs + readOnly: true + - name: inject-config + mountPath: /etc/istio/inject + readOnly: true + livenessProbe: + exec: + command: + - /usr/local/bin/sidecar-injector + - probe + - --probe-path=/health + - --interval=4s + initialDelaySeconds: 4 + periodSeconds: 4 + readinessProbe: + exec: + command: + - /usr/local/bin/sidecar-injector + - probe + - --probe-path=/health + - --interval=4s + initialDelaySeconds: 4 + periodSeconds: 4 + resources: +{{- if .Values.sidecarInjectorWebhook.resources }} +{{ toYaml .Values.sidecarInjectorWebhook.resources | indent 12 }} +{{- else }} +{{ toYaml .Values.global.defaultResources | indent 12 }} +{{- end }} + volumes: + - name: config-volume + configMap: + name: injector-mesh + - name: certs + secret: +{{- if .Values.sidecarInjectorWebhook.selfSigned }} + secretName: istio-sidecar-injector-self-signed +{{- else }} + secretName: istio.istio-sidecar-injector-service-account +{{- end }} + - name: inject-config + configMap: + name: istio-sidecar-injector + items: + - key: config + path: config + - key: values + path: values + affinity: + {{- include "nodeaffinity" . | indent 6 }} + {{- include "podAntiAffinity" . | indent 6 }} +{{- if .Values.sidecarInjectorWebhook.tolerations }} + tolerations: +{{ toYaml .Values.sidecarInjectorWebhook.tolerations | indent 6 }} +{{- end }} diff --git a/istio-1.3.5/install/kubernetes/operator/charts/istio-control/istio-autoinject/templates/mutatingwebhook.yaml b/istio-1.3.5/install/kubernetes/operator/charts/istio-control/istio-autoinject/templates/mutatingwebhook.yaml new file mode 100644 index 0000000..7b40536 --- /dev/null +++ b/istio-1.3.5/install/kubernetes/operator/charts/istio-control/istio-autoinject/templates/mutatingwebhook.yaml @@ -0,0 +1,71 @@ +{{- $ca := genCA "istio-sidecar-injector-ca-{{ .Release.Namespace }}" 3650 }} +apiVersion: admissionregistration.k8s.io/v1beta1 +kind: MutatingWebhookConfiguration +metadata: + {{- if eq .Release.Namespace "istio-system"}} + name: istio-sidecar-injector + {{ else }} + name: istio-sidecar-injector-{{ .Release.Namespace }} + {{- end }} + labels: + app: sidecar-injector + release: {{ .Release.Name }} +webhooks: + - name: sidecar-injector.istio.io + clientConfig: + service: + name: istio-sidecar-injector + namespace: {{ .Release.Namespace }} + path: "/inject" +{{- if .Values.sidecarInjectorWebhook.selfSigned }} + caBundle: {{ $ca.Cert | b64enc }} +{{- else }} + caBundle: "" +{{- end }} + rules: + - operations: [ "CREATE" ] + apiGroups: [""] + apiVersions: ["v1"] + resources: ["pods"] + failurePolicy: Fail + namespaceSelector: +{{- if .Values.sidecarInjectorWebhook.enableNamespacesByDefault }} + matchExpressions: + - key: name + operator: NotIn + values: + - {{ .Release.Namespace }} + - key: istio-injection + operator: NotIn + values: + - disabled + - key: istio-env + operator: DoesNotExist +{{- else if eq .Values.sidecarInjectorWebhook.injectLabel "istio-injection" }} + matchLabels: + istio-injection: enabled +{{- else }} + matchLabels: + istio-env: {{ .Release.Namespace }} +{{- end }} +--- +{{- if .Values.sidecarInjectorWebhook.selfSigned }} + {{- $cn := "istio-sidecar-injector" }} + {{- $altName1 := printf "%s.%s" $cn .Release.Namespace }} + {{- $altName2 := printf "%s.%s.svc" $cn .Release.Namespace }} + {{- $altNames := (list $altName1 $altName2) }} + {{- $cert := genSignedCert $cn nil $altNames 3650 $ca }} +apiVersion: v1 +kind: Secret +metadata: + name: istio-sidecar-injector-self-signed + namespace: {{ .Release.Namespace }} + labels: + app: sidecar-injector + release: {{ .Release.Name }} +type: Opaque +data: + root-cert.pem: {{ $ca.Cert | b64enc }} + cert-chain.pem: {{ $cert.Cert | b64enc }} + key.pem: {{ $cert.Key | b64enc }} +{{- end }} diff --git a/istio-1.3.5/install/kubernetes/operator/charts/istio-control/istio-autoinject/templates/poddisruptionbudget.yaml b/istio-1.3.5/install/kubernetes/operator/charts/istio-control/istio-autoinject/templates/poddisruptionbudget.yaml new file mode 100644 index 0000000..96dfc49 --- /dev/null +++ b/istio-1.3.5/install/kubernetes/operator/charts/istio-control/istio-autoinject/templates/poddisruptionbudget.yaml @@ -0,0 +1,18 @@ +{{- if .Values.global.defaultPodDisruptionBudget.enabled }} +apiVersion: policy/v1beta1 +kind: PodDisruptionBudget +metadata: + name: istio-sidecar-injector + namespace: {{ .Release.Namespace }} + labels: + app: sidecar-injector + release: {{ .Release.Name }} + istio: sidecar-injector +spec: + minAvailable: 1 + selector: + matchLabels: + app: sidecar-injector + release: {{ .Release.Name }} + istio: sidecar-injector +{{- end }} diff --git a/istio-1.3.5/install/kubernetes/operator/charts/istio-control/istio-autoinject/templates/service.yaml b/istio-1.3.5/install/kubernetes/operator/charts/istio-control/istio-autoinject/templates/service.yaml new file mode 100644 index 0000000..890316d --- /dev/null +++ b/istio-1.3.5/install/kubernetes/operator/charts/istio-control/istio-autoinject/templates/service.yaml @@ -0,0 +1,15 @@ +apiVersion: v1 +kind: Service +metadata: + name: istio-sidecar-injector + namespace: {{ .Release.Namespace }} + labels: + app: sidecar-injector + release: {{ .Release.Name }} + istio: sidecar-injector +spec: + ports: + - port: 443 + targetPort: 9443 + selector: + istio: sidecar-injector diff --git a/istio-1.3.5/install/kubernetes/operator/charts/istio-control/istio-autoinject/templates/serviceaccount.yaml b/istio-1.3.5/install/kubernetes/operator/charts/istio-control/istio-autoinject/templates/serviceaccount.yaml new file mode 100644 index 0000000..9b6cc02 --- /dev/null +++ b/istio-1.3.5/install/kubernetes/operator/charts/istio-control/istio-autoinject/templates/serviceaccount.yaml @@ -0,0 +1,15 @@ +apiVersion: v1 +kind: ServiceAccount +{{- if .Values.global.imagePullSecrets }} +imagePullSecrets: +{{- range .Values.global.imagePullSecrets }} + - name: {{ . }} +{{- end }} +{{- end }} +metadata: + name: istio-sidecar-injector-service-account + namespace: {{ .Release.Namespace }} + labels: + app: sidecar-injector + release: {{ .Release.Name }} + istio: sidecar-injector diff --git a/istio-1.3.5/install/kubernetes/operator/charts/istio-control/istio-autoinject/templates/sidecar-injector-configmap.yaml b/istio-1.3.5/install/kubernetes/operator/charts/istio-control/istio-autoinject/templates/sidecar-injector-configmap.yaml new file mode 100644 index 0000000..5269e60 --- /dev/null +++ b/istio-1.3.5/install/kubernetes/operator/charts/istio-control/istio-autoinject/templates/sidecar-injector-configmap.yaml @@ -0,0 +1,22 @@ +{{- if not .Values.global.omitSidecarInjectorConfigMap }} +apiVersion: v1 +kind: ConfigMap +metadata: + name: istio-sidecar-injector + namespace: {{ .Release.Namespace }} + labels: + release: {{ .Release.Name }} + app: sidecar-injector + istio: sidecar-injector +data: + values: |- + {{ .Values | toJson }} + + config: |- + policy: {{ .Values.global.proxy.autoInject }} + alwaysInjectSelector: +{{ toYaml .Values.sidecarInjectorWebhook.alwaysInjectSelector | indent 6 }} + neverInjectSelector: +{{ toYaml .Values.sidecarInjectorWebhook.neverInjectSelector | indent 6 }} +{{ .Files.Get "files/injection-template.yaml" | indent 4 }} +{{- end }} diff --git a/istio-1.3.5/install/kubernetes/operator/charts/istio-control/istio-autoinject/values.yaml b/istio-1.3.5/install/kubernetes/operator/charts/istio-control/istio-autoinject/values.yaml new file mode 100644 index 0000000..79d3e18 --- /dev/null +++ b/istio-1.3.5/install/kubernetes/operator/charts/istio-control/istio-autoinject/values.yaml @@ -0,0 +1,64 @@ +sidecarInjectorWebhook: + # sidecar-injector webhook configuration. + # If down, new pods will fail to start or restart for a short time, but they will + # retry. + replicaCount: 1 + rollingMaxSurge: 100% + rollingMaxUnavailable: 25% + + image: sidecar_injector + + # This enables injection of sidecar in all namespaces, + # with the exception of namespaces with "istio-injection:disabled" annotation + # Only one environment should have this enabled. + enableNamespacesByDefault: false + + # If true, webhook or istioctl injector will rewrite PodSpec for liveness + # health check to redirect request to sidecar. This makes liveness check work + # even when mTLS is enabled. + rewriteAppHTTPProbe: false + + # If true, a self-signed CA will created in order to issue a certificate that + # will be used to authenticate the workload respondible for handling + # the sidecar-injector webhook. + selfSigned: false + + nodeSelector: {} + tolerations: [] + + # If set, will use the value as injection label. The value must match the 'release' label of the injector, + # except when 1.2 istio-injection label is used, which must be set to "enabled". + injectLabel: istio-injection + + # Specify the pod anti-affinity that allows you to constrain which nodes + # your pod is eligible to be scheduled based on labels on pods that are + # already running on the node rather than based on labels on nodes. + # There are currently two types of anti-affinity: + # "requiredDuringSchedulingIgnoredDuringExecution" + # "preferredDuringSchedulingIgnoredDuringExecution" + # which denote "hard" vs. "soft" requirements, you can define your values + # in "podAntiAffinityLabelSelector" and "podAntiAffinityTermLabelSelector" + # correspondingly. + # For example: + # podAntiAffinityLabelSelector: + # - key: security + # operator: In + # values: S1,S2 + # topologyKey: "kubernetes.io/hostname" + # This pod anti-affinity rule says that the pod requires not to be scheduled + # onto a node if that node is already running a pod with label having key + # "security" and value "S1". + podAntiAffinityLabelSelector: [] + podAntiAffinityTermLabelSelector: [] + + # You can use the field called alwaysInjectSelector and neverInjectSelector which will always inject the sidecar or + # always skip the injection on pods that match that label selector, regardless of the global policy. + # See https://istio.io/docs/setup/kubernetes/additional-setup/sidecar-injection/#more-control-adding-exceptions + + neverInjectSelector: [] + alwaysInjectSelector: [] + +# If set, no iptable init will be added. It assumes CNI is installed. +# TODO: rename to 'enableIptables' or add 'interceptionMode: CNI' +istio_cni: + enabled: false diff --git a/istio-1.3.5/install/kubernetes/operator/charts/istio-control/istio-config/Chart.yaml b/istio-1.3.5/install/kubernetes/operator/charts/istio-control/istio-config/Chart.yaml new file mode 100644 index 0000000..22b3d23 --- /dev/null +++ b/istio-1.3.5/install/kubernetes/operator/charts/istio-control/istio-config/Chart.yaml @@ -0,0 +1,13 @@ +apiVersion: v1 +name: istio-config +version: 1.1.0 +appVersion: 1.1.0 +tillerVersion: ">=2.7.2" +description: Helm chart for galley deployment +keywords: + - istio + - galley +sources: + - http://github.com/istio/istio +engine: gotpl +icon: https://istio.io/favicons/android-192x192.png diff --git a/istio-1.3.5/install/kubernetes/operator/charts/istio-control/istio-config/OWNERS b/istio-1.3.5/install/kubernetes/operator/charts/istio-control/istio-config/OWNERS new file mode 100644 index 0000000..d6a0e1b --- /dev/null +++ b/istio-1.3.5/install/kubernetes/operator/charts/istio-control/istio-config/OWNERS @@ -0,0 +1,5 @@ +approvers: + - cmluciano + - geeknoid + - ozevren + - ayj diff --git a/istio-1.3.5/install/kubernetes/operator/charts/istio-control/istio-config/README.md b/istio-1.3.5/install/kubernetes/operator/charts/istio-control/istio-config/README.md new file mode 100644 index 0000000..0dea06e --- /dev/null +++ b/istio-1.3.5/install/kubernetes/operator/charts/istio-control/istio-config/README.md @@ -0,0 +1,35 @@ +# Istio Config + +This component handles the configuration, exposing an MCP server. + +The default implementation is Galley, using the K8S apiserver for storage - other MCP providers may be configured. + +It is recommended to run only one production config server - it registers a validation webhook which will apply +to all Istio configs. It is possible to run a second staging/canary config server in a different namespace. + +# Installation + +Galley relies on DNS certificates. Before installing it in a custom namespace you should update Citadel or +create a custom certificate. + +# Validation + +A cluster should have a single galley with validation enabled - usually the prod environment. +It is possible to enable validation on other environments as well - but each Galley will do its own +validation, and a staging version may impact production validation. + +```bash + + +``` + +```yamml + +security: + ... + dnsCerts: + ... + istio-galley-service-account.MY_NAMESPACE: istio-galley.MY_NAMESPACE.svc + + +``` diff --git a/istio-1.3.5/install/kubernetes/operator/charts/istio-control/istio-config/templates/_affinity.tpl b/istio-1.3.5/install/kubernetes/operator/charts/istio-control/istio-config/templates/_affinity.tpl new file mode 100644 index 0000000..482d746 --- /dev/null +++ b/istio-1.3.5/install/kubernetes/operator/charts/istio-control/istio-config/templates/_affinity.tpl @@ -0,0 +1,93 @@ +{{/* affinity - https://kubernetes.io/docs/concepts/configuration/assign-pod-node/ */}} + +{{- define "nodeaffinity" }} + nodeAffinity: + requiredDuringSchedulingIgnoredDuringExecution: + {{- include "nodeAffinityRequiredDuringScheduling" . }} + preferredDuringSchedulingIgnoredDuringExecution: + {{- include "nodeAffinityPreferredDuringScheduling" . }} +{{- end }} + +{{- define "nodeAffinityRequiredDuringScheduling" }} + nodeSelectorTerms: + - matchExpressions: + - key: beta.kubernetes.io/arch + operator: In + values: + {{- range $key, $val := .Values.global.arch }} + {{- if gt ($val | int) 0 }} + - {{ $key }} + {{- end }} + {{- end }} + {{- $nodeSelector := default .Values.global.defaultNodeSelector .Values.galley.nodeSelector -}} + {{- range $key, $val := $nodeSelector }} + - key: {{ $key }} + operator: In + values: + - {{ $val }} + {{- end }} +{{- end }} + +{{- define "nodeAffinityPreferredDuringScheduling" }} + {{- range $key, $val := .Values.global.arch }} + {{- if gt ($val | int) 0 }} + - weight: {{ $val | int }} + preference: + matchExpressions: + - key: beta.kubernetes.io/arch + operator: In + values: + - {{ $key }} + {{- end }} + {{- end }} +{{- end }} + +{{- define "podAntiAffinity" }} +{{- if or .Values.galley.podAntiAffinityLabelSelector .Values.galley.podAntiAffinityTermLabelSelector}} + podAntiAffinity: + {{- if .Values.galley.podAntiAffinityLabelSelector }} + requiredDuringSchedulingIgnoredDuringExecution: + {{- include "podAntiAffinityRequiredDuringScheduling" . }} + {{- end }} + {{- if .Values.galley.podAntiAffinityTermLabelSelector }} + preferredDuringSchedulingIgnoredDuringExecution: + {{- include "podAntiAffinityPreferredDuringScheduling" . }} + {{- end }} +{{- end }} +{{- end }} + +{{- define "podAntiAffinityRequiredDuringScheduling" }} + {{- range $index, $item := .Values.galley.podAntiAffinityLabelSelector }} + - labelSelector: + matchExpressions: + - key: {{ $item.key }} + operator: {{ $item.operator }} + {{- if $item.values }} + values: + {{- $vals := split "," $item.values }} + {{- range $i, $v := $vals }} + - {{ $v }} + {{- end }} + {{- end }} + topologyKey: {{ $item.topologyKey }} + {{- end }} +{{- end }} + +{{- define "podAntiAffinityPreferredDuringScheduling" }} + {{- range $index, $item := .Values.galley.podAntiAffinityTermLabelSelector }} + - podAffinityTerm: + labelSelector: + matchExpressions: + - key: {{ $item.key }} + operator: {{ $item.operator }} + {{- if $item.values }} + values: + {{- $vals := split "," $item.values }} + {{- range $i, $v := $vals }} + - {{ $v }} + {{- end }} + {{- end }} + topologyKey: {{ $item.topologyKey }} + weight: 100 + {{- end }} +{{- end }} diff --git a/istio-1.3.5/install/kubernetes/operator/charts/istio-control/istio-config/templates/_helpers.tpl b/istio-1.3.5/install/kubernetes/operator/charts/istio-control/istio-config/templates/_helpers.tpl new file mode 100644 index 0000000..e3167c2 --- /dev/null +++ b/istio-1.3.5/install/kubernetes/operator/charts/istio-control/istio-config/templates/_helpers.tpl @@ -0,0 +1,36 @@ +{{/* vim: set filetype=mustache: */}} +{{/* +Expand the name of the chart. +*/}} +{{- define "pilot.name" -}} +{{- default .Chart.Name .Values.galley.nameOverride | trunc 63 | trimSuffix "-" -}} +{{- end -}} + +{{/* +Create a default fully qualified app name. +We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). +If release name contains chart name it will be used as a full name. +*/}} +{{- define "pilot.fullname" -}} +{{- if .Values.galley.fullnameOverride -}} +{{- .Values.galley.fullnameOverride | trunc 63 | trimSuffix "-" -}} +{{- else -}} +{{- $name := default .Chart.Name .Values.galley.nameOverride -}} +{{- if contains $name .Release.Name -}} +{{- .Release.Name | trunc 63 | trimSuffix "-" -}} +{{- else -}} +{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" -}} +{{- end -}} +{{- end -}} +{{- end -}} + +{{/* +Create chart name and version as used by the chart label. +*/}} +{{- define "pilot.chart" -}} +{{- .Chart.Name | trunc 63 | trimSuffix "-" -}} +{{- end -}} + +{{- define "istio.configmap.checksum" -}} +{{- print $.Template.BasePath "/configmap.yaml" | sha256sum -}} +{{- end -}} diff --git a/istio-1.3.5/install/kubernetes/operator/charts/istio-control/istio-config/templates/clusterrole.yaml b/istio-1.3.5/install/kubernetes/operator/charts/istio-control/istio-config/templates/clusterrole.yaml new file mode 100644 index 0000000..a5f23c5 --- /dev/null +++ b/istio-1.3.5/install/kubernetes/operator/charts/istio-control/istio-config/templates/clusterrole.yaml @@ -0,0 +1,40 @@ +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: istio-galley-{{ .Release.Namespace }} + labels: + release: {{ .Release.Name }} +rules: +- apiGroups: ["admissionregistration.k8s.io"] + resources: ["validatingwebhookconfigurations"] + verbs: ["*"] +- apiGroups: ["config.istio.io"] # istio mixer CRD watcher + resources: ["*"] + verbs: ["get", "list", "watch"] +- apiGroups: ["networking.istio.io"] + resources: ["*"] + verbs: ["get", "list", "watch"] +- apiGroups: ["authentication.istio.io"] + resources: ["*"] + verbs: ["get", "list", "watch"] +- apiGroups: ["rbac.istio.io"] + resources: ["*"] + verbs: ["get", "list", "watch"] +- apiGroups: ["extensions","apps"] + resources: ["deployments"] + resourceNames: ["istio-galley"] + verbs: ["get"] +- apiGroups: [""] + resources: ["pods", "nodes", "services", "endpoints", "namespaces"] + verbs: ["get", "list", "watch"] +- apiGroups: ["extensions"] + resources: ["ingresses"] + verbs: ["get", "list", "watch"] +- apiGroups: ["extensions"] + resources: ["deployments/finalizers"] + resourceNames: ["istio-galley"] + verbs: ["update"] +- apiGroups: ["apiextensions.k8s.io"] + resources: ["customresourcedefinitions"] + verbs: ["get", "list", "watch"] +--- diff --git a/istio-1.3.5/install/kubernetes/operator/charts/istio-control/istio-config/templates/clusterrolebinding.yaml b/istio-1.3.5/install/kubernetes/operator/charts/istio-control/istio-config/templates/clusterrolebinding.yaml new file mode 100644 index 0000000..a291f80 --- /dev/null +++ b/istio-1.3.5/install/kubernetes/operator/charts/istio-control/istio-config/templates/clusterrolebinding.yaml @@ -0,0 +1,15 @@ +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: istio-galley-admin-role-binding-{{ .Release.Namespace }} + labels: + release: {{ .Release.Name }} +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: istio-galley-{{ .Release.Namespace }} +subjects: + - kind: ServiceAccount + name: istio-galley-service-account + namespace: {{ .Release.Namespace }} +--- diff --git a/istio-1.3.5/install/kubernetes/operator/charts/istio-control/istio-config/templates/configmap-envoy.yaml b/istio-1.3.5/install/kubernetes/operator/charts/istio-control/istio-config/templates/configmap-envoy.yaml new file mode 100644 index 0000000..d7d8ca5 --- /dev/null +++ b/istio-1.3.5/install/kubernetes/operator/charts/istio-control/istio-config/templates/configmap-envoy.yaml @@ -0,0 +1,90 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + namespace: {{ .Release.Namespace }} + name: galley-envoy-config + labels: + app: galley + istio: galley + release: {{ .Release.Name }} +data: + envoy.yaml.tmpl: |- + admin: + access_log_path: /dev/null + address: + socket_address: + address: 127.0.0.1 + port_value: 15000 + + static_resources: + + clusters: + - name: in.9901 + http2_protocol_options: {} + connect_timeout: 1.000s + + hosts: + - socket_address: + address: 127.0.0.1 + port_value: 9901 + + circuit_breakers: + thresholds: + - max_connections: 100000 + max_pending_requests: 100000 + max_requests: 100000 + max_retries: 3 + + listeners: + - name: "15019" + address: + socket_address: + address: 0.0.0.0 + port_value: 15019 + filter_chains: + - filters: + - name: envoy.http_connection_manager + config: + codec_type: HTTP2 + stat_prefix: "15010" + http2_protocol_options: + max_concurrent_streams: 1073741824 + + access_log: + - name: envoy.file_access_log + config: + path: /dev/stdout + + http_filters: + - name: envoy.router + + route_config: + name: "15019" + + virtual_hosts: + - name: istio-galley + + domains: + - '*' + + routes: + - match: + prefix: / + route: + cluster: in.9901 + timeout: 0.000s + tls_context: + common_tls_context: + alpn_protocols: + - h2 + tls_certificates: + - certificate_chain: + filename: /etc/certs/cert-chain.pem + private_key: + filename: /etc/certs/key.pem + validation_context: + trusted_ca: + filename: /etc/certs/root-cert.pem + require_client_certificate: true +--- + diff --git a/istio-1.3.5/install/kubernetes/operator/charts/istio-control/istio-config/templates/configmap-mesh.yaml b/istio-1.3.5/install/kubernetes/operator/charts/istio-control/istio-config/templates/configmap-mesh.yaml new file mode 100644 index 0000000..1861020 --- /dev/null +++ b/istio-1.3.5/install/kubernetes/operator/charts/istio-control/istio-config/templates/configmap-mesh.yaml @@ -0,0 +1,13 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: istio-mesh-galley + namespace: {{ .Release.Namespace }} + labels: + release: {{ .Release.Name }} +data: + + + mesh: |- +{{ toYaml .Values.galley.mesh | indent 4 }} +--- diff --git a/istio-1.3.5/install/kubernetes/operator/charts/istio-control/istio-config/templates/configmap.yaml b/istio-1.3.5/install/kubernetes/operator/charts/istio-control/istio-config/templates/configmap.yaml new file mode 100644 index 0000000..e05340c --- /dev/null +++ b/istio-1.3.5/install/kubernetes/operator/charts/istio-control/istio-config/templates/configmap.yaml @@ -0,0 +1,13 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: istio-galley-configuration + namespace: {{ .Release.Namespace }} + labels: + release: {{ .Release.Name }} +data: +{{- if .Values.global.configValidation }} + validatingwebhookconfiguration.yaml: |- + {{- include "validatingwebhookconfiguration.yaml.tpl" . | indent 4}} +{{- end}} +--- diff --git a/istio-1.3.5/install/kubernetes/operator/charts/istio-control/istio-config/templates/deployment.yaml b/istio-1.3.5/install/kubernetes/operator/charts/istio-control/istio-config/templates/deployment.yaml new file mode 100644 index 0000000..c654424 --- /dev/null +++ b/istio-1.3.5/install/kubernetes/operator/charts/istio-control/istio-config/templates/deployment.yaml @@ -0,0 +1,190 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: istio-galley + namespace: {{ .Release.Namespace }} + labels: + app: galley + istio: galley + release: {{ .Release.Name }} +spec: + replicas: {{ .Values.galley.replicaCount }} + selector: + matchLabels: + istio: galley + strategy: + rollingUpdate: + maxSurge: {{ .Values.galley.rollingMaxSurge }} + maxUnavailable: {{ .Values.galley.rollingMaxUnavailable }} + template: + metadata: + labels: + app: galley + istio: galley +{{- if eq .Release.Namespace "istio-system"}} + heritage: Tiller + release: istio + chart: galley +{{- end }} + annotations: + sidecar.istio.io/inject: "false" + spec: + serviceAccountName: istio-galley-service-account +{{- if .Values.global.priorityClassName }} + priorityClassName: "{{ .Values.global.priorityClassName }}" +{{- end }} + containers: + - name: galley +{{- if contains "/" .Values.galley.image }} + image: "{{ .Values.galley.image }}" +{{- else }} + image: "{{ .Values.global.hub }}/{{ .Values.galley.image | default "galley" }}:{{ .Values.global.tag }}" +{{- end }} + imagePullPolicy: {{ .Values.global.imagePullPolicy | default "Always" }} + ports: + - containerPort: 9443 + - containerPort: 15014 + - containerPort: 15019 + - containerPort: 9901 + command: + - /usr/local/bin/galley + - server + - --meshConfigFile=/etc/mesh-config/mesh + - --livenessProbeInterval=1s + - --livenessProbePath=/healthliveness + - --readinessProbePath=/healthready + - --readinessProbeInterval=1s + - --insecure=true + {{- if .Values.global.configValidation }} + - --enable-validation=true + {{- else }} + - --enable-validation=false + {{- end }} + - --enable-server=true + - --deployment-namespace={{ .Release.Namespace }} + - --validation-webhook-config-file + - /etc/config/validatingwebhookconfiguration.yaml + - --monitoringPort=15014 + - --validation-port=9443 +{{- if $.Values.global.logging.level }} + - --log_output_level={{ $.Values.global.logging.level }} +{{- end}} + volumeMounts: + {{- if .Values.global.configValidation }} + - name: istio-certs + mountPath: /etc/certs + readOnly: true + {{- end }} + - name: config + mountPath: /etc/config + readOnly: true + - name: mesh-config + mountPath: /etc/mesh-config + readOnly: true + livenessProbe: + exec: + command: + - /usr/local/bin/galley + - probe + - --probe-path=/healthliveness + - --interval=10s + initialDelaySeconds: 5 + periodSeconds: 5 + readinessProbe: + exec: + command: + - /usr/local/bin/galley + - probe + - --probe-path=/healthready + - --interval=10s + initialDelaySeconds: 5 + periodSeconds: 5 + resources: +{{- if .Values.galley.resources }} +{{ toYaml .Values.galley.resources | indent 12 }} +{{- else }} +{{ toYaml .Values.global.defaultResources | indent 12 }} +{{- end }} + +{{- if .Values.global.controlPlaneSecurityEnabled }} + - name: istio-proxy +{{- if contains "/" .Values.global.proxy.image }} + image: "{{ .Values.global.proxy.image }}" +{{- else }} + image: "{{ .Values.global.hub | default "gcr.io/istio-release" }}/{{ .Values.global.proxy.image | default "proxyv2" }}:{{ .Values.global.tag | default "release-1.1-latest-daily" }}" +{{- end }} + imagePullPolicy: {{ .Values.global.imagePullPolicy | default "Always" }} + ports: + - containerPort: 9902 + args: + - proxy + - --serviceCluster + - istio-galley + - --templateFile + - /var/lib/istio/galley/envoy/envoy.yaml.tmpl + - --controlPlaneAuthPolicy + - MUTUAL_TLS + {{- if .Values.global.trustDomain }} + - --trust-domain={{ .Values.global.trustDomain }} + {{- end }} + {{- if .Values.global.logAsJson }} + - --log_as_json + {{- end }} + env: + - name: POD_NAME + valueFrom: + fieldRef: + apiVersion: v1 + fieldPath: metadata.name + - name: POD_NAMESPACE + valueFrom: + fieldRef: + apiVersion: v1 + fieldPath: metadata.namespace + - name: INSTANCE_IP + valueFrom: + fieldRef: + apiVersion: v1 + fieldPath: status.podIP + resources: +{{- if .Values.global.proxy.resources }} +{{ toYaml .Values.global.proxy.resources | indent 12 }} +{{- else }} +{{ toYaml .Values.global.defaultResources | indent 12 }} +{{- end }} + + volumeMounts: + - name: istio-certs + mountPath: /etc/certs + readOnly: true + - name: envoy-config + mountPath: /var/lib/istio/galley/envoy + +{{- end }} + + volumes: + {{- if or .Values.global.controlPlaneSecurityEnabled .Values.global.configValidation }} + - name: istio-certs + secret: + secretName: istio.istio-galley-service-account + - name: envoy-config + configMap: + name: galley-envoy-config + {{- end }} + - name: config + configMap: + name: istio-galley-configuration + # Different config map from pilot, to allow independent config and rollout. + # Both are derived from values.yaml. + - name: mesh-config + configMap: + name: istio-mesh-galley + + affinity: + {{- include "nodeaffinity" . | indent 6 }} + {{- include "podAntiAffinity" . | indent 6 }} +{{- if .Values.galley.tolerations }} + tolerations: +{{ toYaml .Values.galley.tolerations | indent 6 }} +{{- end }} +--- diff --git a/istio-1.3.5/install/kubernetes/operator/charts/istio-control/istio-config/templates/poddisruptionbudget.yaml b/istio-1.3.5/install/kubernetes/operator/charts/istio-control/istio-config/templates/poddisruptionbudget.yaml new file mode 100644 index 0000000..9b9bec9 --- /dev/null +++ b/istio-1.3.5/install/kubernetes/operator/charts/istio-control/istio-config/templates/poddisruptionbudget.yaml @@ -0,0 +1,20 @@ +{{- if .Values.global.defaultPodDisruptionBudget.enabled }} +apiVersion: policy/v1beta1 +kind: PodDisruptionBudget +metadata: + name: istio-galley + namespace: {{ .Release.Namespace }} + labels: + app: galley + release: {{ .Release.Name }} + istio: galley +spec: + minAvailable: 1 + selector: + matchLabels: + app: galley + release: {{ .Release.Name }} + istio: galley +--- + +{{- end }} diff --git a/istio-1.3.5/install/kubernetes/operator/charts/istio-control/istio-config/templates/service.yaml b/istio-1.3.5/install/kubernetes/operator/charts/istio-control/istio-config/templates/service.yaml new file mode 100644 index 0000000..dd5d056 --- /dev/null +++ b/istio-1.3.5/install/kubernetes/operator/charts/istio-control/istio-config/templates/service.yaml @@ -0,0 +1,23 @@ +apiVersion: v1 +kind: Service +metadata: + name: istio-galley + namespace: {{ .Release.Namespace }} + labels: + app: galley + istio: galley + release: {{ .Release.Name }} +spec: + ports: + - port: 443 + name: https-validation + targetPort: 9443 + - port: 15014 + name: http-monitoring + - port: 9901 + name: grpc-mcp + - port: 15019 + name: grpc-tls-mcp + selector: + istio: galley +--- diff --git a/istio-1.3.5/install/kubernetes/operator/charts/istio-control/istio-config/templates/serviceaccount.yaml b/istio-1.3.5/install/kubernetes/operator/charts/istio-control/istio-config/templates/serviceaccount.yaml new file mode 100644 index 0000000..d4cf8ff --- /dev/null +++ b/istio-1.3.5/install/kubernetes/operator/charts/istio-control/istio-config/templates/serviceaccount.yaml @@ -0,0 +1,15 @@ +apiVersion: v1 +kind: ServiceAccount +{{- if .Values.global.imagePullSecrets }} +imagePullSecrets: +{{- range .Values.global.imagePullSecrets }} + - name: {{ . }} +{{- end }} +{{- end }} +metadata: + name: istio-galley-service-account + namespace: {{ .Release.Namespace }} + labels: + app: galley + release: {{ .Release.Name }} +--- diff --git a/istio-1.3.5/install/kubernetes/operator/charts/istio-control/istio-config/templates/validatingwebhookconfiguration.yaml.tpl b/istio-1.3.5/install/kubernetes/operator/charts/istio-control/istio-config/templates/validatingwebhookconfiguration.yaml.tpl new file mode 100644 index 0000000..05da498 --- /dev/null +++ b/istio-1.3.5/install/kubernetes/operator/charts/istio-control/istio-config/templates/validatingwebhookconfiguration.yaml.tpl @@ -0,0 +1,118 @@ +{{ define "validatingwebhookconfiguration.yaml.tpl" }} +apiVersion: admissionregistration.k8s.io/v1beta1 +kind: ValidatingWebhookConfiguration +metadata: + name: istio-galley-{{ .Release.Namespace }} + namespace: {{ .Release.Namespace }} + labels: + app: galley + release: {{ .Release.Name }} + istio: galley +webhooks: + - name: pilot.validation.istio.io + clientConfig: + service: + name: istio-galley + namespace: {{ .Release.Namespace }} + path: "/admitpilot" + caBundle: "" + rules: + - operations: + - CREATE + - UPDATE + apiGroups: + - config.istio.io + apiVersions: + - v1alpha2 + resources: + - httpapispecs + - httpapispecbindings + - quotaspecs + - quotaspecbindings + - operations: + - CREATE + - UPDATE + apiGroups: + - rbac.istio.io + apiVersions: + - "*" + resources: + - "*" + - operations: + - CREATE + - UPDATE + apiGroups: + - authentication.istio.io + apiVersions: + - "*" + resources: + - "*" + - operations: + - CREATE + - UPDATE + apiGroups: + - networking.istio.io + apiVersions: + - "*" + resources: + - destinationrules + - envoyfilters + - gateways + - serviceentries + - sidecars + - virtualservices + failurePolicy: Fail + sideEffects: None + - name: mixer.validation.istio.io + clientConfig: + service: + name: istio-galley + namespace: {{ .Release.Namespace }} + path: "/admitmixer" + caBundle: "" + rules: + - operations: + - CREATE + - UPDATE + apiGroups: + - config.istio.io + apiVersions: + - v1alpha2 + resources: + - rules + - attributemanifests + - circonuses + - deniers + - fluentds + - kubernetesenvs + - listcheckers + - memquotas + - noops + - opas + - prometheuses + - rbacs + - solarwindses + - stackdrivers + - cloudwatches + - dogstatsds + - statsds + - stdios + - apikeys + - authorizations + - checknothings + # - kuberneteses + - listentries + - logentries + - metrics + - quotas + - reportnothings + - tracespans + - adapters + - handlers + - instances + - templates + - zipkins + failurePolicy: Fail + sideEffects: None +{{- end }} +--- diff --git a/istio-1.3.5/install/kubernetes/operator/charts/istio-control/istio-config/values.yaml b/istio-1.3.5/install/kubernetes/operator/charts/istio-control/istio-config/values.yaml new file mode 100644 index 0000000..5853297 --- /dev/null +++ b/istio-1.3.5/install/kubernetes/operator/charts/istio-control/istio-config/values.yaml @@ -0,0 +1,40 @@ +galley: + image: galley + replicaCount: 1 + rollingMaxSurge: 100% + rollingMaxUnavailable: 25% + + resources: + requests: + cpu: 100m + # memory: 128Mi + # limits: + # cpu: 100m + # memory: 128Mi + + # TODO: Galley appears to use the mesh config - need to find which fields are used and need to be configured. + mesh: {} + + nodeSelector: {} + tolerations: [] + + # Specify the pod anti-affinity that allows you to constrain which nodes + # your pod is eligible to be scheduled based on labels on pods that are + # already running on the node rather than based on labels on nodes. + # There are currently two types of anti-affinity: + # "requiredDuringSchedulingIgnoredDuringExecution" + # "preferredDuringSchedulingIgnoredDuringExecution" + # which denote "hard" vs. "soft" requirements, you can define your values + # in "podAntiAffinityLabelSelector" and "podAntiAffinityTermLabelSelector" + # correspondingly. + # For example: + # podAntiAffinityLabelSelector: + # - key: security + # operator: In + # values: S1,S2 + # topologyKey: "kubernetes.io/hostname" + # This pod anti-affinity rule says that the pod requires not to be scheduled + # onto a node if that node is already running a pod with label having key + # "security" and value "S1". + podAntiAffinityLabelSelector: [] + podAntiAffinityTermLabelSelector: [] diff --git a/istio-1.3.5/install/kubernetes/operator/charts/istio-control/istio-discovery/Chart.yaml b/istio-1.3.5/install/kubernetes/operator/charts/istio-control/istio-discovery/Chart.yaml new file mode 100644 index 0000000..4f50841 --- /dev/null +++ b/istio-1.3.5/install/kubernetes/operator/charts/istio-control/istio-discovery/Chart.yaml @@ -0,0 +1,12 @@ +apiVersion: v1 +name: istio-discovery +version: 1.1.0 +appVersion: 1.1.0 +tillerVersion: ">=2.7.2" +description: Helm chart for istio control plane +keywords: + - istio +sources: + - http://github.com/istio/istio +engine: gotpl +icon: https://istio.io/favicons/android-192x192.png diff --git a/istio-1.3.5/install/kubernetes/operator/charts/istio-control/istio-discovery/NOTES.txt b/istio-1.3.5/install/kubernetes/operator/charts/istio-control/istio-discovery/NOTES.txt new file mode 100644 index 0000000..997f4ac --- /dev/null +++ b/istio-1.3.5/install/kubernetes/operator/charts/istio-control/istio-discovery/NOTES.txt @@ -0,0 +1,5 @@ +Minimal control plane for Istio. Pilot and mesh config are included. + +MCP and injector should optionally be installed in the same namespace. Alternatively remote +address of an MCP server can be set. + diff --git a/istio-1.3.5/install/kubernetes/operator/charts/istio-control/istio-discovery/templates/_affinity.tpl b/istio-1.3.5/install/kubernetes/operator/charts/istio-control/istio-discovery/templates/_affinity.tpl new file mode 100644 index 0000000..b24dbcd --- /dev/null +++ b/istio-1.3.5/install/kubernetes/operator/charts/istio-control/istio-discovery/templates/_affinity.tpl @@ -0,0 +1,93 @@ +{{/* affinity - https://kubernetes.io/docs/concepts/configuration/assign-pod-node/ */}} + +{{- define "nodeaffinity" }} + nodeAffinity: + requiredDuringSchedulingIgnoredDuringExecution: + {{- include "nodeAffinityRequiredDuringScheduling" . }} + preferredDuringSchedulingIgnoredDuringExecution: + {{- include "nodeAffinityPreferredDuringScheduling" . }} +{{- end }} + +{{- define "nodeAffinityRequiredDuringScheduling" }} + nodeSelectorTerms: + - matchExpressions: + - key: beta.kubernetes.io/arch + operator: In + values: + {{- range $key, $val := .Values.global.arch }} + {{- if gt ($val | int) 0 }} + - {{ $key }} + {{- end }} + {{- end }} + {{- $nodeSelector := default .Values.global.defaultNodeSelector .Values.pilot.nodeSelector -}} + {{- range $key, $val := $nodeSelector }} + - key: {{ $key }} + operator: In + values: + - {{ $val }} + {{- end }} +{{- end }} + +{{- define "nodeAffinityPreferredDuringScheduling" }} + {{- range $key, $val := .Values.global.arch }} + {{- if gt ($val | int) 0 }} + - weight: {{ $val | int }} + preference: + matchExpressions: + - key: beta.kubernetes.io/arch + operator: In + values: + - {{ $key }} + {{- end }} + {{- end }} +{{- end }} + +{{- define "podAntiAffinity" }} +{{- if or .Values.pilot.podAntiAffinityLabelSelector .Values.pilot.podAntiAffinityTermLabelSelector}} + podAntiAffinity: + {{- if .Values.pilot.podAntiAffinityLabelSelector }} + requiredDuringSchedulingIgnoredDuringExecution: + {{- include "podAntiAffinityRequiredDuringScheduling" . }} + {{- end }} + {{- if .Values.pilot.podAntiAffinityTermLabelSelector }} + preferredDuringSchedulingIgnoredDuringExecution: + {{- include "podAntiAffinityPreferredDuringScheduling" . }} + {{- end }} +{{- end }} +{{- end }} + +{{- define "podAntiAffinityRequiredDuringScheduling" }} + {{- range $index, $item := .Values.pilot.podAntiAffinityLabelSelector }} + - labelSelector: + matchExpressions: + - key: {{ $item.key }} + operator: {{ $item.operator }} + {{- if $item.values }} + values: + {{- $vals := split "," $item.values }} + {{- range $i, $v := $vals }} + - {{ $v }} + {{- end }} + {{- end }} + topologyKey: {{ $item.topologyKey }} + {{- end }} +{{- end }} + +{{- define "podAntiAffinityPreferredDuringScheduling" }} + {{- range $index, $item := .Values.pilot.podAntiAffinityTermLabelSelector }} + - podAffinityTerm: + labelSelector: + matchExpressions: + - key: {{ $item.key }} + operator: {{ $item.operator }} + {{- if $item.values }} + values: + {{- $vals := split "," $item.values }} + {{- range $i, $v := $vals }} + - {{ $v }} + {{- end }} + {{- end }} + topologyKey: {{ $item.topologyKey }} + weight: 100 + {{- end }} +{{- end }} diff --git a/istio-1.3.5/install/kubernetes/operator/charts/istio-control/istio-discovery/templates/_helpers.tpl b/istio-1.3.5/install/kubernetes/operator/charts/istio-control/istio-discovery/templates/_helpers.tpl new file mode 100644 index 0000000..bf69f2e --- /dev/null +++ b/istio-1.3.5/install/kubernetes/operator/charts/istio-control/istio-discovery/templates/_helpers.tpl @@ -0,0 +1,4 @@ +{{/* vim: set filetype=mustache: */}} +{{- define "istio.configmap.checksum" -}} +{{- print $.Template.BasePath "/configmap.yaml" | sha256sum -}} +{{- end -}} diff --git a/istio-1.3.5/install/kubernetes/operator/charts/istio-control/istio-discovery/templates/autoscale.yaml b/istio-1.3.5/install/kubernetes/operator/charts/istio-control/istio-discovery/templates/autoscale.yaml new file mode 100644 index 0000000..f41c4ea --- /dev/null +++ b/istio-1.3.5/install/kubernetes/operator/charts/istio-control/istio-discovery/templates/autoscale.yaml @@ -0,0 +1,23 @@ +{{- if and .Values.pilot.autoscaleEnabled .Values.pilot.autoscaleMin .Values.pilot.autoscaleMax }} +apiVersion: autoscaling/v2beta1 +kind: HorizontalPodAutoscaler +metadata: + name: istio-pilot{{ .Values.version }} + namespace: {{ .Release.Namespace }} + labels: + app: pilot + release: {{ .Release.Name }} +spec: + maxReplicas: {{ .Values.pilot.autoscaleMax }} + minReplicas: {{ .Values.pilot.autoscaleMin }} + scaleTargetRef: + apiVersion: apps/v1 + kind: Deployment + name: istio-pilot{{ .Values.version }} + metrics: + - type: Resource + resource: + name: cpu + targetAverageUtilization: {{ .Values.pilot.cpu.targetAverageUtilization }} +--- +{{- end }} diff --git a/istio-1.3.5/install/kubernetes/operator/charts/istio-control/istio-discovery/templates/clusterrole.yaml b/istio-1.3.5/install/kubernetes/operator/charts/istio-control/istio-discovery/templates/clusterrole.yaml new file mode 100644 index 0000000..5f039c0 --- /dev/null +++ b/istio-1.3.5/install/kubernetes/operator/charts/istio-control/istio-discovery/templates/clusterrole.yaml @@ -0,0 +1,35 @@ +{{ if .Values.clusterResources }} +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: istio-pilot-{{ .Release.Namespace }} + labels: + app: pilot + release: {{ .Release.Name }} +rules: +- apiGroups: ["config.istio.io"] + resources: ["*"] + verbs: ["*"] +- apiGroups: ["rbac.istio.io"] + resources: ["*"] + verbs: ["get", "watch", "list"] +- apiGroups: ["networking.istio.io"] + resources: ["*"] + verbs: ["*"] +- apiGroups: ["authentication.istio.io"] + resources: ["*"] + verbs: ["*"] +- apiGroups: ["apiextensions.k8s.io"] + resources: ["customresourcedefinitions"] + verbs: ["*"] +- apiGroups: ["extensions"] + resources: ["ingresses", "ingresses/status"] + verbs: ["*"] +- apiGroups: [""] + resources: ["configmaps"] + verbs: ["create", "get", "list", "watch", "update"] +- apiGroups: [""] + resources: ["endpoints", "pods", "services", "namespaces", "nodes", "secrets"] + verbs: ["get", "list", "watch"] +--- +{{ end }} diff --git a/istio-1.3.5/install/kubernetes/operator/charts/istio-control/istio-discovery/templates/clusterrolebinding.yaml b/istio-1.3.5/install/kubernetes/operator/charts/istio-control/istio-discovery/templates/clusterrolebinding.yaml new file mode 100644 index 0000000..fd0c690 --- /dev/null +++ b/istio-1.3.5/install/kubernetes/operator/charts/istio-control/istio-discovery/templates/clusterrolebinding.yaml @@ -0,0 +1,18 @@ +{{ if .Values.clusterResources }} +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: istio-pilot-{{ .Release.Namespace }} + labels: + app: pilot + release: {{ .Release.Name }} +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: istio-pilot-{{ .Release.Namespace }} +subjects: + - kind: ServiceAccount + name: istio-pilot-service-account + namespace: {{ .Release.Namespace }} +--- +{{ end }} diff --git a/istio-1.3.5/install/kubernetes/operator/charts/istio-control/istio-discovery/templates/configmap-envoy.yaml b/istio-1.3.5/install/kubernetes/operator/charts/istio-control/istio-discovery/templates/configmap-envoy.yaml new file mode 100644 index 0000000..b4d0476 --- /dev/null +++ b/istio-1.3.5/install/kubernetes/operator/charts/istio-control/istio-discovery/templates/configmap-envoy.yaml @@ -0,0 +1,170 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + namespace: {{ .Release.Namespace }} + name: pilot-envoy-config{{ .Values.version }} + labels: + release: {{ .Release.Name }} +data: + envoy.yaml.tmpl: |- + admin: + access_log_path: /dev/null + address: + socket_address: + address: 127.0.0.1 + port_value: 15000 + + static_resources: + clusters: + - name: in.15010 + http2_protocol_options: {} + connect_timeout: 1.000s + + hosts: + - socket_address: + address: 127.0.0.1 + port_value: 15010 + + circuit_breakers: + thresholds: + - max_connections: 100000 + max_pending_requests: 100000 + max_requests: 100000 + max_retries: 3 + + # TODO: telemetry using EDS + # TODO: other pilots using EDS, load balancing + # TODO: galley using EDS + + - name: out.galley.15019 + http2_protocol_options: {} + connect_timeout: 1.000s + type: STRICT_DNS + + circuit_breakers: + thresholds: + - max_connections: 100000 + max_pending_requests: 100000 + max_requests: 100000 + max_retries: 3 + + tls_context: + common_tls_context: + tls_certificates: + - certificate_chain: + filename: /etc/certs/cert-chain.pem + private_key: + filename: /etc/certs/key.pem + validation_context: + trusted_ca: + filename: /etc/certs/root-cert.pem + verify_subject_alt_name: + - spiffe://cluster.local/ns/{{ .Values.global.configNamespace }}/sa/istio-galley-service-account + + hosts: + - socket_address: + address: istio-galley.{{ .Values.global.configNamespace }} + port_value: 15019 + + + listeners: + - name: "in.15011" + address: + socket_address: + address: 0.0.0.0 + port_value: 15011 + filter_chains: + - filters: + - name: envoy.http_connection_manager + #typed_config + #"@type": "type.googleapis.com/", + config: + codec_type: HTTP2 + stat_prefix: "15011" + http2_protocol_options: + max_concurrent_streams: 1073741824 + + access_log: + - name: envoy.file_access_log + config: + path: /dev/stdout + + http_filters: + - name: envoy.router + + route_config: + name: "15011" + + virtual_hosts: + - name: istio-pilot + + domains: + - '*' + + routes: + - match: + prefix: / + route: + cluster: in.15010 + timeout: 0.000s + decorator: + operation: xDS + + tls_context: + require_client_certificate: true + common_tls_context: + validation_context: + trusted_ca: + filename: /etc/certs/root-cert.pem + + alpn_protocols: + - h2 + + tls_certificates: + - certificate_chain: + filename: /etc/certs/cert-chain.pem + private_key: + filename: /etc/certs/key.pem + + + # Manual 'whitebox' mode + - name: "local.15019" + address: + socket_address: + address: 127.0.0.1 + port_value: 15019 + filter_chains: + - filters: + - name: envoy.http_connection_manager + config: + codec_type: HTTP2 + stat_prefix: "15019" + http2_protocol_options: + max_concurrent_streams: 1073741824 + + access_log: + - name: envoy.file_access_log + config: + path: /dev/stdout + + http_filters: + - name: envoy.router + + route_config: + name: "15019" + + virtual_hosts: + - name: istio-galley + + domains: + - '*' + + routes: + - match: + prefix: / + route: + cluster: out.galley.15019 + timeout: 0.000s + +--- + diff --git a/istio-1.3.5/install/kubernetes/operator/charts/istio-control/istio-discovery/templates/configmap.yaml b/istio-1.3.5/install/kubernetes/operator/charts/istio-control/istio-discovery/templates/configmap.yaml new file mode 100644 index 0000000..7044d58 --- /dev/null +++ b/istio-1.3.5/install/kubernetes/operator/charts/istio-control/istio-discovery/templates/configmap.yaml @@ -0,0 +1,210 @@ +{{- if .Values.pilot.configMap }} +apiVersion: v1 +kind: ConfigMap +metadata: + name: istio{{ .Values.version }} + namespace: {{ .Release.Namespace }} + labels: + release: {{ .Release.Name }} +data: + + meshNetworks: |- + # Network config +{{ toYaml .Values.pilot.meshNetworks | indent 4 }} + + values.yaml: |- +{{ toYaml .Values.pilot | indent 4 }} + + mesh: |- + {{- if .Values.global.enableTracing }} + # Set enableTracing to false to disable request tracing. + enableTracing: {{ .Values.global.enableTracing }} + {{- end }} + + # Set accessLogFile to empty string to disable access log. + accessLogFile: "{{ .Values.global.proxy.accessLogFile }}" + + enableEnvoyAccessLogService: {{ .Values.global.proxy.envoyAccessLogService.enabled }} + + {{- if .Values.mixer.telemetry.reportBatchMaxEntries }} + # reportBatchMaxEntries is the number of requests that are batched before telemetry data is sent to the mixer server + reportBatchMaxEntries: {{ .Values.mixer.telemetry.reportBatchMaxEntries }} + {{- end }} + + {{- if .Values.mixer.telemetry.reportBatchMaxTime }} + # reportBatchMaxTime is the max waiting time before the telemetry data of a request is sent to the mixer server + reportBatchMaxTime: {{ .Values.mixer.telemetry.reportBatchMaxTime }} + {{- end }} + + {{- if .Values.pilot.telemetry.enabled }} + {{- if .Values.global.controlPlaneSecurityEnabled }} + mixerReportServer: istio-telemetry.{{ .Values.global.telemetryNamespace }}.svc.cluster.local:15004 + {{- else }} + mixerReportServer: istio-telemetry.{{ .Values.global.telemetryNamespace }}.svc.cluster.local:9091 + {{- end }} + {{- end }} + + {{- if .Values.global.controlPlaneSecurityEnabled }} + mixerCheckServer: istio-policy.{{ .Values.global.policyNamespace }}.svc.cluster.local:15004 + {{- else }} + mixerCheckServer: istio-policy.{{ .Values.global.policyNamespace }}.svc.cluster.local:9091 + {{- end }} + + {{- if .Values.pilot.authPolicy }} + authPolicy: {{ .Values.pilot.authPolicy }} + {{- end }} + + {{- if .Values.pilot.policy.enabled }} + + # Set the following variable to true to disable policy checks by the Mixer. + # Note that metrics will still be reported to the Mixer. + disablePolicyChecks: false + + # policyCheckFailOpen allows traffic in cases when the mixer policy service cannot be reached. + # Default is false which means the traffic is denied when the client is unable to connect to Mixer. + policyCheckFailOpen: {{ .Values.global.policyCheckFailOpen }} + + {{- else }} + + disablePolicyChecks: true + + {{- end }} + + + # This is the k8s ingress service name, update if you used a different name + {{- if .Values.pilot.ingress }} + {{- if .Values.pilot.ingress.ingressService }} + ingressService: "{{ .Values.pilot.ingress.ingressService }}" + ingressControllerMode: "{{ .Values.pilot.ingress.ingressControllerMode }}" + ingressClass: "{{ .Values.pilot.ingress.ingressClass }}" + {{- end }} + {{- end }} + + {{- if .Values.global.sds.enabled }} + # Unix Domain Socket through which envoy communicates with NodeAgent SDS to get + # key/cert for mTLS. Use secret-mount files instead of SDS if set to empty. + sdsUdsPath: {{ .Values.global.sds.udsPath }} + + {{- else }} + # Set expected values when SDS is disabled + # Unix Domain Socket through which envoy communicates with NodeAgent SDS to get + # key/cert for mTLS. Use secret-mount files instead of SDS if set to empty. + sdsUdsPath: "" + # This flag is used by secret discovery service(SDS). + # If set to true(prerequisite: https://kubernetes.io/docs/concepts/storage/volumes/#projected), Istio will inject volumes mount + # for k8s service account JWT, so that K8s API server mounts k8s service account JWT to envoy container, which + # will be used to generate key/cert eventually. This isn't supported for non-k8s case. + enableSdsTokenMount: false + # This flag is used by secret discovery service(SDS). + # If set to true, envoy will fetch normal k8s service account JWT from '/var/run/secrets/kubernetes.io/serviceaccount/token' + # (https://kubernetes.io/docs/tasks/access-application-cluster/access-cluster/#accessing-the-api-from-a-pod) + # and pass to sds server, which will be used to request key/cert eventually. + # this flag is ignored if enableSdsTokenMount is set. + # This isn't supported for non-k8s case. + sdsUseK8sSaJwt: false + {{- end }} + + {{- if .Values.pilot.useMCP }} + config_sources: + {{- if .Values.global.controlPlaneSecurityEnabled }} + - address: localhost:15019 + {{- else }} + - address: istio-galley:9901 + {{- end }} + {{- end }} + + outboundTrafficPolicy: + mode: {{ .Values.global.outboundTrafficPolicy.mode }} + + {{- if .Values.global.localityLbSetting.enabled }} + localityLbSetting: +{{ toYaml .Values.global.localityLbSetting | indent 6 }} + {{- end }} + + defaultConfig: + # + # TCP connection timeout between Envoy & the application, and between Envoys. + connectTimeout: 10s + # + ### ADVANCED SETTINGS ############# + # Where should envoy's configuration be stored in the istio-proxy container + configPath: "/etc/istio/proxy" + # The pseudo service name used for Envoy. + serviceCluster: istio-proxy + # These settings that determine how long an old Envoy + # process should be kept alive after an occasional reload. + drainDuration: 45s + parentShutdownDuration: 1m0s + # + # Port where Envoy listens (on local host) for admin commands + # You can exec into the istio-proxy container in a pod and + # curl the admin port (curl http://localhost:15000/) to obtain + # diagnostic information from Envoy. See + # https://lyft.github.io/envoy/docs/operations/admin.html + # for more details + proxyAdminPort: 15000 + # + # Set concurrency to a specific number to control the number of Proxy worker threads. + # If set to 0 (default), then start worker thread for each CPU thread/core. + concurrency: {{ .Values.global.proxy.concurrency }} + # + {{- if eq .Values.global.proxy.tracer "lightstep" }} + tracing: + lightstep: + # Address of the LightStep Satellite pool + address: {{ .Values.global.tracer.lightstep.address }} + # Access Token used to communicate with the Satellite pool + accessToken: {{ .Values.global.tracer.lightstep.accessToken }} + # Whether communication with the Satellite pool should be secure + secure: {{ .Values.global.tracer.lightstep.secure }} + # Path to the file containing the cacert to use when verifying TLS + cacertPath: {{ .Values.global.tracer.lightstep.cacertPath }} + {{- else if eq .Values.global.proxy.tracer "zipkin" }} + tracing: + zipkin: + # Address of the Zipkin collector + {{- if .Values.global.tracer.zipkin.address }} + address: {{ .Values.global.tracer.zipkin.address }} + {{- else }} + address: zipkin.{{ .Values.global.telemetryNamespace }}:9411 + {{- end }} + {{- else if eq .Values.global.proxy.tracer "datadog" }} + tracing: + datadog: + # Address of the Datadog Agent + address: {{ .Values.global.tracer.datadog.address }} + {{- else if eq .Values.global.proxy.tracer "stackdriver" }} + tracing: + stackdriver: {} + {{- end }} + + {{- if .Values.global.controlPlaneSecurityEnabled }} + # + # Mutual TLS authentication between sidecars and istio control plane. + controlPlaneAuthPolicy: MUTUAL_TLS + # + # Address where istio Pilot service is running + discoveryAddress: istio-pilot.{{ .Release.Namespace }}:15011 + {{- else }} + # + # Mutual TLS authentication between sidecars and istio control plane. + controlPlaneAuthPolicy: NONE + # + # Address where istio Pilot service is running + discoveryAddress: istio-pilot.{{ .Release.Namespace }}:15010 + {{- end }} + + {{- if .Values.global.proxy.envoyMetricsService.enabled }} + # Envoy's Metrics Service stats sink pushes Envoy metrics to a remote collector via the Metrics Service gRPC API. + envoyMetricsService: + address: {{ .Values.global.proxy.envoyMetricsService.host }}:{{ .Values.global.proxy.envoyMetricsService.port }} + {{- end}} + + + {{- if .Values.global.proxy.envoyAccessLogService.enabled }} + # Envoy's AccessLog Service pushes access logs to a remote collector via the Access Log Service gRPC API. + envoyAccessLogService: + address: {{ .Values.global.proxy.envoyAccessLogService.host }}:{{ .Values.global.proxy.envoyAccessLogService.port }} + {{- end}} +--- +{{- end }} diff --git a/istio-1.3.5/install/kubernetes/operator/charts/istio-control/istio-discovery/templates/deployment.yaml b/istio-1.3.5/install/kubernetes/operator/charts/istio-control/istio-discovery/templates/deployment.yaml new file mode 100644 index 0000000..e949e67 --- /dev/null +++ b/istio-1.3.5/install/kubernetes/operator/charts/istio-control/istio-discovery/templates/deployment.yaml @@ -0,0 +1,243 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: istio-pilot{{ .Values.version }} + namespace: {{ .Release.Namespace }} + # TODO: default template doesn't have this, which one is right ? + labels: + app: pilot + {{- if ne .Values.version ""}} + version: {{ .Values.version }} + {{- end }} + release: {{ .Release.Name }} +{{- range $key, $val := .Values.pilot.deploymentLabels }} + {{ $key }}: "{{ $val }}" +{{- end }} + istio: pilot + annotations: + checksum/config-volume-envoy: {{ include (print $.Template.BasePath "/configmap-envoy.yaml") . | sha256sum }} + checksum/config-volume: {{ include (print $.Template.BasePath "/configmap.yaml") . | sha256sum }} +spec: +{{- if not .Values.pilot.autoscaleEnabled }} +{{- if .Values.pilot.replicaCount }} + replicas: {{ .Values.pilot.replicaCount }} +{{- else }} + replicas: 1 +{{- end }} +{{- end }} + strategy: + rollingUpdate: + maxSurge: {{ .Values.pilot.rollingMaxSurge }} + maxUnavailable: {{ .Values.pilot.rollingMaxUnavailable }} + selector: + matchLabels: + {{- if ne .Values.version ""}} + app: pilot + version: {{ .Values.version }} + {{ else }} + istio: pilot + {{- end }} + template: + metadata: + labels: + app: pilot + {{- if ne .Values.version ""}} + version: {{ .Values.version }} + {{ else }} + # Label used by the 'default' service. For versioned deployments we match with app and version. + # This avoids default deployment picking the canary + istio: pilot + {{- end }} +{{- if eq .Release.Namespace "istio-system"}} + heritage: Tiller + release: istio + chart: pilot +{{- end }} + annotations: + sidecar.istio.io/inject: "false" + checksum/config-volume-envoy: {{ print $.Template.BasePath "/configmap-envoy.yaml" | sha256sum }} + checksum/config-volume: {{ print $.Template.BasePath "/configmap.yaml" | sha256sum }} + spec: + serviceAccountName: istio-pilot-service-account +{{- if .Values.global.priorityClassName }} + priorityClassName: "{{ .Values.global.priorityClassName }}" +{{- end }} + containers: + - name: discovery +{{- if contains "/" .Values.pilot.image }} + image: "{{ .Values.pilot.image }}" +{{- else }} + image: "{{ .Values.global.hub }}/{{ .Values.pilot.image | default "pilot" }}:{{ .Values.global.tag }}" +{{- end }} + imagePullPolicy: {{ .Values.global.imagePullPolicy | default "Always" }} + args: + - "discovery" + - --monitoringAddr=:15014 +{{- if .Values.global.logging.level }} + - --log_output_level={{ .Values.global.logging.level }} +{{- end}} +{{- if .Values.global.logAsJson }} + - --log_as_json +{{- end }} + - --domain + - {{ .Values.global.proxy.clusterDomain }} +{{- if .Values.global.oneNamespace }} + - "-a" + - {{ .Release.Namespace }} +{{- end }} + - --secureGrpcAddr + - "" +{{- if .Values.global.trustDomain }} + - --trust-domain={{ .Values.global.trustDomain }} +{{- end }} +{{- if .Values.plugins }} + - --plugins={{ .Values.pilot.plugins }} +{{- end }} + - --keepaliveMaxServerConnectionAge + - "{{ .Values.pilot.keepaliveMaxServerConnectionAge }}" + ports: + - containerPort: 8080 + - containerPort: 15010 + readinessProbe: + httpGet: + path: /ready + port: 8080 + initialDelaySeconds: 5 + periodSeconds: 30 + timeoutSeconds: 5 + env: + - name: POD_NAME + valueFrom: + fieldRef: + apiVersion: v1 + fieldPath: metadata.name + - name: POD_NAMESPACE + valueFrom: + fieldRef: + apiVersion: v1 + fieldPath: metadata.namespace + {{- if .Values.pilot.env }} + {{- range $key, $val := .Values.pilot.env }} + - name: {{ $key }} + value: "{{ $val }}" + {{- end }} + {{- end }} +{{- if .Values.pilot.traceSampling }} + - name: PILOT_TRACE_SAMPLING + value: "{{ .Values.pilot.traceSampling }}" +{{- end }} + - name: CONFIG_NAMESPACE + value: {{ .Values.pilot.configNamespace }} +{{- if .Values.pilot.appNamespaces }} + - name: APP_NAMESPACE + value: {{ join "," .Values.pilot.appNamespaces }} +{{- end }} + resources: +{{- if .Values.pilot.resources }} +{{ toYaml .Values.pilot.resources | indent 12 }} +{{- else }} +{{ toYaml .Values.global.defaultResources | indent 12 }} +{{- end }} + volumeMounts: + - name: config-volume + mountPath: /etc/istio/config +{{- if .Values.global.controlPlaneSecurityEnabled }} + - name: istio-proxy +{{- if contains "/" .Values.global.proxy.image }} + image: "{{ .Values.global.proxy.image }}" +{{- else }} + image: "{{ .Values.global.hub }}/{{ .Values.global.proxy.image }}:{{ .Values.global.tag }}" +{{- end }} + imagePullPolicy: {{ .Values.global.imagePullPolicy | default "Always" }} + ports: + - containerPort: 15011 + args: + - proxy + - --domain + - $(POD_NAMESPACE).svc.{{ .Values.global.proxy.clusterDomain }} + - --serviceCluster + - istio-pilot + - --templateFile + - /var/lib/envoy/envoy.yaml.tmpl + {{- if .Values.global.controlPlaneSecurityEnabled}} + - --controlPlaneAuthPolicy + - MUTUAL_TLS + {{- else }} + - --controlPlaneAuthPolicy + - NONE + {{- end }} + {{- if .Values.global.trustDomain }} + - --trust-domain={{ .Values.global.trustDomain }} + {{- end }} + {{- if .Values.global.logAsJson }} + - --log_as_json + {{- end }} + env: + - name: POD_NAME + valueFrom: + fieldRef: + apiVersion: v1 + fieldPath: metadata.name + - name: POD_NAMESPACE + valueFrom: + fieldRef: + apiVersion: v1 + fieldPath: metadata.namespace + - name: INSTANCE_IP + valueFrom: + fieldRef: + apiVersion: v1 + fieldPath: status.podIP + resources: +{{- if .Values.global.proxy.resources }} +{{ toYaml .Values.global.proxy.resources | indent 12 }} +{{- else }} +{{ toYaml .Values.global.defaultResources | indent 12 }} +{{- end }} + volumeMounts: + - name: istio-certs + mountPath: /etc/certs + readOnly: true + - name: pilot-envoy-config + mountPath: /var/lib/envoy + {{- if .Values.global.sds.enabled }} + - name: sds-uds-path + mountPath: /var/run/sds + readOnly: true + - name: istio-token + mountPath: /var/run/secrets/tokens + {{- end }} +{{- end }} + volumes: + {{- if .Values.global.sds.enabled }} + - hostPath: + path: /var/run/sds + name: sds-uds-path + - name: istio-token + projected: + sources: + - serviceAccountToken: + audience: {{ .Values.global.trustDomain }} + expirationSeconds: 43200 + path: istio-token + {{- end }} + - name: config-volume + configMap: + name: istio{{ .Values.version }} + - name: pilot-envoy-config + configMap: + name: pilot-envoy-config{{ .Values.version }} + {{- if .Values.global.controlPlaneSecurityEnabled}} + - name: istio-certs + secret: + secretName: istio.istio-pilot-service-account + optional: true + {{- end }} + affinity: + {{- include "nodeaffinity" . | indent 6 }} + {{- include "podAntiAffinity" . | indent 6 }} +{{- if .Values.pilot.tolerations }} + tolerations: +{{ toYaml .Values.pilot.tolerations | indent 6 }} +{{- end }} +--- diff --git a/istio-1.3.5/install/kubernetes/operator/charts/istio-control/istio-discovery/templates/enable-mesh-mtls.yaml b/istio-1.3.5/install/kubernetes/operator/charts/istio-control/istio-discovery/templates/enable-mesh-mtls.yaml new file mode 100644 index 0000000..ae3196a --- /dev/null +++ b/istio-1.3.5/install/kubernetes/operator/charts/istio-control/istio-discovery/templates/enable-mesh-mtls.yaml @@ -0,0 +1,53 @@ +{{ if .Values.clusterResources }} +# Destination rule to disable (m)TLS when talking to API server, as API server doesn't have sidecar. +# Customer should add similar destination rules for other services that dont' have sidecar. +apiVersion: networking.istio.io/v1alpha3 +kind: DestinationRule +metadata: + name: "api-server" + namespace: {{ .Release.Namespace }} + labels: + release: {{ .Release.Name }} +spec: + host: "kubernetes.default.svc.cluster.local" + trafficPolicy: + tls: + mode: DISABLE + +--- + +{{- if .Values.global.mtls.enabled }} + +# Corresponding destination rule to configure client side to use mutual TLS when talking to +# any service (host) in the mesh. +apiVersion: networking.istio.io/v1alpha3 +kind: DestinationRule +metadata: + name: "default" + namespace: {{ .Release.Namespace }} + labels: + release: {{ .Release.Name }} +spec: + host: "*.local" + trafficPolicy: + tls: + mode: ISTIO_MUTUAL +--- +{{- else }} + +apiVersion: networking.istio.io/v1alpha3 +kind: DestinationRule +metadata: + name: "default" + namespace: {{ .Release.Namespace }} + labels: + release: {{ .Release.Name }} +spec: + host: "*.local" + trafficPolicy: + tls: + mode: DISABLE +--- + +{{ end }} +{{ end }} diff --git a/istio-1.3.5/install/kubernetes/operator/charts/istio-control/istio-discovery/templates/poddisruptionbudget.yaml b/istio-1.3.5/install/kubernetes/operator/charts/istio-control/istio-discovery/templates/poddisruptionbudget.yaml new file mode 100644 index 0000000..deef79b --- /dev/null +++ b/istio-1.3.5/install/kubernetes/operator/charts/istio-control/istio-discovery/templates/poddisruptionbudget.yaml @@ -0,0 +1,22 @@ +{{- if .Values.global.defaultPodDisruptionBudget.enabled }} +apiVersion: policy/v1beta1 +kind: PodDisruptionBudget +metadata: + name: istio-pilot{{ .Values.version }} + namespace: {{ .Release.Namespace }} + labels: + app: pilot + release: {{ .Release.Name }} + istio: pilot +spec: + minAvailable: 1 + selector: + matchLabels: + app: pilot + {{- if ne .Values.version ""}} + version: {{ .Values.version }} + {{- end }} + release: {{ .Release.Name }} + istio: pilot +--- +{{- end }} diff --git a/istio-1.3.5/install/kubernetes/operator/charts/istio-control/istio-discovery/templates/service.yaml b/istio-1.3.5/install/kubernetes/operator/charts/istio-control/istio-discovery/templates/service.yaml new file mode 100644 index 0000000..ecfce7d --- /dev/null +++ b/istio-1.3.5/install/kubernetes/operator/charts/istio-control/istio-discovery/templates/service.yaml @@ -0,0 +1,27 @@ +apiVersion: v1 +kind: Service +metadata: + name: istio-pilot{{ .Values.version }} + namespace: {{ .Release.Namespace }} + labels: + app: pilot + release: {{ .Release.Name }} + istio: pilot +spec: + ports: + - port: 15010 + name: grpc-xds # direct + - port: 15011 + name: https-xds # mTLS + - port: 8080 + name: http-legacy-discovery # direct + - port: 15014 + name: http-monitoring + selector: + {{- if ne .Values.version ""}} + app: pilot + version: {{ .Values.version }} + {{ else }} + istio: pilot + {{- end }} +--- diff --git a/istio-1.3.5/install/kubernetes/operator/charts/istio-control/istio-discovery/templates/serviceaccount.yaml b/istio-1.3.5/install/kubernetes/operator/charts/istio-control/istio-discovery/templates/serviceaccount.yaml new file mode 100644 index 0000000..9ce4a22 --- /dev/null +++ b/istio-1.3.5/install/kubernetes/operator/charts/istio-control/istio-discovery/templates/serviceaccount.yaml @@ -0,0 +1,17 @@ +{{ if .Values.clusterResources }} +apiVersion: v1 +kind: ServiceAccount +{{- if .Values.global.imagePullSecrets }} +imagePullSecrets: +{{- range .Values.global.imagePullSecrets }} + - name: {{ . }} +{{- end }} +{{- end }} +metadata: + name: istio-pilot-service-account + namespace: {{ .Release.Namespace }} + labels: + app: pilot + release: {{ .Release.Name }} +--- +{{ end }} diff --git a/istio-1.3.5/install/kubernetes/operator/charts/istio-control/istio-discovery/values.yaml b/istio-1.3.5/install/kubernetes/operator/charts/istio-control/istio-discovery/values.yaml new file mode 100644 index 0000000..c5fb08a --- /dev/null +++ b/istio-1.3.5/install/kubernetes/operator/charts/istio-control/istio-discovery/values.yaml @@ -0,0 +1,113 @@ +#.Values.pilot for discovery and mesh wide config + +## Discovery Settings +pilot: + autoscaleEnabled: true + autoscaleMin: 1 + autoscaleMax: 5 + replicaCount: 1 + rollingMaxSurge: 100% + rollingMaxUnavailable: 25% + + # Can be a full hub/image:tag + image: pilot + traceSampling: 1.0 + + # Resources for a small pilot install + resources: + requests: + cpu: 500m + memory: 2048Mi + + # Namespace for Istio config + configNamespace: istio-config + + # Applications namespace list pilot manages + appNamespaces: [] + + env: + GODEBUG: gctrace=1 + + cpu: + targetAverageUtilization: 80 + + nodeSelector: {} + tolerations: [] + + # Specify the pod anti-affinity that allows you to constrain which nodes + # your pod is eligible to be scheduled based on labels on pods that are + # already running on the node rather than based on labels on nodes. + # There are currently two types of anti-affinity: + # "requiredDuringSchedulingIgnoredDuringExecution" + # "preferredDuringSchedulingIgnoredDuringExecution" + # which denote "hard" vs. "soft" requirements, you can define your values + # in "podAntiAffinityLabelSelector" and "podAntiAffinityTermLabelSelector" + # correspondingly. + # For example: + # podAntiAffinityLabelSelector: + # - key: security + # operator: In + # values: S1,S2 + # topologyKey: "kubernetes.io/hostname" + # This pod anti-affinity rule says that the pod requires not to be scheduled + # onto a node if that node is already running a pod with label having key + # "security" and value "S1". + podAntiAffinityLabelSelector: [] + podAntiAffinityTermLabelSelector: [] + + # The following is used to limit how long a sidecar can be connected + # to a pilot. It balances out load across pilot instances at the cost of + # increasing system churn. + keepaliveMaxServerConnectionAge: 30m + + # Additional labels to apply to the deployment. + deploymentLabels: + + + ## Mesh config settings + + # Used to override control-plane networs + meshNetworks: + networks: {} + + # Install the mesh config map, generated from values.yaml. + # If false, pilot wil use default values (by default) or user-supplied values. + configMap: true + + # Controls legacy k8s ingress + # Only one pilot profile should enable ingress support !!! + ingress: + # If empty, node-port is assumed. + ingressService: istio-ingressgateway + # DEFAULT: all Ingress resources without annotation or with istio annotation + # STRICT: only with istio annotation + # OFF: no ingress or sync. + ingressControllerMode: "OFF" + + # Value to set on "kubernetes.io/ingress.class" annotations to activate, if mode is STRICT + # This is required to be different than 'istio' if multiple ingresses are present. + ingressClass: istio + + telemetry: + # Will not define mixerCheckServer and mixerReportServer + enabled: true + + policy: + # Will not define mixerCheckServer and mixerReportServer + enabled: false + + # Indicate if Galley is enabled to send MCP queries + useMCP: true + +## Mixer settings +mixer: + telemetry: + # Set reportBatchMaxEntries to 0 to use the default batching behavior (i.e., every 100 requests). + # A positive value indicates the number of requests that are batched before telemetry data + # is sent to the mixer server + reportBatchMaxEntries: 100 + + # Set reportBatchMaxTime to 0 to use the default batching behavior (i.e., every 1 second). + # A positive time value indicates the maximum wait time since the last request will telemetry data + # be batched before being sent to the mixer server + reportBatchMaxTime: 1s diff --git a/istio-1.3.5/install/kubernetes/operator/charts/istio-policy/Chart.yaml b/istio-1.3.5/install/kubernetes/operator/charts/istio-policy/Chart.yaml new file mode 100644 index 0000000..f811d74 --- /dev/null +++ b/istio-1.3.5/install/kubernetes/operator/charts/istio-policy/Chart.yaml @@ -0,0 +1,13 @@ +apiVersion: v1 +name: istio-policy +version: 1.1.0 +appVersion: 1.1.0 +tillerVersion: ">=2.7.2" +description: Helm chart for mixer policy deployment +keywords: + - istio + - mixer +sources: + - http://github.com/istio/istio +engine: gotpl +icon: https://istio.io/favicons/android-192x192.png diff --git a/istio-1.3.5/install/kubernetes/operator/charts/istio-policy/templates/_affinity.tpl b/istio-1.3.5/install/kubernetes/operator/charts/istio-policy/templates/_affinity.tpl new file mode 100644 index 0000000..d3a1d08 --- /dev/null +++ b/istio-1.3.5/install/kubernetes/operator/charts/istio-policy/templates/_affinity.tpl @@ -0,0 +1,93 @@ +{{/* affinity - https://kubernetes.io/docs/concepts/configuration/assign-pod-node/ */}} + +{{- define "nodeaffinity" }} + nodeAffinity: + requiredDuringSchedulingIgnoredDuringExecution: + {{- include "nodeAffinityRequiredDuringScheduling" . }} + preferredDuringSchedulingIgnoredDuringExecution: + {{- include "nodeAffinityPreferredDuringScheduling" . }} +{{- end }} + +{{- define "nodeAffinityRequiredDuringScheduling" }} + nodeSelectorTerms: + - matchExpressions: + - key: beta.kubernetes.io/arch + operator: In + values: + {{- range $key, $val := .Values.global.arch }} + {{- if gt ($val | int) 0 }} + - {{ $key }} + {{- end }} + {{- end }} + {{- $nodeSelector := default .Values.global.defaultNodeSelector .Values.mixer.policy.nodeSelector -}} + {{- range $key, $val := $nodeSelector }} + - key: {{ $key }} + operator: In + values: + - {{ $val }} + {{- end }} +{{- end }} + +{{- define "nodeAffinityPreferredDuringScheduling" }} + {{- range $key, $val := .Values.global.arch }} + {{- if gt ($val | int) 0 }} + - weight: {{ $val | int }} + preference: + matchExpressions: + - key: beta.kubernetes.io/arch + operator: In + values: + - {{ $key }} + {{- end }} + {{- end }} +{{- end }} + +{{- define "podAntiAffinity" }} +{{- if or .Values.mixer.policy.podAntiAffinityLabelSelector .Values.mixer.policy.podAntiAffinityTermLabelSelector}} + podAntiAffinity: + {{- if .Values.mixer.policy.podAntiAffinityLabelSelector }} + requiredDuringSchedulingIgnoredDuringExecution: + {{- include "podAntiAffinityRequiredDuringScheduling" . }} + {{- end }} + {{- if .Values.mixer.policy.podAntiAffinityTermLabelSelector }} + preferredDuringSchedulingIgnoredDuringExecution: + {{- include "podAntiAffinityPreferredDuringScheduling" . }} + {{- end }} +{{- end }} +{{- end }} + +{{- define "podAntiAffinityRequiredDuringScheduling" }} + {{- range $index, $item := .Values.mixer.policy.podAntiAffinityLabelSelector }} + - labelSelector: + matchExpressions: + - key: {{ $item.key }} + operator: {{ $item.operator }} + {{- if $item.values }} + values: + {{- $vals := split "," $item.values }} + {{- range $i, $v := $vals }} + - {{ $v }} + {{- end }} + {{- end }} + topologyKey: {{ $item.topologyKey }} + {{- end }} +{{- end }} + +{{- define "podAntiAffinityPreferredDuringScheduling" }} + {{- range $index, $item := .Values.mixer.policy.podAntiAffinityTermLabelSelector }} + - podAffinityTerm: + labelSelector: + matchExpressions: + - key: {{ $item.key }} + operator: {{ $item.operator }} + {{- if $item.values }} + values: + {{- $vals := split "," $item.values }} + {{- range $i, $v := $vals }} + - {{ $v }} + {{- end }} + {{- end }} + topologyKey: {{ $item.topologyKey }} + weight: 100 + {{- end }} +{{- end }} diff --git a/istio-1.3.5/install/kubernetes/operator/charts/istio-policy/templates/_helpers.tpl b/istio-1.3.5/install/kubernetes/operator/charts/istio-policy/templates/_helpers.tpl new file mode 100644 index 0000000..236e347 --- /dev/null +++ b/istio-1.3.5/install/kubernetes/operator/charts/istio-policy/templates/_helpers.tpl @@ -0,0 +1,32 @@ +{{/* vim: set filetype=mustache: */}} +{{/* +Expand the name of the chart. +*/}} +{{- define "mixer.name" -}} +{{- default .Chart.Name .Values.mixer.policy.nameOverride | trunc 63 | trimSuffix "-" -}} +{{- end -}} + +{{/* +Create a default fully qualified app name. +We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). +If release name contains chart name it will be used as a full name. +*/}} +{{- define "mixer.fullname" -}} +{{- if .Values.mixer.policy.fullnameOverride -}} +{{- .Values.mixer.policy.fullnameOverride | trunc 63 | trimSuffix "-" -}} +{{- else -}} +{{- $name := default .Chart.Name .Values.mixer.policy.nameOverride -}} +{{- if contains $name .Release.Name -}} +{{- .Release.Name | trunc 63 | trimSuffix "-" -}} +{{- else -}} +{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" -}} +{{- end -}} +{{- end -}} +{{- end -}} + +{{/* +Create chart name and version as used by the chart label. +*/}} +{{- define "mixer.chart" -}} +{{- .Chart.Name | trunc 63 | trimSuffix "-" -}} +{{- end -}} diff --git a/istio-1.3.5/install/kubernetes/operator/charts/istio-policy/templates/autoscale.yaml b/istio-1.3.5/install/kubernetes/operator/charts/istio-policy/templates/autoscale.yaml new file mode 100644 index 0000000..b448a5e --- /dev/null +++ b/istio-1.3.5/install/kubernetes/operator/charts/istio-policy/templates/autoscale.yaml @@ -0,0 +1,23 @@ +{{- if .Values.mixer.policy.autoscaleMin }} +apiVersion: autoscaling/v2beta1 +kind: HorizontalPodAutoscaler +metadata: + name: istio-policy + namespace: {{ .Release.Namespace }} + labels: + app: istio-policy + release: {{ .Release.Name }} +spec: + maxReplicas: {{ .Values.mixer.policy.autoscaleMax }} + minReplicas: {{ .Values.mixer.policy.autoscaleMin }} + scaleTargetRef: + apiVersion: apps/v1 + kind: Deployment + name: istio-policy + metrics: + - type: Resource + resource: + name: cpu + targetAverageUtilization: {{ .Values.mixer.policy.cpu.targetAverageUtilization }} +--- +{{- end }} diff --git a/istio-1.3.5/install/kubernetes/operator/charts/istio-policy/templates/clusterrole.yaml b/istio-1.3.5/install/kubernetes/operator/charts/istio-policy/templates/clusterrole.yaml new file mode 100644 index 0000000..b04cf13 --- /dev/null +++ b/istio-1.3.5/install/kubernetes/operator/charts/istio-policy/templates/clusterrole.yaml @@ -0,0 +1,21 @@ +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: istio-policy + labels: + release: {{ .Release.Name }} + app: istio-policy +rules: +- apiGroups: ["config.istio.io"] # istio CRD watcher + resources: ["*"] + verbs: ["create", "get", "list", "watch", "patch"] +- apiGroups: ["apiextensions.k8s.io"] + resources: ["customresourcedefinitions"] + verbs: ["get", "list", "watch"] +- apiGroups: [""] + resources: ["configmaps", "endpoints", "pods", "services", "namespaces", "secrets", "replicationcontrollers"] + verbs: ["get", "list", "watch"] +- apiGroups: ["extensions", "apps"] + resources: ["replicasets"] + verbs: ["get", "list", "watch"] +--- diff --git a/istio-1.3.5/install/kubernetes/operator/charts/istio-policy/templates/clusterrolebinding.yaml b/istio-1.3.5/install/kubernetes/operator/charts/istio-policy/templates/clusterrolebinding.yaml new file mode 100644 index 0000000..6683425 --- /dev/null +++ b/istio-1.3.5/install/kubernetes/operator/charts/istio-policy/templates/clusterrolebinding.yaml @@ -0,0 +1,16 @@ +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: istio-policy-admin-role-binding-{{ .Release.Namespace }} + labels: + app: istio-policy + release: {{ .Release.Name }} +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: istio-policy +subjects: + - kind: ServiceAccount + name: istio-policy-service-account + namespace: {{ .Release.Namespace }} +--- diff --git a/istio-1.3.5/install/kubernetes/operator/charts/istio-policy/templates/config.yaml b/istio-1.3.5/install/kubernetes/operator/charts/istio-policy/templates/config.yaml new file mode 100644 index 0000000..c07e9ea --- /dev/null +++ b/istio-1.3.5/install/kubernetes/operator/charts/istio-policy/templates/config.yaml @@ -0,0 +1,328 @@ +{{ if not (eq .Release.Namespace "istio-system") }} +apiVersion: "config.istio.io/v1alpha2" +kind: attributemanifest +metadata: + name: istioproxy + namespace: {{ .Release.Namespace }} + labels: + app: istio-policy + release: {{ .Release.Name }} +spec: + attributes: + origin.ip: + valueType: IP_ADDRESS + origin.uid: + valueType: STRING + origin.user: + valueType: STRING + request.headers: + valueType: STRING_MAP + request.id: + valueType: STRING + request.host: + valueType: STRING + request.method: + valueType: STRING + request.path: + valueType: STRING + request.url_path: + valueType: STRING + request.query_params: + valueType: STRING_MAP + request.reason: + valueType: STRING + request.referer: + valueType: STRING + request.scheme: + valueType: STRING + request.total_size: + valueType: INT64 + request.size: + valueType: INT64 + request.time: + valueType: TIMESTAMP + request.useragent: + valueType: STRING + response.code: + valueType: INT64 + response.duration: + valueType: DURATION + response.headers: + valueType: STRING_MAP + response.total_size: + valueType: INT64 + response.size: + valueType: INT64 + response.time: + valueType: TIMESTAMP + response.grpc_status: + valueType: STRING + response.grpc_message: + valueType: STRING + source.uid: + valueType: STRING + source.user: # DEPRECATED + valueType: STRING + source.principal: + valueType: STRING + destination.uid: + valueType: STRING + destination.principal: + valueType: STRING + destination.port: + valueType: INT64 + connection.event: + valueType: STRING + connection.id: + valueType: STRING + connection.received.bytes: + valueType: INT64 + connection.received.bytes_total: + valueType: INT64 + connection.sent.bytes: + valueType: INT64 + connection.sent.bytes_total: + valueType: INT64 + connection.duration: + valueType: DURATION + connection.mtls: + valueType: BOOL + connection.requested_server_name: + valueType: STRING + context.protocol: + valueType: STRING + context.proxy_error_code: + valueType: STRING + context.timestamp: + valueType: TIMESTAMP + context.time: + valueType: TIMESTAMP + # Deprecated, kept for compatibility + context.reporter.local: + valueType: BOOL + context.reporter.kind: + valueType: STRING + context.reporter.uid: + valueType: STRING + context.proxy_version: + valueType: STRING + api.service: + valueType: STRING + api.version: + valueType: STRING + api.operation: + valueType: STRING + api.protocol: + valueType: STRING + request.auth.principal: + valueType: STRING + request.auth.audiences: + valueType: STRING + request.auth.presenter: + valueType: STRING + request.auth.claims: + valueType: STRING_MAP + request.auth.raw_claims: + valueType: STRING + request.api_key: + valueType: STRING + rbac.permissive.response_code: + valueType: STRING + rbac.permissive.effective_policy_id: + valueType: STRING + check.error_code: + valueType: INT64 + check.error_message: + valueType: STRING + check.cache_hit: + valueType: BOOL + quota.cache_hit: + valueType: BOOL + +--- +apiVersion: "config.istio.io/v1alpha2" +kind: attributemanifest +metadata: + name: kubernetes + namespace: {{ .Release.Namespace }} + labels: + app: istio-policy + release: {{ .Release.Name }} +spec: + attributes: + source.ip: + valueType: IP_ADDRESS + source.labels: + valueType: STRING_MAP + source.metadata: + valueType: STRING_MAP + source.name: + valueType: STRING + source.namespace: + valueType: STRING + source.owner: + valueType: STRING + source.serviceAccount: + valueType: STRING + source.services: + valueType: STRING + source.workload.uid: + valueType: STRING + source.workload.name: + valueType: STRING + source.workload.namespace: + valueType: STRING + destination.ip: + valueType: IP_ADDRESS + destination.labels: + valueType: STRING_MAP + destination.metadata: + valueType: STRING_MAP + destination.owner: + valueType: STRING + destination.name: + valueType: STRING + destination.container.name: + valueType: STRING + destination.namespace: + valueType: STRING + destination.service.uid: + valueType: STRING + destination.service.name: + valueType: STRING + destination.service.namespace: + valueType: STRING + destination.service.host: + valueType: STRING + destination.serviceAccount: + valueType: STRING + destination.workload.uid: + valueType: STRING + destination.workload.name: + valueType: STRING + destination.workload.namespace: + valueType: STRING +--- +{{- if .Values.mixer.policy.adapters.kubernetesenv.enabled }} +apiVersion: "config.istio.io/v1alpha2" +kind: handler +metadata: + name: kubernetesenv + namespace: {{ .Release.Namespace }} + labels: + app: istio-policy + release: {{ .Release.Name }} +spec: + compiledAdapter: kubernetesenv + params: + # when running from mixer root, use the following config after adding a + # symbolic link to a kubernetes config file via: + # + # $ ln -s ~/.kube/config mixer/adapter/kubernetes/kubeconfig + # + # kubeconfig_path: "mixer/adapter/kubernetes/kubeconfig" + +--- +apiVersion: "config.istio.io/v1alpha2" +kind: rule +metadata: + name: kubeattrgenrulerule + namespace: {{ .Release.Namespace }} + labels: + app: istio-policy + release: {{ .Release.Name }} +spec: + actions: + - handler: kubernetesenv + instances: + - attributes +--- +apiVersion: "config.istio.io/v1alpha2" +kind: rule +metadata: + name: tcpkubeattrgenrulerule + namespace: {{ .Release.Namespace }} + labels: + app: istio-policy + release: {{ .Release.Name }} +spec: + match: context.protocol == "tcp" + actions: + - handler: kubernetesenv + instances: + - attributes +--- +apiVersion: "config.istio.io/v1alpha2" +kind: instance +metadata: + name: attributes + namespace: {{ .Release.Namespace }} + labels: + app: istio-policy + release: {{ .Release.Name }} +spec: + compiledTemplate: kubernetes + params: + # Pass the required attribute data to the adapter + source_uid: source.uid | "" + source_ip: source.ip | ip("0.0.0.0") # default to unspecified ip addr + destination_uid: destination.uid | "" + destination_port: destination.port | 0 + attributeBindings: + # Fill the new attributes from the adapter produced output. + # $out refers to an instance of OutputTemplate message + source.ip: $out.source_pod_ip | ip("0.0.0.0") + source.uid: $out.source_pod_uid | "unknown" + source.labels: $out.source_labels | emptyStringMap() + source.name: $out.source_pod_name | "unknown" + source.namespace: $out.source_namespace | "default" + source.owner: $out.source_owner | "unknown" + source.serviceAccount: $out.source_service_account_name | "unknown" + source.workload.uid: $out.source_workload_uid | "unknown" + source.workload.name: $out.source_workload_name | "unknown" + source.workload.namespace: $out.source_workload_namespace | "unknown" + destination.ip: $out.destination_pod_ip | ip("0.0.0.0") + destination.uid: $out.destination_pod_uid | "unknown" + destination.labels: $out.destination_labels | emptyStringMap() + destination.name: $out.destination_pod_name | "unknown" + destination.container.name: $out.destination_container_name | "unknown" + destination.namespace: $out.destination_namespace | "default" + destination.owner: $out.destination_owner | "unknown" + destination.serviceAccount: $out.destination_service_account_name | "unknown" + destination.workload.uid: $out.destination_workload_uid | "unknown" + destination.workload.name: $out.destination_workload_name | "unknown" + destination.workload.namespace: $out.destination_workload_namespace | "unknown" +{{- end }} +{{- end }} + +--- +# Configuration needed by Mixer. +# Mixer cluster is delivered via CDS +# Specify mixer cluster settings +apiVersion: networking.istio.io/v1alpha3 +kind: DestinationRule +metadata: + name: istio-policy + namespace: {{ .Release.Namespace }} + labels: + app: istio-policy + release: {{ .Release.Name }} +spec: + host: istio-policy.{{ .Release.Namespace }}.svc.{{ .Values.global.proxy.clusterDomain }} + {{- if .Values.global.defaultConfigVisibilitySettings }} + exportTo: + - '*' + {{- end }} + trafficPolicy: + {{- if .Values.global.controlPlaneSecurityEnabled }} + portLevelSettings: + - port: + number: 15004 + tls: + mode: ISTIO_MUTUAL + {{- end}} + connectionPool: + http: + http2MaxRequests: 10000 + maxRequestsPerConnection: 10000 +--- diff --git a/istio-1.3.5/install/kubernetes/operator/charts/istio-policy/templates/deployment.yaml b/istio-1.3.5/install/kubernetes/operator/charts/istio-policy/templates/deployment.yaml new file mode 100644 index 0000000..5849ced --- /dev/null +++ b/istio-1.3.5/install/kubernetes/operator/charts/istio-policy/templates/deployment.yaml @@ -0,0 +1,209 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: istio-policy + namespace: {{ .Release.Namespace }} + labels: + app: istio-policy + istio: mixer + release: {{ .Release.Name }} +spec: + replicas: {{ .Values.mixer.policy.replicaCount }} + strategy: + rollingUpdate: + maxSurge: {{ .Values.mixer.policy.rollingMaxSurge }} + maxUnavailable: {{ .Values.mixer.policy.rollingMaxUnavailable }} + selector: + matchLabels: + app: istio-policy + istio: mixer + istio-mixer-type: policy + template: + metadata: + labels: + app: istio-policy + istio: mixer + istio-mixer-type: policy + annotations: + sidecar.istio.io/inject: "false" +{{- with .Values.mixer.policy.podAnnotations }} +{{ toYaml . | indent 8 }} +{{- end }} + spec: + serviceAccountName: istio-policy-service-account +{{- if .Values.global.priorityClassName }} + priorityClassName: "{{ .Values.global.priorityClassName }}" +{{- end }} + volumes: + - name: istio-certs + secret: + secretName: istio.istio-policy-service-account + optional: true + {{- if .Values.global.sds.enabled }} + - hostPath: + path: /var/run/sds + name: sds-uds-path + - name: istio-token + projected: + sources: + - serviceAccountToken: + audience: {{ .Values.global.trustDomain }} + expirationSeconds: 43200 + path: istio-token + {{- end }} + - name: uds-socket + emptyDir: {} + - name: policy-adapter-secret + secret: + secretName: policy-adapter-secret + optional: true + affinity: + {{- include "nodeaffinity" . | indent 6 }} + {{- include "podAntiAffinity" . | indent 6 }} +{{- if .Values.mixer.policy.tolerations }} + tolerations: +{{ toYaml .Values.mixer.policy.tolerations | indent 6 }} +{{- end }} + containers: + - name: mixer +{{- if contains "/" .Values.mixer.policy.image }} + image: "{{ .Values.mixer.policy.image }}" +{{- else }} + image: "{{ .Values.global.hub }}/{{ .Values.mixer.policy.image }}:{{ .Values.global.tag }}" +{{- end }} + imagePullPolicy: {{ .Values.global.imagePullPolicy | default "Always" }} + ports: + - containerPort: 15014 + - containerPort: 42422 + args: + - --monitoringPort=15014 + - --address + - unix:///sock/mixer.socket +{{- if .Values.global.logging.level }} + - --log_output_level={{ .Values.global.logging.level }} +{{- end}} +{{- if .Values.global.logAsJson }} + - --log_as_json +{{- end }} +{{- if .Values.global.useMCP }} + {{- if .Values.global.controlPlaneSecurityEnabled}} + - --configStoreURL=mcps://istio-galley.{{ .Values.global.configNamespace }}.svc:15019 + {{- else }} + - --configStoreURL=mcp://istio-galley.{{ .Values.global.configNamespace }}.svc:9901 + {{- end }} +{{- else }} + - --configStoreURL=k8s:// +{{- end }} + - --configDefaultNamespace={{ .Values.global.configNamespace }} + {{- if .Values.mixer.policy.adapters.useAdapterCRDs }} + - --useAdapterCRDs=true + {{- else }} + - --useAdapterCRDs=false + {{- end }} + - --useTemplateCRDs=false + {{- if .Values.global.tracer.zipkin.address }} + - --trace_zipkin_url=http://{{- .Values.global.tracer.zipkin.address }}/api/v1/spans + {{- else }} + - --trace_zipkin_url=http://zipkin.{{ .Values.global.telemetryNamespace }}:9411/api/v1/spans + {{- end }} + {{- if .Values.mixer.policy.env }} + env: + {{- range $key, $val := .Values.mixer.policy.env }} + - name: {{ $key }} + value: "{{ $val }}" + {{- end }} + {{- end }} + resources: +{{- if .Values.mixer.policy.resources }} +{{ toYaml .Values.mixer.policy.resources | indent 10 }} +{{- else }} +{{ toYaml .Values.global.defaultResources | indent 10 }} +{{- end }} + volumeMounts: +{{- if .Values.global.useMCP }} + - name: istio-certs + mountPath: /etc/certs + readOnly: true +{{- end }} + - name: uds-socket + mountPath: /sock + - name: policy-adapter-secret + mountPath: /var/run/secrets/istio.io/policy/adapter + readOnly: true + livenessProbe: + httpGet: + path: /version + port: 15014 + initialDelaySeconds: 5 + periodSeconds: 5 + - name: istio-proxy +{{- if contains "/" .Values.global.proxy.image }} + image: "{{ .Values.global.proxy.image }}" +{{- else }} + image: "{{ .Values.global.hub }}/{{ .Values.global.proxy.image }}:{{ .Values.global.tag }}" +{{- end }} + imagePullPolicy: {{ .Values.global.imagePullPolicy | default "Always" }} + ports: + - containerPort: 9091 + - containerPort: 15004 + - containerPort: 15090 + protocol: TCP + name: http-envoy-prom + args: + - proxy + - --domain + - $(POD_NAMESPACE).svc.{{ .Values.global.proxy.clusterDomain }} + - --serviceCluster + - istio-policy + - --templateFile + - /etc/istio/proxy/envoy_policy.yaml.tmpl + {{- if .Values.global.controlPlaneSecurityEnabled }} + - --controlPlaneAuthPolicy + - MUTUAL_TLS + {{- else }} + - --controlPlaneAuthPolicy + - NONE + {{- end }} + {{- if .Values.global.trustDomain }} + - --trust-domain={{ .Values.global.trustDomain }} + {{- end }} + {{- if .Values.global.logAsJson }} + - --log_as_json + {{- end }} + env: + - name: POD_NAME + valueFrom: + fieldRef: + apiVersion: v1 + fieldPath: metadata.name + - name: POD_NAMESPACE + valueFrom: + fieldRef: + apiVersion: v1 + fieldPath: metadata.namespace + - name: INSTANCE_IP + valueFrom: + fieldRef: + apiVersion: v1 + fieldPath: status.podIP + resources: +{{- if .Values.global.proxy.resources }} +{{ toYaml .Values.global.proxy.resources | indent 10 }} +{{- else }} +{{ toYaml .Values.global.defaultResources | indent 10 }} +{{- end }} + volumeMounts: + - name: istio-certs + mountPath: /etc/certs + readOnly: true + {{- if .Values.global.sds.enabled }} + - name: sds-uds-path + mountPath: /var/run/sds + readOnly: true + - name: istio-token + mountPath: /var/run/secrets/tokens + {{- end }} + - name: uds-socket + mountPath: /sock +--- + diff --git a/istio-1.3.5/install/kubernetes/operator/charts/istio-policy/templates/poddisruptionbudget.yaml b/istio-1.3.5/install/kubernetes/operator/charts/istio-policy/templates/poddisruptionbudget.yaml new file mode 100644 index 0000000..f153cb6 --- /dev/null +++ b/istio-1.3.5/install/kubernetes/operator/charts/istio-policy/templates/poddisruptionbudget.yaml @@ -0,0 +1,22 @@ +{{- if .Values.global.defaultPodDisruptionBudget.enabled }} +apiVersion: policy/v1beta1 +kind: PodDisruptionBudget +metadata: + name: istio-policy + namespace: {{ .Release.Namespace }} + labels: + app: istio-policy + release: {{ .Release.Name }} + istio: mixer + istio-mixer-type: policy +spec: + minAvailable: 1 + selector: + matchLabels: + app: istio-policy + release: {{ .Release.Name }} + istio: mixer + istio-mixer-type: policy +--- + +{{- end }} diff --git a/istio-1.3.5/install/kubernetes/operator/charts/istio-policy/templates/service.yaml b/istio-1.3.5/install/kubernetes/operator/charts/istio-policy/templates/service.yaml new file mode 100644 index 0000000..b420433 --- /dev/null +++ b/istio-1.3.5/install/kubernetes/operator/charts/istio-policy/templates/service.yaml @@ -0,0 +1,24 @@ +apiVersion: v1 +kind: Service +metadata: + name: istio-policy + namespace: {{ .Release.Namespace }} + labels: + app: istio-policy + istio: mixer + release: {{ .Release.Name }} +spec: + ports: + - name: grpc-mixer + port: 9091 + - name: grpc-mixer-mtls + port: 15004 + - name: http-policy-monitoring + port: 15014 + selector: + app: istio-policy +{{- if .Values.mixer.policy.sessionAffinityEnabled }} + sessionAffinity: ClientIP +{{- end }} +--- + diff --git a/istio-1.3.5/install/kubernetes/operator/charts/istio-policy/templates/serviceaccount.yaml b/istio-1.3.5/install/kubernetes/operator/charts/istio-policy/templates/serviceaccount.yaml new file mode 100644 index 0000000..988aba8 --- /dev/null +++ b/istio-1.3.5/install/kubernetes/operator/charts/istio-policy/templates/serviceaccount.yaml @@ -0,0 +1,15 @@ +apiVersion: v1 +kind: ServiceAccount +{{- if .Values.global.imagePullSecrets }} +imagePullSecrets: +{{- range .Values.global.imagePullSecrets }} + - name: {{ . }} +{{- end }} +{{- end }} +metadata: + name: istio-policy-service-account + namespace: {{ .Release.Namespace }} + labels: + app: istio-policy + release: {{ .Release.Name }} +--- diff --git a/istio-1.3.5/install/kubernetes/operator/charts/istio-policy/values.yaml b/istio-1.3.5/install/kubernetes/operator/charts/istio-policy/values.yaml new file mode 100644 index 0000000..0759b50 --- /dev/null +++ b/istio-1.3.5/install/kubernetes/operator/charts/istio-policy/values.yaml @@ -0,0 +1,45 @@ +mixer: + policy: + image: mixer + + replicaCount: 1 + rollingMaxSurge: 100% + rollingMaxUnavailable: 25% + autoscaleEnabled: true + autoscaleMin: 1 + autoscaleMax: 5 + cpu: + targetAverageUtilization: 80 + + podAnnotations: {} + + env: + GODEBUG: gctrace=1 + + adapters: + kubernetesenv: + enabled: true + + nodeSelector: {} + tolerations: [] + + # Specify the pod anti-affinity that allows you to constrain which nodes + # your pod is eligible to be scheduled based on labels on pods that are + # already running on the node rather than based on labels on nodes. + # There are currently two types of anti-affinity: + # "requiredDuringSchedulingIgnoredDuringExecution" + # "preferredDuringSchedulingIgnoredDuringExecution" + # which denote "hard" vs. "soft" requirements, you can define your values + # in "podAntiAffinityLabelSelector" and "podAntiAffinityTermLabelSelector" + # correspondingly. + # For example: + # podAntiAffinityLabelSelector: + # - key: security + # operator: In + # values: S1,S2 + # topologyKey: "kubernetes.io/hostname" + # This pod anti-affinity rule says that the pod requires not to be scheduled + # onto a node if that node is already running a pod with label having key + # "security" and value "S1". + podAntiAffinityLabelSelector: [] + podAntiAffinityTermLabelSelector: [] diff --git a/istio-1.3.5/install/kubernetes/operator/charts/istio-telemetry/grafana/Chart.yaml b/istio-1.3.5/install/kubernetes/operator/charts/istio-telemetry/grafana/Chart.yaml new file mode 100644 index 0000000..8ed3469 --- /dev/null +++ b/istio-1.3.5/install/kubernetes/operator/charts/istio-telemetry/grafana/Chart.yaml @@ -0,0 +1,6 @@ +apiVersion: v1 +description: A Helm chart for Kubernetes +name: grafana +version: 1.1.0 +appVersion: 1.1.0 +tillerVersion: ">=2.7.2" diff --git a/istio-1.3.5/install/kubernetes/operator/charts/istio-telemetry/grafana/dashboards/galley-dashboard.json b/istio-1.3.5/install/kubernetes/operator/charts/istio-telemetry/grafana/dashboards/galley-dashboard.json new file mode 100644 index 0000000..47160d7 --- /dev/null +++ b/istio-1.3.5/install/kubernetes/operator/charts/istio-telemetry/grafana/dashboards/galley-dashboard.json @@ -0,0 +1,1819 @@ +{ + "__inputs": [ + { + "name": "DS_PROMETHEUS", + "label": "Prometheus", + "description": "", + "type": "datasource", + "pluginId": "prometheus", + "pluginName": "Prometheus" + } + ], + "annotations": { + "list": [ + { + "builtIn": 1, + "datasource": "-- Grafana --", + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations & Alerts", + "type": "dashboard" + } + ] + }, + "editable": false, + "gnetId": null, + "graphTooltip": 0, + "links": [], + "panels": [ + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 5, + "w": 24, + "x": 0, + "y": 0 + }, + "id": 46, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(istio_build{component=\"galley\"}) by (tag)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{ tag }}", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Galley Versions", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 5 + }, + "id": 40, + "panels": [], + "title": "Resource Usage", + "type": "row" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 8, + "w": 6, + "x": 0, + "y": 6 + }, + "id": 36, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "process_virtual_memory_bytes{job=\"galley\"}", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "Virtual Memory", + "refId": "A" + }, + { + "expr": "process_resident_memory_bytes{job=\"galley\"}", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "Resident Memory", + "refId": "B" + }, + { + "expr": "go_memstats_heap_sys_bytes{job=\"galley\"}", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "heap sys", + "refId": "C" + }, + { + "expr": "go_memstats_heap_alloc_bytes{job=\"galley\"}", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "heap alloc", + "refId": "D" + }, + { + "expr": "go_memstats_alloc_bytes{job=\"galley\"}", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "Alloc", + "refId": "F" + }, + { + "expr": "go_memstats_heap_inuse_bytes{job=\"galley\"}", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "Heap in-use", + "refId": "G" + }, + { + "expr": "go_memstats_stack_inuse_bytes{job=\"galley\"}", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "Stack in-use", + "refId": "H" + }, + { + "expr": "sum(container_memory_usage_bytes{container_name=~\"galley\", pod_name=~\"istio-galley-.*\"})", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Total (kis)", + "refId": "E" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Memory", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 8, + "w": 6, + "x": 6, + "y": 6 + }, + "id": 38, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(rate(container_cpu_usage_seconds_total{job=\"kubernetes-cadvisor\",container_name=~\"galley\", pod_name=~\"istio-galley-.*\"}[1m]))", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "Total (k8s)", + "refId": "A" + }, + { + "expr": "sum(rate(container_cpu_usage_seconds_total{job=\"kubernetes-cadvisor\",container_name=~\"galley\", pod_name=~\"istio-galley-.*\"}[1m])) by (container_name)", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "{{ container_name }} (k8s)", + "refId": "B" + }, + { + "expr": "irate(process_cpu_seconds_total{job=\"galley\"}[1m])", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "galley (self-reported)", + "refId": "C" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "CPU", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 8, + "w": 6, + "x": 12, + "y": 6 + }, + "id": 42, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "process_open_fds{job=\"galley\"}", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "Open FDs (galley)", + "refId": "A" + }, + { + "expr": "container_fs_usage_bytes{container_name=~\"galley\", pod_name=~\"istio-galley-.*\"}", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "{{ container_name }} ", + "refId": "B" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Disk", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 8, + "w": 6, + "x": 18, + "y": 6 + }, + "id": 44, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "go_goroutines{job=\"istio-galley\"}", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "goroutines_total", + "refId": "A" + }, + { + "expr": "galley_mcp_source_clients_total", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "clients_total", + "refId": "B" + }, + { + "expr": "go_goroutines{job=\"istio-galley\"}/galley_mcp_source_clients_total", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "avg_goroutines_per_client", + "refId": "C" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Goroutines", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 14 + }, + "id": 10, + "panels": [], + "title": "Runtime", + "type": "row" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 6, + "w": 8, + "x": 0, + "y": 15 + }, + "id": 2, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(rate(galley_runtime_strategy_on_change_total[1m])) * 60", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Strategy Change Events", + "refId": "A" + }, + { + "expr": "sum(rate(galley_runtime_processor_events_processed_total[1m])) * 60", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Processed Events", + "refId": "B" + }, + { + "expr": "sum(rate(galley_runtime_processor_snapshots_published_total[1m])) * 60", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Snapshot Published", + "refId": "C" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Event Rates", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": "Events/min", + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": "", + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 6, + "w": 8, + "x": 8, + "y": 15 + }, + "id": 4, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(rate(galley_runtime_strategy_timer_max_time_reached_total[1m])) * 60", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Max Time Reached", + "refId": "A" + }, + { + "expr": "sum(rate(galley_runtime_strategy_timer_quiesce_reached_total[1m])) * 60", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Quiesce Reached", + "refId": "B" + }, + { + "expr": "sum(rate(galley_runtime_strategy_timer_resets_total[1m])) * 60", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Timer Resets", + "refId": "C" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Timer Rates", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": "Events/min", + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 6, + "w": 8, + "x": 16, + "y": 15 + }, + "id": 8, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 3, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": true, + "steppedLine": false, + "targets": [ + { + "expr": "histogram_quantile(0.50, sum by (le) (galley_runtime_processor_snapshot_events_total_bucket))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "P50", + "refId": "A" + }, + { + "expr": "histogram_quantile(0.90, sum by (le) (galley_runtime_processor_snapshot_events_total_bucket))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "P90", + "refId": "B" + }, + { + "expr": "histogram_quantile(0.95, sum by (le) (galley_runtime_processor_snapshot_events_total_bucket))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "P95", + "refId": "C" + }, + { + "expr": "histogram_quantile(0.99, sum by (le) (galley_runtime_processor_snapshot_events_total_bucket))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "P99", + "refId": "D" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Events Per Snapshot", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 6, + "w": 8, + "x": 8, + "y": 21 + }, + "id": 6, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum by (typeURL) (galley_runtime_state_type_instances_total)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{ typeURL }}", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "State Type Instances", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": "Count", + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 27 + }, + "id": 34, + "panels": [], + "title": "Validation", + "type": "row" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 6, + "w": 8, + "x": 0, + "y": 28 + }, + "id": 28, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "galley_validation_cert_key_updates{job=\"galley\"}", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Key Updates", + "refId": "A" + }, + { + "expr": "galley_validation_cert_key_update_errors{job=\"galley\"}", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Key Update Errors: {{ error }}", + "refId": "B" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Validation Webhook Certificate", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 6, + "w": 8, + "x": 8, + "y": 28 + }, + "id": 30, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(galley_validation_passed{job=\"galley\"}) by (group, version, resource)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Passed: {{ group }}/{{ version }}/{{resource}}", + "refId": "A" + }, + { + "expr": "sum(galley_validation_failed{job=\"galley\"}) by (group, version, resource, reason)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Failed: {{ group }}/{{ version }}/{{resource}} ({{ reason}})", + "refId": "B" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Resource Validation", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 6, + "w": 8, + "x": 16, + "y": 28 + }, + "id": 32, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(galley_validation_http_error{job=\"galley\"}) by (status)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{ status }}", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Validation HTTP Errors", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 34 + }, + "id": 12, + "panels": [], + "title": "Kubernetes Source", + "type": "row" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 6, + "w": 8, + "x": 0, + "y": 35 + }, + "id": 14, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "rate(galley_source_kube_event_success_total[1m]) * 60", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Success", + "refId": "A" + }, + { + "expr": "rate(galley_source_kube_event_error_total[1m]) * 60", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Error", + "refId": "B" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Source Event Rate", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": "Events/min", + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 6, + "w": 8, + "x": 8, + "y": 35 + }, + "id": 16, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "rate(galley_source_kube_dynamic_converter_success_total[1m]) * 60", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{apiVersion=\"{{apiVersion}}\",group=\"{{group}}\",kind=\"{{kind}}\"}", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Kubernetes Object Conversion Successes", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": "Conversions/min", + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 6, + "w": 8, + "x": 16, + "y": 35 + }, + "id": 24, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "rate(galley_source_kube_dynamic_converter_failure_total[1m]) * 60", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Error", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Kubernetes Object Conversion Failures", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": "Failures/min", + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 41 + }, + "id": 18, + "panels": [], + "title": "Mesh Configuration Protocol", + "type": "row" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 6, + "w": 8, + "x": 0, + "y": 42 + }, + "id": 20, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(galley_mcp_source_clients_total)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Clients", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Connected Clients", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 6, + "w": 8, + "x": 8, + "y": 42 + }, + "id": 22, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum by(collection)(irate(galley_mcp_source_request_acks_total[1m]) * 60)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Request ACKs", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": "ACKs/min", + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 6, + "w": 8, + "x": 16, + "y": 42 + }, + "id": 26, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "rate(galley_mcp_source_request_nacks_total[1m]) * 60", + "format": "time_series", + "intervalFactor": 1, + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Request NACKs", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": "NACKs/min", + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + } + ], + "refresh": "5s", + "schemaVersion": 16, + "style": "dark", + "tags": [], + "templating": { + "list": [] + }, + "time": { + "from": "now-5m", + "to": "now" + }, + "timepicker": { + "refresh_intervals": [ + "5s", + "10s", + "30s", + "1m", + "5m", + "15m", + "30m", + "1h", + "2h", + "1d" + ], + "time_options": [ + "5m", + "15m", + "1h", + "6h", + "12h", + "24h", + "2d", + "7d", + "30d" + ] + }, + "timezone": "", + "title": "Istio Galley Dashboard", + "uid": "TSEY6jLmk", + "version": 1 +} diff --git a/istio-1.3.5/install/kubernetes/operator/charts/istio-telemetry/grafana/dashboards/istio-mesh-dashboard.json b/istio-1.3.5/install/kubernetes/operator/charts/istio-telemetry/grafana/dashboards/istio-mesh-dashboard.json new file mode 100644 index 0000000..0eecf6a --- /dev/null +++ b/istio-1.3.5/install/kubernetes/operator/charts/istio-telemetry/grafana/dashboards/istio-mesh-dashboard.json @@ -0,0 +1,953 @@ +{ + "__inputs": [ + { + "name": "DS_PROMETHEUS", + "label": "Prometheus", + "description": "", + "type": "datasource", + "pluginId": "prometheus", + "pluginName": "Prometheus" + } + ], + "__requires": [ + { + "type": "grafana", + "id": "grafana", + "name": "Grafana", + "version": "5.2.3" + }, + { + "type": "panel", + "id": "graph", + "name": "Graph", + "version": "5.0.0" + }, + { + "type": "datasource", + "id": "prometheus", + "name": "Prometheus", + "version": "5.0.0" + }, + { + "type": "panel", + "id": "singlestat", + "name": "Singlestat", + "version": "5.0.0" + }, + { + "type": "panel", + "id": "table", + "name": "Table", + "version": "5.0.0" + }, + { + "type": "panel", + "id": "text", + "name": "Text", + "version": "5.0.0" + } + ], + "annotations": { + "list": [ + { + "builtIn": 1, + "datasource": "-- Grafana --", + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations & Alerts", + "type": "dashboard" + } + ] + }, + "editable": false, + "gnetId": null, + "graphTooltip": 0, + "id": null, + "links": [], + "panels": [ + { + "content": "
\n
\n Istio\n
\n
\n Istio is an open platform that provides a uniform way to connect,\n manage, and \n secure microservices.\n
\n Need help? Join the Istio community.\n
\n
", + "gridPos": { + "h": 3, + "w": 24, + "x": 0, + "y": 0 + }, + "height": "50px", + "id": 13, + "links": [], + "mode": "html", + "style": { + "font-size": "18pt" + }, + "title": "", + "transparent": true, + "type": "text" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "datasource": "Prometheus", + "format": "ops", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "gridPos": { + "h": 3, + "w": 6, + "x": 0, + "y": 3 + }, + "id": 20, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": true, + "lineColor": "rgb(31, 120, 193)", + "show": true + }, + "tableColumn": "", + "targets": [ + { + "expr": "round(sum(irate(istio_requests_total{reporter=\"destination\"}[1m])), 0.001)", + "intervalFactor": 1, + "refId": "A", + "step": 4 + } + ], + "thresholds": "", + "title": "Global Request Volume", + "transparent": false, + "type": "singlestat", + "valueFontSize": "80%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "avg" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "datasource": "Prometheus", + "format": "percentunit", + "gauge": { + "maxValue": 100, + "minValue": 80, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": false + }, + "gridPos": { + "h": 3, + "w": 6, + "x": 6, + "y": 3 + }, + "id": 21, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": true, + "lineColor": "rgb(31, 120, 193)", + "show": true + }, + "tableColumn": "", + "targets": [ + { + "expr": "sum(rate(istio_requests_total{reporter=\"destination\", response_code!~\"5.*\"}[1m])) / sum(rate(istio_requests_total{reporter=\"destination\"}[1m]))", + "format": "time_series", + "intervalFactor": 1, + "refId": "A", + "step": 4 + } + ], + "thresholds": "95, 99, 99.5", + "title": "Global Success Rate (non-5xx responses)", + "transparent": false, + "type": "singlestat", + "valueFontSize": "80%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "avg" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "datasource": "Prometheus", + "format": "ops", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "gridPos": { + "h": 3, + "w": 6, + "x": 12, + "y": 3 + }, + "id": 22, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": true, + "lineColor": "rgb(31, 120, 193)", + "show": true + }, + "tableColumn": "", + "targets": [ + { + "expr": "sum(irate(istio_requests_total{reporter=\"destination\", response_code=~\"4.*\"}[1m])) ", + "format": "time_series", + "intervalFactor": 1, + "refId": "A", + "step": 4 + } + ], + "thresholds": "", + "title": "4xxs", + "transparent": false, + "type": "singlestat", + "valueFontSize": "80%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "avg" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "datasource": "Prometheus", + "format": "ops", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "gridPos": { + "h": 3, + "w": 6, + "x": 18, + "y": 3 + }, + "id": 23, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": true, + "lineColor": "rgb(31, 120, 193)", + "show": true + }, + "tableColumn": "", + "targets": [ + { + "expr": "sum(irate(istio_requests_total{reporter=\"destination\", response_code=~\"5.*\"}[1m])) ", + "format": "time_series", + "intervalFactor": 1, + "refId": "A", + "step": 4 + } + ], + "thresholds": "", + "title": "5xxs", + "transparent": false, + "type": "singlestat", + "valueFontSize": "80%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "avg" + }, + { + "columns": [], + "datasource": "Prometheus", + "fontSize": "100%", + "gridPos": { + "h": 21, + "w": 24, + "x": 0, + "y": 6 + }, + "hideTimeOverride": false, + "id": 73, + "links": [], + "pageSize": null, + "repeat": null, + "repeatDirection": "v", + "scroll": true, + "showHeader": true, + "sort": { + "col": 4, + "desc": true + }, + "styles": [ + { + "alias": "Workload", + "colorMode": null, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "link": false, + "linkTargetBlank": false, + "linkTooltip": "Workload dashboard", + "linkUrl": "/dashboard/db/istio-workload-dashboard?var-namespace=$__cell_2&var-workload=$__cell_", + "pattern": "destination_workload", + "preserveFormat": false, + "sanitize": false, + "thresholds": [], + "type": "hidden", + "unit": "short" + }, + { + "alias": "", + "colorMode": null, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "pattern": "Time", + "thresholds": [], + "type": "hidden", + "unit": "short" + }, + { + "alias": "Requests", + "colorMode": null, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "pattern": "Value #A", + "thresholds": [], + "type": "number", + "unit": "ops" + }, + { + "alias": "P50 Latency", + "colorMode": null, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "pattern": "Value #B", + "thresholds": [], + "type": "number", + "unit": "s" + }, + { + "alias": "P90 Latency", + "colorMode": null, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "pattern": "Value #D", + "thresholds": [], + "type": "number", + "unit": "s" + }, + { + "alias": "P99 Latency", + "colorMode": null, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "pattern": "Value #E", + "thresholds": [], + "type": "number", + "unit": "s" + }, + { + "alias": "Success Rate", + "colorMode": "cell", + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "pattern": "Value #F", + "thresholds": [ + ".95", + " 1.00" + ], + "type": "number", + "unit": "percentunit" + }, + { + "alias": "Workload", + "colorMode": null, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "link": true, + "linkTooltip": "$__cell dashboard", + "linkUrl": "/dashboard/db/istio-workload-dashboard?var-workload=$__cell_2&var-namespace=$__cell_3", + "pattern": "destination_workload_var", + "thresholds": [], + "type": "number", + "unit": "short" + }, + { + "alias": "Service", + "colorMode": null, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "link": true, + "linkTooltip": "$__cell dashboard", + "linkUrl": "/dashboard/db/istio-service-dashboard?var-service=$__cell", + "pattern": "destination_service", + "thresholds": [], + "type": "string", + "unit": "short" + }, + { + "alias": "", + "colorMode": null, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "pattern": "destination_workload_namespace", + "thresholds": [], + "type": "hidden", + "unit": "short" + } + ], + "targets": [ + { + "expr": "label_join(sum(rate(istio_requests_total{reporter=\"destination\", response_code=\"200\"}[1m])) by (destination_workload, destination_workload_namespace, destination_service), \"destination_workload_var\", \".\", \"destination_workload\", \"destination_workload_namespace\")", + "format": "table", + "hide": false, + "instant": true, + "intervalFactor": 1, + "legendFormat": "{{ destination_workload}}.{{ destination_workload_namespace }}", + "refId": "A" + }, + { + "expr": "label_join((histogram_quantile(0.50, sum(rate(istio_request_duration_milliseconds_bucket{reporter=\"destination\"}[1m])) by (le, destination_workload, destination_workload_namespace)) / 1000) or histogram_quantile(0.50, sum(rate(istio_request_duration_seconds_bucket{reporter=\"destination\"}[1m])) by (le, destination_workload, destination_workload_namespace)), \"destination_workload_var\", \".\", \"destination_workload\", \"destination_workload_namespace\")", + "format": "table", + "hide": false, + "instant": true, + "intervalFactor": 1, + "legendFormat": "{{ destination_workload}}.{{ destination_workload_namespace }}", + "refId": "B" + }, + { + "expr": "label_join((histogram_quantile(0.90, sum(rate(istio_request_duration_milliseconds_bucket{reporter=\"destination\"}[1m])) by (le, destination_workload, destination_workload_namespace)) / 1000) or histogram_quantile(0.90, sum(rate(istio_request_duration_seconds_bucket{reporter=\"destination\"}[1m])) by (le, destination_workload, destination_workload_namespace)), \"destination_workload_var\", \".\", \"destination_workload\", \"destination_workload_namespace\")", + "format": "table", + "hide": false, + "instant": true, + "intervalFactor": 1, + "legendFormat": "{{ destination_workload }}.{{ destination_workload_namespace }}", + "refId": "D" + }, + { + "expr": "label_join((histogram_quantile(0.99, sum(rate(istio_request_duration_milliseconds_bucket{reporter=\"destination\"}[1m])) by (le, destination_workload, destination_workload_namespace)) / 1000) or histogram_quantile(0.99, sum(rate(istio_request_duration_seconds_bucket{reporter=\"destination\"}[1m])) by (le, destination_workload, destination_workload_namespace)), \"destination_workload_var\", \".\", \"destination_workload\", \"destination_workload_namespace\")", + "format": "table", + "hide": false, + "instant": true, + "intervalFactor": 1, + "legendFormat": "{{ destination_workload }}.{{ destination_workload_namespace }}", + "refId": "E" + }, + { + "expr": "label_join((sum(rate(istio_requests_total{reporter=\"destination\", response_code!~\"5.*\"}[1m])) by (destination_workload, destination_workload_namespace) / sum(rate(istio_requests_total{reporter=\"destination\"}[1m])) by (destination_workload, destination_workload_namespace)), \"destination_workload_var\", \".\", \"destination_workload\", \"destination_workload_namespace\")", + "format": "table", + "hide": false, + "instant": true, + "interval": "", + "intervalFactor": 1, + "legendFormat": "{{ destination_workload }}.{{ destination_workload_namespace }}", + "refId": "F" + } + ], + "timeFrom": null, + "title": "HTTP/GRPC Workloads", + "transform": "table", + "transparent": false, + "type": "table" + }, + { + "columns": [], + "datasource": "Prometheus", + "fontSize": "100%", + "gridPos": { + "h": 18, + "w": 24, + "x": 0, + "y": 27 + }, + "hideTimeOverride": false, + "id": 109, + "links": [], + "pageSize": null, + "repeatDirection": "v", + "scroll": true, + "showHeader": true, + "sort": { + "col": 2, + "desc": true + }, + "styles": [ + { + "alias": "Workload", + "colorMode": null, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "link": false, + "linkTargetBlank": false, + "linkTooltip": "$__cell dashboard", + "linkUrl": "/dashboard/db/istio-tcp-workload-dashboard?var-namespace=$__cell_2&&var-workload=$__cell", + "pattern": "destination_workload", + "preserveFormat": false, + "sanitize": false, + "thresholds": [], + "type": "hidden", + "unit": "short" + }, + { + "alias": "Bytes Sent", + "colorMode": null, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "pattern": "Value #A", + "thresholds": [ + "" + ], + "type": "number", + "unit": "Bps" + }, + { + "alias": "Bytes Received", + "colorMode": null, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "pattern": "Value #C", + "thresholds": [], + "type": "number", + "unit": "Bps" + }, + { + "alias": "", + "colorMode": null, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "pattern": "Time", + "thresholds": [], + "type": "hidden", + "unit": "short" + }, + { + "alias": "Workload", + "colorMode": null, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "link": true, + "linkTooltip": "$__cell dashboard", + "linkUrl": "/dashboard/db/istio-workload-dashboard?var-namespace=$__cell_3&var-workload=$__cell_2", + "pattern": "destination_workload_var", + "thresholds": [], + "type": "string", + "unit": "short" + }, + { + "alias": "", + "colorMode": null, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "pattern": "destination_workload_namespace", + "thresholds": [], + "type": "hidden", + "unit": "short" + }, + { + "alias": "Service", + "colorMode": null, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "link": true, + "linkTooltip": "$__cell dashboard", + "linkUrl": "/dashboard/db/istio-service-dashboard?var-service=$__cell", + "pattern": "destination_service", + "thresholds": [], + "type": "number", + "unit": "short" + } + ], + "targets": [ + { + "expr": "label_join(sum(rate(istio_tcp_received_bytes_total{reporter=\"source\"}[1m])) by (destination_workload, destination_workload_namespace, destination_service), \"destination_workload_var\", \".\", \"destination_workload\", \"destination_workload_namespace\")", + "format": "table", + "hide": false, + "instant": true, + "intervalFactor": 1, + "legendFormat": "{{ destination_workload }}", + "refId": "C" + }, + { + "expr": "label_join(sum(rate(istio_tcp_sent_bytes_total{reporter=\"source\"}[1m])) by (destination_workload, destination_workload_namespace, destination_service), \"destination_workload_var\", \".\", \"destination_workload\", \"destination_workload_namespace\")", + "format": "table", + "hide": false, + "instant": true, + "intervalFactor": 1, + "legendFormat": "{{ destination_workload }}", + "refId": "A" + } + ], + "timeFrom": null, + "title": "TCP Workloads", + "transform": "table", + "transparent": false, + "type": "table" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 9, + "w": 24, + "x": 0, + "y": 45 + }, + "id": 111, + "legend": { + "alignAsTable": false, + "avg": false, + "current": false, + "max": false, + "min": false, + "rightSide": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(istio_build) by (component, tag)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{ component }}: {{ tag }}", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Istio Components by Version", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "transparent": false, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + } + ], + "refresh": "5s", + "schemaVersion": 16, + "style": "dark", + "tags": [], + "templating": { + "list": [] + }, + "time": { + "from": "now-5m", + "to": "now" + }, + "timepicker": { + "refresh_intervals": [ + "5s", + "10s", + "30s", + "1m", + "5m", + "15m", + "30m", + "1h", + "2h", + "1d" + ], + "time_options": [ + "5m", + "15m", + "1h", + "6h", + "12h", + "24h", + "2d", + "7d", + "30d" + ] + }, + "timezone": "browser", + "title": "Istio Mesh Dashboard", + "version": 4 +} diff --git a/istio-1.3.5/install/kubernetes/operator/charts/istio-telemetry/grafana/dashboards/istio-performance-dashboard.json b/istio-1.3.5/install/kubernetes/operator/charts/istio-telemetry/grafana/dashboards/istio-performance-dashboard.json new file mode 100644 index 0000000..e4c9682 --- /dev/null +++ b/istio-1.3.5/install/kubernetes/operator/charts/istio-telemetry/grafana/dashboards/istio-performance-dashboard.json @@ -0,0 +1,1822 @@ +{ + "annotations": { + "list": [ + { + "builtIn": 1, + "datasource": "-- Grafana --", + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations & Alerts", + "type": "dashboard" + } + ] + }, + "editable": false, + "gnetId": null, + "graphTooltip": 0, + "id": 9, + "links": [], + "panels": [ + { + "collapsed": true, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 0 + }, + "id": 21, + "panels": [ + { + "content": "The charts on this dashboard are intended to show Istio main components cost in terms resources utilization under steady load.\n\n- **vCPU/1k rps:** shows vCPU utilization by the main Istio components normalized by 1000 requests/second. When idle or low traffic, this chart will be blank. The curve for istio-proxy refers to the services sidecars only.\n- **vCPU:** vCPU utilization by Istio components, not normalized.\n- **Memory:** memory footprint for the components. Telemetry and policy are normalized by 1k rps, and no data is shown when there is no traffic. For ingress and istio-proxy, the data is per instance.\n- **Bytes transferred/ sec:** shows the number of bytes flowing through each Istio component.\n\n\n", + "gridPos": { + "h": 6, + "w": 24, + "x": 0, + "y": 1 + }, + "id": 19, + "links": [], + "mode": "markdown", + "timeFrom": null, + "timeShift": null, + "title": "Performance Dashboard README", + "transparent": true, + "type": "text" + } + ], + "title": "Performance Dashboard Notes", + "type": "row" + }, + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 1 + }, + "id": 6, + "panels": [], + "title": "vCPU Usage", + "type": "row" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "fill": 1, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 2 + }, + "id": 4, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "(sum(irate(container_cpu_usage_seconds_total{job=\"kubernetes-cadvisor\",pod_name=~\"istio-telemetry-.*\",container_name=~\"mixer|istio-proxy\"}[1m]))/ (round(sum(irate(istio_requests_total[1m])), 0.001)/1000))/ (sum(irate(istio_requests_total{source_workload=\"istio-ingressgateway\"}[1m])) >bool 10)", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "istio-telemetry", + "refId": "A" + }, + { + "expr": "(sum(irate(container_cpu_usage_seconds_total{job=\"kubernetes-cadvisor\",pod_name=~\"istio-ingressgateway-.*\",container_name=\"istio-proxy\"}[1m])) / (round(sum(irate(istio_requests_total{source_workload=\"istio-ingressgateway\", reporter=\"source\"}[1m])), 0.001)/1000))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "istio-ingressgateway", + "refId": "B" + }, + { + "expr": "(sum(irate(container_cpu_usage_seconds_total{job=\"kubernetes-cadvisor\",namespace!=\"istio-control\",container_name=\"istio-proxy\"}[1m]))/ (round(sum(irate(istio_requests_total[1m])), 0.001)/1000))/ (sum(irate(istio_requests_total{source_workload=\"istio-ingressgateway\"}[1m])) >bool 10)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "istio-proxy", + "refId": "C" + }, + { + "expr": "(sum(irate(container_cpu_usage_seconds_total{job=\"kubernetes-cadvisor\",pod_name=~\"istio-policy-.*\",container_name=~\"mixer|istio-proxy\"}[1m]))/ (round(sum(irate(istio_requests_total[1m])), 0.001)/1000))/ (sum(irate(istio_requests_total{source_workload=\"istio-ingressgateway\"}[1m])) >bool 10)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "istio-policy", + "refId": "D" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "vCPU / 1k rps", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "fill": 1, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 2 + }, + "id": 7, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(rate(container_cpu_usage_seconds_total{job=\"kubernetes-cadvisor\",pod_name=~\"istio-telemetry-.*\",container_name=~\"mixer|istio-proxy\"}[1m]))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "istio-telemetry", + "refId": "A" + }, + { + "expr": "sum(rate(container_cpu_usage_seconds_total{job=\"kubernetes-cadvisor\",pod_name=~\"istio-ingressgateway-.*\",container_name=\"istio-proxy\"}[1m]))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "istio-ingressgateway", + "refId": "B" + }, + { + "expr": "sum(rate(container_cpu_usage_seconds_total{job=\"kubernetes-cadvisor\",namespace!=\"istio-control\",container_name=\"istio-proxy\"}[1m]))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "istio-proxy", + "refId": "C" + }, + { + "expr": "sum(rate(container_cpu_usage_seconds_total{job=\"kubernetes-cadvisor\",pod_name=~\"istio-policy-.*\",container_name=~\"mixer|istio-proxy\"}[1m]))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "istio-policy", + "refId": "D" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "vCPU", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 10 + }, + "id": 13, + "panels": [], + "title": "Memory and Data Rates", + "type": "row" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "fill": 1, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 11 + }, + "id": 902, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "(sum(container_memory_usage_bytes{pod_name=~\"istio-telemetry-.*\"}) / (sum(irate(istio_requests_total[1m])) / 1000)) / (sum(irate(istio_requests_total{source_workload=\"istio-ingressgateway\"}[1m])) >bool 10)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "istio-telemetry / 1k rps", + "refId": "A" + }, + { + "expr": "sum(container_memory_usage_bytes{pod_name=~\"istio-ingressgateway-.*\"}) / count(container_memory_usage_bytes{pod_name=~\"istio-ingressgateway-.*\",container_name!=\"POD\"})", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "per istio-ingressgateway", + "refId": "B" + }, + { + "expr": "sum(container_memory_usage_bytes{namespace!=\"istio-control\",container_name=\"istio-proxy\"}) / count(container_memory_usage_bytes{namespace!=\"istio-control\",container_name=\"istio-proxy\"})", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "per istio proxy", + "refId": "C" + }, + { + "expr": "(sum(container_memory_usage_bytes{pod_name=~\"istio-policy-.*\"}) / (sum(irate(istio_requests_total[1m])) / 1000))/ (sum(irate(istio_requests_total{source_workload=\"istio-istio-ingressgateway\"}[1m])) >bool 10)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "istio-policy / 1k rps", + "refId": "D" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Memory Usage", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "bytes", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "fill": 1, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 11 + }, + "id": 11, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(irate(istio_response_bytes_sum{destination_workload=\"istio-telemetry\"}[1m])) + sum(irate(istio_request_bytes_sum{destination_workload=\"istio-telemetry\"}[1m]))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "istio-telemetry", + "refId": "A" + }, + { + "expr": "sum(irate(istio_response_bytes_sum{source_workload=\"istio-ingressgateway\", reporter=\"source\"}[1m]))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "istio-ingressgateway", + "refId": "B" + }, + { + "expr": "sum(irate(istio_response_bytes_sum{source_workload_namespace!=\"istio-control\", reporter=\"source\"}[1m])) + sum(irate(istio_response_bytes_sum{destination_workload_namespace!=\"istio-control\", reporter=\"destination\"}[1m])) + sum(irate(istio_request_bytes_sum{source_workload_namespace!=\"istio-control\", reporter=\"source\"}[1m])) + sum(irate(istio_request_bytes_sum{destination_workload_namespace!=\"istio-control\", reporter=\"destination\"}[1m]))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "istio-proxy", + "refId": "C" + }, + { + "expr": "sum(irate(istio_response_bytes_sum{destination_workload=\"istio-policy\"}[1m])) + sum(irate(istio_request_bytes_sum{destination_workload=\"istio-policy\"}[1m]))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "istio_policy", + "refId": "D" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Bytes transferred / sec", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "Bps", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 19 + }, + "id": 17, + "panels": [], + "title": "Istio Component Versions", + "type": "row" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "fill": 1, + "gridPos": { + "h": 8, + "w": 24, + "x": 0, + "y": 20 + }, + "id": 15, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(istio_build) by (component, tag)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{ component }}: {{ tag }}", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Istio Components by Version", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 31 + }, + "id": 71, + "panels": [], + "title": "Proxy Resource Usage", + "type": "row" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 7, + "w": 6, + "x": 0, + "y": 32 + }, + "id": 72, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(container_memory_usage_bytes{container_name=\"istio-proxy\"})", + "format": "time_series", + "hide": false, + "intervalFactor": 2, + "legendFormat": "{{ container_name }} (k8s)", + "refId": "B", + "step": 2 + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Memory", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "bytes", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 7, + "w": 6, + "x": 6, + "y": 32 + }, + "id": 73, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(rate(container_cpu_usage_seconds_total{job=\"kubernetes-cadvisor\",container_name=\"istio-proxy\"}[1m]))", + "format": "time_series", + "hide": false, + "intervalFactor": 2, + "legendFormat": "Total (k8s)", + "refId": "A", + "step": 2 + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "vCPU", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 7, + "w": 6, + "x": 12, + "y": 32 + }, + "id": 702, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(container_fs_usage_bytes{container_name=\"istio-proxy\"})", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "{{ container_name }}", + "refId": "B", + "step": 2 + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Disk", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "bytes", + "label": "", + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "decimals": null, + "format": "none", + "label": "", + "logBase": 1024, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 39 + }, + "id": 69, + "panels": [], + "title": "Pilot Resource Usage", + "type": "row" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 7, + "w": 6, + "x": 0, + "y": 40 + }, + "id": 5, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "process_virtual_memory_bytes{job=\"pilot\"}", + "format": "time_series", + "instant": false, + "intervalFactor": 2, + "legendFormat": "Virtual Memory", + "refId": "I", + "step": 2 + }, + { + "expr": "process_resident_memory_bytes{job=\"pilot\"}", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "Resident Memory", + "refId": "H", + "step": 2 + }, + { + "expr": "go_memstats_heap_sys_bytes{job=\"pilot\"}", + "format": "time_series", + "hide": true, + "intervalFactor": 2, + "legendFormat": "heap sys", + "refId": "A" + }, + { + "expr": "go_memstats_heap_alloc_bytes{job=\"pilot\"}", + "format": "time_series", + "hide": true, + "intervalFactor": 2, + "legendFormat": "heap alloc", + "refId": "D" + }, + { + "expr": "go_memstats_alloc_bytes{job=\"pilot\"}", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "Alloc", + "refId": "F", + "step": 2 + }, + { + "expr": "go_memstats_heap_inuse_bytes{job=\"pilot\"}", + "format": "time_series", + "hide": false, + "intervalFactor": 2, + "legendFormat": "Heap in-use", + "refId": "E", + "step": 2 + }, + { + "expr": "go_memstats_stack_inuse_bytes{job=\"pilot\"}", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "Stack in-use", + "refId": "G", + "step": 2 + }, + { + "expr": "sum(container_memory_usage_bytes{container_name=~\"discovery|istio-proxy\", pod_name=~\"istio-pilot-.*\"})", + "format": "time_series", + "hide": false, + "intervalFactor": 2, + "legendFormat": "Total (k8s)", + "refId": "C", + "step": 2 + }, + { + "expr": "container_memory_usage_bytes{container_name=~\"discovery|istio-proxy\", pod_name=~\"istio-pilot-.*\"}", + "format": "time_series", + "hide": false, + "intervalFactor": 2, + "legendFormat": "{{ container_name }} (k8s)", + "refId": "B", + "step": 2 + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Memory", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "bytes", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 7, + "w": 6, + "x": 6, + "y": 40 + }, + "id": 602, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(rate(container_cpu_usage_seconds_total{job=\"kubernetes-cadvisor\",container_name=~\"discovery|istio-proxy\", pod_name=~\"istio-pilot-.*\"}[1m]))", + "format": "time_series", + "hide": false, + "intervalFactor": 2, + "legendFormat": "Total (k8s)", + "refId": "A", + "step": 2 + }, + { + "expr": "sum(rate(container_cpu_usage_seconds_total{job=\"kubernetes-cadvisor\",container_name=~\"discovery|istio-proxy\", pod_name=~\"istio-pilot-.*\"}[1m])) by (container_name)", + "format": "time_series", + "hide": false, + "intervalFactor": 2, + "legendFormat": "{{ container_name }} (k8s)", + "refId": "B", + "step": 2 + }, + { + "expr": "irate(process_cpu_seconds_total{job=\"pilot\"}[1m])", + "format": "time_series", + "hide": false, + "intervalFactor": 2, + "legendFormat": "pilot (self-reported)", + "refId": "C", + "step": 2 + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "vCPU", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 7, + "w": 6, + "x": 12, + "y": 40 + }, + "id": 74, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "process_open_fds{job=\"pilot\"}", + "format": "time_series", + "hide": true, + "instant": false, + "interval": "", + "intervalFactor": 2, + "legendFormat": "Open FDs (pilot)", + "refId": "A" + }, + { + "expr": "container_fs_usage_bytes{container_name=~\"discovery|istio-proxy\", pod_name=~\"istio-pilot-.*\"}", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "{{ container_name }}", + "refId": "B", + "step": 2 + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Disk", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "bytes", + "label": "", + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "decimals": null, + "format": "none", + "label": "", + "logBase": 1024, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 7, + "w": 6, + "x": 18, + "y": 40 + }, + "id": 402, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": false, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "go_goroutines{job=\"istio-pilot\"}", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "Number of Goroutines", + "refId": "A", + "step": 2 + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Goroutines", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": "", + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 47 + }, + "id": 93, + "panels": [], + "title": "Mixer Resource Usage", + "type": "row" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 7, + "w": 6, + "x": 0, + "y": 48 + }, + "id": 94, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "process_virtual_memory_bytes{job=~\"istio-telemetry|istio-policy\"}", + "format": "time_series", + "instant": false, + "intervalFactor": 2, + "legendFormat": "Virtual Memory", + "refId": "I", + "step": 2 + }, + { + "expr": "process_resident_memory_bytes{job=~\"istio-telemetry|istio-policy\"}", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "Resident Memory", + "refId": "H", + "step": 2 + }, + { + "expr": "go_memstats_heap_sys_bytes{job=~\"istio-telemetry|istio-policy\"}", + "format": "time_series", + "hide": true, + "intervalFactor": 2, + "legendFormat": "heap sys", + "refId": "A" + }, + { + "expr": "go_memstats_heap_alloc_bytes{job=~\"istio-telemetry|istio-policy\"}", + "format": "time_series", + "hide": true, + "intervalFactor": 2, + "legendFormat": "heap alloc", + "refId": "D" + }, + { + "expr": "go_memstats_alloc_bytes{job=~\"istio-telemetry|istio-policy\"}", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "Alloc", + "refId": "F", + "step": 2 + }, + { + "expr": "go_memstats_heap_inuse_bytes{job=~\"istio-telemetry|istio-policy\"}", + "format": "time_series", + "hide": false, + "intervalFactor": 2, + "legendFormat": "Heap in-use", + "refId": "E", + "step": 2 + }, + { + "expr": "go_memstats_stack_inuse_bytes{job=~\"istio-telemetry|istio-policy\"}", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "Stack in-use", + "refId": "G", + "step": 2 + }, + { + "expr": "sum(container_memory_usage_bytes{container_name=~\"mixer|istio-proxy\", pod_name=~\"istio-telemetry-.*\"})", + "format": "time_series", + "hide": false, + "intervalFactor": 2, + "legendFormat": "Total (k8s)", + "refId": "C", + "step": 2 + }, + { + "expr": "container_memory_usage_bytes{container_name=~\"mixer|istio-proxy\", pod_name=~\"istio-telemetry-.*\"}", + "format": "time_series", + "hide": false, + "intervalFactor": 2, + "legendFormat": "{{ container_name }} (k8s)", + "refId": "B", + "step": 2 + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Memory", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "bytes", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 7, + "w": 6, + "x": 6, + "y": 48 + }, + "id": 95, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(rate(container_cpu_usage_seconds_total{job=\"kubernetes-cadvisor\",container_name=~\"mixer|istio-proxy\", pod_name=~\"istio-telemetry-.*\"}[1m]))", + "format": "time_series", + "hide": false, + "intervalFactor": 2, + "legendFormat": "Total (k8s)", + "refId": "A", + "step": 2 + }, + { + "expr": "sum(rate(container_cpu_usage_seconds_total{job=\"kubernetes-cadvisor\",container_name=~\"mixer|istio-proxy\", pod_name=~\"istio-telemetry-.*\"}[1m])) by (container_name)", + "format": "time_series", + "hide": false, + "intervalFactor": 2, + "legendFormat": "{{ container_name }} (k8s)", + "refId": "B", + "step": 2 + }, + { + "expr": "irate(process_cpu_seconds_total{job=~\"istio-telemetry|istio-policy\"}[1m])", + "format": "time_series", + "hide": false, + "intervalFactor": 2, + "legendFormat": "mixer (self-reported)", + "refId": "C", + "step": 2 + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "vCPU", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 7, + "w": 6, + "x": 12, + "y": 48 + }, + "id": 96, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "process_open_fds{job=~\"istio-telemetry|istio-policy\"}", + "format": "time_series", + "hide": true, + "instant": false, + "interval": "", + "intervalFactor": 2, + "legendFormat": "Open FDs (mixer)", + "refId": "A" + }, + { + "expr": "container_fs_usage_bytes{container_name=~\"mixer|istio-proxy\", pod_name=~\"istio-telemetry-.*\"}", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "{{ container_name }}", + "refId": "B", + "step": 2 + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Disk", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "bytes", + "label": "", + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "decimals": null, + "format": "none", + "label": "", + "logBase": 1024, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 7, + "w": 6, + "x": 18, + "y": 48 + }, + "id": 97, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": false, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "go_goroutines{job=\"istio-telemetry\"}", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "Number of Goroutines", + "refId": "A", + "step": 2 + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Goroutines", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": "", + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + } + ], + "refresh": "10s", + "schemaVersion": 18, + "style": "dark", + "tags": [], + "templating": { + "list": [] + }, + "time": { + "from": "now-5m", + "to": "now" + }, + "timepicker": { + "refresh_intervals": [ + "5s", + "10s", + "30s", + "1m", + "5m", + "15m", + "30m", + "1h", + "2h", + "1d" + ], + "time_options": [ + "5m", + "15m", + "1h", + "6h", + "12h", + "24h", + "2d", + "7d", + "30d" + ] + }, + "timezone": "", + "title": "Istio Performance Dashboard", + "uid": "vu8e0VWZk", + "version": 22 +} diff --git a/istio-1.3.5/install/kubernetes/operator/charts/istio-telemetry/grafana/dashboards/istio-service-dashboard.json b/istio-1.3.5/install/kubernetes/operator/charts/istio-telemetry/grafana/dashboards/istio-service-dashboard.json new file mode 100644 index 0000000..f4d58a2 --- /dev/null +++ b/istio-1.3.5/install/kubernetes/operator/charts/istio-telemetry/grafana/dashboards/istio-service-dashboard.json @@ -0,0 +1,2601 @@ +{ + "annotations": { + "list": [ + { + "builtIn": 1, + "datasource": "-- Grafana --", + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations & Alerts", + "type": "dashboard" + } + ] + }, + "editable": false, + "gnetId": null, + "graphTooltip": 0, + "iteration": 1536442501501, + "links": [], + "panels": [ + { + "content": "
\nSERVICE: $service\n
", + "gridPos": { + "h": 3, + "w": 24, + "x": 0, + "y": 0 + }, + "id": 89, + "links": [], + "mode": "html", + "title": "", + "transparent": true, + "type": "text" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "datasource": "Prometheus", + "format": "ops", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "gridPos": { + "h": 4, + "w": 6, + "x": 0, + "y": 3 + }, + "id": 12, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": true, + "lineColor": "rgb(31, 120, 193)", + "show": true + }, + "tableColumn": "", + "targets": [ + { + "expr": "round(sum(irate(istio_requests_total{reporter=\"source\",destination_service=~\"$service\"}[5m])), 0.001)", + "format": "time_series", + "intervalFactor": 1, + "refId": "A", + "step": 4 + } + ], + "thresholds": "", + "title": "Client Request Volume", + "transparent": false, + "type": "singlestat", + "valueFontSize": "80%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "current" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "rgba(50, 172, 45, 0.97)", + "rgba(237, 129, 40, 0.89)", + "rgba(245, 54, 54, 0.9)" + ], + "datasource": "Prometheus", + "decimals": null, + "format": "percentunit", + "gauge": { + "maxValue": 100, + "minValue": 80, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": false + }, + "gridPos": { + "h": 4, + "w": 6, + "x": 6, + "y": 3 + }, + "id": 14, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": true, + "lineColor": "rgb(31, 120, 193)", + "show": true + }, + "tableColumn": "", + "targets": [ + { + "expr": "sum(irate(istio_requests_total{reporter=\"source\",destination_service=~\"$service\",response_code!~\"5.*\"}[5m])) / sum(irate(istio_requests_total{reporter=\"source\",destination_service=~\"$service\"}[5m]))", + "format": "time_series", + "intervalFactor": 1, + "refId": "B" + } + ], + "thresholds": "95, 99, 99.5", + "title": "Client Success Rate (non-5xx responses)", + "transparent": false, + "type": "singlestat", + "valueFontSize": "80%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "avg" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 4, + "w": 6, + "x": 12, + "y": 3 + }, + "id": 87, + "legend": { + "alignAsTable": false, + "avg": false, + "current": false, + "hideEmpty": false, + "hideZero": false, + "max": false, + "min": false, + "rightSide": true, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "(histogram_quantile(0.50, sum(irate(istio_request_duration_milliseconds_bucket{reporter=\"source\",destination_service=~\"$service\"}[1m])) by (le)) / 1000) or histogram_quantile(0.50, sum(irate(istio_request_duration_seconds_bucket{reporter=\"source\",destination_service=~\"$service\"}[1m])) by (le))", + "format": "time_series", + "interval": "", + "intervalFactor": 1, + "legendFormat": "P50", + "refId": "A" + }, + { + "expr": "(histogram_quantile(0.90, sum(irate(istio_request_duration_milliseconds_bucket{reporter=\"source\",destination_service=~\"$service\"}[1m])) by (le)) / 1000) or histogram_quantile(0.90, sum(irate(istio_request_duration_seconds_bucket{reporter=\"source\",destination_service=~\"$service\"}[1m])) by (le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "P90", + "refId": "B" + }, + { + "expr": "(histogram_quantile(0.99, sum(irate(istio_request_duration_milliseconds_bucket{reporter=\"source\",destination_service=~\"$service\"}[1m])) by (le)) / 1000) or histogram_quantile(0.99, sum(irate(istio_request_duration_seconds_bucket{reporter=\"source\",destination_service=~\"$service\"}[1m])) by (le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "P99", + "refId": "C" + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Client Request Duration", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "s", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "#299c46", + "rgba(237, 129, 40, 0.89)", + "#d44a3a" + ], + "datasource": "Prometheus", + "format": "Bps", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "gridPos": { + "h": 4, + "w": 6, + "x": 18, + "y": 3 + }, + "id": 84, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": true, + "lineColor": "rgb(31, 120, 193)", + "show": true + }, + "tableColumn": "", + "targets": [ + { + "expr": "sum(irate(istio_tcp_received_bytes_total{reporter=\"source\", destination_service=~\"$service\"}[1m]))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "", + "refId": "A" + } + ], + "thresholds": "", + "title": "TCP Received Bytes", + "transparent": false, + "type": "singlestat", + "valueFontSize": "80%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "avg" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "datasource": "Prometheus", + "format": "ops", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "gridPos": { + "h": 4, + "w": 6, + "x": 0, + "y": 7 + }, + "id": 97, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": true, + "lineColor": "rgb(31, 120, 193)", + "show": true + }, + "tableColumn": "", + "targets": [ + { + "expr": "round(sum(irate(istio_requests_total{reporter=\"destination\",destination_service=~\"$service\"}[5m])), 0.001)", + "format": "time_series", + "intervalFactor": 1, + "refId": "A", + "step": 4 + } + ], + "thresholds": "", + "title": "Server Request Volume", + "transparent": false, + "type": "singlestat", + "valueFontSize": "80%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "current" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "rgba(50, 172, 45, 0.97)", + "rgba(237, 129, 40, 0.89)", + "rgba(245, 54, 54, 0.9)" + ], + "datasource": "Prometheus", + "decimals": null, + "format": "percentunit", + "gauge": { + "maxValue": 100, + "minValue": 80, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": false + }, + "gridPos": { + "h": 4, + "w": 6, + "x": 6, + "y": 7 + }, + "id": 98, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": true, + "lineColor": "rgb(31, 120, 193)", + "show": true + }, + "tableColumn": "", + "targets": [ + { + "expr": "sum(irate(istio_requests_total{reporter=\"destination\",destination_service=~\"$service\",response_code!~\"5.*\"}[5m])) / sum(irate(istio_requests_total{reporter=\"destination\",destination_service=~\"$service\"}[5m]))", + "format": "time_series", + "intervalFactor": 1, + "refId": "B" + } + ], + "thresholds": "95, 99, 99.5", + "title": "Server Success Rate (non-5xx responses)", + "transparent": false, + "type": "singlestat", + "valueFontSize": "80%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "avg" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 4, + "w": 6, + "x": 12, + "y": 7 + }, + "id": 99, + "legend": { + "alignAsTable": false, + "avg": false, + "current": false, + "hideEmpty": false, + "hideZero": false, + "max": false, + "min": false, + "rightSide": true, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "(histogram_quantile(0.50, sum(irate(istio_request_duration_milliseconds_bucket{reporter=\"destination\",destination_service=~\"$service\"}[1m])) by (le)) / 1000) or histogram_quantile(0.50, sum(irate(istio_request_duration_seconds_bucket{reporter=\"destination\",destination_service=~\"$service\"}[1m])) by (le))", + "format": "time_series", + "interval": "", + "intervalFactor": 1, + "legendFormat": "P50", + "refId": "A" + }, + { + "expr": "(histogram_quantile(0.90, sum(irate(istio_request_duration_milliseconds_bucket{reporter=\"destination\",destination_service=~\"$service\"}[1m])) by (le)) / 1000) or histogram_quantile(0.90, sum(irate(istio_request_duration_seconds_bucket{reporter=\"destination\",destination_service=~\"$service\"}[1m])) by (le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "P90", + "refId": "B" + }, + { + "expr": "(histogram_quantile(0.99, sum(irate(istio_request_duration_milliseconds_bucket{reporter=\"destination\",destination_service=~\"$service\"}[1m])) by (le)) / 1000) or histogram_quantile(0.99, sum(irate(istio_request_duration_seconds_bucket{reporter=\"destination\",destination_service=~\"$service\"}[1m])) by (le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "P99", + "refId": "C" + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Server Request Duration", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "s", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "#299c46", + "rgba(237, 129, 40, 0.89)", + "#d44a3a" + ], + "datasource": "Prometheus", + "format": "Bps", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "gridPos": { + "h": 4, + "w": 6, + "x": 18, + "y": 7 + }, + "id": 100, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": true, + "lineColor": "rgb(31, 120, 193)", + "show": true + }, + "tableColumn": "", + "targets": [ + { + "expr": "sum(irate(istio_tcp_sent_bytes_total{reporter=\"source\", destination_service=~\"$service\"}[1m])) ", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "", + "refId": "A" + } + ], + "thresholds": "", + "title": "TCP Sent Bytes", + "transparent": false, + "type": "singlestat", + "valueFontSize": "80%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "avg" + }, + { + "content": "
\nCLIENT WORKLOADS\n
", + "gridPos": { + "h": 3, + "w": 24, + "x": 0, + "y": 11 + }, + "id": 45, + "links": [], + "mode": "html", + "title": "", + "transparent": true, + "type": "text" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 0, + "gridPos": { + "h": 6, + "w": 12, + "x": 0, + "y": 14 + }, + "id": 25, + "legend": { + "avg": false, + "current": false, + "hideEmpty": true, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null as zero", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "round(sum(irate(istio_requests_total{connection_security_policy=\"mutual_tls\",destination_service=~\"$service\",reporter=\"source\",source_workload=~\"$srcwl\",source_workload_namespace=~\"$srcns\"}[5m])) by (source_workload, source_workload_namespace, response_code), 0.001)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{ source_workload }}.{{ source_workload_namespace }} : {{ response_code }} (🔐mTLS)", + "refId": "B", + "step": 2 + }, + { + "expr": "round(sum(irate(istio_requests_total{connection_security_policy!=\"mutual_tls\", destination_service=~\"$service\", reporter=\"source\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[5m])) by (source_workload, source_workload_namespace, response_code), 0.001)", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ source_workload }}.{{ source_workload_namespace }} : {{ response_code }}", + "refId": "A", + "step": 2 + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Incoming Requests by Source And Response Code", + "tooltip": { + "shared": false, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [ + "total" + ] + }, + "yaxes": [ + { + "format": "ops", + "label": null, + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 6, + "w": 12, + "x": 12, + "y": 14 + }, + "id": 26, + "legend": { + "avg": false, + "current": false, + "hideEmpty": true, + "hideZero": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(irate(istio_requests_total{reporter=\"source\", connection_security_policy=\"mutual_tls\", destination_service=~\"$service\",response_code!~\"5.*\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[5m])) by (source_workload, source_workload_namespace) / sum(irate(istio_requests_total{reporter=\"source\", connection_security_policy=\"mutual_tls\", destination_service=~\"$service\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[5m])) by (source_workload, source_workload_namespace)", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ source_workload }}.{{ source_workload_namespace }} (🔐mTLS)", + "refId": "A", + "step": 2 + }, + { + "expr": "sum(irate(istio_requests_total{reporter=\"source\", connection_security_policy!=\"mutual_tls\", destination_service=~\"$service\",response_code!~\"5.*\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[5m])) by (source_workload, source_workload_namespace) / sum(irate(istio_requests_total{reporter=\"source\", connection_security_policy!=\"mutual_tls\", destination_service=~\"$service\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[5m])) by (source_workload, source_workload_namespace)", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ source_workload }}.{{ source_workload_namespace }}", + "refId": "B", + "step": 2 + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Incoming Success Rate (non-5xx responses) By Source", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "percentunit", + "label": null, + "logBase": 1, + "max": "1.01", + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "description": "", + "fill": 1, + "gridPos": { + "h": 6, + "w": 8, + "x": 0, + "y": 20 + }, + "id": 27, + "legend": { + "alignAsTable": false, + "avg": false, + "current": false, + "hideEmpty": true, + "hideZero": false, + "max": false, + "min": false, + "rightSide": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "(histogram_quantile(0.50, sum(irate(istio_request_duration_milliseconds_bucket{reporter=\"source\", connection_security_policy=\"mutual_tls\", destination_service=~\"$service\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le)) / 1000) or histogram_quantile(0.50, sum(irate(istio_request_duration_seconds_bucket{reporter=\"source\", connection_security_policy=\"mutual_tls\", destination_service=~\"$service\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{source_workload}}.{{source_workload_namespace}} P50 (🔐mTLS)", + "refId": "D", + "step": 2 + }, + { + "expr": "(histogram_quantile(0.90, sum(irate(istio_request_duration_milliseconds_bucket{reporter=\"source\", connection_security_policy=\"mutual_tls\", destination_service=~\"$service\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le)) / 1000) or histogram_quantile(0.90, sum(irate(istio_request_duration_seconds_bucket{reporter=\"source\", connection_security_policy=\"mutual_tls\", destination_service=~\"$service\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{source_workload}}.{{source_workload_namespace}} P90 (🔐mTLS)", + "refId": "A", + "step": 2 + }, + { + "expr": "(histogram_quantile(0.95, sum(irate(istio_request_duration_milliseconds_bucket{reporter=\"source\", connection_security_policy=\"mutual_tls\", destination_service=~\"$service\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le)) / 1000) or histogram_quantile(0.95, sum(irate(istio_request_duration_seconds_bucket{reporter=\"source\", connection_security_policy=\"mutual_tls\", destination_service=~\"$service\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{source_workload}}.{{source_workload_namespace}} P95 (🔐mTLS)", + "refId": "B", + "step": 2 + }, + { + "expr": "(histogram_quantile(0.99, sum(irate(istio_request_duration_milliseconds_bucket{reporter=\"source\", connection_security_policy=\"mutual_tls\", destination_service=~\"$service\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le)) / 1000) or histogram_quantile(0.99, sum(irate(istio_request_duration_seconds_bucket{reporter=\"source\", connection_security_policy=\"mutual_tls\", destination_service=~\"$service\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{source_workload}}.{{source_workload_namespace}} P99 (🔐mTLS)", + "refId": "C", + "step": 2 + }, + { + "expr": "(histogram_quantile(0.50, sum(irate(istio_request_duration_milliseconds_bucket{reporter=\"source\", connection_security_policy!=\"mutual_tls\", destination_service=~\"$service\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le)) / 1000) or histogram_quantile(0.50, sum(irate(istio_request_duration_seconds_bucket{reporter=\"source\", connection_security_policy!=\"mutual_tls\", destination_service=~\"$service\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{source_workload}}.{{source_workload_namespace}} P50", + "refId": "E", + "step": 2 + }, + { + "expr": "(histogram_quantile(0.90, sum(irate(istio_request_duration_milliseconds_bucket{reporter=\"source\", connection_security_policy!=\"mutual_tls\", destination_service=~\"$service\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le)) / 1000) or histogram_quantile(0.90, sum(irate(istio_request_duration_seconds_bucket{reporter=\"source\", connection_security_policy!=\"mutual_tls\", destination_service=~\"$service\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{source_workload}}.{{source_workload_namespace}} P90", + "refId": "F", + "step": 2 + }, + { + "expr": "(histogram_quantile(0.95, sum(irate(istio_request_duration_milliseconds_bucket{reporter=\"source\", connection_security_policy!=\"mutual_tls\", destination_service=~\"$service\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le)) / 1000) or histogram_quantile(0.95, sum(irate(istio_request_duration_seconds_bucket{reporter=\"source\", connection_security_policy!=\"mutual_tls\", destination_service=~\"$service\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{source_workload}}.{{source_workload_namespace}} P95", + "refId": "G", + "step": 2 + }, + { + "expr": "(histogram_quantile(0.99, sum(irate(istio_request_duration_milliseconds_bucket{reporter=\"source\", connection_security_policy!=\"mutual_tls\", destination_service=~\"$service\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le)) / 1000) or histogram_quantile(0.99, sum(irate(istio_request_duration_seconds_bucket{reporter=\"source\", connection_security_policy!=\"mutual_tls\", destination_service=~\"$service\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{source_workload}}.{{source_workload_namespace}} P99", + "refId": "H", + "step": 2 + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Incoming Request Duration by Source", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "s", + "label": null, + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 6, + "w": 8, + "x": 8, + "y": 20 + }, + "id": 28, + "legend": { + "alignAsTable": false, + "avg": false, + "current": false, + "hideEmpty": true, + "max": false, + "min": false, + "rightSide": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "histogram_quantile(0.50, sum(irate(istio_request_bytes_bucket{reporter=\"source\", connection_security_policy=\"mutual_tls\", destination_service=~\"$service\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{source_workload}}.{{source_workload_namespace}} P50 (🔐mTLS)", + "refId": "D", + "step": 2 + }, + { + "expr": "histogram_quantile(0.90, sum(irate(istio_request_bytes_bucket{reporter=\"source\", connection_security_policy=\"mutual_tls\", destination_service=~\"$service\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{source_workload}}.{{source_workload_namespace}} P90 (🔐mTLS)", + "refId": "A", + "step": 2 + }, + { + "expr": "histogram_quantile(0.95, sum(irate(istio_request_bytes_bucket{reporter=\"source\", connection_security_policy=\"mutual_tls\", destination_service=~\"$service\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{source_workload}}.{{source_workload_namespace}} P95 (🔐mTLS)", + "refId": "B", + "step": 2 + }, + { + "expr": "histogram_quantile(0.99, sum(irate(istio_request_bytes_bucket{reporter=\"source\", connection_security_policy=\"mutual_tls\", destination_service=~\"$service\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{source_workload}}.{{source_workload_namespace}} P99 (🔐mTLS)", + "refId": "C", + "step": 2 + }, + { + "expr": "histogram_quantile(0.50, sum(irate(istio_request_bytes_bucket{reporter=\"source\", connection_security_policy!=\"mutual_tls\", destination_service=~\"$service\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{source_workload}}.{{source_workload_namespace}} P50", + "refId": "E", + "step": 2 + }, + { + "expr": "histogram_quantile(0.90, sum(irate(istio_request_bytes_bucket{reporter=\"source\", connection_security_policy!=\"mutual_tls\", destination_service=~\"$service\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{source_workload}}.{{source_workload_namespace}} P90", + "refId": "F", + "step": 2 + }, + { + "expr": "histogram_quantile(0.95, sum(irate(istio_request_bytes_bucket{reporter=\"source\", connection_security_policy!=\"mutual_tls\", destination_service=~\"$service\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{source_workload}}.{{source_workload_namespace}} P95", + "refId": "G", + "step": 2 + }, + { + "expr": "histogram_quantile(0.99, sum(irate(istio_request_bytes_bucket{reporter=\"source\", connection_security_policy!=\"mutual_tls\", destination_service=~\"$service\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{source_workload}}.{{source_workload_namespace}} P99", + "refId": "H", + "step": 2 + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Incoming Request Size By Source", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "decbytes", + "label": null, + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 6, + "w": 8, + "x": 16, + "y": 20 + }, + "id": 68, + "legend": { + "alignAsTable": false, + "avg": false, + "current": false, + "hideEmpty": true, + "max": false, + "min": false, + "rightSide": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "histogram_quantile(0.50, sum(irate(istio_response_bytes_bucket{reporter=\"source\", connection_security_policy=\"mutual_tls\", destination_service=~\"$service\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{source_workload}}.{{source_workload_namespace}} P50 (🔐mTLS)", + "refId": "D", + "step": 2 + }, + { + "expr": "histogram_quantile(0.90, sum(irate(istio_response_bytes_bucket{reporter=\"source\", connection_security_policy=\"mutual_tls\", destination_service=~\"$service\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{source_workload}}.{{source_workload_namespace}} P90 (🔐mTLS)", + "refId": "A", + "step": 2 + }, + { + "expr": "histogram_quantile(0.95, sum(irate(istio_response_bytes_bucket{reporter=\"source\", connection_security_policy=\"mutual_tls\", destination_service=~\"$service\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{source_workload}}.{{source_workload_namespace}} P95 (🔐mTLS)", + "refId": "B", + "step": 2 + }, + { + "expr": "histogram_quantile(0.99, sum(irate(istio_response_bytes_bucket{reporter=\"source\", connection_security_policy=\"mutual_tls\", destination_service=~\"$service\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{source_workload}}.{{source_workload_namespace}} P99 (🔐mTLS)", + "refId": "C", + "step": 2 + }, + { + "expr": "histogram_quantile(0.50, sum(irate(istio_response_bytes_bucket{reporter=\"source\", connection_security_policy!=\"mutual_tls\", destination_service=~\"$service\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{source_workload}}.{{source_workload_namespace}} P50", + "refId": "E", + "step": 2 + }, + { + "expr": "histogram_quantile(0.90, sum(irate(istio_response_bytes_bucket{reporter=\"source\", connection_security_policy!=\"mutual_tls\", destination_service=~\"$service\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{source_workload}}.{{source_workload_namespace}} P90", + "refId": "F", + "step": 2 + }, + { + "expr": "histogram_quantile(0.95, sum(irate(istio_response_bytes_bucket{reporter=\"source\", connection_security_policy!=\"mutual_tls\", destination_service=~\"$service\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{source_workload}}.{{source_workload_namespace}} P95", + "refId": "G", + "step": 2 + }, + { + "expr": "histogram_quantile(0.99, sum(irate(istio_response_bytes_bucket{reporter=\"source\", connection_security_policy!=\"mutual_tls\", destination_service=~\"$service\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{source_workload}}.{{source_workload_namespace}} P99", + "refId": "H", + "step": 2 + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Response Size By Source", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "decbytes", + "label": null, + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 6, + "w": 12, + "x": 0, + "y": 26 + }, + "id": 80, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "round(sum(irate(istio_tcp_received_bytes_total{reporter=\"source\", connection_security_policy=\"mutual_tls\", destination_service=~\"$service\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace), 0.001)", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ source_workload }}.{{ source_workload_namespace}} (🔐mTLS)", + "refId": "A", + "step": 2 + }, + { + "expr": "round(sum(irate(istio_tcp_received_bytes_total{reporter=\"source\", connection_security_policy!=\"mutual_tls\", destination_service=~\"$service\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace), 0.001)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{ source_workload }}.{{ source_workload_namespace}}", + "refId": "B", + "step": 2 + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Bytes Received from Incoming TCP Connection", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "Bps", + "label": null, + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 6, + "w": 12, + "x": 12, + "y": 26 + }, + "id": 82, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "round(sum(irate(istio_tcp_sent_bytes_total{connection_security_policy=\"mutual_tls\", reporter=\"source\", destination_service=~\"$service\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace), 0.001)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{ source_workload }}.{{ source_workload_namespace}} (🔐mTLS)", + "refId": "A", + "step": 2 + }, + { + "expr": "round(sum(irate(istio_tcp_sent_bytes_total{connection_security_policy!=\"mutual_tls\", reporter=\"source\", destination_service=~\"$service\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace), 0.001)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{ source_workload }}.{{ source_workload_namespace}}", + "refId": "B", + "step": 2 + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Bytes Sent to Incoming TCP Connection", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "Bps", + "label": null, + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "content": "
\nSERVICE WORKLOADS\n
", + "gridPos": { + "h": 3, + "w": 24, + "x": 0, + "y": 32 + }, + "id": 69, + "links": [], + "mode": "html", + "title": "", + "transparent": true, + "type": "text" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 0, + "gridPos": { + "h": 6, + "w": 12, + "x": 0, + "y": 35 + }, + "id": 90, + "legend": { + "avg": false, + "current": false, + "hideEmpty": true, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null as zero", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "round(sum(irate(istio_requests_total{connection_security_policy=\"mutual_tls\",destination_service=~\"$service\",reporter=\"destination\",destination_workload=~\"$dstwl\",destination_workload_namespace=~\"$dstns\"}[5m])) by (destination_workload, destination_workload_namespace, response_code), 0.001)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{ destination_workload }}.{{ destination_workload_namespace }} : {{ response_code }} (🔐mTLS)", + "refId": "B", + "step": 2 + }, + { + "expr": "round(sum(irate(istio_requests_total{connection_security_policy!=\"mutual_tls\", destination_service=~\"$service\", reporter=\"destination\", destination_workload=~\"$dstwl\", destination_workload_namespace=~\"$dstns\"}[5m])) by (destination_workload, destination_workload_namespace, response_code), 0.001)", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_workload }}.{{ destination_workload_namespace }} : {{ response_code }}", + "refId": "A", + "step": 2 + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Incoming Requests by Destination And Response Code", + "tooltip": { + "shared": false, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [ + "total" + ] + }, + "yaxes": [ + { + "format": "ops", + "label": null, + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 6, + "w": 12, + "x": 12, + "y": 35 + }, + "id": 91, + "legend": { + "avg": false, + "current": false, + "hideEmpty": true, + "hideZero": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(irate(istio_requests_total{reporter=\"destination\", connection_security_policy=\"mutual_tls\", destination_service=~\"$service\",response_code!~\"5.*\", destination_workload=~\"$dstwl\", destination_workload_namespace=~\"$dstns\"}[5m])) by (destination_workload, destination_workload_namespace) / sum(irate(istio_requests_total{reporter=\"destination\", connection_security_policy=\"mutual_tls\", destination_service=~\"$service\", destination_workload=~\"$dstwl\", destination_workload_namespace=~\"$dstns\"}[5m])) by (destination_workload, destination_workload_namespace)", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_workload }}.{{ destination_workload_namespace }} (🔐mTLS)", + "refId": "A", + "step": 2 + }, + { + "expr": "sum(irate(istio_requests_total{reporter=\"destination\", connection_security_policy!=\"mutual_tls\", destination_service=~\"$service\",response_code!~\"5.*\", destination_workload=~\"$dstwl\", destination_workload_namespace=~\"$dstns\"}[5m])) by (destination_workload, destination_workload_namespace) / sum(irate(istio_requests_total{reporter=\"destination\", connection_security_policy!=\"mutual_tls\", destination_service=~\"$service\", destination_workload=~\"$dstwl\", destination_workload_namespace=~\"$dstns\"}[5m])) by (destination_workload, destination_workload_namespace)", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_workload }}.{{ destination_workload_namespace }}", + "refId": "B", + "step": 2 + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Incoming Success Rate (non-5xx responses) By Source", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "percentunit", + "label": null, + "logBase": 1, + "max": "1.01", + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "description": "", + "fill": 1, + "gridPos": { + "h": 6, + "w": 8, + "x": 0, + "y": 41 + }, + "id": 94, + "legend": { + "alignAsTable": false, + "avg": false, + "current": false, + "hideEmpty": true, + "hideZero": false, + "max": false, + "min": false, + "rightSide": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "(histogram_quantile(0.50, sum(irate(istio_request_duration_milliseconds_bucket{reporter=\"destination\", connection_security_policy=\"mutual_tls\", destination_service=~\"$service\", destination_workload=~\"$dstwl\", destination_workload_namespace=~\"$dstns\"}[1m])) by (destination_workload, destination_workload_namespace, le)) / 1000) or histogram_quantile(0.50, sum(irate(istio_request_duration_seconds_bucket{reporter=\"destination\", connection_security_policy=\"mutual_tls\", destination_service=~\"$service\", destination_workload=~\"$dstwl\", destination_workload_namespace=~\"$dstns\"}[1m])) by (destination_workload, destination_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_workload }}.{{ destination_workload_namespace }} P50 (🔐mTLS)", + "refId": "D", + "step": 2 + }, + { + "expr": "(histogram_quantile(0.90, sum(irate(istio_request_duration_milliseconds_bucket{reporter=\"destination\", connection_security_policy=\"mutual_tls\", destination_service=~\"$service\", destination_workload=~\"$dstwl\", destination_workload_namespace=~\"$dstns\"}[1m])) by (destination_workload, destination_workload_namespace, le)) / 1000) or histogram_quantile(0.90, sum(irate(istio_request_duration_seconds_bucket{reporter=\"destination\", connection_security_policy=\"mutual_tls\", destination_service=~\"$service\", destination_workload=~\"$dstwl\", destination_workload_namespace=~\"$dstns\"}[1m])) by (destination_workload, destination_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_workload }}.{{ destination_workload_namespace }} P90 (🔐mTLS)", + "refId": "A", + "step": 2 + }, + { + "expr": "(histogram_quantile(0.95, sum(irate(istio_request_duration_milliseconds_bucket{reporter=\"destination\", connection_security_policy=\"mutual_tls\", destination_service=~\"$service\", destination_workload=~\"$dstwl\", destination_workload_namespace=~\"$dstns\"}[1m])) by (destination_workload, destination_workload_namespace, le)) / 1000) or histogram_quantile(0.95, sum(irate(istio_request_duration_seconds_bucket{reporter=\"destination\", connection_security_policy=\"mutual_tls\", destination_service=~\"$service\", destination_workload=~\"$dstwl\", destination_workload_namespace=~\"$dstns\"}[1m])) by (destination_workload, destination_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_workload }}.{{ destination_workload_namespace }} P95 (🔐mTLS)", + "refId": "B", + "step": 2 + }, + { + "expr": "(histogram_quantile(0.99, sum(irate(istio_request_duration_milliseconds_bucket{reporter=\"destination\", connection_security_policy=\"mutual_tls\", destination_service=~\"$service\", destination_workload=~\"$dstwl\", destination_workload_namespace=~\"$dstns\"}[1m])) by (destination_workload, destination_workload_namespace, le)) / 1000) or histogram_quantile(0.99, sum(irate(istio_request_duration_seconds_bucket{reporter=\"destination\", connection_security_policy=\"mutual_tls\", destination_service=~\"$service\", destination_workload=~\"$dstwl\", destination_workload_namespace=~\"$dstns\"}[1m])) by (destination_workload, destination_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_workload }}.{{ destination_workload_namespace }} P99 (🔐mTLS)", + "refId": "C", + "step": 2 + }, + { + "expr": "(histogram_quantile(0.50, sum(irate(istio_request_duration_milliseconds_bucket{reporter=\"destination\", connection_security_policy!=\"mutual_tls\", destination_service=~\"$service\", destination_workload=~\"$dstwl\", destination_workload_namespace=~\"$dstns\"}[1m])) by (destination_workload, destination_workload_namespace, le)) / 1000) or histogram_quantile(0.50, sum(irate(istio_request_duration_seconds_bucket{reporter=\"destination\", connection_security_policy!=\"mutual_tls\", destination_service=~\"$service\", destination_workload=~\"$dstwl\", destination_workload_namespace=~\"$dstns\"}[1m])) by (destination_workload, destination_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_workload }}.{{ destination_workload_namespace }} P50", + "refId": "E", + "step": 2 + }, + { + "expr": "(histogram_quantile(0.90, sum(irate(istio_request_duration_milliseconds_bucket{reporter=\"destination\", connection_security_policy!=\"mutual_tls\", destination_service=~\"$service\", destination_workload=~\"$dstwl\", destination_workload_namespace=~\"$dstns\"}[1m])) by (destination_workload, destination_workload_namespace, le)) / 1000) or histogram_quantile(0.90, sum(irate(istio_request_duration_seconds_bucket{reporter=\"destination\", connection_security_policy!=\"mutual_tls\", destination_service=~\"$service\", destination_workload=~\"$dstwl\", destination_workload_namespace=~\"$dstns\"}[1m])) by (destination_workload, destination_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_workload }}.{{ destination_workload_namespace }} P90", + "refId": "F", + "step": 2 + }, + { + "expr": "(histogram_quantile(0.95, sum(irate(istio_request_duration_milliseconds_bucket{reporter=\"destination\", connection_security_policy!=\"mutual_tls\", destination_service=~\"$service\", destination_workload=~\"$dstwl\", destination_workload_namespace=~\"$dstns\"}[1m])) by (destination_workload, destination_workload_namespace, le)) / 1000) or histogram_quantile(0.95, sum(irate(istio_request_duration_seconds_bucket{reporter=\"destination\", connection_security_policy!=\"mutual_tls\", destination_service=~\"$service\", destination_workload=~\"$dstwl\", destination_workload_namespace=~\"$dstns\"}[1m])) by (destination_workload, destination_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_workload }}.{{ destination_workload_namespace }} P95", + "refId": "G", + "step": 2 + }, + { + "expr": "(histogram_quantile(0.99, sum(irate(istio_request_duration_milliseconds_bucket{reporter=\"destination\", connection_security_policy!=\"mutual_tls\", destination_service=~\"$service\", destination_workload=~\"$dstwl\", destination_workload_namespace=~\"$dstns\"}[1m])) by (destination_workload, destination_workload_namespace, le)) / 1000) or histogram_quantile(0.99, sum(irate(istio_request_duration_seconds_bucket{reporter=\"destination\", connection_security_policy!=\"mutual_tls\", destination_service=~\"$service\", destination_workload=~\"$dstwl\", destination_workload_namespace=~\"$dstns\"}[1m])) by (destination_workload, destination_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_workload }}.{{ destination_workload_namespace }} P99", + "refId": "H", + "step": 2 + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Incoming Request Duration by Source", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "s", + "label": null, + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 6, + "w": 8, + "x": 8, + "y": 41 + }, + "id": 95, + "legend": { + "alignAsTable": false, + "avg": false, + "current": false, + "hideEmpty": true, + "max": false, + "min": false, + "rightSide": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "histogram_quantile(0.50, sum(irate(istio_request_bytes_bucket{reporter=\"destination\", connection_security_policy=\"mutual_tls\", destination_service=~\"$service\", destination_workload=~\"$dstwl\", destination_workload_namespace=~\"$dstns\"}[1m])) by (destination_workload, destination_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_workload }}.{{ destination_workload_namespace }} P50 (🔐mTLS)", + "refId": "D", + "step": 2 + }, + { + "expr": "histogram_quantile(0.90, sum(irate(istio_request_bytes_bucket{reporter=\"destination\", connection_security_policy=\"mutual_tls\", destination_service=~\"$service\", destination_workload=~\"$dstwl\", destination_workload_namespace=~\"$dstns\"}[1m])) by (destination_workload, destination_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_workload }}.{{ destination_workload_namespace }} P90 (🔐mTLS)", + "refId": "A", + "step": 2 + }, + { + "expr": "histogram_quantile(0.95, sum(irate(istio_request_bytes_bucket{reporter=\"destination\", connection_security_policy=\"mutual_tls\", destination_service=~\"$service\", destination_workload=~\"$dstwl\", destination_workload_namespace=~\"$dstns\"}[1m])) by (destination_workload, destination_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_workload }}.{{ destination_workload_namespace }} P95 (🔐mTLS)", + "refId": "B", + "step": 2 + }, + { + "expr": "histogram_quantile(0.99, sum(irate(istio_request_bytes_bucket{reporter=\"destination\", connection_security_policy=\"mutual_tls\", destination_service=~\"$service\", destination_workload=~\"$dstwl\", destination_workload_namespace=~\"$dstns\"}[1m])) by (destination_workload, destination_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_workload }}.{{ destination_workload_namespace }} P99 (🔐mTLS)", + "refId": "C", + "step": 2 + }, + { + "expr": "histogram_quantile(0.50, sum(irate(istio_request_bytes_bucket{reporter=\"destination\", connection_security_policy!=\"mutual_tls\", destination_service=~\"$service\", destination_workload=~\"$dstwl\", destination_workload_namespace=~\"$dstns\"}[1m])) by (destination_workload, destination_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_workload }}.{{ destination_workload_namespace }} P50", + "refId": "E", + "step": 2 + }, + { + "expr": "histogram_quantile(0.90, sum(irate(istio_request_bytes_bucket{reporter=\"destination\", connection_security_policy!=\"mutual_tls\", destination_service=~\"$service\", destination_workload=~\"$dstwl\", destination_workload_namespace=~\"$dstns\"}[1m])) by (destination_workload, destination_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_workload }}.{{ destination_workload_namespace }} P90", + "refId": "F", + "step": 2 + }, + { + "expr": "histogram_quantile(0.95, sum(irate(istio_request_bytes_bucket{reporter=\"destination\", connection_security_policy!=\"mutual_tls\", destination_service=~\"$service\", destination_workload=~\"$dstwl\", destination_workload_namespace=~\"$dstns\"}[1m])) by (destination_workload, destination_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_workload }}.{{ destination_workload_namespace }} P95", + "refId": "G", + "step": 2 + }, + { + "expr": "histogram_quantile(0.99, sum(irate(istio_request_bytes_bucket{reporter=\"destination\", connection_security_policy!=\"mutual_tls\", destination_service=~\"$service\", destination_workload=~\"$dstwl\", destination_workload_namespace=~\"$dstns\"}[1m])) by (destination_workload, destination_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_workload }}.{{ destination_workload_namespace }} P99", + "refId": "H", + "step": 2 + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Incoming Request Size By Source", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "decbytes", + "label": null, + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 6, + "w": 8, + "x": 16, + "y": 41 + }, + "id": 96, + "legend": { + "alignAsTable": false, + "avg": false, + "current": false, + "hideEmpty": true, + "max": false, + "min": false, + "rightSide": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "histogram_quantile(0.50, sum(irate(istio_response_bytes_bucket{reporter=\"destination\", connection_security_policy=\"mutual_tls\", destination_service=~\"$service\", destination_workload=~\"$dstwl\", destination_workload_namespace=~\"$dstns\"}[1m])) by (destination_workload, destination_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_workload }}.{{ destination_workload_namespace }} P50 (🔐mTLS)", + "refId": "D", + "step": 2 + }, + { + "expr": "histogram_quantile(0.90, sum(irate(istio_response_bytes_bucket{reporter=\"destination\", connection_security_policy=\"mutual_tls\", destination_service=~\"$service\", destination_workload=~\"$dstwl\", destination_workload_namespace=~\"$dstns\"}[1m])) by (destination_workload, destination_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_workload }}.{{ destination_workload_namespace }} P90 (🔐mTLS)", + "refId": "A", + "step": 2 + }, + { + "expr": "histogram_quantile(0.95, sum(irate(istio_response_bytes_bucket{reporter=\"destination\", connection_security_policy=\"mutual_tls\", destination_service=~\"$service\", destination_workload=~\"$dstwl\", destination_workload_namespace=~\"$dstns\"}[1m])) by (destination_workload, destination_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_workload }}.{{ destination_workload_namespace }} P95 (🔐mTLS)", + "refId": "B", + "step": 2 + }, + { + "expr": "histogram_quantile(0.99, sum(irate(istio_response_bytes_bucket{reporter=\"destination\", connection_security_policy=\"mutual_tls\", destination_service=~\"$service\", destination_workload=~\"$dstwl\", destination_workload_namespace=~\"$dstns\"}[1m])) by (destination_workload, destination_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_workload }}.{{ destination_workload_namespace }} P99 (🔐mTLS)", + "refId": "C", + "step": 2 + }, + { + "expr": "histogram_quantile(0.50, sum(irate(istio_response_bytes_bucket{reporter=\"destination\", connection_security_policy!=\"mutual_tls\", destination_service=~\"$service\", destination_workload=~\"$dstwl\", destination_workload_namespace=~\"$dstns\"}[1m])) by (destination_workload, destination_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_workload }}.{{ destination_workload_namespace }} P50", + "refId": "E", + "step": 2 + }, + { + "expr": "histogram_quantile(0.90, sum(irate(istio_response_bytes_bucket{reporter=\"destination\", connection_security_policy!=\"mutual_tls\", destination_service=~\"$service\", destination_workload=~\"$dstwl\", destination_workload_namespace=~\"$dstns\"}[1m])) by (destination_workload, destination_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_workload }}.{{ destination_workload_namespace }} P90", + "refId": "F", + "step": 2 + }, + { + "expr": "histogram_quantile(0.95, sum(irate(istio_response_bytes_bucket{reporter=\"destination\", connection_security_policy!=\"mutual_tls\", destination_service=~\"$service\", destination_workload=~\"$dstwl\", destination_workload_namespace=~\"$dstns\"}[1m])) by (destination_workload, destination_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_workload }}.{{ destination_workload_namespace }} P95", + "refId": "G", + "step": 2 + }, + { + "expr": "histogram_quantile(0.99, sum(irate(istio_response_bytes_bucket{reporter=\"destination\", connection_security_policy!=\"mutual_tls\", destination_service=~\"$service\", destination_workload=~\"$dstwl\", destination_workload_namespace=~\"$dstns\"}[1m])) by (destination_workload, destination_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_workload }}.{{ destination_workload_namespace }} P99", + "refId": "H", + "step": 2 + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Response Size By Source", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "decbytes", + "label": null, + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 6, + "w": 12, + "x": 0, + "y": 47 + }, + "id": 92, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "round(sum(irate(istio_tcp_received_bytes_total{reporter=\"source\", connection_security_policy=\"mutual_tls\", destination_service=~\"$service\", destination_workload=~\"$dstwl\", destination_workload_namespace=~\"$dstns\"}[1m])) by (destination_workload, destination_workload_namespace), 0.001)", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_workload }}.{{ destination_workload_namespace}} (🔐mTLS)", + "refId": "A", + "step": 2 + }, + { + "expr": "round(sum(irate(istio_tcp_received_bytes_total{reporter=\"source\", connection_security_policy!=\"mutual_tls\", destination_service=~\"$service\", destination_workload=~\"$dstwl\", destination_workload_namespace=~\"$dstns\"}[1m])) by (destination_workload, destination_workload_namespace), 0.001)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{ destination_workload }}.{{ destination_workload_namespace}}", + "refId": "B", + "step": 2 + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Bytes Received from Incoming TCP Connection", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "Bps", + "label": null, + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 6, + "w": 12, + "x": 12, + "y": 47 + }, + "id": 93, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "round(sum(irate(istio_tcp_sent_bytes_total{connection_security_policy=\"mutual_tls\", reporter=\"source\", destination_service=~\"$service\", destination_workload=~\"$dstwl\", destination_workload_namespace=~\"$dstns\"}[1m])) by (destination_workload, destination_workload_namespace), 0.001)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{ destination_workload }}.{{destination_workload_namespace }} (🔐mTLS)", + "refId": "A", + "step": 2 + }, + { + "expr": "round(sum(irate(istio_tcp_sent_bytes_total{connection_security_policy!=\"mutual_tls\", reporter=\"source\", destination_service=~\"$service\", destination_workload=~\"$dstwl\", destination_workload_namespace=~\"$dstns\"}[1m])) by (destination_workload, destination_workload_namespace), 0.001)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{ destination_workload }}.{{destination_workload_namespace }}", + "refId": "B", + "step": 2 + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Bytes Sent to Incoming TCP Connection", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "Bps", + "label": null, + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + } + ], + "refresh": "10s", + "schemaVersion": 16, + "style": "dark", + "tags": [], + "templating": { + "list": [ + { + "allValue": null, + "datasource": "Prometheus", + "hide": 0, + "includeAll": false, + "label": "Service", + "multi": false, + "name": "service", + "options": [], + "query": "label_values(destination_service)", + "refresh": 1, + "regex": "", + "sort": 0, + "tagValuesQuery": "", + "tags": [], + "tagsQuery": "", + "type": "query", + "useTags": false + }, + { + "allValue": null, + "current": { + "text": "All", + "value": "$__all" + }, + "datasource": "Prometheus", + "hide": 0, + "includeAll": true, + "label": "Client Workload Namespace", + "multi": true, + "name": "srcns", + "options": [], + "query": "query_result( sum(istio_requests_total{reporter=\"destination\", destination_service=\"$service\"}) by (source_workload_namespace) or sum(istio_tcp_sent_bytes_total{reporter=\"destination\", destination_service=~\"$service\"}) by (source_workload_namespace))", + "refresh": 1, + "regex": "/.*namespace=\"([^\"]*).*/", + "sort": 2, + "tagValuesQuery": "", + "tags": [], + "tagsQuery": "", + "type": "query", + "useTags": false + }, + { + "allValue": null, + "current": { + "text": "All", + "value": "$__all" + }, + "datasource": "Prometheus", + "hide": 0, + "includeAll": true, + "label": "Client Workload", + "multi": true, + "name": "srcwl", + "options": [], + "query": "query_result( sum(istio_requests_total{reporter=\"destination\", destination_service=~\"$service\", source_workload_namespace=~\"$srcns\"}) by (source_workload) or sum(istio_tcp_sent_bytes_total{reporter=\"destination\", destination_service=~\"$service\", source_workload_namespace=~\"$srcns\"}) by (source_workload))", + "refresh": 1, + "regex": "/.*workload=\"([^\"]*).*/", + "sort": 3, + "tagValuesQuery": "", + "tags": [], + "tagsQuery": "", + "type": "query", + "useTags": false + }, + { + "allValue": null, + "current": { + "text": "All", + "value": "$__all" + }, + "datasource": "Prometheus", + "hide": 0, + "includeAll": true, + "label": "Service Workload Namespace", + "multi": true, + "name": "dstns", + "options": [], + "query": "query_result( sum(istio_requests_total{reporter=\"destination\", destination_service=\"$service\"}) by (destination_workload_namespace) or sum(istio_tcp_sent_bytes_total{reporter=\"destination\", destination_service=~\"$service\"}) by (destination_workload_namespace))", + "refresh": 1, + "regex": "/.*namespace=\"([^\"]*).*/", + "sort": 2, + "tagValuesQuery": "", + "tags": [], + "tagsQuery": "", + "type": "query", + "useTags": false + }, + { + "allValue": null, + "current": { + "text": "All", + "value": "$__all" + }, + "datasource": "Prometheus", + "hide": 0, + "includeAll": true, + "label": "Service Workload", + "multi": true, + "name": "dstwl", + "options": [], + "query": "query_result( sum(istio_requests_total{reporter=\"destination\", destination_service=~\"$service\", destination_workload_namespace=~\"$dstns\"}) by (destination_workload) or sum(istio_tcp_sent_bytes_total{reporter=\"destination\", destination_service=~\"$service\", destination_workload_namespace=~\"$dstns\"}) by (destination_workload))", + "refresh": 1, + "regex": "/.*workload=\"([^\"]*).*/", + "sort": 3, + "tagValuesQuery": "", + "tags": [], + "tagsQuery": "", + "type": "query", + "useTags": false + } + ] + }, + "time": { + "from": "now-5m", + "to": "now" + }, + "timepicker": { + "refresh_intervals": [ + "5s", + "10s", + "30s", + "1m", + "5m", + "15m", + "30m", + "1h", + "2h", + "1d" + ], + "time_options": [ + "5m", + "15m", + "1h", + "6h", + "12h", + "24h", + "2d", + "7d", + "30d" + ] + }, + "timezone": "", + "title": "Istio Service Dashboard", + "uid": "LJ_uJAvmk", + "version": 1 +} diff --git a/istio-1.3.5/install/kubernetes/operator/charts/istio-telemetry/grafana/dashboards/istio-workload-dashboard.json b/istio-1.3.5/install/kubernetes/operator/charts/istio-telemetry/grafana/dashboards/istio-workload-dashboard.json new file mode 100644 index 0000000..62ad1b5 --- /dev/null +++ b/istio-1.3.5/install/kubernetes/operator/charts/istio-telemetry/grafana/dashboards/istio-workload-dashboard.json @@ -0,0 +1,2303 @@ +{ + "__inputs": [ + { + "name": "DS_PROMETHEUS", + "label": "Prometheus", + "description": "", + "type": "datasource", + "pluginId": "prometheus", + "pluginName": "Prometheus" + } + ], + "__requires": [ + { + "type": "grafana", + "id": "grafana", + "name": "Grafana", + "version": "5.0.4" + }, + { + "type": "panel", + "id": "graph", + "name": "Graph", + "version": "5.0.0" + }, + { + "type": "datasource", + "id": "prometheus", + "name": "Prometheus", + "version": "5.0.0" + }, + { + "type": "panel", + "id": "singlestat", + "name": "Singlestat", + "version": "5.0.0" + }, + { + "type": "panel", + "id": "text", + "name": "Text", + "version": "5.0.0" + } + ], + "annotations": { + "list": [ + { + "builtIn": 1, + "datasource": "-- Grafana --", + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations & Alerts", + "type": "dashboard" + } + ] + }, + "editable": false, + "gnetId": null, + "graphTooltip": 0, + "id": null, + "iteration": 1531345461465, + "links": [], + "panels": [ + { + "content": "
\nWORKLOAD: $workload.$namespace\n
", + "gridPos": { + "h": 3, + "w": 24, + "x": 0, + "y": 0 + }, + "id": 89, + "links": [], + "mode": "html", + "title": "", + "transparent": true, + "type": "text" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "datasource": "Prometheus", + "format": "ops", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "gridPos": { + "h": 4, + "w": 8, + "x": 0, + "y": 3 + }, + "id": 12, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": true, + "lineColor": "rgb(31, 120, 193)", + "show": true + }, + "tableColumn": "", + "targets": [ + { + "expr": "round(sum(irate(istio_requests_total{reporter=\"destination\",destination_workload_namespace=~\"$namespace\",destination_workload=~\"$workload\"}[5m])), 0.001)", + "format": "time_series", + "intervalFactor": 1, + "refId": "A", + "step": 4 + } + ], + "thresholds": "", + "title": "Incoming Request Volume", + "transparent": false, + "type": "singlestat", + "valueFontSize": "80%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "current" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "rgba(50, 172, 45, 0.97)", + "rgba(237, 129, 40, 0.89)", + "rgba(245, 54, 54, 0.9)" + ], + "datasource": "Prometheus", + "decimals": null, + "format": "percentunit", + "gauge": { + "maxValue": 100, + "minValue": 80, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": false + }, + "gridPos": { + "h": 4, + "w": 8, + "x": 8, + "y": 3 + }, + "id": 14, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": true, + "lineColor": "rgb(31, 120, 193)", + "show": true + }, + "tableColumn": "", + "targets": [ + { + "expr": "sum(irate(istio_requests_total{reporter=\"destination\",destination_workload_namespace=~\"$namespace\",destination_workload=~\"$workload\",response_code!~\"5.*\"}[5m])) / sum(irate(istio_requests_total{reporter=\"destination\",destination_workload_namespace=~\"$namespace\",destination_workload=~\"$workload\"}[5m]))", + "format": "time_series", + "intervalFactor": 1, + "refId": "B" + } + ], + "thresholds": "95, 99, 99.5", + "title": "Incoming Success Rate (non-5xx responses)", + "transparent": false, + "type": "singlestat", + "valueFontSize": "80%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "avg" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 4, + "w": 8, + "x": 16, + "y": 3 + }, + "id": 87, + "legend": { + "alignAsTable": false, + "avg": false, + "current": false, + "hideEmpty": false, + "hideZero": false, + "max": false, + "min": false, + "rightSide": true, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "(histogram_quantile(0.50, sum(irate(istio_request_duration_milliseconds_bucket{reporter=\"destination\",destination_workload=~\"$workload\", destination_workload_namespace=~\"$namespace\"}[1m])) by (le)) / 1000) or histogram_quantile(0.50, sum(irate(istio_request_duration_seconds_bucket{reporter=\"destination\",destination_workload=~\"$workload\", destination_workload_namespace=~\"$namespace\"}[1m])) by (le))", + "format": "time_series", + "interval": "", + "intervalFactor": 1, + "legendFormat": "P50", + "refId": "A" + }, + { + "expr": "(histogram_quantile(0.50, sum(irate(istio_request_duration_milliseconds_bucket{reporter=\"destination\",destination_workload=~\"$workload\", destination_workload_namespace=~\"$namespace\"}[1m])) by (le)) / 1000) or histogram_quantile(0.90, sum(irate(istio_request_duration_seconds_bucket{reporter=\"destination\",destination_workload=~\"$workload\", destination_workload_namespace=~\"$namespace\"}[1m])) by (le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "P90", + "refId": "B" + }, + { + "expr": "(histogram_quantile(0.50, sum(irate(istio_request_duration_milliseconds_bucket{reporter=\"destination\",destination_workload=~\"$workload\", destination_workload_namespace=~\"$namespace\"}[1m])) by (le)) / 1000) or histogram_quantile(0.99, sum(irate(istio_request_duration_seconds_bucket{reporter=\"destination\",destination_workload=~\"$workload\", destination_workload_namespace=~\"$namespace\"}[1m])) by (le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "P99", + "refId": "C" + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Request Duration", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "s", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ] + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "#299c46", + "rgba(237, 129, 40, 0.89)", + "#d44a3a" + ], + "datasource": "Prometheus", + "format": "Bps", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "gridPos": { + "h": 4, + "w": 12, + "x": 0, + "y": 7 + }, + "id": 84, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": true, + "lineColor": "rgb(31, 120, 193)", + "show": true + }, + "tableColumn": "", + "targets": [ + { + "expr": "sum(irate(istio_tcp_sent_bytes_total{reporter=\"destination\", destination_workload_namespace=~\"$namespace\", destination_workload=~\"$workload\"}[1m])) + sum(irate(istio_tcp_received_bytes_total{reporter=\"destination\", destination_workload_namespace=~\"$namespace\", destination_workload=~\"$workload\"}[1m]))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "", + "refId": "A" + } + ], + "thresholds": "", + "title": "TCP Server Traffic", + "transparent": false, + "type": "singlestat", + "valueFontSize": "80%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "avg" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "#299c46", + "rgba(237, 129, 40, 0.89)", + "#d44a3a" + ], + "datasource": "Prometheus", + "format": "Bps", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "gridPos": { + "h": 4, + "w": 12, + "x": 12, + "y": 7 + }, + "id": 85, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": true, + "lineColor": "rgb(31, 120, 193)", + "show": true + }, + "tableColumn": "", + "targets": [ + { + "expr": "sum(irate(istio_tcp_sent_bytes_total{reporter=\"source\", source_workload_namespace=~\"$namespace\", source_workload=~\"$workload\"}[1m])) + sum(irate(istio_tcp_received_bytes_total{reporter=\"source\", source_workload_namespace=~\"$namespace\", source_workload=~\"$workload\"}[1m]))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "", + "refId": "A" + } + ], + "thresholds": "", + "title": "TCP Client Traffic", + "transparent": false, + "type": "singlestat", + "valueFontSize": "80%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "avg" + }, + { + "content": "
\nINBOUND WORKLOADS\n
", + "gridPos": { + "h": 3, + "w": 24, + "x": 0, + "y": 11 + }, + "id": 45, + "links": [], + "mode": "html", + "title": "", + "transparent": true, + "type": "text" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 0, + "gridPos": { + "h": 6, + "w": 12, + "x": 0, + "y": 14 + }, + "id": 25, + "legend": { + "avg": false, + "current": false, + "hideEmpty": true, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null as zero", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "round(sum(irate(istio_requests_total{connection_security_policy=\"mutual_tls\", destination_workload_namespace=~\"$namespace\", destination_workload=~\"$workload\", reporter=\"destination\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[5m])) by (source_workload, source_workload_namespace, response_code), 0.001)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{ source_workload }}.{{ source_workload_namespace }} : {{ response_code }} (🔐mTLS)", + "refId": "B", + "step": 2 + }, + { + "expr": "round(sum(irate(istio_requests_total{connection_security_policy!=\"mutual_tls\", destination_workload_namespace=~\"$namespace\", destination_workload=~\"$workload\", reporter=\"destination\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[5m])) by (source_workload, source_workload_namespace, response_code), 0.001)", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ source_workload }}.{{ source_workload_namespace }} : {{ response_code }}", + "refId": "A", + "step": 2 + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Incoming Requests by Source And Response Code", + "tooltip": { + "shared": false, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [ + "total" + ] + }, + "yaxes": [ + { + "format": "ops", + "label": null, + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ] + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 6, + "w": 12, + "x": 12, + "y": 14 + }, + "id": 26, + "legend": { + "avg": false, + "current": false, + "hideEmpty": true, + "hideZero": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(irate(istio_requests_total{reporter=\"destination\", connection_security_policy=\"mutual_tls\", destination_workload_namespace=~\"$namespace\", destination_workload=~\"$workload\",response_code!~\"5.*\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[5m])) by (source_workload, source_workload_namespace) / sum(irate(istio_requests_total{reporter=\"destination\", connection_security_policy=\"mutual_tls\", destination_workload_namespace=~\"$namespace\", destination_workload=~\"$workload\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[5m])) by (source_workload, source_workload_namespace)", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ source_workload }}.{{ source_workload_namespace }} (🔐mTLS)", + "refId": "A", + "step": 2 + }, + { + "expr": "sum(irate(istio_requests_total{reporter=\"destination\", connection_security_policy!=\"mutual_tls\", destination_workload_namespace=~\"$namespace\", destination_workload=~\"$workload\",response_code!~\"5.*\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[5m])) by (source_workload, source_workload_namespace) / sum(irate(istio_requests_total{reporter=\"destination\", connection_security_policy!=\"mutual_tls\", destination_workload_namespace=~\"$namespace\", destination_workload=~\"$workload\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[5m])) by (source_workload, source_workload_namespace)", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ source_workload }}.{{ source_workload_namespace }}", + "refId": "B", + "step": 2 + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Incoming Success Rate (non-5xx responses) By Source", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "percentunit", + "label": null, + "logBase": 1, + "max": "1.01", + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ] + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "description": "", + "fill": 1, + "gridPos": { + "h": 6, + "w": 8, + "x": 0, + "y": 20 + }, + "id": 27, + "legend": { + "alignAsTable": false, + "avg": false, + "current": false, + "hideEmpty": true, + "hideZero": false, + "max": false, + "min": false, + "rightSide": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "(histogram_quantile(0.50, sum(irate(istio_request_duration_milliseconds_bucket{reporter=\"destination\", connection_security_policy=\"mutual_tls\", destination_workload=~\"$workload\", destination_workload_namespace=~\"$namespace\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le)) / 1000) or histogram_quantile(0.50, sum(irate(istio_request_duration_seconds_bucket{reporter=\"destination\", connection_security_policy=\"mutual_tls\", destination_workload=~\"$workload\", destination_workload_namespace=~\"$namespace\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{source_workload}}.{{source_workload_namespace}} P50 (🔐mTLS)", + "refId": "D", + "step": 2 + }, + { + "expr": "(histogram_quantile(0.90, sum(irate(istio_request_duration_milliseconds_bucket{reporter=\"destination\", connection_security_policy=\"mutual_tls\", destination_workload=~\"$workload\", destination_workload_namespace=~\"$namespace\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le)) / 1000) or histogram_quantile(0.90, sum(irate(istio_request_duration_seconds_bucket{reporter=\"destination\", connection_security_policy=\"mutual_tls\", destination_workload=~\"$workload\", destination_workload_namespace=~\"$namespace\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{source_workload}}.{{source_workload_namespace}} P90 (🔐mTLS)", + "refId": "A", + "step": 2 + }, + { + "expr": "(histogram_quantile(0.95, sum(irate(istio_request_duration_milliseconds_bucket{reporter=\"destination\", connection_security_policy=\"mutual_tls\", destination_workload=~\"$workload\", destination_workload_namespace=~\"$namespace\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le)) / 1000) or histogram_quantile(0.95, sum(irate(istio_request_duration_seconds_bucket{reporter=\"destination\", connection_security_policy=\"mutual_tls\", destination_workload=~\"$workload\", destination_workload_namespace=~\"$namespace\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{source_workload}}.{{source_workload_namespace}} P95 (🔐mTLS)", + "refId": "B", + "step": 2 + }, + { + "expr": "(histogram_quantile(0.99, sum(irate(istio_request_duration_milliseconds_bucket{reporter=\"destination\", connection_security_policy=\"mutual_tls\", destination_workload=~\"$workload\", destination_workload_namespace=~\"$namespace\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le)) / 1000) or histogram_quantile(0.99, sum(irate(istio_request_duration_seconds_bucket{reporter=\"destination\", connection_security_policy=\"mutual_tls\", destination_workload=~\"$workload\", destination_workload_namespace=~\"$namespace\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{source_workload}}.{{source_workload_namespace}} P99 (🔐mTLS)", + "refId": "C", + "step": 2 + }, + { + "expr": "(histogram_quantile(0.50, sum(irate(istio_request_duration_milliseconds_bucket{reporter=\"destination\", connection_security_policy!=\"mutual_tls\", destination_workload=~\"$workload\", destination_workload_namespace=~\"$namespace\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le)) / 1000) or histogram_quantile(0.50, sum(irate(istio_request_duration_seconds_bucket{reporter=\"destination\", connection_security_policy!=\"mutual_tls\", destination_workload=~\"$workload\", destination_workload_namespace=~\"$namespace\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{source_workload}}.{{source_workload_namespace}} P50", + "refId": "E", + "step": 2 + }, + { + "expr": "(histogram_quantile(0.90, sum(irate(istio_request_duration_milliseconds_bucket{reporter=\"destination\", connection_security_policy!=\"mutual_tls\", destination_workload=~\"$workload\", destination_workload_namespace=~\"$namespace\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le)) / 1000) or histogram_quantile(0.90, sum(irate(istio_request_duration_seconds_bucket{reporter=\"destination\", connection_security_policy!=\"mutual_tls\", destination_workload=~\"$workload\", destination_workload_namespace=~\"$namespace\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{source_workload}}.{{source_workload_namespace}} P90", + "refId": "F", + "step": 2 + }, + { + "expr": "(histogram_quantile(0.95, sum(irate(istio_request_duration_milliseconds_bucket{reporter=\"destination\", connection_security_policy!=\"mutual_tls\", destination_workload=~\"$workload\", destination_workload_namespace=~\"$namespace\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le)) / 1000) or histogram_quantile(0.95, sum(irate(istio_request_duration_seconds_bucket{reporter=\"destination\", connection_security_policy!=\"mutual_tls\", destination_workload=~\"$workload\", destination_workload_namespace=~\"$namespace\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{source_workload}}.{{source_workload_namespace}} P95", + "refId": "G", + "step": 2 + }, + { + "expr": "(histogram_quantile(0.99, sum(irate(istio_request_duration_milliseconds_bucket{reporter=\"destination\", connection_security_policy!=\"mutual_tls\", destination_workload=~\"$workload\", destination_workload_namespace=~\"$namespace\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le)) / 1000) or histogram_quantile(0.99, sum(irate(istio_request_duration_seconds_bucket{reporter=\"destination\", connection_security_policy!=\"mutual_tls\", destination_workload=~\"$workload\", destination_workload_namespace=~\"$namespace\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{source_workload}}.{{source_workload_namespace}} P99", + "refId": "H", + "step": 2 + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Incoming Request Duration by Source", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "s", + "label": null, + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ] + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 6, + "w": 8, + "x": 8, + "y": 20 + }, + "id": 28, + "legend": { + "alignAsTable": false, + "avg": false, + "current": false, + "hideEmpty": true, + "max": false, + "min": false, + "rightSide": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "histogram_quantile(0.50, sum(irate(istio_request_bytes_bucket{reporter=\"destination\", connection_security_policy=\"mutual_tls\", destination_workload=~\"$workload\", destination_workload_namespace=~\"$namespace\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{source_workload}}.{{source_workload_namespace}} P50 (🔐mTLS)", + "refId": "D", + "step": 2 + }, + { + "expr": "histogram_quantile(0.90, sum(irate(istio_request_bytes_bucket{reporter=\"destination\", connection_security_policy=\"mutual_tls\", destination_workload=~\"$workload\", destination_workload_namespace=~\"$namespace\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{source_workload}}.{{source_workload_namespace}} P90 (🔐mTLS)", + "refId": "A", + "step": 2 + }, + { + "expr": "histogram_quantile(0.95, sum(irate(istio_request_bytes_bucket{reporter=\"destination\", connection_security_policy=\"mutual_tls\", destination_workload=~\"$workload\", destination_workload_namespace=~\"$namespace\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{source_workload}}.{{source_workload_namespace}} P95 (🔐mTLS)", + "refId": "B", + "step": 2 + }, + { + "expr": "histogram_quantile(0.99, sum(irate(istio_request_bytes_bucket{reporter=\"destination\", connection_security_policy=\"mutual_tls\", destination_workload=~\"$workload\", destination_workload_namespace=~\"$namespace\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{source_workload}}.{{source_workload_namespace}} P99 (🔐mTLS)", + "refId": "C", + "step": 2 + }, + { + "expr": "histogram_quantile(0.50, sum(irate(istio_request_bytes_bucket{reporter=\"destination\", connection_security_policy!=\"mutual_tls\", destination_workload=~\"$workload\", destination_workload_namespace=~\"$namespace\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{source_workload}}.{{source_workload_namespace}} P50", + "refId": "E", + "step": 2 + }, + { + "expr": "histogram_quantile(0.90, sum(irate(istio_request_bytes_bucket{reporter=\"destination\", connection_security_policy!=\"mutual_tls\", destination_workload=~\"$workload\", destination_workload_namespace=~\"$namespace\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{source_workload}}.{{source_workload_namespace}} P90", + "refId": "F", + "step": 2 + }, + { + "expr": "histogram_quantile(0.95, sum(irate(istio_request_bytes_bucket{reporter=\"destination\", connection_security_policy!=\"mutual_tls\", destination_workload=~\"$workload\", destination_workload_namespace=~\"$namespace\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{source_workload}}.{{source_workload_namespace}} P95", + "refId": "G", + "step": 2 + }, + { + "expr": "histogram_quantile(0.99, sum(irate(istio_request_bytes_bucket{reporter=\"destination\", connection_security_policy!=\"mutual_tls\", destination_workload=~\"$workload\", destination_workload_namespace=~\"$namespace\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{source_workload}}.{{source_workload_namespace}} P99", + "refId": "H", + "step": 2 + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Incoming Request Size By Source", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "decbytes", + "label": null, + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ] + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 6, + "w": 8, + "x": 16, + "y": 20 + }, + "id": 68, + "legend": { + "alignAsTable": false, + "avg": false, + "current": false, + "hideEmpty": true, + "max": false, + "min": false, + "rightSide": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "histogram_quantile(0.50, sum(irate(istio_response_bytes_bucket{reporter=\"destination\", connection_security_policy=\"mutual_tls\", destination_workload=~\"$workload\", destination_workload_namespace=~\"$namespace\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{source_workload}}.{{source_workload_namespace}} P50 (🔐mTLS)", + "refId": "D", + "step": 2 + }, + { + "expr": "histogram_quantile(0.90, sum(irate(istio_response_bytes_bucket{reporter=\"destination\", connection_security_policy=\"mutual_tls\", destination_workload=~\"$workload\", destination_workload_namespace=~\"$namespace\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{source_workload}}.{{source_workload_namespace}} P90 (🔐mTLS)", + "refId": "A", + "step": 2 + }, + { + "expr": "histogram_quantile(0.95, sum(irate(istio_response_bytes_bucket{reporter=\"destination\", connection_security_policy=\"mutual_tls\", destination_workload=~\"$workload\", destination_workload_namespace=~\"$namespace\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{source_workload}}.{{source_workload_namespace}} P95 (🔐mTLS)", + "refId": "B", + "step": 2 + }, + { + "expr": "histogram_quantile(0.99, sum(irate(istio_response_bytes_bucket{reporter=\"destination\", connection_security_policy=\"mutual_tls\", destination_workload=~\"$workload\", destination_workload_namespace=~\"$namespace\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{source_workload}}.{{source_workload_namespace}} P99 (🔐mTLS)", + "refId": "C", + "step": 2 + }, + { + "expr": "histogram_quantile(0.50, sum(irate(istio_response_bytes_bucket{reporter=\"destination\", connection_security_policy!=\"mutual_tls\", destination_workload=~\"$workload\", destination_workload_namespace=~\"$namespace\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{source_workload}}.{{source_workload_namespace}} P50", + "refId": "E", + "step": 2 + }, + { + "expr": "histogram_quantile(0.90, sum(irate(istio_response_bytes_bucket{reporter=\"destination\", connection_security_policy!=\"mutual_tls\", destination_workload=~\"$workload\", destination_workload_namespace=~\"$namespace\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{source_workload}}.{{source_workload_namespace}} P90", + "refId": "F", + "step": 2 + }, + { + "expr": "histogram_quantile(0.95, sum(irate(istio_response_bytes_bucket{reporter=\"destination\", connection_security_policy!=\"mutual_tls\", destination_workload=~\"$workload\", destination_workload_namespace=~\"$namespace\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{source_workload}}.{{source_workload_namespace}} P95", + "refId": "G", + "step": 2 + }, + { + "expr": "histogram_quantile(0.99, sum(irate(istio_response_bytes_bucket{reporter=\"destination\", connection_security_policy!=\"mutual_tls\", destination_workload=~\"$workload\", destination_workload_namespace=~\"$namespace\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{source_workload}}.{{source_workload_namespace}} P99", + "refId": "H", + "step": 2 + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Response Size By Source", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "decbytes", + "label": null, + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ] + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 6, + "w": 12, + "x": 0, + "y": 26 + }, + "id": 80, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "round(sum(irate(istio_tcp_received_bytes_total{reporter=\"destination\", connection_security_policy=\"mutual_tls\", destination_workload_namespace=~\"$namespace\", destination_workload=~\"$workload\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace), 0.001)", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ source_workload }}.{{ source_workload_namespace}} (🔐mTLS)", + "refId": "A", + "step": 2 + }, + { + "expr": "round(sum(irate(istio_tcp_received_bytes_total{reporter=\"destination\", connection_security_policy!=\"mutual_tls\", destination_workload_namespace=~\"$namespace\", destination_workload=~\"$workload\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace), 0.001)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{ source_workload }}.{{ source_workload_namespace}}", + "refId": "B", + "step": 2 + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Bytes Received from Incoming TCP Connection", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "Bps", + "label": null, + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ] + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 6, + "w": 12, + "x": 12, + "y": 26 + }, + "id": 82, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "round(sum(irate(istio_tcp_sent_bytes_total{connection_security_policy=\"mutual_tls\", reporter=\"destination\", destination_workload_namespace=~\"$namespace\", destination_workload=~\"$workload\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace), 0.001)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{ source_workload }}.{{ source_workload_namespace}} (🔐mTLS)", + "refId": "A", + "step": 2 + }, + { + "expr": "round(sum(irate(istio_tcp_sent_bytes_total{connection_security_policy!=\"mutual_tls\", reporter=\"destination\", destination_workload_namespace=~\"$namespace\", destination_workload=~\"$workload\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace), 0.001)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{ source_workload }}.{{ source_workload_namespace}}", + "refId": "B", + "step": 2 + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Bytes Sent to Incoming TCP Connection", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "Bps", + "label": null, + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ] + }, + { + "content": "
\nOUTBOUND SERVICES\n
", + "gridPos": { + "h": 3, + "w": 24, + "x": 0, + "y": 32 + }, + "id": 69, + "links": [], + "mode": "html", + "title": "", + "transparent": true, + "type": "text" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 0, + "gridPos": { + "h": 6, + "w": 12, + "x": 0, + "y": 35 + }, + "id": 70, + "legend": { + "avg": false, + "current": false, + "hideEmpty": true, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null as zero", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "round(sum(irate(istio_requests_total{connection_security_policy=\"mutual_tls\", source_workload_namespace=~\"$namespace\", source_workload=~\"$workload\", reporter=\"source\", destination_service=~\"$dstsvc\"}[5m])) by (destination_service, response_code), 0.001)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{ destination_service }} : {{ response_code }} (🔐mTLS)", + "refId": "B", + "step": 2 + }, + { + "expr": "round(sum(irate(istio_requests_total{connection_security_policy!=\"mutual_tls\", source_workload_namespace=~\"$namespace\", source_workload=~\"$workload\", reporter=\"source\", destination_service=~\"$dstsvc\"}[5m])) by (destination_service, response_code), 0.001)", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_service }} : {{ response_code }}", + "refId": "A", + "step": 2 + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Outgoing Requests by Destination And Response Code", + "tooltip": { + "shared": false, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [ + "total" + ] + }, + "yaxes": [ + { + "format": "ops", + "label": null, + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ] + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 6, + "w": 12, + "x": 12, + "y": 35 + }, + "id": 71, + "legend": { + "avg": false, + "current": false, + "hideEmpty": true, + "hideZero": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(irate(istio_requests_total{reporter=\"source\", connection_security_policy=\"mutual_tls\", source_workload_namespace=~\"$namespace\", source_workload=~\"$workload\",response_code!~\"5.*\", destination_service=~\"$dstsvc\"}[5m])) by (destination_service) / sum(irate(istio_requests_total{reporter=\"source\", connection_security_policy=\"mutual_tls\", source_workload_namespace=~\"$namespace\", source_workload=~\"$workload\", destination_service=~\"$dstsvc\"}[5m])) by (destination_service)", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_service }} (🔐mTLS)", + "refId": "A", + "step": 2 + }, + { + "expr": "sum(irate(istio_requests_total{reporter=\"source\", connection_security_policy!=\"mutual_tls\", source_workload_namespace=~\"$namespace\", source_workload=~\"$workload\",response_code!~\"5.*\", destination_service=~\"$dstsvc\"}[5m])) by (destination_service) / sum(irate(istio_requests_total{reporter=\"source\", connection_security_policy!=\"mutual_tls\", source_workload_namespace=~\"$namespace\", source_workload=~\"$workload\", destination_service=~\"$dstsvc\"}[5m])) by (destination_service)", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{destination_service }}", + "refId": "B", + "step": 2 + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Outgoing Success Rate (non-5xx responses) By Destination", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "percentunit", + "label": null, + "logBase": 1, + "max": "1.01", + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ] + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "description": "", + "fill": 1, + "gridPos": { + "h": 6, + "w": 8, + "x": 0, + "y": 41 + }, + "id": 72, + "legend": { + "alignAsTable": false, + "avg": false, + "current": false, + "hideEmpty": true, + "hideZero": false, + "max": false, + "min": false, + "rightSide": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "(histogram_quantile(0.50, sum(irate(istio_request_duration_milliseconds_bucket{reporter=\"source\", connection_security_policy=\"mutual_tls\", source_workload=~\"$workload\", source_workload_namespace=~\"$namespace\", destination_service=~\"$dstsvc\"}[1m])) by (destination_service, le)) / 1000) or histogram_quantile(0.50, sum(irate(istio_request_duration_seconds_bucket{reporter=\"source\", connection_security_policy=\"mutual_tls\", source_workload=~\"$workload\", source_workload_namespace=~\"$namespace\", destination_service=~\"$dstsvc\"}[1m])) by (destination_service, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_service }} P50 (🔐mTLS)", + "refId": "D", + "step": 2 + }, + { + "expr": "(histogram_quantile(0.90, sum(irate(istio_request_duration_milliseconds_bucket{reporter=\"source\", connection_security_policy=\"mutual_tls\", source_workload=~\"$workload\", source_workload_namespace=~\"$namespace\", destination_service=~\"$dstsvc\"}[1m])) by (destination_service, le)) / 1000) or histogram_quantile(0.90, sum(irate(istio_request_duration_seconds_bucket{reporter=\"source\", connection_security_policy=\"mutual_tls\", source_workload=~\"$workload\", source_workload_namespace=~\"$namespace\", destination_service=~\"$dstsvc\"}[1m])) by (destination_service, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_service }} P90 (🔐mTLS)", + "refId": "A", + "step": 2 + }, + { + "expr": "(histogram_quantile(0.95, sum(irate(istio_request_duration_milliseconds_bucket{reporter=\"source\", connection_security_policy=\"mutual_tls\", source_workload=~\"$workload\", source_workload_namespace=~\"$namespace\", destination_service=~\"$dstsvc\"}[1m])) by (destination_service, le)) / 1000) or histogram_quantile(0.95, sum(irate(istio_request_duration_seconds_bucket{reporter=\"source\", connection_security_policy=\"mutual_tls\", source_workload=~\"$workload\", source_workload_namespace=~\"$namespace\", destination_service=~\"$dstsvc\"}[1m])) by (destination_service, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_service }} P95 (🔐mTLS)", + "refId": "B", + "step": 2 + }, + { + "expr": "(histogram_quantile(0.99, sum(irate(istio_request_duration_milliseconds_bucket{reporter=\"source\", connection_security_policy=\"mutual_tls\", source_workload=~\"$workload\", source_workload_namespace=~\"$namespace\", destination_service=~\"$dstsvc\"}[1m])) by (destination_service, le)) / 1000) or histogram_quantile(0.99, sum(irate(istio_request_duration_seconds_bucket{reporter=\"source\", connection_security_policy=\"mutual_tls\", source_workload=~\"$workload\", source_workload_namespace=~\"$namespace\", destination_service=~\"$dstsvc\"}[1m])) by (destination_service, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_service }} P99 (🔐mTLS)", + "refId": "C", + "step": 2 + }, + { + "expr": "(histogram_quantile(0.50, sum(irate(istio_request_duration_milliseconds_bucket{reporter=\"source\", connection_security_policy!=\"mutual_tls\", source_workload=~\"$workload\", source_workload_namespace=~\"$namespace\", destination_service=~\"$dstsvc\"}[1m])) by (destination_service, le)) / 1000) or histogram_quantile(0.50, sum(irate(istio_request_duration_seconds_bucket{reporter=\"source\", connection_security_policy!=\"mutual_tls\", source_workload=~\"$workload\", source_workload_namespace=~\"$namespace\", destination_service=~\"$dstsvc\"}[1m])) by (destination_service, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_service }} P50", + "refId": "E", + "step": 2 + }, + { + "expr": "(histogram_quantile(0.90, sum(irate(istio_request_duration_milliseconds_bucket{reporter=\"source\", connection_security_policy!=\"mutual_tls\", source_workload=~\"$workload\", source_workload_namespace=~\"$namespace\", destination_service=~\"$dstsvc\"}[1m])) by (destination_service, le)) / 1000) or histogram_quantile(0.90, sum(irate(istio_request_duration_seconds_bucket{reporter=\"source\", connection_security_policy!=\"mutual_tls\", source_workload=~\"$workload\", source_workload_namespace=~\"$namespace\", destination_service=~\"$dstsvc\"}[1m])) by (destination_service, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_service }} P90", + "refId": "F", + "step": 2 + }, + { + "expr": "(histogram_quantile(0.95, sum(irate(istio_request_duration_milliseconds_bucket{reporter=\"source\", connection_security_policy!=\"mutual_tls\", source_workload=~\"$workload\", source_workload_namespace=~\"$namespace\", destination_service=~\"$dstsvc\"}[1m])) by (destination_service, le)) / 1000) or histogram_quantile(0.95, sum(irate(istio_request_duration_seconds_bucket{reporter=\"source\", connection_security_policy!=\"mutual_tls\", source_workload=~\"$workload\", source_workload_namespace=~\"$namespace\", destination_service=~\"$dstsvc\"}[1m])) by (destination_service, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_service }} P95", + "refId": "G", + "step": 2 + }, + { + "expr": "(histogram_quantile(0.99, sum(irate(istio_request_duration_milliseconds_bucket{reporter=\"source\", connection_security_policy!=\"mutual_tls\", source_workload=~\"$workload\", source_workload_namespace=~\"$namespace\", destination_service=~\"$dstsvc\"}[1m])) by (destination_service, le)) / 1000) or histogram_quantile(0.99, sum(irate(istio_request_duration_seconds_bucket{reporter=\"source\", connection_security_policy!=\"mutual_tls\", source_workload=~\"$workload\", source_workload_namespace=~\"$namespace\", destination_service=~\"$dstsvc\"}[1m])) by (destination_service, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_service }} P99", + "refId": "H", + "step": 2 + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Outgoing Request Duration by Destination", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "s", + "label": null, + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ] + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 6, + "w": 8, + "x": 8, + "y": 41 + }, + "id": 73, + "legend": { + "alignAsTable": false, + "avg": false, + "current": false, + "hideEmpty": true, + "max": false, + "min": false, + "rightSide": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "histogram_quantile(0.50, sum(irate(istio_request_bytes_bucket{reporter=\"source\", connection_security_policy=\"mutual_tls\", source_workload=~\"$workload\", source_workload_namespace=~\"$namespace\", destination_service=~\"$dstsvc\"}[1m])) by (destination_service, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_service }} P50 (🔐mTLS)", + "refId": "D", + "step": 2 + }, + { + "expr": "histogram_quantile(0.90, sum(irate(istio_request_bytes_bucket{reporter=\"source\", connection_security_policy=\"mutual_tls\", source_workload=~\"$workload\", source_workload_namespace=~\"$namespace\", destination_service=~\"$dstsvc\"}[1m])) by (destination_service, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_service }} P90 (🔐mTLS)", + "refId": "A", + "step": 2 + }, + { + "expr": "histogram_quantile(0.95, sum(irate(istio_request_bytes_bucket{reporter=\"source\", connection_security_policy=\"mutual_tls\", source_workload=~\"$workload\", source_workload_namespace=~\"$namespace\", destination_service=~\"$dstsvc\"}[1m])) by (destination_service, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_service }} P95 (🔐mTLS)", + "refId": "B", + "step": 2 + }, + { + "expr": "histogram_quantile(0.99, sum(irate(istio_request_bytes_bucket{reporter=\"source\", connection_security_policy=\"mutual_tls\", source_workload=~\"$workload\", source_workload_namespace=~\"$namespace\", destination_service=~\"$dstsvc\"}[1m])) by (destination_service, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_service }} P99 (🔐mTLS)", + "refId": "C", + "step": 2 + }, + { + "expr": "histogram_quantile(0.50, sum(irate(istio_request_bytes_bucket{reporter=\"source\", connection_security_policy!=\"mutual_tls\", source_workload=~\"$workload\", source_workload_namespace=~\"$namespace\", destination_service=~\"$dstsvc\"}[1m])) by (destination_service, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_service }} P50", + "refId": "E", + "step": 2 + }, + { + "expr": "histogram_quantile(0.90, sum(irate(istio_request_bytes_bucket{reporter=\"source\", connection_security_policy!=\"mutual_tls\", source_workload=~\"$workload\", source_workload_namespace=~\"$namespace\", destination_service=~\"$dstsvc\"}[1m])) by (destination_service, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_service }} P90", + "refId": "F", + "step": 2 + }, + { + "expr": "histogram_quantile(0.95, sum(irate(istio_request_bytes_bucket{reporter=\"source\", connection_security_policy!=\"mutual_tls\", source_workload=~\"$workload\", source_workload_namespace=~\"$namespace\", destination_service=~\"$dstsvc\"}[1m])) by (destination_service, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_service }} P95", + "refId": "G", + "step": 2 + }, + { + "expr": "histogram_quantile(0.99, sum(irate(istio_request_bytes_bucket{reporter=\"source\", connection_security_policy!=\"mutual_tls\", source_workload=~\"$workload\", source_workload_namespace=~\"$namespace\", destination_service=~\"$dstsvc\"}[1m])) by (destination_service, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_service }} P99", + "refId": "H", + "step": 2 + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Outgoing Request Size By Destination", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "decbytes", + "label": null, + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ] + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 6, + "w": 8, + "x": 16, + "y": 41 + }, + "id": 74, + "legend": { + "alignAsTable": false, + "avg": false, + "current": false, + "hideEmpty": true, + "max": false, + "min": false, + "rightSide": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "histogram_quantile(0.50, sum(irate(istio_response_bytes_bucket{reporter=\"source\", connection_security_policy=\"mutual_tls\", source_workload=~\"$workload\", source_workload_namespace=~\"$namespace\", destination_service=~\"$dstsvc\"}[1m])) by (destination_service, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_service }} P50 (🔐mTLS)", + "refId": "D", + "step": 2 + }, + { + "expr": "histogram_quantile(0.90, sum(irate(istio_response_bytes_bucket{reporter=\"source\", connection_security_policy=\"mutual_tls\", source_workload=~\"$workload\", source_workload_namespace=~\"$namespace\", destination_service=~\"$dstsvc\"}[1m])) by (destination_service, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_service }} P90 (🔐mTLS)", + "refId": "A", + "step": 2 + }, + { + "expr": "histogram_quantile(0.95, sum(irate(istio_response_bytes_bucket{reporter=\"source\", connection_security_policy=\"mutual_tls\", source_workload=~\"$workload\", source_workload_namespace=~\"$namespace\", destination_service=~\"$dstsvc\"}[1m])) by (destination_service, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_service }} P95 (🔐mTLS)", + "refId": "B", + "step": 2 + }, + { + "expr": "histogram_quantile(0.99, sum(irate(istio_response_bytes_bucket{reporter=\"source\", connection_security_policy=\"mutual_tls\", source_workload=~\"$workload\", source_workload_namespace=~\"$namespace\", destination_service=~\"$dstsvc\"}[1m])) by (destination_service, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_service }} P99 (🔐mTLS)", + "refId": "C", + "step": 2 + }, + { + "expr": "histogram_quantile(0.50, sum(irate(istio_response_bytes_bucket{reporter=\"source\", connection_security_policy!=\"mutual_tls\", source_workload=~\"$workload\", source_workload_namespace=~\"$namespace\", destination_service=~\"$dstsvc\"}[1m])) by (destination_service, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_service }} P50", + "refId": "E", + "step": 2 + }, + { + "expr": "histogram_quantile(0.90, sum(irate(istio_response_bytes_bucket{reporter=\"source\", connection_security_policy!=\"mutual_tls\", source_workload=~\"$workload\", source_workload_namespace=~\"$namespace\", destination_service=~\"$dstsvc\"}[1m])) by (destination_service, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_service }} P90", + "refId": "F", + "step": 2 + }, + { + "expr": "histogram_quantile(0.95, sum(irate(istio_response_bytes_bucket{reporter=\"source\", connection_security_policy!=\"mutual_tls\", source_workload=~\"$workload\", source_workload_namespace=~\"$namespace\", destination_service=~\"$dstsvc\"}[1m])) by (destination_service, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_service }} P95", + "refId": "G", + "step": 2 + }, + { + "expr": "histogram_quantile(0.99, sum(irate(istio_response_bytes_bucket{reporter=\"source\", connection_security_policy!=\"mutual_tls\", source_workload=~\"$workload\", source_workload_namespace=~\"$namespace\", destination_service=~\"$dstsvc\"}[1m])) by (destination_service, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_service }} P99", + "refId": "H", + "step": 2 + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Response Size By Destination", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "decbytes", + "label": null, + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ] + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 6, + "w": 12, + "x": 0, + "y": 47 + }, + "id": 76, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "round(sum(irate(istio_tcp_sent_bytes_total{connection_security_policy=\"mutual_tls\", reporter=\"source\", source_workload_namespace=~\"$namespace\", source_workload=~\"$workload\", destination_service=~\"$dstsvc\"}[1m])) by (destination_service), 0.001)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{ destination_service }} (🔐mTLS)", + "refId": "A", + "step": 2 + }, + { + "expr": "round(sum(irate(istio_tcp_sent_bytes_total{connection_security_policy!=\"mutual_tls\", reporter=\"source\", source_workload_namespace=~\"$namespace\", source_workload=~\"$workload\", destination_service=~\"$dstsvc\"}[1m])) by (destination_service), 0.001)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{ destination_service }}", + "refId": "B", + "step": 2 + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Bytes Sent on Outgoing TCP Connection", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "Bps", + "label": null, + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ] + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 6, + "w": 12, + "x": 12, + "y": 47 + }, + "id": 78, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "round(sum(irate(istio_tcp_received_bytes_total{reporter=\"source\", connection_security_policy=\"mutual_tls\", source_workload_namespace=~\"$namespace\", source_workload=~\"$workload\", destination_service=~\"$dstsvc\"}[1m])) by (destination_service), 0.001)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{ destination_service }} (🔐mTLS)", + "refId": "A", + "step": 2 + }, + { + "expr": "round(sum(irate(istio_tcp_received_bytes_total{reporter=\"source\", connection_security_policy!=\"mutual_tls\", source_workload_namespace=~\"$namespace\", source_workload=~\"$workload\", destination_service=~\"$dstsvc\"}[1m])) by (destination_service), 0.001)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{ destination_service }}", + "refId": "B", + "step": 2 + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Bytes Received from Outgoing TCP Connection", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "Bps", + "label": null, + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ] + } + ], + "refresh": "10s", + "schemaVersion": 16, + "style": "dark", + "tags": [], + "templating": { + "list": [ + { + "allValue": null, + "current": {}, + "datasource": "Prometheus", + "hide": 0, + "includeAll": false, + "label": "Namespace", + "multi": false, + "name": "namespace", + "options": [], + "query": "query_result(sum(istio_requests_total) by (destination_workload_namespace) or sum(istio_tcp_sent_bytes_total) by (destination_workload_namespace))", + "refresh": 1, + "regex": "/.*_namespace=\"([^\"]*).*/", + "sort": 0, + "tagValuesQuery": "", + "tags": [], + "tagsQuery": "", + "type": "query", + "useTags": false + }, + { + "allValue": null, + "current": {}, + "datasource": "Prometheus", + "hide": 0, + "includeAll": false, + "label": "Workload", + "multi": false, + "name": "workload", + "options": [], + "query": "query_result((sum(istio_requests_total{destination_workload_namespace=~\"$namespace\"}) by (destination_workload) or sum(istio_requests_total{source_workload_namespace=~\"$namespace\"}) by (source_workload)) or (sum(istio_tcp_sent_bytes_total{destination_workload_namespace=~\"$namespace\"}) by (destination_workload) or sum(istio_tcp_sent_bytes_total{source_workload_namespace=~\"$namespace\"}) by (source_workload)))", + "refresh": 1, + "regex": "/.*workload=\"([^\"]*).*/", + "sort": 1, + "tagValuesQuery": "", + "tags": [], + "tagsQuery": "", + "type": "query", + "useTags": false + }, + { + "allValue": null, + "current": {}, + "datasource": "Prometheus", + "hide": 0, + "includeAll": true, + "label": "Inbound Workload Namespace", + "multi": true, + "name": "srcns", + "options": [], + "query": "query_result( sum(istio_requests_total{reporter=\"destination\", destination_workload=\"$workload\", destination_workload_namespace=~\"$namespace\"}) by (source_workload_namespace) or sum(istio_tcp_sent_bytes_total{reporter=\"destination\", destination_workload=\"$workload\", destination_workload_namespace=~\"$namespace\"}) by (source_workload_namespace))", + "refresh": 1, + "regex": "/.*namespace=\"([^\"]*).*/", + "sort": 2, + "tagValuesQuery": "", + "tags": [], + "tagsQuery": "", + "type": "query", + "useTags": false + }, + { + "allValue": null, + "current": {}, + "datasource": "Prometheus", + "hide": 0, + "includeAll": true, + "label": "Inbound Workload", + "multi": true, + "name": "srcwl", + "options": [], + "query": "query_result( sum(istio_requests_total{reporter=\"destination\", destination_workload=\"$workload\", destination_workload_namespace=~\"$namespace\", source_workload_namespace=~\"$srcns\"}) by (source_workload) or sum(istio_tcp_sent_bytes_total{reporter=\"destination\", destination_workload=\"$workload\", destination_workload_namespace=~\"$namespace\", source_workload_namespace=~\"$srcns\"}) by (source_workload))", + "refresh": 1, + "regex": "/.*workload=\"([^\"]*).*/", + "sort": 3, + "tagValuesQuery": "", + "tags": [], + "tagsQuery": "", + "type": "query", + "useTags": false + }, + { + "allValue": null, + "current": {}, + "datasource": "Prometheus", + "hide": 0, + "includeAll": true, + "label": "Destination Service", + "multi": true, + "name": "dstsvc", + "options": [], + "query": "query_result( sum(istio_requests_total{reporter=\"source\", source_workload=~\"$workload\", source_workload_namespace=~\"$namespace\"}) by (destination_service) or sum(istio_tcp_sent_bytes_total{reporter=\"source\", source_workload=~\"$workload\", source_workload_namespace=~\"$namespace\"}) by (destination_service))", + "refresh": 1, + "regex": "/.*destination_service=\"([^\"]*).*/", + "sort": 4, + "tagValuesQuery": "", + "tags": [], + "tagsQuery": "", + "type": "query", + "useTags": false + } + ] + }, + "time": { + "from": "now-5m", + "to": "now" + }, + "timepicker": { + "refresh_intervals": [ + "5s", + "10s", + "30s", + "1m", + "5m", + "15m", + "30m", + "1h", + "2h", + "1d" + ], + "time_options": [ + "5m", + "15m", + "1h", + "6h", + "12h", + "24h", + "2d", + "7d", + "30d" + ] + }, + "timezone": "", + "title": "Istio Workload Dashboard", + "uid": "UbsSZTDik", + "version": 1 +} diff --git a/istio-1.3.5/install/kubernetes/operator/charts/istio-telemetry/grafana/dashboards/mixer-dashboard.json b/istio-1.3.5/install/kubernetes/operator/charts/istio-telemetry/grafana/dashboards/mixer-dashboard.json new file mode 100644 index 0000000..8ca438c --- /dev/null +++ b/istio-1.3.5/install/kubernetes/operator/charts/istio-telemetry/grafana/dashboards/mixer-dashboard.json @@ -0,0 +1,1808 @@ +{ + "__inputs": [ + { + "name": "DS_PROMETHEUS", + "label": "Prometheus", + "description": "", + "type": "datasource", + "pluginId": "prometheus", + "pluginName": "Prometheus" + } + ], + "__requires": [ + { + "type": "grafana", + "id": "grafana", + "name": "Grafana", + "version": "5.2.3" + }, + { + "type": "panel", + "id": "graph", + "name": "Graph", + "version": "5.0.0" + }, + { + "type": "datasource", + "id": "prometheus", + "name": "Prometheus", + "version": "5.0.0" + }, + { + "type": "panel", + "id": "text", + "name": "Text", + "version": "5.0.0" + } + ], + "annotations": { + "list": [ + { + "builtIn": 1, + "datasource": "-- Grafana --", + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "limit": 100, + "name": "Annotations & Alerts", + "showIn": 0, + "type": "dashboard" + } + ] + }, + "editable": false, + "gnetId": null, + "graphTooltip": 1, + "id": null, + "iteration": 1543881232533, + "links": [], + "panels": [ + { + "content": "

Deployed Versions

", + "gridPos": { + "h": 3, + "w": 24, + "x": 0, + "y": 0 + }, + "height": "40", + "id": 62, + "links": [], + "mode": "html", + "title": "", + "transparent": true, + "type": "text" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 5, + "w": 24, + "x": 0, + "y": 3 + }, + "id": 64, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(istio_build{component=\"mixer\"}) by (tag)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{ tag }}", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Mixer Versions", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "content": "

Resource Usage

", + "gridPos": { + "h": 3, + "w": 24, + "x": 0, + "y": 8 + }, + "height": "40", + "id": 29, + "links": [], + "mode": "html", + "title": "", + "transparent": true, + "type": "text" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 7, + "w": 6, + "x": 0, + "y": 11 + }, + "id": 5, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(process_virtual_memory_bytes{job=~\"istio-telemetry|istio-policy\"}) by (job)", + "format": "time_series", + "instant": false, + "intervalFactor": 2, + "legendFormat": "Virtual Memory ({{ job }})", + "refId": "I" + }, + { + "expr": "sum(process_resident_memory_bytes{job=~\"istio-telemetry|istio-policy\"}) by (job)", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "Resident Memory ({{ job }})", + "refId": "H" + }, + { + "expr": "sum(go_memstats_heap_sys_bytes{job=~\"istio-telemetry|istio-policy\"}) by (job)", + "format": "time_series", + "hide": true, + "intervalFactor": 2, + "legendFormat": "heap sys ({{ job }})", + "refId": "A" + }, + { + "expr": "sum(go_memstats_heap_alloc_bytes{job=~\"istio-telemetry|istio-policy\"}) by (job)", + "format": "time_series", + "hide": true, + "intervalFactor": 2, + "legendFormat": "heap alloc ({{ job }})", + "refId": "D" + }, + { + "expr": "sum(go_memstats_alloc_bytes{job=~\"istio-telemetry|istio-policy\"}) by (job)", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "Alloc ({{ job }})", + "refId": "F" + }, + { + "expr": "sum(go_memstats_heap_inuse_bytes{job=~\"istio-telemetry|istio-policy\"}) by (job)", + "format": "time_series", + "hide": false, + "intervalFactor": 2, + "legendFormat": "Heap in-use ({{ job }})", + "refId": "E" + }, + { + "expr": "sum(go_memstats_stack_inuse_bytes{job=~\"istio-telemetry|istio-policy\"}) by (job)", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "Stack in-use ({{ job }})", + "refId": "G" + }, + { + "expr": "sum(label_replace(container_memory_usage_bytes{container_name=~\"mixer|istio-proxy\", pod_name=~\"istio-telemetry-.*|istio-policy-.*\"}, \"service\", \"$1\" , \"pod_name\", \"(istio-telemetry|istio-policy)-.*\")) by (service)", + "format": "time_series", + "hide": false, + "intervalFactor": 2, + "legendFormat": "{{ service }} total (k8s)", + "refId": "C" + }, + { + "expr": "sum(label_replace(container_memory_usage_bytes{container_name=~\"mixer|istio-proxy\", pod_name=~\"istio-telemetry-.*|istio-policy-.*\"}, \"service\", \"$1\" , \"pod_name\", \"(istio-telemetry|istio-policy)-.*\")) by (container_name, service)", + "format": "time_series", + "hide": false, + "intervalFactor": 2, + "legendFormat": "{{ service }} - {{ container_name }} (k8s)", + "refId": "B" + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Memory", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "bytes", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 7, + "w": 6, + "x": 6, + "y": 11 + }, + "id": 6, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "label_replace(sum(rate(container_cpu_usage_seconds_total{job=\"kubernetes-cadvisor\",container_name=~\"mixer|istio-proxy\", pod_name=~\"istio-telemetry-.*|istio-policy-.*\"}[1m])) by (pod_name), \"service\", \"$1\" , \"pod_name\", \"(istio-telemetry|istio-policy)-.*\")", + "format": "time_series", + "hide": false, + "intervalFactor": 2, + "legendFormat": "{{ service }} total (k8s)", + "refId": "A" + }, + { + "expr": "label_replace(sum(rate(container_cpu_usage_seconds_total{job=\"kubernetes-cadvisor\",container_name=~\"mixer|istio-proxy\", pod_name=~\"istio-telemetry-.*|istio-policy-.*\"}[1m])) by (container_name, pod_name), \"service\", \"$1\" , \"pod_name\", \"(istio-telemetry|istio-policy)-.*\")", + "format": "time_series", + "hide": false, + "intervalFactor": 2, + "legendFormat": "{{ service }} - {{ container_name }} (k8s)", + "refId": "B" + }, + { + "expr": "sum(irate(process_cpu_seconds_total{job=~\"istio-telemetry|istio-policy\"}[1m])) by (job)", + "format": "time_series", + "hide": false, + "intervalFactor": 2, + "legendFormat": "{{ job }} (self-reported)", + "refId": "C" + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "CPU", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 7, + "w": 6, + "x": 12, + "y": 11 + }, + "id": 7, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(process_open_fds{job=~\"istio-telemetry|istio-policy\"}) by (job)", + "format": "time_series", + "hide": true, + "instant": false, + "interval": "", + "intervalFactor": 2, + "legendFormat": "Open FDs ({{ job }})", + "refId": "A" + }, + { + "expr": "sum(label_replace(container_fs_usage_bytes{container_name=~\"mixer|istio-proxy\", pod_name=~\"istio-telemetry-.*|istio-policy-.*\"}, \"service\", \"$1\" , \"pod_name\", \"(istio-telemetry|istio-policy)-.*\")) by (container_name, service)", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "{{ service }} - {{ container_name }}", + "refId": "B" + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Disk", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "bytes", + "label": "", + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "decimals": null, + "format": "none", + "label": "", + "logBase": 1024, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 7, + "w": 6, + "x": 18, + "y": 11 + }, + "id": 4, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": false, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(go_goroutines{job=~\"istio-telemetry|istio-policy\"}) by (job)", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "Number of Goroutines ({{ job }})", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Goroutines", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": "", + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "content": "

Mixer Overview

", + "gridPos": { + "h": 3, + "w": 24, + "x": 0, + "y": 18 + }, + "height": "40px", + "id": 30, + "links": [], + "mode": "html", + "title": "", + "transparent": true, + "type": "text" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 6, + "w": 6, + "x": 0, + "y": 21 + }, + "id": 9, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(rate(grpc_io_server_completed_rpcs[1m]))", + "format": "time_series", + "hide": false, + "intervalFactor": 2, + "legendFormat": "mixer (Total)", + "refId": "B" + }, + { + "expr": "sum(rate(grpc_io_server_completed_rpcs[1m])) by (grpc_server_method)", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "mixer ({{ grpc_server_method }})", + "refId": "C" + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Incoming Requests", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "ops", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 6, + "w": 6, + "x": 6, + "y": 21 + }, + "id": 8, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [ + { + "alias": "{}", + "yaxis": 1 + } + ], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "histogram_quantile(0.5, sum(rate(grpc_io_server_server_latency_bucket{}[1m])) by (grpc_server_method, le))", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "{{ grpc_server_method }} 0.5", + "refId": "B" + }, + { + "expr": "histogram_quantile(0.9, sum(rate(grpc_io_server_server_latency_bucket{}[1m])) by (grpc_server_method, le))", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "{{ grpc_server_method }} 0.9", + "refId": "C" + }, + { + "expr": "histogram_quantile(0.99, sum(rate(grpc_io_server_server_latency_bucket{}[1m])) by (grpc_server_method, le))", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "{{ grpc_server_method }} 0.99", + "refId": "D" + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Response Durations", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "ms", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 6, + "w": 6, + "x": 12, + "y": 21 + }, + "id": 11, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(rate(grpc_server_handled_total{grpc_code=~\"Unknown|Unimplemented|Internal|DataLoss\"}[1m])) by (grpc_method)", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "Mixer {{ grpc_method }}", + "refId": "B" + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Server Error Rate (5xx responses)", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 6, + "w": 6, + "x": 18, + "y": 21 + }, + "id": 12, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(irate(grpc_server_handled_total{grpc_code!=\"OK\",grpc_service=~\".*Mixer\"}[1m])) by (grpc_method)", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "Mixer {{ grpc_method }}", + "refId": "B" + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Non-successes (4xxs)", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "content": "

Adapters and Config

", + "gridPos": { + "h": 3, + "w": 24, + "x": 0, + "y": 27 + }, + "id": 28, + "links": [], + "mode": "html", + "title": "", + "transparent": true, + "type": "text" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 7, + "w": 12, + "x": 0, + "y": 30 + }, + "id": 13, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(irate(mixer_runtime_dispatches_total{adapter=~\"$adapter\"}[1m])) by (adapter)", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "{{ adapter }}", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Adapter Dispatch Count", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 7, + "w": 12, + "x": 12, + "y": 30 + }, + "id": 14, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "histogram_quantile(0.5, sum(irate(mixer_runtime_dispatch_duration_seconds_bucket{adapter=~\"$adapter\"}[1m])) by (adapter, le))", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "{{ adapter }} - p50", + "refId": "A" + }, + { + "expr": "histogram_quantile(0.9, sum(irate(mixer_runtime_dispatch_duration_seconds_bucket{adapter=~\"$adapter\"}[1m])) by (adapter, le))", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "{{ adapter }} - p90 ", + "refId": "B" + }, + { + "expr": "histogram_quantile(0.99, sum(irate(mixer_runtime_dispatch_duration_seconds_bucket{adapter=~\"$adapter\"}[1m])) by (adapter, le))", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "{{ adapter }} - p99", + "refId": "C" + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Adapter Dispatch Duration", + "tooltip": { + "shared": true, + "sort": 1, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "s", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 7, + "w": 6, + "x": 0, + "y": 37 + }, + "id": 60, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "scalar(topk(1, max(mixer_config_rule_config_count) by (configID)))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Rules", + "refId": "A" + }, + { + "expr": "scalar(topk(1, max(mixer_config_rule_config_error_count) by (configID)))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Config Errors", + "refId": "B" + }, + { + "expr": "scalar(topk(1, max(mixer_config_rule_config_match_error_count) by (configID)))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Match Errors", + "refId": "C" + }, + { + "expr": "scalar(topk(1, max(mixer_config_unsatisfied_action_handler_count) by (configID)))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Unsatisfied Actions", + "refId": "D" + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Rules", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 7, + "w": 6, + "x": 6, + "y": 37 + }, + "id": 56, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "scalar(topk(1, max(mixer_config_instance_config_count) by (configID)))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Instances", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Instances in Latest Config", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 7, + "w": 6, + "x": 12, + "y": 37 + }, + "id": 54, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "scalar(topk(1, max(mixer_config_handler_config_count) by (configID)))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Handlers", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Handlers in Latest Config", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 7, + "w": 6, + "x": 18, + "y": 37 + }, + "id": 58, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "scalar(topk(1, max(mixer_config_attribute_count) by (configID)))", + "format": "time_series", + "instant": false, + "intervalFactor": 1, + "legendFormat": "Attributes", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Attributes in Latest Config", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "content": "

Individual Adapters

", + "gridPos": { + "h": 3, + "w": 24, + "x": 0, + "y": 44 + }, + "id": 23, + "links": [], + "mode": "html", + "title": "", + "transparent": true, + "type": "text" + }, + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 47 + }, + "id": 46, + "panels": [], + "repeat": "adapter", + "title": "$adapter Adapter", + "type": "row" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 7, + "w": 12, + "x": 0, + "y": 48 + }, + "id": 17, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "label_replace(irate(mixer_runtime_dispatches_total{adapter=~\"$adapter\"}[1m]),\"handler\", \"$1 ($3)\", \"handler\", \"(.*)\\\\.(.*)\\\\.(.*)\")", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "{{ handler }} (error: {{ error }})", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Dispatch Count By Handler", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 7, + "w": 12, + "x": 12, + "y": 48 + }, + "id": 18, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "label_replace(histogram_quantile(0.5, sum(rate(mixer_runtime_dispatch_duration_seconds_bucket{adapter=~\"$adapter\"}[1m])) by (handler, error, le)), \"handler_short\", \"$1 ($3)\", \"handler\", \"(.*)\\\\.(.*)\\\\.(.*)\")", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "p50 - {{ handler_short }} (error: {{ error }})", + "refId": "A" + }, + { + "expr": "label_replace(histogram_quantile(0.9, sum(irate(mixer_runtime_dispatch_duration_seconds_bucket{adapter=~\"$adapter\"}[1m])) by (handler, error, le)), \"handler_short\", \"$1 ($3)\", \"handler\", \"(.*)\\\\.(.*)\\\\.(.*)\")", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "p90 - {{ handler_short }} (error: {{ error }})", + "refId": "D" + }, + { + "expr": "label_replace(histogram_quantile(0.99, sum(irate(mixer_runtime_dispatch_duration_seconds_bucket{adapter=~\"$adapter\"}[1m])) by (handler, error, le)), \"handler_short\", \"$1 ($3)\", \"handler\", \"(.*)\\\\.(.*)\\\\.(.*)\")", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "p99 - {{ handler_short }} (error: {{ error }})", + "refId": "E" + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Dispatch Duration By Handler", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "s", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + } + ], + "refresh": "5s", + "schemaVersion": 16, + "style": "dark", + "tags": [], + "templating": { + "list": [ + { + "allValue": null, + "current": {}, + "datasource": "Prometheus", + "hide": 0, + "includeAll": true, + "label": "Adapter", + "multi": true, + "name": "adapter", + "options": [], + "query": "label_values(adapter)", + "refresh": 2, + "regex": "", + "sort": 1, + "tagValuesQuery": "", + "tags": [], + "tagsQuery": "", + "type": "query", + "useTags": false + } + ] + }, + "time": { + "from": "now-5m", + "to": "now" + }, + "timepicker": { + "refresh_intervals": [ + "5s", + "10s", + "30s", + "1m", + "5m", + "15m", + "30m", + "1h", + "2h", + "1d" + ], + "time_options": [ + "5m", + "15m", + "1h", + "6h", + "12h", + "24h", + "2d", + "7d", + "30d" + ] + }, + "timezone": "", + "title": "Istio Mixer Dashboard", + "version": 4 +} diff --git a/istio-1.3.5/install/kubernetes/operator/charts/istio-telemetry/grafana/dashboards/pilot-dashboard.json b/istio-1.3.5/install/kubernetes/operator/charts/istio-telemetry/grafana/dashboards/pilot-dashboard.json new file mode 100644 index 0000000..d37b1d1 --- /dev/null +++ b/istio-1.3.5/install/kubernetes/operator/charts/istio-telemetry/grafana/dashboards/pilot-dashboard.json @@ -0,0 +1,1788 @@ +{ + "annotations": { + "list": [ + { + "builtIn": 1, + "datasource": "-- Grafana --", + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations & Alerts", + "type": "dashboard" + } + ] + }, + "editable": false, + "gnetId": null, + "graphTooltip": 1, + "id": 6, + "links": [], + "panels": [ + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 0 + }, + "id": 60, + "panels": [], + "title": "Deployed Versions", + "type": "row" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 5, + "w": 24, + "x": 0, + "y": 1 + }, + "id": 56, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(istio_build{component=\"pilot\"}) by (tag)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{ tag }}", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Pilot Versions", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 6 + }, + "id": 62, + "panels": [], + "title": "Resource Usage", + "type": "row" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 7, + "w": 6, + "x": 0, + "y": 7 + }, + "id": 5, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "process_virtual_memory_bytes{job=\"pilot\"}", + "format": "time_series", + "instant": false, + "intervalFactor": 2, + "legendFormat": "Virtual Memory", + "refId": "I", + "step": 2 + }, + { + "expr": "process_resident_memory_bytes{job=\"pilot\"}", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "Resident Memory", + "refId": "H", + "step": 2 + }, + { + "expr": "go_memstats_heap_sys_bytes{job=\"pilot\"}", + "format": "time_series", + "hide": true, + "intervalFactor": 2, + "legendFormat": "heap sys", + "refId": "A" + }, + { + "expr": "go_memstats_heap_alloc_bytes{job=\"pilot\"}", + "format": "time_series", + "hide": true, + "intervalFactor": 2, + "legendFormat": "heap alloc", + "refId": "D" + }, + { + "expr": "go_memstats_alloc_bytes{job=\"pilot\"}", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "Alloc", + "refId": "F", + "step": 2 + }, + { + "expr": "go_memstats_heap_inuse_bytes{job=\"pilot\"}", + "format": "time_series", + "hide": false, + "intervalFactor": 2, + "legendFormat": "Heap in-use", + "refId": "E", + "step": 2 + }, + { + "expr": "go_memstats_stack_inuse_bytes{job=\"pilot\"}", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "Stack in-use", + "refId": "G", + "step": 2 + }, + { + "expr": "sum(container_memory_usage_bytes{container_name=~\"discovery|istio-proxy\", pod_name=~\"istio-pilot-.*\"})", + "format": "time_series", + "hide": false, + "intervalFactor": 2, + "legendFormat": "Total (k8s)", + "refId": "C", + "step": 2 + }, + { + "expr": "container_memory_usage_bytes{container_name=~\"discovery|istio-proxy\", pod_name=~\"istio-pilot-.*\"}", + "format": "time_series", + "hide": false, + "intervalFactor": 2, + "legendFormat": "{{ container_name }} (k8s)", + "refId": "B", + "step": 2 + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Memory", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "bytes", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 7, + "w": 6, + "x": 6, + "y": 7 + }, + "id": 6, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(rate(container_cpu_usage_seconds_total{job=\"kubernetes-cadvisor\",container_name=~\"discovery|istio-proxy\", pod_name=~\"istio-pilot-.*\"}[1m]))", + "format": "time_series", + "hide": false, + "intervalFactor": 2, + "legendFormat": "Total (k8s)", + "refId": "A", + "step": 2 + }, + { + "expr": "sum(rate(container_cpu_usage_seconds_total{job=\"kubernetes-cadvisor\",container_name=~\"discovery|istio-proxy\", pod_name=~\"istio-pilot-.*\"}[1m])) by (container_name)", + "format": "time_series", + "hide": false, + "intervalFactor": 2, + "legendFormat": "{{ container_name }} (k8s)", + "refId": "B", + "step": 2 + }, + { + "expr": "irate(process_cpu_seconds_total{job=\"pilot\"}[1m])", + "format": "time_series", + "hide": false, + "intervalFactor": 2, + "legendFormat": "pilot (self-reported)", + "refId": "C", + "step": 2 + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "CPU", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 7, + "w": 6, + "x": 12, + "y": 7 + }, + "id": 7, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "process_open_fds{job=\"pilot\"}", + "format": "time_series", + "hide": true, + "instant": false, + "interval": "", + "intervalFactor": 2, + "legendFormat": "Open FDs (pilot)", + "refId": "A" + }, + { + "expr": "container_fs_usage_bytes{container_name=~\"discovery|istio-proxy\", pod_name=~\"istio-pilot-.*\"}", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "{{ container_name }}", + "refId": "B", + "step": 2 + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Disk", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "bytes", + "label": "", + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "decimals": null, + "format": "none", + "label": "", + "logBase": 1024, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 7, + "w": 6, + "x": 18, + "y": 7 + }, + "id": 4, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": false, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "go_goroutines{job=\"istio-pilot\"}", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "Number of Goroutines", + "refId": "A", + "step": 2 + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Goroutines", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": "", + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 14 + }, + "id": 58, + "panels": [], + "title": "Pilot Push Information", + "type": "row" + }, + { + "aliasColors": {}, + "bars": true, + "dashLength": 10, + "dashes": false, + "description": "Shows pilot pushes", + "fill": 1, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 15 + }, + "id": 622, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": false, + "linewidth": 1, + "links": [], + "nullPointMode": "null as zero", + "paceLength": 10, + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": true, + "steppedLine": false, + "targets": [ + { + "expr": "sum(rate(pilot_xds_pushes{type!~\".*_senderr\"}[1m])) by (type)", + "format": "time_series", + "instant": false, + "interval": "", + "intervalFactor": 1, + "legendFormat": "{{ type }}", + "refId": "B", + "step": 2 + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Pilot Pushes", + "tooltip": { + "shared": false, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [ + "total" + ] + }, + "yaxes": [ + { + "format": "ops", + "label": null, + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "description": "Captures a variety of pilot errors", + "fill": 1, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 15 + }, + "id": 67, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "label_replace(sum(pilot_xds_cds_reject{job=\"pilot\"}) by (node, err), \"node\", \"$1\", \"node\", \".*~.*~(.*)~.*\")", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "Rejected CDS Configs - {{ node }}: {{ err }}", + "refId": "C" + }, + { + "expr": "pilot_xds_eds_reject{job=\"pilot\"}", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "Rejected EDS Configs", + "refId": "D" + }, + { + "expr": "rate(pilot_xds_write_timeout{job=\"pilot\"}[1m])", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Write Timeouts", + "refId": "F" + }, + { + "expr": "rate(pilot_xds_push_timeout{job=\"pilot\"}[1m])", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Push Timeouts", + "refId": "G" + }, + { + "expr": "sum(rate(pilot_xds_push_errors{job=\"pilot\"}[1m]))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "Push Errors ({{ type }})", + "refId": "I" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Pilot Errors", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 23 + }, + "id": 64, + "panels": [], + "title": "xDS", + "type": "row" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 6, + "w": 8, + "x": 0, + "y": 24 + }, + "id": 40, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(irate(envoy_cluster_update_success{cluster_name=\"xds-grpc\"}[1m]))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "XDS GRPC Successes", + "refId": "C" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Updates", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "ops", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "ops", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 6, + "w": 8, + "x": 8, + "y": 24 + }, + "id": 42, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "round(sum(rate(envoy_cluster_update_attempt{cluster_name=\"xds-grpc\"}[1m])) - sum(rate(envoy_cluster_update_success{cluster_name=\"xds-grpc\"}[1m])))", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "XDS GRPC ", + "refId": "A", + "step": 2 + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Failures", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "ops", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 6, + "w": 8, + "x": 16, + "y": 24 + }, + "id": 41, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(envoy_cluster_upstream_cx_active{cluster_name=\"xds-grpc\"})", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "Pilot (XDS GRPC)", + "refId": "C", + "step": 2 + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Active Connections", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 8, + "w": 8, + "x": 0, + "y": 30 + }, + "id": 45, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "pilot_conflict_inbound_listener{job=\"pilot\"}", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Inbound Listeners", + "refId": "B" + }, + { + "expr": "pilot_conflict_outbound_listener_http_over_current_tcp{job=\"pilot\"}", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Outbound Listeners (http over current tcp)", + "refId": "A" + }, + { + "expr": "pilot_conflict_outbound_listener_tcp_over_current_tcp{job=\"pilot\"}", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Outbound Listeners (tcp over current tcp)", + "refId": "C" + }, + { + "expr": "pilot_conflict_outbound_listener_tcp_over_current_http{job=\"pilot\"}", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Outbound Listeners (tcp over current http)", + "refId": "D" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Conflicts", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 8, + "w": 8, + "x": 8, + "y": 30 + }, + "id": 47, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "pilot_virt_services{job=\"pilot\"}", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Virtual Services", + "refId": "A" + }, + { + "expr": "pilot_services{job=\"pilot\"}", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Services", + "refId": "B" + }, + { + "expr": "label_replace(sum(pilot_xds_cds_reject{job=\"pilot\"}) by (node, err), \"node\", \"$1\", \"node\", \".*~.*~(.*)~.*\")", + "format": "time_series", + "hide": true, + "intervalFactor": 1, + "legendFormat": "Rejected CDS Configs - {{ node }}: {{ err }}", + "refId": "C" + }, + { + "expr": "pilot_xds_eds_reject{job=\"pilot\"}", + "format": "time_series", + "hide": true, + "intervalFactor": 1, + "legendFormat": "Rejected EDS Configs", + "refId": "D" + }, + { + "expr": "pilot_xds{job=\"pilot\"}", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Connected Endpoints", + "refId": "E" + }, + { + "expr": "rate(pilot_xds_write_timeout{job=\"pilot\"}[1m])", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Write Timeouts", + "refId": "F" + }, + { + "expr": "rate(pilot_xds_push_timeout{job=\"pilot\"}[1m])", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Push Timeouts", + "refId": "G" + }, + { + "expr": "rate(pilot_xds_pushes{job=\"pilot\"}[1m])", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Pushes ({{ type }})", + "refId": "H" + }, + { + "expr": "rate(pilot_xds_push_errors{job=\"pilot\"}[1m])", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Push Errors ({{ type }})", + "refId": "I" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "ADS Monitoring", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 8, + "w": 8, + "x": 16, + "y": 30 + }, + "id": 49, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "label_replace(sum(pilot_xds_cds_reject{job=\"pilot\"}) by (node, err), \"node\", \"$1\", \"node\", \".*~.*~(.*)~.*\")", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{ node }} ({{ err }})", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Rejected CDS Configs", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 7, + "w": 8, + "x": 0, + "y": 38 + }, + "id": 52, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "label_replace(sum(pilot_xds_eds_reject{job=\"pilot\"}) by (node, err), \"node\", \"$1\", \"node\", \".*~.*~(.*)~.*\")", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{ node }} ({{err}})", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Rejected EDS Configs", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 7, + "w": 8, + "x": 8, + "y": 38 + }, + "id": 54, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "label_replace(sum(pilot_xds_lds_reject{job=\"pilot\"}) by (node, err), \"node\", \"$1\", \"node\", \".*~.*~(.*)~.*\")", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{ node }} ({{err}})", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Rejected LDS Configs", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 7, + "w": 8, + "x": 16, + "y": 38 + }, + "id": 53, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "label_replace(sum(pilot_xds_rds_reject{job=\"pilot\"}) by (node, err), \"node\", \"$1\", \"node\", \".*~.*~(.*)~.*\")", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{ node }} ({{err}})", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Rejected RDS Configs", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": { + "outbound|80||default-http-backend.kube-system.svc.cluster.local": "rgba(255, 255, 255, 0.97)" + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 7, + "w": 8, + "x": 0, + "y": 45 + }, + "id": 51, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [ + { + "alias": "outbound|80||default-http-backend.kube-system.svc.cluster.local", + "yaxis": 1 + } + ], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(pilot_xds_eds_instances{job=\"pilot\"}) by (cluster)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{ cluster }}", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "EDS Instances", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + } + ], + "refresh": "5s", + "schemaVersion": 18, + "style": "dark", + "tags": [], + "templating": { + "list": [] + }, + "time": { + "from": "now-5m", + "to": "now" + }, + "timepicker": { + "refresh_intervals": [ + "5s", + "10s", + "30s", + "1m", + "5m", + "15m", + "30m", + "1h", + "2h", + "1d" + ], + "time_options": [ + "5m", + "15m", + "1h", + "6h", + "12h", + "24h", + "2d", + "7d", + "30d" + ] + }, + "timezone": "browser", + "title": "Istio Pilot Dashboard", + "uid": "3--MLVZZk", + "version": 1 +} diff --git a/istio-1.3.5/install/kubernetes/operator/charts/istio-telemetry/grafana/fix_datasources.sh b/istio-1.3.5/install/kubernetes/operator/charts/istio-telemetry/grafana/fix_datasources.sh new file mode 100755 index 0000000..0442adf --- /dev/null +++ b/istio-1.3.5/install/kubernetes/operator/charts/istio-telemetry/grafana/fix_datasources.sh @@ -0,0 +1,30 @@ +#!/bin/bash + +# Copyright Istio Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +set -e + +THIS_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" +UX=$(uname) + +for db in "${THIS_DIR}"/dashboards/*.json; do + if [[ ${UX} == "Darwin" ]]; then + # shellcheck disable=SC2016 + sed -i '' 's/${DS_PROMETHEUS}/Prometheus/g' "$db" + else + # shellcheck disable=SC2016 + sed -i 's/${DS_PROMETHEUS}/Prometheus/g' "$db" + fi +done diff --git a/istio-1.3.5/install/kubernetes/operator/charts/istio-telemetry/grafana/templates/_affinity.tpl b/istio-1.3.5/install/kubernetes/operator/charts/istio-telemetry/grafana/templates/_affinity.tpl new file mode 100644 index 0000000..4630b80 --- /dev/null +++ b/istio-1.3.5/install/kubernetes/operator/charts/istio-telemetry/grafana/templates/_affinity.tpl @@ -0,0 +1,93 @@ +{{/* affinity - https://kubernetes.io/docs/concepts/configuration/assign-pod-node/ */}} + +{{- define "nodeaffinity" }} + nodeAffinity: + requiredDuringSchedulingIgnoredDuringExecution: + {{- include "nodeAffinityRequiredDuringScheduling" . }} + preferredDuringSchedulingIgnoredDuringExecution: + {{- include "nodeAffinityPreferredDuringScheduling" . }} +{{- end }} + +{{- define "nodeAffinityRequiredDuringScheduling" }} + nodeSelectorTerms: + - matchExpressions: + - key: beta.kubernetes.io/arch + operator: In + values: + {{- range $key, $val := .Values.global.arch }} + {{- if gt ($val | int) 0 }} + - {{ $key }} + {{- end }} + {{- end }} + {{- $nodeSelector := default .Values.global.defaultNodeSelector .Values.grafana.nodeSelector -}} + {{- range $key, $val := $nodeSelector }} + - key: {{ $key }} + operator: In + values: + - {{ $val }} + {{- end }} +{{- end }} + +{{- define "nodeAffinityPreferredDuringScheduling" }} + {{- range $key, $val := .Values.global.arch }} + {{- if gt ($val | int) 0 }} + - weight: {{ $val | int }} + preference: + matchExpressions: + - key: beta.kubernetes.io/arch + operator: In + values: + - {{ $key }} + {{- end }} + {{- end }} +{{- end }} + +{{- define "podAntiAffinity" }} +{{- if or .Values.grafana.podAntiAffinityLabelSelector .Values.grafana.podAntiAffinityTermLabelSelector}} + podAntiAffinity: + {{- if .Values.grafana.podAntiAffinityLabelSelector }} + requiredDuringSchedulingIgnoredDuringExecution: + {{- include "podAntiAffinityRequiredDuringScheduling" . }} + {{- end }} + {{- if .Values.grafana.podAntiAffinityTermLabelSelector }} + preferredDuringSchedulingIgnoredDuringExecution: + {{- include "podAntiAffinityPreferredDuringScheduling" . }} + {{- end }} +{{- end }} +{{- end }} + +{{- define "podAntiAffinityRequiredDuringScheduling" }} + {{- range $index, $item := .Values.grafana.podAntiAffinityLabelSelector }} + - labelSelector: + matchExpressions: + - key: {{ $item.key }} + operator: {{ $item.operator }} + {{- if $item.values }} + values: + {{- $vals := split "," $item.values }} + {{- range $i, $v := $vals }} + - {{ $v }} + {{- end }} + {{- end }} + topologyKey: {{ $item.topologyKey }} + {{- end }} +{{- end }} + +{{- define "podAntiAffinityPreferredDuringScheduling" }} + {{- range $index, $item := .Values.grafana.podAntiAffinityTermLabelSelector }} + - podAffinityTerm: + labelSelector: + matchExpressions: + - key: {{ $item.key }} + operator: {{ $item.operator }} + {{- if $item.values }} + values: + {{- $vals := split "," $item.values }} + {{- range $i, $v := $vals }} + - {{ $v }} + {{- end }} + {{- end }} + topologyKey: {{ $item.topologyKey }} + weight: 100 + {{- end }} +{{- end }} diff --git a/istio-1.3.5/install/kubernetes/operator/charts/istio-telemetry/grafana/templates/configmap-dashboards.yaml b/istio-1.3.5/install/kubernetes/operator/charts/istio-telemetry/grafana/templates/configmap-dashboards.yaml new file mode 100644 index 0000000..046dbca --- /dev/null +++ b/istio-1.3.5/install/kubernetes/operator/charts/istio-telemetry/grafana/templates/configmap-dashboards.yaml @@ -0,0 +1,16 @@ +{{- $files := .Files }} +{{- range $path, $bytes := .Files.Glob "dashboards/*.json" }} +{{- $filename := trimSuffix (ext $path) (base $path) }} +apiVersion: v1 +kind: ConfigMap +metadata: + name: istio-grafana-configuration-dashboards-{{ $filename }} + namespace: {{ $.Release.Namespace }} + labels: + app: grafana + release: {{ $.Release.Name }} + istio: grafana +data: + {{ base $path }}: '{{ $files.Get $path }}' +--- +{{- end }} diff --git a/istio-1.3.5/install/kubernetes/operator/charts/istio-telemetry/grafana/templates/configmap.yaml b/istio-1.3.5/install/kubernetes/operator/charts/istio-telemetry/grafana/templates/configmap.yaml new file mode 100644 index 0000000..ca1349e --- /dev/null +++ b/istio-1.3.5/install/kubernetes/operator/charts/istio-telemetry/grafana/templates/configmap.yaml @@ -0,0 +1,42 @@ +{{ $datasources := index .Values.grafana.datasources "datasources.yaml" }} +apiVersion: v1 +kind: ConfigMap +metadata: + name: istio-grafana + namespace: {{ .Release.Namespace }} + labels: + app: grafana + release: {{ .Release.Name }} + istio: grafana +data: + datasources.yaml: |- + apiVersion: 1 + datasources: + - name: Prometheus + type: prometheus + orgId: 1 +{{- if .Values.grafana.prometheusNamespace }} + url: http://prometheus.{{ .Values.grafana.prometheusNamespace }}:9090 +{{ else }} + url: http://prometheus:9090 +{{- end }} + access: proxy + isDefault: true + jsonData: + timeInterval: 5s + editable: true + +{{- if $datasources.datasources }} + - + {{- range $key, $value := $datasources.datasources }} +{{ toYaml $value | indent 6 }} + {{- end -}} +{{- end }} + + +{{- if .Values.grafana.dashboardProviders }} + {{- range $key, $value := .Values.grafana.dashboardProviders }} + {{ $key }}: | +{{ toYaml $value | indent 4 }} + {{- end -}} +{{- end -}} diff --git a/istio-1.3.5/install/kubernetes/operator/charts/istio-telemetry/grafana/templates/deployment.yaml b/istio-1.3.5/install/kubernetes/operator/charts/istio-telemetry/grafana/templates/deployment.yaml new file mode 100644 index 0000000..33fad3c --- /dev/null +++ b/istio-1.3.5/install/kubernetes/operator/charts/istio-telemetry/grafana/templates/deployment.yaml @@ -0,0 +1,132 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: grafana + namespace: {{ .Release.Namespace }} + labels: + app: grafana + release: {{ .Release.Name }} +spec: + replicas: {{ .Values.grafana.replicaCount }} + selector: + matchLabels: + app: grafana + template: + metadata: + labels: + app: grafana + chart: grafana + heritage: Tiller + release: istio-system + annotations: + sidecar.istio.io/inject: "false" + spec: + securityContext: + runAsUser: 472 + fsGroup: 472 +{{- if .Values.global.priorityClassName }} + priorityClassName: "{{ .Values.global.priorityClassName }}" +{{- end }} +{{- if .Values.global.imagePullSecrets }} + imagePullSecrets: +{{- range .Values.global.imagePullSecrets }} + - name: {{ . }} +{{- end }} +{{- end }} + containers: + - name: {{ .Chart.Name }} + image: "{{ .Values.grafana.image.repository }}:{{ .Values.grafana.image.tag }}" + imagePullPolicy: {{ .Values.global.imagePullPolicy | default "Always" }} + ports: + - containerPort: 3000 + readinessProbe: + httpGet: + path: /login + port: 3000 + env: + - name: GRAFANA_PORT + value: "3000" +{{- if .Values.grafana.security.enabled }} + - name: GF_SECURITY_ADMIN_USER + valueFrom: + secretKeyRef: + name: {{ .Values.grafana.security.secretName }} + key: {{ .Values.grafana.security.usernameKey }} + - name: GF_SECURITY_ADMIN_PASSWORD + valueFrom: + secretKeyRef: + name: {{ .Values.grafana.security.secretName }} + key: {{ .Values.grafana.security.passphraseKey }} + - name: GF_AUTH_BASIC_ENABLED + value: "true" + - name: GF_AUTH_ANONYMOUS_ENABLED + value: "false" + - name: GF_AUTH_DISABLE_LOGIN_FORM + value: "false" +{{- else }} + - name: GF_AUTH_BASIC_ENABLED + value: "false" + - name: GF_AUTH_ANONYMOUS_ENABLED + value: "true" + - name: GF_AUTH_ANONYMOUS_ORG_ROLE + value: Admin +{{- end }} + - name: GF_PATHS_DATA + value: /data/grafana + {{- range $key, $value := $.Values.env }} + - name: {{ $key }} + value: {{ $value | quote }} + {{- end }} + {{- range $key, $secret := $.Values.envSecrets }} + - name: {{ $key }} + valueFrom: + secretKeyRef: + name: {{ $secret }} + key: {{ $key | quote }} + {{- end }} + resources: +{{- if .Values.grafana.resources }} +{{ toYaml .Values.grafana.resources | indent 12 }} +{{- else }} +{{ toYaml .Values.global.defaultResources | indent 12 }} +{{- end }} + volumeMounts: + - name: data + mountPath: /data/grafana + {{- range $path, $bytes := .Files.Glob "dashboards/*.json" }} + {{- $filename := trimSuffix (ext $path) (base $path) }} + - name: dashboards-istio-{{ $filename }} + mountPath: "/var/lib/grafana/dashboards/istio/{{ base $path }}" + subPath: {{ base $path }} + readOnly: true + {{- end }} + - name: config + mountPath: "/etc/grafana/provisioning/datasources/datasources.yaml" + subPath: datasources.yaml + - name: config + mountPath: "/etc/grafana/provisioning/dashboards/dashboardproviders.yaml" + subPath: dashboardproviders.yaml + affinity: + {{- include "nodeaffinity" . | indent 6 }} + {{- include "podAntiAffinity" . | indent 6 }} +{{- if .Values.grafana.tolerations }} + tolerations: +{{ toYaml .Values.grafana.tolerations | indent 6 }} +{{- end }} + volumes: + - name: config + configMap: + name: istio-grafana + - name: data +{{- if .Values.grafana.persist }} + persistentVolumeClaim: + claimName: istio-grafana-pvc +{{- else }} + emptyDir: {} +{{- end }} +{{- range $path, $bytes := .Files.Glob "dashboards/*.json" }} +{{- $filename := trimSuffix (ext $path) (base $path) }} + - name: dashboards-istio-{{ $filename }} + configMap: + name: istio-grafana-configuration-dashboards-{{ $filename }} +{{- end }} diff --git a/istio-1.3.5/install/kubernetes/operator/charts/istio-telemetry/grafana/templates/destination-rule.yaml b/istio-1.3.5/install/kubernetes/operator/charts/istio-telemetry/grafana/templates/destination-rule.yaml new file mode 100644 index 0000000..141a4a2 --- /dev/null +++ b/istio-1.3.5/install/kubernetes/operator/charts/istio-telemetry/grafana/templates/destination-rule.yaml @@ -0,0 +1,10 @@ +apiVersion: networking.istio.io/v1alpha3 +kind: DestinationRule +metadata: + name: grafana + namespace: {{ .Release.Namespace }} +spec: + host: grafana.{{ .Release.Namespace }} + trafficPolicy: + tls: + mode: DISABLE diff --git a/istio-1.3.5/install/kubernetes/operator/charts/istio-telemetry/grafana/templates/grafana-policy.yaml b/istio-1.3.5/install/kubernetes/operator/charts/istio-telemetry/grafana/templates/grafana-policy.yaml new file mode 100644 index 0000000..223cccf --- /dev/null +++ b/istio-1.3.5/install/kubernetes/operator/charts/istio-telemetry/grafana/templates/grafana-policy.yaml @@ -0,0 +1,13 @@ +apiVersion: authentication.istio.io/v1alpha1 +kind: Policy +metadata: + name: grafana-ports-mtls-disabled + namespace: {{ .Release.Namespace }} + labels: + app: grafana + release: {{ .Release.Name }} +spec: + targets: + - name: grafana + ports: + - number: {{ .Values.grafana.service.externalPort }} diff --git a/istio-1.3.5/install/kubernetes/operator/charts/istio-telemetry/grafana/templates/pvc.yaml b/istio-1.3.5/install/kubernetes/operator/charts/istio-telemetry/grafana/templates/pvc.yaml new file mode 100644 index 0000000..d2d14ae --- /dev/null +++ b/istio-1.3.5/install/kubernetes/operator/charts/istio-telemetry/grafana/templates/pvc.yaml @@ -0,0 +1,16 @@ +{{- if .Values.grafana.persist }} +kind: PersistentVolumeClaim +apiVersion: v1 +metadata: + name: istio-grafana-pvc + labels: + app: grafana + release: {{ .Release.Name }} +spec: + storageClassName: {{ .Values.grafana.storageClassName }} + accessModes: + - {{ .Values.grafana.accessMode }} + resources: + requests: + storage: 5Gi +{{- end }} diff --git a/istio-1.3.5/install/kubernetes/operator/charts/istio-telemetry/grafana/templates/service.yaml b/istio-1.3.5/install/kubernetes/operator/charts/istio-telemetry/grafana/templates/service.yaml new file mode 100644 index 0000000..7854d3a --- /dev/null +++ b/istio-1.3.5/install/kubernetes/operator/charts/istio-telemetry/grafana/templates/service.yaml @@ -0,0 +1,30 @@ +apiVersion: v1 +kind: Service +metadata: + name: grafana + namespace: {{ .Release.Namespace }} + annotations: + {{- range $key, $val := .Values.grafana.service.annotations }} + {{ $key }}: {{ $val | quote }} + {{- end }} + labels: + app: grafana + release: {{ .Release.Name }} +spec: + type: {{ .Values.grafana.service.type }} + ports: + - port: {{ .Values.grafana.service.externalPort }} + targetPort: 3000 + protocol: TCP + name: {{ .Values.grafana.service.name }} + selector: + app: grafana +{{- if .Values.grafana.service.loadBalancerIP }} + loadBalancerIP: "{{ .Values.grafana.service.loadBalancerIP }}" +{{- end }} + {{if .Values.grafana.service.loadBalancerSourceRanges}} + loadBalancerSourceRanges: + {{range $rangeList := .Values.grafana.service.loadBalancerSourceRanges}} + - {{ $rangeList }} + {{end}} + {{end}} \ No newline at end of file diff --git a/istio-1.3.5/install/kubernetes/operator/charts/istio-telemetry/grafana/templates/tests/test-grafana-connection.yaml b/istio-1.3.5/install/kubernetes/operator/charts/istio-telemetry/grafana/templates/tests/test-grafana-connection.yaml new file mode 100644 index 0000000..79e3f79 --- /dev/null +++ b/istio-1.3.5/install/kubernetes/operator/charts/istio-telemetry/grafana/templates/tests/test-grafana-connection.yaml @@ -0,0 +1,28 @@ +{{- if .Values.global.enableHelmTest }} +apiVersion: v1 +kind: Pod +metadata: + name: grafana-test + namespace: {{ .Release.Namespace }} + labels: + app: grafana-test + release: {{ .Release.Name }} + istio: grafana + annotations: + sidecar.istio.io/inject: "false" + helm.sh/hook: test-success +spec: +{{- if .Values.global.priorityClassName }} + priorityClassName: "{{ .Values.global.priorityClassName }}" +{{- end }} + containers: + - name: "grafana-test" + image: {{ .Values.global.hub }}/{{ .Values.global.proxy.image }}:{{ .Values.global.tag }} + imagePullPolicy: "{{ .Values.global.imagePullPolicy }}" + command: ['curl'] + args: ['http://grafana:{{ .Values.grafana.service.externalPort }}'] + restartPolicy: Never + affinity: + {{- include "nodeaffinity" . | indent 4 }} + {{- include "podAntiAffinity" . | indent 4 }} +{{- end }} diff --git a/istio-1.3.5/install/kubernetes/operator/charts/istio-telemetry/grafana/values.yaml b/istio-1.3.5/install/kubernetes/operator/charts/istio-telemetry/grafana/values.yaml new file mode 100644 index 0000000..71ced38 --- /dev/null +++ b/istio-1.3.5/install/kubernetes/operator/charts/istio-telemetry/grafana/values.yaml @@ -0,0 +1,121 @@ +grafana: + enabled: true + replicaCount: 1 + image: + repository: grafana/grafana + tag: 6.1.6 + persist: false + storageClassName: "" + accessMode: ReadWriteMany + security: + enabled: false + secretName: grafana + usernameKey: username + passphraseKey: passphrase + + contextPath: /grafana + service: + annotations: {} + name: http + type: ClusterIP + externalPort: 3000 + loadBalancerIP: + loadBalancerSourceRanges: + + ingress: + enabled: false + ## Used to create an Ingress record. + hosts: + - grafana.local + annotations: + # kubernetes.io/ingress.class: nginx + # kubernetes.io/tls-acme: "true" + tls: + # Secrets must be manually created in the namespace. + # - secretName: grafana-tls + # hosts: + # - grafana.local + + # Optional: prometheus may be deployed in a different namespace + # prometheusNamespace: istio-telemetry + + # Additional datasources. Prometheus included in the config map. + datasources: + datasources.yaml: + apiVersion: 1 + datasources: + # - name: Prometheus2 + # type: prometheus2 + # orgId: 2 + # url: http://prometheus:9090 + # access: proxy + # isDefault: false + # jsonData: + # timeInterval: 5s + # editable: true + + dashboardProviders: + dashboardproviders.yaml: + apiVersion: 1 + providers: + - name: 'istio' + orgId: 1 + folder: 'istio' + type: file + disableDeletion: false + options: + path: /var/lib/grafana/dashboards/istio + + nodeSelector: {} + tolerations: [] + + env: {} + # Define additional environment variables for configuring grafana. + # @see https://grafana.com/docs/installation/configuration/#using-environment-variables + # Format: env_variable_name: value + # For example: + # GF_SMTP_ENABLED: true + # GF_SMTP_HOST: email-smtp.eu-west-1.amazonaws.com:2587 + # GF_SMTP_FROM_ADDRESS: alerts@mydomain.com + # GF_SMTP_FROM_NAME: Grafana + + envSecrets: {} + # The key name and ENV name must match in the secrets file. + # @see https://grafana.com/docs/installation/configuration/#using-environment-variables + # For example: + # --- + # apiVersion: v1 + # kind: Secret + # metadata: + # name: grafana-secrets + # namespace: istio-system + # data: + # GF_SMTP_USER: bXl1c2Vy + # GF_SMTP_PASSWORD: bXlwYXNzd29yZA== + # type: Opaque + # --- + # env_variable_key_name: secretsName + # --- + # GF_SMTP_USER: grafana-secrets + # GF_SMTP_PASSWORD: grafana-secrets + + # Specify the pod anti-affinity that allows you to constrain which nodes + # your pod is eligible to be scheduled based on labels on pods that are + # already running on the node rather than based on labels on nodes. + # There are currently two types of anti-affinity: + # "requiredDuringSchedulingIgnoredDuringExecution" + # "preferredDuringSchedulingIgnoredDuringExecution" + # which denote "hard" vs. "soft" requirements, you can define your values + # in "podAntiAffinityLabelSelector" and "podAntiAffinityTermLabelSelector" + # correspondingly. + # For example: + # podAntiAffinityLabelSelector: + # - key: security + # operator: In + # values: S1,S2 + # topologyKey: "kubernetes.io/hostname" + # This pod anti-affinity rule says that the pod requires not to be scheduled + # onto a node if that node is already running a pod with label having key + # "security" and value "S1". + podAntiAffinityLabelSelector: [] + podAntiAffinityTermLabelSelector: [] diff --git a/istio-1.3.5/install/kubernetes/operator/charts/istio-telemetry/kiali/Chart.yaml b/istio-1.3.5/install/kubernetes/operator/charts/istio-telemetry/kiali/Chart.yaml new file mode 100644 index 0000000..9d6ac19 --- /dev/null +++ b/istio-1.3.5/install/kubernetes/operator/charts/istio-telemetry/kiali/Chart.yaml @@ -0,0 +1,6 @@ +apiVersion: v1 +description: Kiali is an open source project for service mesh observability, refer to https://www.kiali.io for details. +name: kiali +version: 1.1.0 +appVersion: 1.1.0 +tillerVersion: ">=2.7.2" diff --git a/istio-1.3.5/install/kubernetes/operator/charts/istio-telemetry/kiali/templates/_affinity.tpl b/istio-1.3.5/install/kubernetes/operator/charts/istio-telemetry/kiali/templates/_affinity.tpl new file mode 100644 index 0000000..333eb9a --- /dev/null +++ b/istio-1.3.5/install/kubernetes/operator/charts/istio-telemetry/kiali/templates/_affinity.tpl @@ -0,0 +1,93 @@ +{{/* affinity - https://kubernetes.io/docs/concepts/configuration/assign-pod-node/ */}} + +{{- define "nodeaffinity" }} + nodeAffinity: + requiredDuringSchedulingIgnoredDuringExecution: + {{- include "nodeAffinityRequiredDuringScheduling" . }} + preferredDuringSchedulingIgnoredDuringExecution: + {{- include "nodeAffinityPreferredDuringScheduling" . }} +{{- end }} + +{{- define "nodeAffinityRequiredDuringScheduling" }} + nodeSelectorTerms: + - matchExpressions: + - key: beta.kubernetes.io/arch + operator: In + values: + {{- range $key, $val := .Values.global.arch }} + {{- if gt ($val | int) 0 }} + - {{ $key }} + {{- end }} + {{- end }} + {{- $nodeSelector := default .Values.global.defaultNodeSelector .Values.nodeSelector -}} + {{- range $key, $val := $nodeSelector }} + - key: {{ $key }} + operator: In + values: + - {{ $val }} + {{- end }} +{{- end }} + +{{- define "nodeAffinityPreferredDuringScheduling" }} + {{- range $key, $val := .Values.global.arch }} + {{- if gt ($val | int) 0 }} + - weight: {{ $val | int }} + preference: + matchExpressions: + - key: beta.kubernetes.io/arch + operator: In + values: + - {{ $key }} + {{- end }} + {{- end }} +{{- end }} + +{{- define "podAntiAffinity" }} +{{- if or .Values.podAntiAffinityLabelSelector .Values.podAntiAffinityTermLabelSelector}} + podAntiAffinity: + {{- if .Values.podAntiAffinityLabelSelector }} + requiredDuringSchedulingIgnoredDuringExecution: + {{- include "podAntiAffinityRequiredDuringScheduling" . }} + {{- end }} + {{- if or .Values.podAntiAffinityTermLabelSelector}} + preferredDuringSchedulingIgnoredDuringExecution: + {{- include "podAntiAffinityPreferredDuringScheduling" . }} + {{- end }} +{{- end }} +{{- end }} + +{{- define "podAntiAffinityRequiredDuringScheduling" }} + {{- range $index, $item := .Values.podAntiAffinityLabelSelector }} + - labelSelector: + matchExpressions: + - key: {{ $item.key }} + operator: {{ $item.operator }} + {{- if $item.values }} + values: + {{- $vals := split "," $item.values }} + {{- range $i, $v := $vals }} + - {{ $v }} + {{- end }} + {{- end }} + topologyKey: {{ $item.topologyKey }} + {{- end }} +{{- end }} + +{{- define "podAntiAffinityPreferredDuringScheduling" }} + {{- range $index, $item := .Values.podAntiAffinityTermLabelSelector }} + - podAffinityTerm: + labelSelector: + matchExpressions: + - key: {{ $item.key }} + operator: {{ $item.operator }} + {{- if $item.values }} + values: + {{- $vals := split "," $item.values }} + {{- range $i, $v := $vals }} + - {{ $v }} + {{- end }} + {{- end }} + topologyKey: {{ $item.topologyKey }} + weight: 100 + {{- end }} +{{- end }} diff --git a/istio-1.3.5/install/kubernetes/operator/charts/istio-telemetry/kiali/templates/clusterrole.yaml b/istio-1.3.5/install/kubernetes/operator/charts/istio-telemetry/kiali/templates/clusterrole.yaml new file mode 100644 index 0000000..f67b05a --- /dev/null +++ b/istio-1.3.5/install/kubernetes/operator/charts/istio-telemetry/kiali/templates/clusterrole.yaml @@ -0,0 +1,237 @@ +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: kiali + labels: + app: kiali + release: {{ .Release.Name }} +rules: + - apiGroups: [""] + resources: + - configmaps + - endpoints + - namespaces + - nodes + - pods + - services + - replicationcontrollers + verbs: + - get + - list + - watch + - apiGroups: ["extensions", "apps"] + resources: + - deployments + - statefulsets + - replicasets + verbs: + - get + - list + - watch + - apiGroups: ["autoscaling"] + resources: + - horizontalpodautoscalers + verbs: + - get + - list + - watch + - apiGroups: ["batch"] + resources: + - cronjobs + - jobs + verbs: + - get + - list + - watch + - apiGroups: ["config.istio.io"] + resources: + - apikeys + - authorizations + - checknothings + - circonuses + - deniers + - fluentds + - handlers + - kubernetesenvs + - kuberneteses + - listcheckers + - listentries + - logentries + - memquotas + - metrics + - opas + - prometheuses + - quotas + - quotaspecbindings + - quotaspecs + - rbacs + - reportnothings + - rules + - solarwindses + - stackdrivers + - statsds + - stdios + verbs: + - create + - delete + - get + - list + - patch + - watch + - apiGroups: ["networking.istio.io"] + resources: + - destinationrules + - gateways + - serviceentries + - sidecars + - virtualservices + verbs: + - create + - delete + - get + - list + - patch + - watch + - apiGroups: ["authentication.istio.io"] + resources: + - policies + - meshpolicies + verbs: + - create + - delete + - get + - list + - patch + - watch + - apiGroups: ["rbac.istio.io"] + resources: + - clusterrbacconfigs + - rbacconfigs + - serviceroles + - servicerolebindings + verbs: + - create + - delete + - get + - list + - patch + - watch + - apiGroups: ["monitoring.kiali.io"] + resources: + - monitoringdashboards + verbs: + - get +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: kiali-viewer + labels: + app: kiali + release: {{ .Release.Name }} +rules: + - apiGroups: [""] + resources: + - configmaps + - endpoints + - namespaces + - nodes + - pods + - services + - replicationcontrollers + verbs: + - get + - list + - watch + - apiGroups: ["extensions", "apps"] + resources: + - deployments + - statefulsets + - replicasets + verbs: + - get + - list + - watch + - apiGroups: ["autoscaling"] + resources: + - horizontalpodautoscalers + verbs: + - get + - list + - watch + - apiGroups: ["batch"] + resources: + - cronjobs + - jobs + verbs: + - get + - list + - watch + - apiGroups: ["config.istio.io"] + resources: + - apikeys + - authorizations + - checknothings + - circonuses + - deniers + - fluentds + - handlers + - kubernetesenvs + - kuberneteses + - listcheckers + - listentries + - logentries + - memquotas + - metrics + - opas + - prometheuses + - quotas + - quotaspecbindings + - quotaspecs + - rbacs + - reportnothings + - rules + - servicecontrolreports + - servicecontrols + - solarwindses + - stackdrivers + - statsds + - stdios + verbs: + - get + - list + - watch + - apiGroups: ["networking.istio.io"] + resources: + - destinationrules + - gateways + - serviceentries + - sidecars + - virtualservices + verbs: + - get + - list + - watch + - apiGroups: ["authentication.istio.io"] + resources: + - policies + - meshpolicies + verbs: + - get + - list + - watch + - apiGroups: ["rbac.istio.io"] + resources: + - clusterrbacconfigs + - rbacconfigs + - serviceroles + - servicerolebindings + verbs: + - get + - list + - watch + - apiGroups: ["monitoring.kiali.io"] + resources: + - monitoringdashboards + verbs: + - get diff --git a/istio-1.3.5/install/kubernetes/operator/charts/istio-telemetry/kiali/templates/clusterrolebinding.yaml b/istio-1.3.5/install/kubernetes/operator/charts/istio-telemetry/kiali/templates/clusterrolebinding.yaml new file mode 100644 index 0000000..14a1bf3 --- /dev/null +++ b/istio-1.3.5/install/kubernetes/operator/charts/istio-telemetry/kiali/templates/clusterrolebinding.yaml @@ -0,0 +1,33 @@ +{{- if not .Values.kiali.dashboard.viewOnlyMode }} +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: kiali + labels: + app: kiali + release: {{ .Release.Name }} +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: kiali +subjects: + - kind: ServiceAccount + name: kiali-service-account + namespace: {{ .Release.Namespace }} +{{- else }} +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: istio-kiali-viewer-role-binding-{{ .Release.Namespace }} + labels: + app: kiali + release: {{ .Release.Name }} +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: kiali-viewer +subjects: +- kind: ServiceAccount + name: kiali-service-account + namespace: {{ .Release.Namespace }} +{{- end }} diff --git a/istio-1.3.5/install/kubernetes/operator/charts/istio-telemetry/kiali/templates/configmap.yaml b/istio-1.3.5/install/kubernetes/operator/charts/istio-telemetry/kiali/templates/configmap.yaml new file mode 100644 index 0000000..eddd387 --- /dev/null +++ b/istio-1.3.5/install/kubernetes/operator/charts/istio-telemetry/kiali/templates/configmap.yaml @@ -0,0 +1,28 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: kiali + namespace: {{ .Release.Namespace }} + labels: + app: kiali + release: {{ .Release.Name }} +data: + config.yaml: | + istio_namespace: {{ .Release.Namespace }} + server: + port: 20001 +{{- if .Values.kiali.contextPath }} + web_root: {{ .Values.kiali.contextPath }} +{{- end }} + external_services: + istio: + url_service_version: http://istio-pilot.{{ .Values.global.istioNamespace }}:8080/version + jaeger: + url: {{ .Values.kiali.dashboard.jaegerURL }} + grafana: + url: {{ .Values.kiali.dashboard.grafanaURL }} +{{- if .Values.kiali.security.enabled }} + identity: + cert_file: {{ .Values.kiali.security.cert_file }} + private_key_file: {{ .Values.kiali.security.private_key_file }} +{{- end}} \ No newline at end of file diff --git a/istio-1.3.5/install/kubernetes/operator/charts/istio-telemetry/kiali/templates/demosecret.yaml b/istio-1.3.5/install/kubernetes/operator/charts/istio-telemetry/kiali/templates/demosecret.yaml new file mode 100644 index 0000000..7a48b82 --- /dev/null +++ b/istio-1.3.5/install/kubernetes/operator/charts/istio-telemetry/kiali/templates/demosecret.yaml @@ -0,0 +1,14 @@ +{{- if .Values.kiali.createDemoSecret }} +apiVersion: v1 +kind: Secret +metadata: + name: {{ .Values.kiali.dashboard.secretName }} + namespace: {{ .Release.Namespace }} + labels: + app: kiali + release: {{ .Release.Name }} +type: Opaque +data: + username: YWRtaW4= # admin + passphrase: YWRtaW4= # admin + {{- end }} diff --git a/istio-1.3.5/install/kubernetes/operator/charts/istio-telemetry/kiali/templates/deployment.yaml b/istio-1.3.5/install/kubernetes/operator/charts/istio-telemetry/kiali/templates/deployment.yaml new file mode 100644 index 0000000..9515190 --- /dev/null +++ b/istio-1.3.5/install/kubernetes/operator/charts/istio-telemetry/kiali/templates/deployment.yaml @@ -0,0 +1,99 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: kiali + namespace: {{ .Release.Namespace }} + labels: + app: kiali + release: {{ .Release.Name }} +spec: + replicas: {{ .Values.kiali.replicaCount }} + selector: + matchLabels: + app: kiali + template: + metadata: + name: kiali + labels: + app: kiali + release: {{ .Release.Name }} + annotations: + sidecar.istio.io/inject: "false" + scheduler.alpha.kubernetes.io/critical-pod: "" + prometheus.io/scrape: "true" + prometheus.io/port: "9090" + kiali.io/runtimes: go,kiali + spec: + serviceAccountName: kiali-service-account +{{- if .Values.global.priorityClassName }} + priorityClassName: "{{ .Values.global.priorityClassName }}" +{{- end }} + containers: + - image: "{{ .Values.kiali.hub }}/{{ .Values.kiali.image }}:{{ .Values.kiali.tag }}" + imagePullPolicy: {{ .Values.global.imagePullPolicy | default "Always" }} + name: kiali + command: + - "/opt/kiali/kiali" + - "-config" + - "/kiali-configuration/config.yaml" + - "-v" + - "3" + readinessProbe: + httpGet: + path: {{ .Values.kiali.contextPath }}/healthz + port: 20001 + scheme: {{ if .Values.kiali.security.enabled }} 'HTTPS' {{ else }} 'HTTP' {{ end }} + initialDelaySeconds: 5 + periodSeconds: 30 + livenessProbe: + httpGet: + path: {{ .Values.kiali.contextPath }}/healthz + port: 20001 + scheme: {{ if .Values.kiali.security.enabled }} 'HTTPS' {{ else }} 'HTTP' {{ end }} + initialDelaySeconds: 5 + periodSeconds: 30 + env: + - name: ACTIVE_NAMESPACE + valueFrom: + fieldRef: + fieldPath: metadata.namespace + - name: PROMETHEUS_SERVICE_URL + {{- if .Values.global.prometheusNamespace }} + value: http://prometheus.{{ .Values.global.prometheusNamespace }}:9090 + {{ else }} + value: http://prometheus:9090 + {{- end }} +{{- if .Values.kiali.contextPath }} + - name: SERVER_WEB_ROOT + value: {{ .Values.kiali.contextPath }} +{{- end }} + volumeMounts: + - name: kiali-configuration + mountPath: "/kiali-configuration" + - name: kiali-cert + mountPath: "/kiali-cert" + - name: kiali-secret + mountPath: "/kiali-secret" + resources: +{{- if .Values.kiali.resources }} +{{ toYaml .Values.kiali.resources | indent 10 }} +{{- else }} +{{ toYaml .Values.global.defaultResources | indent 10 }} +{{- end }} + volumes: + - name: kiali-configuration + configMap: + name: kiali + - name: kiali-cert + secret: + secretName: istio.kiali-service-account +{{- if not .Values.kiali.security.enabled }} + optional: true +{{- end }} + - name: kiali-secret + secret: + secretName: {{ .Values.kiali.dashboard.secretName }} + optional: true + affinity: + {{- include "nodeaffinity" . | indent 6 }} + {{- include "podAntiAffinity" . | indent 6 }} diff --git a/istio-1.3.5/install/kubernetes/operator/charts/istio-telemetry/kiali/templates/service.yaml b/istio-1.3.5/install/kubernetes/operator/charts/istio-telemetry/kiali/templates/service.yaml new file mode 100644 index 0000000..3b4f9c6 --- /dev/null +++ b/istio-1.3.5/install/kubernetes/operator/charts/istio-telemetry/kiali/templates/service.yaml @@ -0,0 +1,15 @@ +apiVersion: v1 +kind: Service +metadata: + name: kiali + namespace: {{ .Release.Namespace }} + labels: + app: kiali + release: {{ .Release.Name }} +spec: + ports: + - name: http-kiali + protocol: TCP + port: 20001 + selector: + app: kiali diff --git a/istio-1.3.5/install/kubernetes/operator/charts/istio-telemetry/kiali/templates/serviceaccount.yaml b/istio-1.3.5/install/kubernetes/operator/charts/istio-telemetry/kiali/templates/serviceaccount.yaml new file mode 100644 index 0000000..54824ba --- /dev/null +++ b/istio-1.3.5/install/kubernetes/operator/charts/istio-telemetry/kiali/templates/serviceaccount.yaml @@ -0,0 +1,14 @@ +apiVersion: v1 +kind: ServiceAccount + {{- if .Values.global.imagePullSecrets }} +imagePullSecrets: + {{- range .Values.global.imagePullSecrets }} +- name: {{ . }} + {{- end }} + {{- end }} +metadata: + name: kiali-service-account + namespace: {{ .Release.Namespace }} + labels: + app: kiali + release: {{ .Release.Name }} diff --git a/istio-1.3.5/install/kubernetes/operator/charts/istio-telemetry/kiali/values.yaml b/istio-1.3.5/install/kubernetes/operator/charts/istio-telemetry/kiali/values.yaml new file mode 100644 index 0000000..7a75d2f --- /dev/null +++ b/istio-1.3.5/install/kubernetes/operator/charts/istio-telemetry/kiali/values.yaml @@ -0,0 +1,65 @@ +# +# addon kiali +# +kiali: + enabled: false # Note that if using the demo or demo-auth yaml when installing via Helm, this default will be `true`. + replicaCount: 1 + hub: docker.io/kiali + tag: v1.1.0 + image: kiali + contextPath: /kiali # The root context path to access the Kiali UI. + nodeSelector: {} + + # Specify the pod anti-affinity that allows you to constrain which nodes + # your pod is eligible to be scheduled based on labels on pods that are + # already running on the node rather than based on labels on nodes. + # There are currently two types of anti-affinity: + # "requiredDuringSchedulingIgnoredDuringExecution" + # "preferredDuringSchedulingIgnoredDuringExecution" + # which denote "hard" vs. "soft" requirements, you can define your values + # in "podAntiAffinityLabelSelector" and "podAntiAffinityTermLabelSelector" + # correspondingly. + # For example: + # podAntiAffinityLabelSelector: + # - key: security + # operator: In + # values: S1,S2 + # topologyKey: "kubernetes.io/hostname" + # This pod anti-affinity rule says that the pod requires not to be scheduled + # onto a node if that node is already running a pod with label having key + # "security" and value "S1". + podAntiAffinityLabelSelector: [] + podAntiAffinityTermLabelSelector: [] + + ingress: + enabled: false + ## Used to create an Ingress record. + hosts: + - kiali.local + annotations: + # kubernetes.io/ingress.class: nginx + # kubernetes.io/tls-acme: "true" + tls: + # Secrets must be manually created in the namespace. + # - secretName: kiali-tls + # hosts: + # - kiali.local + + dashboard: + secretName: kiali # You must create a secret with this name - one is not provided out-of-box. + usernameKey: username # This is the key name within the secret whose value is the actual username. + passphraseKey: passphrase # This is the key name within the secret whose value is the actual passphrase. + viewOnlyMode: false # Bind the service account to a role with only read access + grafanaURL: # If you have Grafana installed and it is accessible to client browsers, then set this to its external URL. Kiali will redirect users to this URL when Grafana metrics are to be shown. + jaegerURL: # If you have Jaeger installed and it is accessible to client browsers, then set this property to its external URL. Kiali will redirect users to this URL when Jaeger tracing is to be shown. + + # Optional: prometheus may be deployed in a different namespace + prometheusNamespace: + + # When true, a secret will be created with a default username and password. Useful for demos. + createDemoSecret: true + + security: + enabled: true + cert_file: /kiali-cert/cert-chain.pem + private_key_file: /kiali-cert/key.pem diff --git a/istio-1.3.5/install/kubernetes/operator/charts/istio-telemetry/mixer-telemetry/Chart.yaml b/istio-1.3.5/install/kubernetes/operator/charts/istio-telemetry/mixer-telemetry/Chart.yaml new file mode 100644 index 0000000..5356739 --- /dev/null +++ b/istio-1.3.5/install/kubernetes/operator/charts/istio-telemetry/mixer-telemetry/Chart.yaml @@ -0,0 +1,13 @@ +apiVersion: v1 +name: mixer-telemetry +version: 1.1.0 +appVersion: 1.1.0 +tillerVersion: ">=2.7.2" +description: Helm chart for mixer deployment +keywords: + - istio + - mixer +sources: + - http://github.com/istio/istio +engine: gotpl +icon: https://istio.io/favicons/android-192x192.png diff --git a/istio-1.3.5/install/kubernetes/operator/charts/istio-telemetry/mixer-telemetry/templates/_affinity.tpl b/istio-1.3.5/install/kubernetes/operator/charts/istio-telemetry/mixer-telemetry/templates/_affinity.tpl new file mode 100644 index 0000000..9c4f998 --- /dev/null +++ b/istio-1.3.5/install/kubernetes/operator/charts/istio-telemetry/mixer-telemetry/templates/_affinity.tpl @@ -0,0 +1,93 @@ +{{/* affinity - https://kubernetes.io/docs/concepts/configuration/assign-pod-node/ */}} + +{{- define "nodeaffinity" }} + nodeAffinity: + requiredDuringSchedulingIgnoredDuringExecution: + {{- include "nodeAffinityRequiredDuringScheduling" . }} + preferredDuringSchedulingIgnoredDuringExecution: + {{- include "nodeAffinityPreferredDuringScheduling" . }} +{{- end }} + +{{- define "nodeAffinityRequiredDuringScheduling" }} + nodeSelectorTerms: + - matchExpressions: + - key: beta.kubernetes.io/arch + operator: In + values: + {{- range $key, $val := .Values.global.arch }} + {{- if gt ($val | int) 0 }} + - {{ $key }} + {{- end }} + {{- end }} + {{- $nodeSelector := default .Values.global.defaultNodeSelector .Values.mixer.telemetry.nodeSelector -}} + {{- range $key, $val := $nodeSelector }} + - key: {{ $key }} + operator: In + values: + - {{ $val }} + {{- end }} +{{- end }} + +{{- define "nodeAffinityPreferredDuringScheduling" }} + {{- range $key, $val := .Values.global.arch }} + {{- if gt ($val | int) 0 }} + - weight: {{ $val | int }} + preference: + matchExpressions: + - key: beta.kubernetes.io/arch + operator: In + values: + - {{ $key }} + {{- end }} + {{- end }} +{{- end }} + +{{- define "podAntiAffinity" }} +{{- if or .Values.mixer.telemetry.podAntiAffinityLabelSelector .Values.mixer.telemetry.podAntiAffinityTermLabelSelector}} + podAntiAffinity: + {{- if .Values.mixer.telemetry.podAntiAffinityLabelSelector }} + requiredDuringSchedulingIgnoredDuringExecution: + {{- include "podAntiAffinityRequiredDuringScheduling" . }} + {{- end }} + {{- if .Values.mixer.telemetry.podAntiAffinityTermLabelSelector }} + preferredDuringSchedulingIgnoredDuringExecution: + {{- include "podAntiAffinityPreferredDuringScheduling" . }} + {{- end }} +{{- end }} +{{- end }} + +{{- define "podAntiAffinityRequiredDuringScheduling" }} + {{- range $index, $item := .Values.mixer.telemetry.podAntiAffinityLabelSelector }} + - labelSelector: + matchExpressions: + - key: {{ $item.key }} + operator: {{ $item.operator }} + {{- if $item.values }} + values: + {{- $vals := split "," $item.values }} + {{- range $i, $v := $vals }} + - {{ $v }} + {{- end }} + {{- end }} + topologyKey: {{ $item.topologyKey }} + {{- end }} +{{- end }} + +{{- define "podAntiAffinityPreferredDuringScheduling" }} + {{- range $index, $item := .Values.mixer.telemetry.podAntiAffinityTermLabelSelector }} + - podAffinityTerm: + labelSelector: + matchExpressions: + - key: {{ $item.key }} + operator: {{ $item.operator }} + {{- if $item.values }} + values: + {{- $vals := split "," $item.values }} + {{- range $i, $v := $vals }} + - {{ $v }} + {{- end }} + {{- end }} + topologyKey: {{ $item.topologyKey }} + weight: 100 + {{- end }} +{{- end }} diff --git a/istio-1.3.5/install/kubernetes/operator/charts/istio-telemetry/mixer-telemetry/templates/autoscale.yaml b/istio-1.3.5/install/kubernetes/operator/charts/istio-telemetry/mixer-telemetry/templates/autoscale.yaml new file mode 100644 index 0000000..0e458db --- /dev/null +++ b/istio-1.3.5/install/kubernetes/operator/charts/istio-telemetry/mixer-telemetry/templates/autoscale.yaml @@ -0,0 +1,23 @@ +{{- if .Values.mixer.telemetry.autoscaleMin }} +apiVersion: autoscaling/v2beta1 +kind: HorizontalPodAutoscaler +metadata: + name: istio-telemetry + namespace: {{ .Release.Namespace }} + labels: + release: {{ .Release.Name }} + app: istio-telemetry +spec: + maxReplicas: {{ .Values.mixer.telemetry.autoscaleMax }} + minReplicas: {{ .Values.mixer.telemetry.autoscaleMin }} + scaleTargetRef: + apiVersion: apps/v1 + kind: Deployment + name: istio-telemetry + metrics: + - type: Resource + resource: + name: cpu + targetAverageUtilization: {{ .Values.mixer.telemetry.cpu.targetAverageUtilization }} +--- +{{- end }} diff --git a/istio-1.3.5/install/kubernetes/operator/charts/istio-telemetry/mixer-telemetry/templates/clusterrole.yaml b/istio-1.3.5/install/kubernetes/operator/charts/istio-telemetry/mixer-telemetry/templates/clusterrole.yaml new file mode 100644 index 0000000..bd10d8d --- /dev/null +++ b/istio-1.3.5/install/kubernetes/operator/charts/istio-telemetry/mixer-telemetry/templates/clusterrole.yaml @@ -0,0 +1,21 @@ +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: istio-mixer-{{ .Release.Namespace }} + labels: + app: istio-telemetry + release: {{ .Release.Name }} +rules: +- apiGroups: ["config.istio.io"] # istio CRD watcher + resources: ["*"] + verbs: ["create", "get", "list", "watch", "patch"] +- apiGroups: ["apiextensions.k8s.io"] + resources: ["customresourcedefinitions"] + verbs: ["get", "list", "watch"] +- apiGroups: [""] + resources: ["configmaps", "endpoints", "pods", "services", "namespaces", "secrets", "replicationcontrollers"] + verbs: ["get", "list", "watch"] +- apiGroups: ["extensions", "apps"] + resources: ["replicasets"] + verbs: ["get", "list", "watch"] +--- diff --git a/istio-1.3.5/install/kubernetes/operator/charts/istio-telemetry/mixer-telemetry/templates/clusterrolebinding.yaml b/istio-1.3.5/install/kubernetes/operator/charts/istio-telemetry/mixer-telemetry/templates/clusterrolebinding.yaml new file mode 100644 index 0000000..5dd8046 --- /dev/null +++ b/istio-1.3.5/install/kubernetes/operator/charts/istio-telemetry/mixer-telemetry/templates/clusterrolebinding.yaml @@ -0,0 +1,16 @@ +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: istio-mixer-admin-role-binding-{{ .Release.Namespace }} + labels: + app: istio-telemetry + release: {{ .Release.Name }} +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: istio-mixer-{{ .Release.Namespace }} +subjects: + - kind: ServiceAccount + name: istio-mixer-service-account + namespace: {{ .Release.Namespace }} +--- diff --git a/istio-1.3.5/install/kubernetes/operator/charts/istio-telemetry/mixer-telemetry/templates/config.yaml b/istio-1.3.5/install/kubernetes/operator/charts/istio-telemetry/mixer-telemetry/templates/config.yaml new file mode 100644 index 0000000..fe5a892 --- /dev/null +++ b/istio-1.3.5/install/kubernetes/operator/charts/istio-telemetry/mixer-telemetry/templates/config.yaml @@ -0,0 +1,1002 @@ +apiVersion: "config.istio.io/v1alpha2" +kind: attributemanifest +metadata: + name: istioproxy + namespace: {{ .Release.Namespace }} + labels: + app: istio-telemetry + release: {{ .Release.Name }} +spec: + attributes: + origin.ip: + valueType: IP_ADDRESS + origin.uid: + valueType: STRING + origin.user: + valueType: STRING + request.headers: + valueType: STRING_MAP + request.id: + valueType: STRING + request.host: + valueType: STRING + request.method: + valueType: STRING + request.path: + valueType: STRING + request.url_path: + valueType: STRING + request.query_params: + valueType: STRING_MAP + request.reason: + valueType: STRING + request.referer: + valueType: STRING + request.scheme: + valueType: STRING + request.total_size: + valueType: INT64 + request.size: + valueType: INT64 + request.time: + valueType: TIMESTAMP + request.useragent: + valueType: STRING + response.code: + valueType: INT64 + response.duration: + valueType: DURATION + response.headers: + valueType: STRING_MAP + response.total_size: + valueType: INT64 + response.size: + valueType: INT64 + response.time: + valueType: TIMESTAMP + response.grpc_status: + valueType: STRING + response.grpc_message: + valueType: STRING + source.uid: + valueType: STRING + source.user: # DEPRECATED + valueType: STRING + source.principal: + valueType: STRING + destination.uid: + valueType: STRING + destination.principal: + valueType: STRING + destination.port: + valueType: INT64 + connection.event: + valueType: STRING + connection.id: + valueType: STRING + connection.received.bytes: + valueType: INT64 + connection.received.bytes_total: + valueType: INT64 + connection.sent.bytes: + valueType: INT64 + connection.sent.bytes_total: + valueType: INT64 + connection.duration: + valueType: DURATION + connection.mtls: + valueType: BOOL + connection.requested_server_name: + valueType: STRING + context.protocol: + valueType: STRING + context.proxy_error_code: + valueType: STRING + context.timestamp: + valueType: TIMESTAMP + context.time: + valueType: TIMESTAMP + # Deprecated, kept for compatibility + context.reporter.local: + valueType: BOOL + context.reporter.kind: + valueType: STRING + context.reporter.uid: + valueType: STRING + context.proxy_version: + valueType: STRING + api.service: + valueType: STRING + api.version: + valueType: STRING + api.operation: + valueType: STRING + api.protocol: + valueType: STRING + request.auth.principal: + valueType: STRING + request.auth.audiences: + valueType: STRING + request.auth.presenter: + valueType: STRING + request.auth.claims: + valueType: STRING_MAP + request.auth.raw_claims: + valueType: STRING + request.api_key: + valueType: STRING + rbac.permissive.response_code: + valueType: STRING + rbac.permissive.effective_policy_id: + valueType: STRING + check.error_code: + valueType: INT64 + check.error_message: + valueType: STRING + check.cache_hit: + valueType: BOOL + quota.cache_hit: + valueType: BOOL + context.proxy_version: + valueType: STRING + +--- +apiVersion: "config.istio.io/v1alpha2" +kind: attributemanifest +metadata: + name: kubernetes + namespace: {{ .Release.Namespace }} + labels: + app: istio-telemetry + release: {{ .Release.Name }} +spec: + attributes: + source.ip: + valueType: IP_ADDRESS + source.labels: + valueType: STRING_MAP + source.metadata: + valueType: STRING_MAP + source.name: + valueType: STRING + source.namespace: + valueType: STRING + source.owner: + valueType: STRING + source.serviceAccount: + valueType: STRING + source.services: + valueType: STRING + source.workload.uid: + valueType: STRING + source.workload.name: + valueType: STRING + source.workload.namespace: + valueType: STRING + destination.ip: + valueType: IP_ADDRESS + destination.labels: + valueType: STRING_MAP + destination.metadata: + valueType: STRING_MAP + destination.owner: + valueType: STRING + destination.name: + valueType: STRING + destination.container.name: + valueType: STRING + destination.namespace: + valueType: STRING + destination.service.uid: + valueType: STRING + destination.service.name: + valueType: STRING + destination.service.namespace: + valueType: STRING + destination.service.host: + valueType: STRING + destination.serviceAccount: + valueType: STRING + destination.workload.uid: + valueType: STRING + destination.workload.name: + valueType: STRING + destination.workload.namespace: + valueType: STRING +--- +{{- if .Values.mixer.adapters.stdio.enabled }} +apiVersion: "config.istio.io/v1alpha2" +kind: handler +metadata: + name: stdio + namespace: {{ .Release.Namespace }} + labels: + app: istio-telemetry + release: {{ .Release.Name }} +spec: + compiledAdapter: stdio + params: + outputAsJson: {{ .Values.mixer.adapters.stdio.outputAsJson }} +--- +apiVersion: "config.istio.io/v1alpha2" +kind: instance +metadata: + name: accesslog + namespace: {{ .Release.Namespace }} + labels: + app: istio-telemetry + release: {{ .Release.Name }} +spec: + compiledTemplate: logentry + params: + severity: '"Info"' + timestamp: request.time + variables: + sourceIp: source.ip | ip("0.0.0.0") + sourceApp: source.labels["app"] | "" + sourcePrincipal: source.principal | "" + sourceName: source.name | "" + sourceWorkload: source.workload.name | "" + sourceNamespace: source.namespace | "" + sourceOwner: source.owner | "" + destinationApp: destination.labels["app"] | "" + destinationIp: destination.ip | ip("0.0.0.0") + destinationServiceHost: destination.service.host | "" + destinationWorkload: destination.workload.name | "" + destinationName: destination.name | "" + destinationNamespace: destination.namespace | "" + destinationOwner: destination.owner | "" + destinationPrincipal: destination.principal | "" + apiClaims: request.auth.raw_claims | "" + apiKey: request.api_key | request.headers["x-api-key"] | "" + protocol: request.scheme | context.protocol | "http" + method: request.method | "" + url: request.path | "" + responseCode: response.code | 0 + responseFlags: context.proxy_error_code | "" + responseSize: response.size | 0 + permissiveResponseCode: rbac.permissive.response_code | "none" + permissiveResponsePolicyID: rbac.permissive.effective_policy_id | "none" + requestSize: request.size | 0 + requestId: request.headers["x-request-id"] | "" + clientTraceId: request.headers["x-client-trace-id"] | "" + latency: response.duration | "0ms" + connection_security_policy: conditional((context.reporter.kind | "inbound") == "outbound", "unknown", conditional(connection.mtls | false, "mutual_tls", "none")) + requestedServerName: connection.requested_server_name | "" + userAgent: request.useragent | "" + responseTimestamp: response.time + receivedBytes: request.total_size | 0 + sentBytes: response.total_size | 0 + referer: request.referer | "" + httpAuthority: request.headers[":authority"] | request.host | "" + xForwardedFor: request.headers["x-forwarded-for"] | "0.0.0.0" + reporter: conditional((context.reporter.kind | "inbound") == "outbound", "source", "destination") + grpcStatus: response.grpc_status | "" + grpcMessage: response.grpc_message | "" + monitored_resource_type: '"global"' +--- +apiVersion: "config.istio.io/v1alpha2" +kind: instance +metadata: + name: tcpaccesslog + namespace: {{ .Release.Namespace }} + labels: + app: istio-telemetry + release: {{ .Release.Name }} +spec: + compiledTemplate: logentry + params: + severity: '"Info"' + timestamp: context.time | timestamp("2017-01-01T00:00:00Z") + variables: + connectionEvent: connection.event | "" + sourceIp: source.ip | ip("0.0.0.0") + sourceApp: source.labels["app"] | "" + sourcePrincipal: source.principal | "" + sourceName: source.name | "" + sourceWorkload: source.workload.name | "" + sourceNamespace: source.namespace | "" + sourceOwner: source.owner | "" + destinationApp: destination.labels["app"] | "" + destinationIp: destination.ip | ip("0.0.0.0") + destinationServiceHost: destination.service.host | "" + destinationWorkload: destination.workload.name | "" + destinationName: destination.name | "" + destinationNamespace: destination.namespace | "" + destinationOwner: destination.owner | "" + destinationPrincipal: destination.principal | "" + protocol: context.protocol | "tcp" + connectionDuration: connection.duration | "0ms" + connection_security_policy: conditional((context.reporter.kind | "inbound") == "outbound", "unknown", conditional(connection.mtls | false, "mutual_tls", "none")) + requestedServerName: connection.requested_server_name | "" + receivedBytes: connection.received.bytes | 0 + sentBytes: connection.sent.bytes | 0 + totalReceivedBytes: connection.received.bytes_total | 0 + totalSentBytes: connection.sent.bytes_total | 0 + reporter: conditional((context.reporter.kind | "inbound") == "outbound", "source", "destination") + responseFlags: context.proxy_error_code | "" + monitored_resource_type: '"global"' +--- +apiVersion: "config.istio.io/v1alpha2" +kind: rule +metadata: + name: stdio + namespace: {{ .Release.Namespace }} + labels: + app: istio-telemetry + release: {{ .Release.Name }} +spec: + match: context.protocol == "http" || context.protocol == "grpc" + actions: + - handler: stdio + instances: + - accesslog +--- +apiVersion: "config.istio.io/v1alpha2" +kind: rule +metadata: + name: stdiotcp + namespace: {{ .Release.Namespace }} + labels: + app: istio-telemetry + release: {{ .Release.Name }} +spec: + match: context.protocol == "tcp" + actions: + - handler: stdio + instances: + - tcpaccesslog +{{- end }} +--- +{{- if .Values.mixer.adapters.prometheus.enabled }} +apiVersion: "config.istio.io/v1alpha2" +kind: instance +metadata: + name: requestcount + namespace: {{ .Release.Namespace }} + labels: + app: istio-telemetry + release: {{ .Release.Name }} +spec: + compiledTemplate: metric + params: + value: "1" + dimensions: + reporter: conditional((context.reporter.kind | "inbound") == "outbound", "source", "destination") + source_workload: source.workload.name | "unknown" + source_workload_namespace: source.workload.namespace | "unknown" + source_principal: source.principal | "unknown" + source_app: source.labels["app"] | "unknown" + source_version: source.labels["version"] | "unknown" + destination_workload: destination.workload.name | "unknown" + destination_workload_namespace: destination.workload.namespace | "unknown" + destination_principal: destination.principal | "unknown" + destination_app: destination.labels["app"] | "unknown" + destination_version: destination.labels["version"] | "unknown" + destination_service: destination.service.host | "unknown" + destination_service_name: destination.service.name | "unknown" + destination_service_namespace: destination.service.namespace | "unknown" + request_protocol: api.protocol | context.protocol | "unknown" + response_code: response.code | 200 + response_flags: context.proxy_error_code | "-" + permissive_response_code: rbac.permissive.response_code | "none" + permissive_response_policyid: rbac.permissive.effective_policy_id | "none" + connection_security_policy: conditional((context.reporter.kind | "inbound") == "outbound", "unknown", conditional(connection.mtls | false, "mutual_tls", "none")) + monitored_resource_type: '"UNSPECIFIED"' +--- +apiVersion: "config.istio.io/v1alpha2" +kind: instance +metadata: + name: requestduration + namespace: {{ .Release.Namespace }} + labels: + app: istio-telemetry + release: {{ .Release.Name }} +spec: + compiledTemplate: metric + params: + value: response.duration | "0ms" + dimensions: + reporter: conditional((context.reporter.kind | "inbound") == "outbound", "source", "destination") + source_workload: source.workload.name | "unknown" + source_workload_namespace: source.workload.namespace | "unknown" + source_principal: source.principal | "unknown" + source_app: source.labels["app"] | "unknown" + source_version: source.labels["version"] | "unknown" + destination_workload: destination.workload.name | "unknown" + destination_workload_namespace: destination.workload.namespace | "unknown" + destination_principal: destination.principal | "unknown" + destination_app: destination.labels["app"] | "unknown" + destination_version: destination.labels["version"] | "unknown" + destination_service: destination.service.host | "unknown" + destination_service_name: destination.service.name | "unknown" + destination_service_namespace: destination.service.namespace | "unknown" + request_protocol: api.protocol | context.protocol | "unknown" + response_code: response.code | 200 + response_flags: context.proxy_error_code | "-" + permissive_response_code: rbac.permissive.response_code | "none" + permissive_response_policyid: rbac.permissive.effective_policy_id | "none" + connection_security_policy: conditional((context.reporter.kind | "inbound") == "outbound", "unknown", conditional(connection.mtls | false, "mutual_tls", "none")) + monitored_resource_type: '"UNSPECIFIED"' +--- +apiVersion: "config.istio.io/v1alpha2" +kind: instance +metadata: + name: requestsize + namespace: {{ .Release.Namespace }} + labels: + app: istio-telemetry + release: {{ .Release.Name }} +spec: + compiledTemplate: metric + params: + value: request.size | 0 + dimensions: + reporter: conditional((context.reporter.kind | "inbound") == "outbound", "source", "destination") + source_workload: source.workload.name | "unknown" + source_workload_namespace: source.workload.namespace | "unknown" + source_principal: source.principal | "unknown" + source_app: source.labels["app"] | "unknown" + source_version: source.labels["version"] | "unknown" + destination_workload: destination.workload.name | "unknown" + destination_workload_namespace: destination.workload.namespace | "unknown" + destination_principal: destination.principal | "unknown" + destination_app: destination.labels["app"] | "unknown" + destination_version: destination.labels["version"] | "unknown" + destination_service: destination.service.host | "unknown" + destination_service_name: destination.service.name | "unknown" + destination_service_namespace: destination.service.namespace | "unknown" + request_protocol: api.protocol | context.protocol | "unknown" + response_code: response.code | 200 + response_flags: context.proxy_error_code | "-" + permissive_response_code: rbac.permissive.response_code | "none" + permissive_response_policyid: rbac.permissive.effective_policy_id | "none" + connection_security_policy: conditional((context.reporter.kind | "inbound") == "outbound", "unknown", conditional(connection.mtls | false, "mutual_tls", "none")) + monitored_resource_type: '"UNSPECIFIED"' +--- +apiVersion: "config.istio.io/v1alpha2" +kind: instance +metadata: + name: responsesize + namespace: {{ .Release.Namespace }} + labels: + app: istio-telemetry + release: {{ .Release.Name }} +spec: + compiledTemplate: metric + params: + value: response.size | 0 + dimensions: + reporter: conditional((context.reporter.kind | "inbound") == "outbound", "source", "destination") + source_workload: source.workload.name | "unknown" + source_workload_namespace: source.workload.namespace | "unknown" + source_principal: source.principal | "unknown" + source_app: source.labels["app"] | "unknown" + source_version: source.labels["version"] | "unknown" + destination_workload: destination.workload.name | "unknown" + destination_workload_namespace: destination.workload.namespace | "unknown" + destination_principal: destination.principal | "unknown" + destination_app: destination.labels["app"] | "unknown" + destination_version: destination.labels["version"] | "unknown" + destination_service: destination.service.host | "unknown" + destination_service_name: destination.service.name | "unknown" + destination_service_namespace: destination.service.namespace | "unknown" + request_protocol: api.protocol | context.protocol | "unknown" + response_code: response.code | 200 + response_flags: context.proxy_error_code | "-" + permissive_response_code: rbac.permissive.response_code | "none" + permissive_response_policyid: rbac.permissive.effective_policy_id | "none" + connection_security_policy: conditional((context.reporter.kind | "inbound") == "outbound", "unknown", conditional(connection.mtls | false, "mutual_tls", "none")) + monitored_resource_type: '"UNSPECIFIED"' +--- +apiVersion: "config.istio.io/v1alpha2" +kind: instance +metadata: + name: tcpbytesent + namespace: {{ .Release.Namespace }} + labels: + app: istio-telemetry + release: {{ .Release.Name }} +spec: + compiledTemplate: metric + params: + value: connection.sent.bytes | 0 + dimensions: + reporter: conditional((context.reporter.kind | "inbound") == "outbound", "source", "destination") + source_workload: source.workload.name | "unknown" + source_workload_namespace: source.workload.namespace | "unknown" + source_principal: source.principal | "unknown" + source_app: source.labels["app"] | "unknown" + source_version: source.labels["version"] | "unknown" + destination_workload: destination.workload.name | "unknown" + destination_workload_namespace: destination.workload.namespace | "unknown" + destination_principal: destination.principal | "unknown" + destination_app: destination.labels["app"] | "unknown" + destination_version: destination.labels["version"] | "unknown" + destination_service: destination.service.host | "unknown" + destination_service_name: destination.service.name | "unknown" + destination_service_namespace: destination.service.namespace | "unknown" + connection_security_policy: conditional((context.reporter.kind | "inbound") == "outbound", "unknown", conditional(connection.mtls | false, "mutual_tls", "none")) + response_flags: context.proxy_error_code | "-" + monitored_resource_type: '"UNSPECIFIED"' +--- +apiVersion: "config.istio.io/v1alpha2" +kind: instance +metadata: + name: tcpbytereceived + namespace: {{ .Release.Namespace }} + labels: + app: istio-telemetry + release: {{ .Release.Name }} +spec: + compiledTemplate: metric + params: + value: connection.received.bytes | 0 + dimensions: + reporter: conditional((context.reporter.kind | "inbound") == "outbound", "source", "destination") + source_workload: source.workload.name | "unknown" + source_workload_namespace: source.workload.namespace | "unknown" + source_principal: source.principal | "unknown" + source_app: source.labels["app"] | "unknown" + source_version: source.labels["version"] | "unknown" + destination_workload: destination.workload.name | "unknown" + destination_workload_namespace: destination.workload.namespace | "unknown" + destination_principal: destination.principal | "unknown" + destination_app: destination.labels["app"] | "unknown" + destination_version: destination.labels["version"] | "unknown" + destination_service: destination.service.host | "unknown" + destination_service_name: destination.service.name | "unknown" + destination_service_namespace: destination.service.namespace | "unknown" + connection_security_policy: conditional((context.reporter.kind | "inbound") == "outbound", "unknown", conditional(connection.mtls | false, "mutual_tls", "none")) + response_flags: context.proxy_error_code | "-" + monitored_resource_type: '"UNSPECIFIED"' +--- +apiVersion: "config.istio.io/v1alpha2" +kind: instance +metadata: + name: tcpconnectionsopened + namespace: {{ .Release.Namespace }} + labels: + app: istio-telemetry + release: {{ .Release.Name }} +spec: + compiledTemplate: metric + params: + value: "1" + dimensions: + reporter: conditional((context.reporter.kind | "inbound") == "outbound", "source", "destination") + source_workload: source.workload.name | "unknown" + source_workload_namespace: source.workload.namespace | "unknown" + source_principal: source.principal | "unknown" + source_app: source.labels["app"] | "unknown" + source_version: source.labels["version"] | "unknown" + destination_workload: destination.workload.name | "unknown" + destination_workload_namespace: destination.workload.namespace | "unknown" + destination_principal: destination.principal | "unknown" + destination_app: destination.labels["app"] | "unknown" + destination_version: destination.labels["version"] | "unknown" + destination_service: destination.service.name | "unknown" + destination_service_name: destination.service.name | "unknown" + destination_service_namespace: destination.service.namespace | "unknown" + connection_security_policy: conditional((context.reporter.kind | "inbound") == "outbound", "unknown", conditional(connection.mtls | false, "mutual_tls", "none")) + response_flags: context.proxy_error_code | "-" + monitored_resource_type: '"UNSPECIFIED"' +--- +apiVersion: "config.istio.io/v1alpha2" +kind: instance +metadata: + name: tcpconnectionsclosed + namespace: {{ .Release.Namespace }} + labels: + app: istio-telemetry + release: {{ .Release.Name }} +spec: + compiledTemplate: metric + params: + value: "1" + dimensions: + reporter: conditional((context.reporter.kind | "inbound") == "outbound", "source", "destination") + source_workload: source.workload.name | "unknown" + source_workload_namespace: source.workload.namespace | "unknown" + source_principal: source.principal | "unknown" + source_app: source.labels["app"] | "unknown" + source_version: source.labels["version"] | "unknown" + destination_workload: destination.workload.name | "unknown" + destination_workload_namespace: destination.workload.namespace | "unknown" + destination_principal: destination.principal | "unknown" + destination_app: destination.labels["app"] | "unknown" + destination_version: destination.labels["version"] | "unknown" + destination_service: destination.service.name | "unknown" + destination_service_name: destination.service.name | "unknown" + destination_service_namespace: destination.service.namespace | "unknown" + connection_security_policy: conditional((context.reporter.kind | "inbound") == "outbound", "unknown", conditional(connection.mtls | false, "mutual_tls", "none")) + response_flags: context.proxy_error_code | "-" + monitored_resource_type: '"UNSPECIFIED"' +--- +apiVersion: "config.istio.io/v1alpha2" +kind: handler +metadata: + name: prometheus + namespace: {{ .Release.Namespace }} + labels: + app: istio-telemetry + release: {{ .Release.Name }} +spec: + compiledAdapter: prometheus + params: + metricsExpirationPolicy: + metricsExpiryDuration: "{{ .Values.mixer.adapters.prometheus.metricsExpiryDuration }}" + metrics: + - name: requests_total + instance_name: requestcount.instance.{{ .Release.Namespace }} + kind: COUNTER + label_names: + - reporter + - source_app + - source_principal + - source_workload + - source_workload_namespace + - source_version + - destination_app + - destination_principal + - destination_workload + - destination_workload_namespace + - destination_version + - destination_service + - destination_service_name + - destination_service_namespace + - request_protocol + - response_code + - response_flags + - permissive_response_code + - permissive_response_policyid + - connection_security_policy + - name: request_duration_seconds + instance_name: requestduration.instance.{{ .Release.Namespace }} + kind: DISTRIBUTION + label_names: + - reporter + - source_app + - source_principal + - source_workload + - source_workload_namespace + - source_version + - destination_app + - destination_principal + - destination_workload + - destination_workload_namespace + - destination_version + - destination_service + - destination_service_name + - destination_service_namespace + - request_protocol + - response_code + - response_flags + - permissive_response_code + - permissive_response_policyid + - connection_security_policy + buckets: + explicit_buckets: + bounds: [0.005, 0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 1, 2.5, 5, 10] + - name: request_bytes + instance_name: requestsize.instance.{{ .Release.Namespace }} + kind: DISTRIBUTION + label_names: + - reporter + - source_app + - source_principal + - source_workload + - source_workload_namespace + - source_version + - destination_app + - destination_principal + - destination_workload + - destination_workload_namespace + - destination_version + - destination_service + - destination_service_name + - destination_service_namespace + - request_protocol + - response_code + - response_flags + - permissive_response_code + - permissive_response_policyid + - connection_security_policy + buckets: + exponentialBuckets: + numFiniteBuckets: 8 + scale: 1 + growthFactor: 10 + - name: response_bytes + instance_name: responsesize.instance.{{ .Release.Namespace }} + kind: DISTRIBUTION + label_names: + - reporter + - source_app + - source_principal + - source_workload + - source_workload_namespace + - source_version + - destination_app + - destination_principal + - destination_workload + - destination_workload_namespace + - destination_version + - destination_service + - destination_service_name + - destination_service_namespace + - request_protocol + - response_code + - response_flags + - permissive_response_code + - permissive_response_policyid + - connection_security_policy + buckets: + exponentialBuckets: + numFiniteBuckets: 8 + scale: 1 + growthFactor: 10 + - name: tcp_sent_bytes_total + instance_name: tcpbytesent.instance.{{ .Release.Namespace }} + kind: COUNTER + label_names: + - reporter + - source_app + - source_principal + - source_workload + - source_workload_namespace + - source_version + - destination_app + - destination_principal + - destination_workload + - destination_workload_namespace + - destination_version + - destination_service + - destination_service_name + - destination_service_namespace + - connection_security_policy + - response_flags + - name: tcp_received_bytes_total + instance_name: tcpbytereceived.instance.{{ .Release.Namespace }} + kind: COUNTER + label_names: + - reporter + - source_app + - source_principal + - source_workload + - source_workload_namespace + - source_version + - destination_app + - destination_principal + - destination_workload + - destination_workload_namespace + - destination_version + - destination_service + - destination_service_name + - destination_service_namespace + - connection_security_policy + - response_flags + - name: tcp_connections_opened_total + instance_name: tcpconnectionsopened.instance.{{ .Release.Namespace }} + kind: COUNTER + label_names: + - reporter + - source_app + - source_principal + - source_workload + - source_workload_namespace + - source_version + - destination_app + - destination_principal + - destination_workload + - destination_workload_namespace + - destination_version + - destination_service + - destination_service_name + - destination_service_namespace + - connection_security_policy + - response_flags + - name: tcp_connections_closed_total + instance_name: tcpconnectionsclosed.instance.{{ .Release.Namespace }} + kind: COUNTER + label_names: + - reporter + - source_app + - source_principal + - source_workload + - source_workload_namespace + - source_version + - destination_app + - destination_principal + - destination_workload + - destination_workload_namespace + - destination_version + - destination_service + - destination_service_name + - destination_service_namespace + - connection_security_policy + - response_flags +--- +apiVersion: "config.istio.io/v1alpha2" +kind: rule +metadata: + name: promhttp + namespace: {{ .Release.Namespace }} + labels: + app: istio-telemetry + release: {{ .Release.Name }} +spec: + match: (context.protocol == "http" || context.protocol == "grpc") && (match((request.useragent | "-"), "kube-probe*") == false) && (match((request.useragent | "-"), "Prometheus*") == false) + actions: + - handler: prometheus + instances: + - requestcount + - requestduration + - requestsize + - responsesize +--- +apiVersion: "config.istio.io/v1alpha2" +kind: rule +metadata: + name: promtcp + namespace: {{ .Release.Namespace }} + labels: + app: istio-telemetry + release: {{ .Release.Name }} +spec: + match: context.protocol == "tcp" + actions: + - handler: prometheus + instances: + - tcpbytesent + - tcpbytereceived +--- +apiVersion: "config.istio.io/v1alpha2" +kind: rule +metadata: + name: promtcpconnectionopen + namespace: {{ .Release.Namespace }} + labels: + app: istio-telemetry + release: {{ .Release.Name }} +spec: + match: context.protocol == "tcp" && ((connection.event | "na") == "open") + actions: + - handler: prometheus + instances: + - tcpconnectionsopened +--- +apiVersion: "config.istio.io/v1alpha2" +kind: rule +metadata: + name: promtcpconnectionclosed + namespace: {{ .Release.Namespace }} + labels: + app: istio-telemetry + release: {{ .Release.Name }} +spec: + match: context.protocol == "tcp" && ((connection.event | "na") == "close") + actions: + - handler: prometheus + instances: + - tcpconnectionsclosed +{{- end }} +--- +{{- if .Values.mixer.adapters.kubernetesenv.enabled }} +apiVersion: "config.istio.io/v1alpha2" +kind: handler +metadata: + name: kubernetesenv + namespace: {{ .Release.Namespace }} + labels: + app: istio-telemetry + release: {{ .Release.Name }} +spec: + compiledAdapter: kubernetesenv + params: + # when running from mixer root, use the following config after adding a + # symbolic link to a kubernetes config file via: + # + # $ ln -s ~/.kube/config mixer/adapter/kubernetes/kubeconfig + # + # kubeconfig_path: "mixer/adapter/kubernetes/kubeconfig" + +--- +apiVersion: "config.istio.io/v1alpha2" +kind: rule +metadata: + name: kubeattrgenrulerule + namespace: {{ .Release.Namespace }} + labels: + app: istio-telemetry + release: {{ .Release.Name }} +spec: + actions: + - handler: kubernetesenv + instances: + - attributes +--- +apiVersion: "config.istio.io/v1alpha2" +kind: rule +metadata: + name: tcpkubeattrgenrulerule + namespace: {{ .Release.Namespace }} + labels: + app: istio-telemetry + release: {{ .Release.Name }} +spec: + match: context.protocol == "tcp" + actions: + - handler: kubernetesenv + instances: + - attributes +--- +apiVersion: "config.istio.io/v1alpha2" +kind: instance +metadata: + name: attributes + namespace: {{ .Release.Namespace }} + labels: + app: istio-telemetry + release: {{ .Release.Name }} +spec: + compiledTemplate: kubernetes + params: + # Pass the required attribute data to the adapter + source_uid: source.uid | "" + source_ip: source.ip | ip("0.0.0.0") # default to unspecified ip addr + destination_uid: destination.uid | "" + destination_port: destination.port | 0 + attributeBindings: + # Fill the new attributes from the adapter produced output. + # $out refers to an instance of OutputTemplate message + source.ip: $out.source_pod_ip | ip("0.0.0.0") + source.uid: $out.source_pod_uid | "unknown" + source.labels: $out.source_labels | emptyStringMap() + source.name: $out.source_pod_name | "unknown" + source.namespace: $out.source_namespace | "default" + source.owner: $out.source_owner | "unknown" + source.serviceAccount: $out.source_service_account_name | "unknown" + source.workload.uid: $out.source_workload_uid | "unknown" + source.workload.name: $out.source_workload_name | "unknown" + source.workload.namespace: $out.source_workload_namespace | "unknown" + destination.ip: $out.destination_pod_ip | ip("0.0.0.0") + destination.uid: $out.destination_pod_uid | "unknown" + destination.labels: $out.destination_labels | emptyStringMap() + destination.name: $out.destination_pod_name | "unknown" + destination.container.name: $out.destination_container_name | "unknown" + destination.namespace: $out.destination_namespace | "default" + destination.owner: $out.destination_owner | "unknown" + destination.serviceAccount: $out.destination_service_account_name | "unknown" + destination.workload.uid: $out.destination_workload_uid | "unknown" + destination.workload.name: $out.destination_workload_name | "unknown" + destination.workload.namespace: $out.destination_workload_namespace | "unknown" +{{- end }} +--- +apiVersion: networking.istio.io/v1alpha3 +kind: DestinationRule +metadata: + name: istio-telemetry + namespace: {{ .Release.Namespace }} + labels: + app: istio-telemetry + release: {{ .Release.Name }} +spec: + host: istio-telemetry.{{ .Release.Namespace }}.svc.{{ .Values.global.proxy.clusterDomain }} + {{- if .Values.global.defaultConfigVisibilitySettings }} + exportTo: + - '*' + {{- end }} + trafficPolicy: + {{- if .Values.global.controlPlaneSecurityEnabled }} + portLevelSettings: + - port: + number: 15004 + tls: + mode: ISTIO_MUTUAL + {{- end}} + connectionPool: + http: + http2MaxRequests: 10000 + maxRequestsPerConnection: 10000 +--- diff --git a/istio-1.3.5/install/kubernetes/operator/charts/istio-telemetry/mixer-telemetry/templates/configmap-envoy.yaml b/istio-1.3.5/install/kubernetes/operator/charts/istio-telemetry/mixer-telemetry/templates/configmap-envoy.yaml new file mode 100644 index 0000000..1c753af --- /dev/null +++ b/istio-1.3.5/install/kubernetes/operator/charts/istio-telemetry/mixer-telemetry/templates/configmap-envoy.yaml @@ -0,0 +1,299 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + namespace: {{ .Release.Namespace }} + name: telemetry-envoy-config + labels: + release: {{ .Release.Name }} +data: + # Explicitly defined - moved from istio/istio/pilot/docker. + envoy.yaml.tmpl: |- + admin: + access_log_path: /dev/null + address: + socket_address: + address: 127.0.0.1 + port_value: 15000 + stats_config: + use_all_default_tags: false + stats_tags: + - tag_name: cluster_name + regex: '^cluster\.((.+?(\..+?\.svc\.cluster\.local)?)\.)' + - tag_name: tcp_prefix + regex: '^tcp\.((.*?)\.)\w+?$' + - tag_name: response_code + regex: '_rq(_(\d{3}))$' + - tag_name: response_code_class + regex: '_rq(_(\dxx))$' + - tag_name: http_conn_manager_listener_prefix + regex: '^listener(?=\.).*?\.http\.(((?:[_.[:digit:]]*|[_\[\]aAbBcCdDeEfF[:digit:]]*))\.)' + - tag_name: http_conn_manager_prefix + regex: '^http\.(((?:[_.[:digit:]]*|[_\[\]aAbBcCdDeEfF[:digit:]]*))\.)' + - tag_name: listener_address + regex: '^listener\.(((?:[_.[:digit:]]*|[_\[\]aAbBcCdDeEfF[:digit:]]*))\.)' + + static_resources: + clusters: + - name: prometheus_stats + type: STATIC + connect_timeout: 0.250s + lb_policy: ROUND_ROBIN + hosts: + - socket_address: + protocol: TCP + address: 127.0.0.1 + port_value: 15000 + + - name: inbound_9092 + circuit_breakers: + thresholds: + - max_connections: 100000 + max_pending_requests: 100000 + max_requests: 100000 + max_retries: 3 + connect_timeout: 1.000s + hosts: + - pipe: + path: /sock/mixer.socket + http2_protocol_options: {} + + - name: out.galley.15019 + http2_protocol_options: {} + connect_timeout: 1.000s + type: STRICT_DNS + + circuit_breakers: + thresholds: + - max_connections: 100000 + max_pending_requests: 100000 + max_requests: 100000 + max_retries: 3 + + tls_context: + common_tls_context: + tls_certificates: + - certificate_chain: + filename: /etc/certs/cert-chain.pem + private_key: + filename: /etc/certs/key.pem + validation_context: + trusted_ca: + filename: /etc/certs/root-cert.pem + verify_subject_alt_name: + - spiffe://cluster.local/ns/{{ .Values.global.configNamespace }}/sa/istio-galley-service-account + + hosts: + - socket_address: + address: istio-galley.{{ .Values.global.configNamespace }} + port_value: 15019 + + + listeners: + - name: "15090" + address: + socket_address: + protocol: TCP + address: 0.0.0.0 + port_value: 15090 + filter_chains: + - filters: + - name: envoy.http_connection_manager + config: + codec_type: AUTO + stat_prefix: stats + route_config: + virtual_hosts: + - name: backend + domains: + - '*' + routes: + - match: + prefix: /stats/prometheus + route: + cluster: prometheus_stats + http_filters: + - name: envoy.router + + - name: "15004" + address: + socket_address: + address: 0.0.0.0 + port_value: 15004 + filter_chains: + - filters: + - config: + codec_type: HTTP2 + http2_protocol_options: + max_concurrent_streams: 1073741824 + generate_request_id: true + http_filters: + - config: + default_destination_service: istio-telemetry.{{ .Release.Namespace }}.svc.cluster.local + service_configs: + istio-telemetry.{{ .Release.Namespace }}.svc.cluster.local: + disable_check_calls: true + {{"{{"}}- if .DisableReportCalls {{"}}"}} + disable_report_calls: true + {{"{{"}}- end {{"}}"}} + mixer_attributes: + attributes: + destination.service.host: + string_value: istio-telemetry.{{ .Release.Namespace }}.svc.cluster.local + destination.service.uid: + string_value: istio://{{ .Release.Namespace }}/services/istio-telemetry + destination.service.name: + string_value: istio-telemetry + destination.service.namespace: + string_value: {{ .Release.Namespace }} + destination.uid: + string_value: kubernetes://{{"{{"}} .PodName {{"}}"}}.{{ .Release.Namespace }} + destination.namespace: + string_value: {{.Release.Namespace }} + destination.ip: + bytes_value: {{"{{"}} .PodIP {{"}}"}} + destination.port: + int64_value: 15004 + context.reporter.kind: + string_value: inbound + context.reporter.uid: + string_value: kubernetes://{{"{{"}} .PodName {{"}}"}}.{{ .Release.Namespace }} + transport: + check_cluster: mixer_check_server + report_cluster: inbound_9092 + name: mixer + - name: envoy.router + route_config: + name: "15004" + virtual_hosts: + - domains: + - '*' + name: istio-telemetry.{{ .Release.Namespace }}.svc.cluster.local + routes: + - decorator: + operation: Report + match: + prefix: / + route: + cluster: inbound_9092 + timeout: 0.000s + stat_prefix: "15004" + name: envoy.http_connection_manager + {{- if .Values.global.controlPlaneSecurityEnabled }} + tls_context: + common_tls_context: + alpn_protocols: + - h2 + tls_certificates: + - certificate_chain: + filename: /etc/certs/cert-chain.pem + private_key: + filename: /etc/certs/key.pem + validation_context: + trusted_ca: + filename: /etc/certs/root-cert.pem + require_client_certificate: true + {{- end }} + + - name: "9091" + address: + socket_address: + address: 0.0.0.0 + port_value: 9091 + filter_chains: + - filters: + - config: + codec_type: HTTP2 + http2_protocol_options: + max_concurrent_streams: 1073741824 + generate_request_id: true + http_filters: + - config: + default_destination_service: istio-telemetry.{{ .Release.Namespace }}.svc.cluster.local + service_configs: + istio-telemetry.{{ .Release.Namespace }}.svc.cluster.local: + disable_check_calls: true + {{"{{"}}- if .DisableReportCalls {{"}}"}} + disable_report_calls: true + {{"{{"}}- end {{"}}"}} + mixer_attributes: + attributes: + destination.service.host: + string_value: istio-telemetry.{{ .Release.Namespace }}.svc.cluster.local + destination.service.uid: + string_value: istio://{{ .Release.Namespace }}/services/istio-telemetry + destination.service.name: + string_value: istio-telemetry + destination.service.namespace: + string_value: {{ .Release.Namespace }} + destination.uid: + string_value: kubernetes://{{"{{"}} .PodName {{"}}"}}.{{ .Release.Namespace }} + destination.namespace: + string_value: {{.Release.Namespace }} + destination.ip: + bytes_value: {{"{{"}} .PodIP {{"}}"}} + destination.port: + int64_value: 9091 + context.reporter.kind: + string_value: inbound + context.reporter.uid: + string_value: kubernetes://{{"{{"}} .PodName {{"}}"}}.{{ .Release.Namespace }} + transport: + check_cluster: mixer_check_server + report_cluster: inbound_9092 + name: mixer + - name: envoy.router + route_config: + name: "9091" + virtual_hosts: + - domains: + - '*' + name: istio-telemetry.{{ .Release.Namespace }}.svc.cluster.local + routes: + - decorator: + operation: Report + match: + prefix: / + route: + cluster: inbound_9092 + timeout: 0.000s + stat_prefix: "9091" + name: envoy.http_connection_manager + + - name: "local.15019" + address: + socket_address: + address: 127.0.0.1 + port_value: 15019 + filter_chains: + - filters: + - name: envoy.http_connection_manager + config: + codec_type: HTTP2 + stat_prefix: "15019" + http2_protocol_options: + max_concurrent_streams: 1073741824 + + access_log: + - name: envoy.file_access_log + config: + path: /dev/stdout + + http_filters: + - name: envoy.router + + route_config: + name: "15019" + + virtual_hosts: + - name: istio-galley + + domains: + - '*' + + routes: + - match: + prefix: / + route: + cluster: out.galley.15019 + timeout: 0.000s +--- diff --git a/istio-1.3.5/install/kubernetes/operator/charts/istio-telemetry/mixer-telemetry/templates/deployment.yaml b/istio-1.3.5/install/kubernetes/operator/charts/istio-telemetry/mixer-telemetry/templates/deployment.yaml new file mode 100644 index 0000000..f754089 --- /dev/null +++ b/istio-1.3.5/install/kubernetes/operator/charts/istio-telemetry/mixer-telemetry/templates/deployment.yaml @@ -0,0 +1,212 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: istio-telemetry + namespace: {{ .Release.Namespace }} + labels: + app: istio-mixer + istio: mixer + release: {{ .Release.Name }} + istio-mixer-type: telemetry +spec: + replicas: {{ .Values.mixer.telemetry.replicaCount }} + strategy: + rollingUpdate: + maxSurge: {{ .Values.mixer.telemetry.rollingMaxSurge }} + maxUnavailable: {{ .Values.mixer.telemetry.rollingMaxUnavailable }} + selector: + matchLabels: + istio: mixer + istio-mixer-type: telemetry + template: + metadata: + labels: + app: istio-telemetry + istio: mixer + istio-mixer-type: telemetry + annotations: + sidecar.istio.io/inject: "false" +{{- with .Values.mixer.telemetry.podAnnotations }} +{{ toYaml . | indent 8 }} +{{- end }} + spec: + serviceAccountName: istio-mixer-service-account + volumes: + - name: istio-certs + secret: + secretName: istio.istio-mixer-service-account + optional: true + {{- if .Values.global.sds.enabled }} + - hostPath: + path: /var/run/sds + name: sds-uds-path + - name: istio-token + projected: + sources: + - serviceAccountToken: + audience: {{ .Values.global.trustDomain }} + expirationSeconds: 43200 + path: istio-token + {{- end }} + - name: uds-socket + emptyDir: {} + - name: telemetry-adapter-secret + secret: + secretName: telemetry-adapter-secret + optional: true + - name: telemetry-envoy-config + configMap: + name: telemetry-envoy-config + affinity: + {{- include "nodeaffinity" . | indent 6 }} + {{- include "podAntiAffinity" . | indent 6 }} +{{- if .Values.mixer.telemetry.tolerations }} + tolerations: +{{ toYaml .Values.mixer.telemetry.tolerations | indent 6 }} +{{- end }} + containers: + - name: mixer +{{- if contains "/" .Values.mixer.telemetry.image }} + image: "{{ .Values.mixer.telemetry.image }}" +{{- else }} + image: "{{ .Values.global.hub }}/{{ .Values.mixer.telemetry.image }}:{{ .Values.global.tag }}" +{{- end }} + imagePullPolicy: {{ .Values.global.imagePullPolicy | default "Always" }} + ports: + - containerPort: 15014 + - containerPort: 42422 + args: + - --monitoringPort=15014 + - --address + - unix:///sock/mixer.socket +{{- if .Values.global.logging.level }} + - --log_output_level={{ .Values.global.logging.level }} +{{- end}} +{{- if .Values.global.logAsJson }} + - --log_as_json +{{- end }} +{{- if .Values.mixer.telemetry.useMCP }} + {{- if .Values.global.controlPlaneSecurityEnabled}} + - --configStoreURL=mcp://localhost:15019 + {{- else }} + - --configStoreURL=mcp://istio-galley.{{ .Values.global.configNamespace }}.svc:9901 + {{- end }} +{{- else }} + - --configStoreURL=k8s:// +{{- end }} + - --configDefaultNamespace={{ .Values.global.telemetryNamespace }} + {{- if .Values.mixer.adapters.useAdapterCRDs }} + - --useAdapterCRDs=true + {{- else }} + - --useAdapterCRDs=false + {{- end }} + - --useTemplateCRDs=false + {{- if .Values.global.tracer.zipkin.address }} + - --trace_zipkin_url=http://{{- .Values.global.tracer.zipkin.address }}/api/v1/spans + {{- else }} + - --trace_zipkin_url=http://zipkin.{{ .Values.global.telemetryNamespace }}:9411/api/v1/spans + {{- end }} + {{- if .Values.mixer.env }} + env: + {{- range $key, $val := .Values.mixer.env }} + - name: {{ $key }} + value: "{{ $val }}" + {{- end }} + {{- end }} + resources: +{{- if .Values.mixer.telemetry.resources }} +{{ toYaml .Values.mixer.telemetry.resources | indent 10 }} +{{- else }} +{{ toYaml .Values.global.defaultResources | indent 10 }} +{{- end }} + volumeMounts: +{{- if .Values.mixer.telemetry.useMCP }} + - name: istio-certs + mountPath: /etc/certs + readOnly: true +{{- end }} + - name: uds-socket + mountPath: /sock + - name: telemetry-adapter-secret + mountPath: /var/run/secrets/istio.io/telemetry/adapter + readOnly: true + livenessProbe: + httpGet: + path: /version + port: 15014 + initialDelaySeconds: 5 + periodSeconds: 5 +{{- if .Values.global.controlPlaneSecurityEnabled }} + - name: istio-proxy +{{- if contains "/" .Values.global.proxy.image }} + image: "{{ .Values.global.proxy.image }}" +{{- else }} + image: "{{ .Values.global.hub }}/{{ .Values.global.proxy.image }}:{{ .Values.global.tag }}" +{{- end }} + imagePullPolicy: {{ .Values.global.imagePullPolicy | default "Always" }} + ports: + - containerPort: 9091 + - containerPort: 15004 + - containerPort: 15090 + protocol: TCP + name: http-envoy-prom + args: + - proxy + - --domain + - $(POD_NAMESPACE).svc.{{ .Values.global.proxy.clusterDomain }} + - --serviceCluster + - istio-telemetry + - --templateFile + - /var/lib/envoy/envoy.yaml.tmpl + {{- if .Values.global.controlPlaneSecurityEnabled }} + - --controlPlaneAuthPolicy + - MUTUAL_TLS + {{- else }} + - --controlPlaneAuthPolicy + - NONE + {{- end }} + {{- if .Values.global.trustDomain }} + - --trust-domain={{ .Values.global.trustDomain }} + {{- end }} + {{- if .Values.global.logAsJson }} + - --log_as_json + {{- end }} + env: + - name: POD_NAME + valueFrom: + fieldRef: + apiVersion: v1 + fieldPath: metadata.name + - name: POD_NAMESPACE + valueFrom: + fieldRef: + apiVersion: v1 + fieldPath: metadata.namespace + - name: INSTANCE_IP + valueFrom: + fieldRef: + apiVersion: v1 + fieldPath: status.podIP + resources: +{{- if .Values.global.proxy.resources }} +{{ toYaml .Values.global.proxy.resources | indent 10 }} +{{- else }} +{{ toYaml .Values.global.defaultResources | indent 10 }} +{{- end }} + volumeMounts: + - name: telemetry-envoy-config + mountPath: /var/lib/envoy + - name: istio-certs + mountPath: /etc/certs + readOnly: true + {{- if .Values.global.sds.enabled }} + - name: sds-uds-path + mountPath: /var/run/sds + readOnly: true + - name: istio-token + mountPath: /var/run/secrets/tokens + {{- end }} + - name: uds-socket + mountPath: /sock +{{- end }} +--- diff --git a/istio-1.3.5/install/kubernetes/operator/charts/istio-telemetry/mixer-telemetry/templates/poddisruptionbudget.yaml b/istio-1.3.5/install/kubernetes/operator/charts/istio-telemetry/mixer-telemetry/templates/poddisruptionbudget.yaml new file mode 100644 index 0000000..3bdf9a5 --- /dev/null +++ b/istio-1.3.5/install/kubernetes/operator/charts/istio-telemetry/mixer-telemetry/templates/poddisruptionbudget.yaml @@ -0,0 +1,22 @@ +{{- if .Values.global.defaultPodDisruptionBudget.enabled }} +apiVersion: policy/v1beta1 +kind: PodDisruptionBudget +metadata: + name: istio-telemetry + namespace: {{ .Release.Namespace }} + labels: + app: istio-telemetry + release: {{ .Release.Name }} + istio: mixer + istio-mixer-type: telemetry +spec: + minAvailable: 1 + selector: + matchLabels: + app: istio-telemetry + release: {{ .Release.Name }} + istio: mixer + istio-mixer-type: telemetry +--- + +{{- end }} diff --git a/istio-1.3.5/install/kubernetes/operator/charts/istio-telemetry/mixer-telemetry/templates/service.yaml b/istio-1.3.5/install/kubernetes/operator/charts/istio-telemetry/mixer-telemetry/templates/service.yaml new file mode 100644 index 0000000..92e7d11 --- /dev/null +++ b/istio-1.3.5/install/kubernetes/operator/charts/istio-telemetry/mixer-telemetry/templates/service.yaml @@ -0,0 +1,26 @@ +apiVersion: v1 +kind: Service +metadata: + name: istio-telemetry + namespace: {{ .Release.Namespace }} + labels: + app: istio-telemetry + istio: mixer + release: {{ .Release.Name }} +spec: + ports: + - name: grpc-mixer + port: 9091 + - name: grpc-mixer-mtls + port: 15004 + - name: http-monitoring + port: 15014 + - name: prometheus + port: 42422 + selector: + istio: mixer + istio-mixer-type: telemetry +{{- if .Values.mixer.telemetry.sessionAffinityEnabled }} + sessionAffinity: ClientIP +{{- end }} +--- diff --git a/istio-1.3.5/install/kubernetes/operator/charts/istio-telemetry/mixer-telemetry/templates/serviceaccount.yaml b/istio-1.3.5/install/kubernetes/operator/charts/istio-telemetry/mixer-telemetry/templates/serviceaccount.yaml new file mode 100644 index 0000000..0e026ff --- /dev/null +++ b/istio-1.3.5/install/kubernetes/operator/charts/istio-telemetry/mixer-telemetry/templates/serviceaccount.yaml @@ -0,0 +1,15 @@ +apiVersion: v1 +kind: ServiceAccount +{{- if .Values.global.imagePullSecrets }} +imagePullSecrets: +{{- range .Values.global.imagePullSecrets }} + - name: {{ . }} +{{- end }} +{{- end }} +metadata: + name: istio-mixer-service-account + namespace: {{ .Release.Namespace }} + labels: + app: istio-telemetry + release: {{ .Release.Name }} +--- diff --git a/istio-1.3.5/install/kubernetes/operator/charts/istio-telemetry/mixer-telemetry/templates/stackdriver.yaml b/istio-1.3.5/install/kubernetes/operator/charts/istio-telemetry/mixer-telemetry/templates/stackdriver.yaml new file mode 100644 index 0000000..87ad849 --- /dev/null +++ b/istio-1.3.5/install/kubernetes/operator/charts/istio-telemetry/mixer-telemetry/templates/stackdriver.yaml @@ -0,0 +1,889 @@ +{{- if .Values.mixer.adapters.stackdriver.enabled }} +apiVersion: "config.istio.io/v1alpha2" +kind: handler +metadata: + name: stackdriver + namespace: {{ .Release.Namespace }} + labels: + app: istio-telemetry + release: {{ .Release.Name }} +spec: + compiledAdapter: stackdriver + params: + {{- if .Values.mixer.adapters.stackdriver.tracer.enabled }} + trace: + sampleProbability: {{ .Values.mixer.adapters.stackdriver.tracer.sampleProbability | default 1 }} + {{- end }} + pushInterval: 10s + {{- if ne .Values.mixer.adapters.stackdriver.auth.serviceAccountPath "" }} + serviceAccountPath: {{ .Values.mixer.adapters.stackdriver.auth.serviceAccountPath }} + {{- end }} + {{- if ne .Values.mixer.adapters.stackdriver.auth.apiKey "" }} + apiKey: {{ .Values.mixer.adapters.stackdriver.auth.apiKey }} + {{- end }} + {{- if .Values.mixer.adapters.stackdriver.auth.appCredentials }} + appCredentials: {{ .Values.mixer.adapters.stackdriver.auth.appCredentials }} + {{- end }} + metricInfo: + server-request-count.instance.{{ .Release.Namespace }}: + # Due to a bug in gogoproto deserialization, Enums in maps must be + # specified by their integer value, not variant name. See + # https://github.com/googleapis/googleapis/blob/master/google/api/metric.proto + # MetricKind and ValueType for the values to provide. + kind: 3 # CUMULATIVE + value: 2 # INT64 + metric_type: "istio.io/service/server/request_count" + server-request-bytes.instance.{{ .Release.Namespace }}: + kind: 3 # CUMULATIVE + value: 5 # DISTRIBUTION + buckets: + exponentialBuckets: + numFiniteBuckets: 20 + scale: 1 + growthFactor: 2 + metric_type: "istio.io/service/server/request_bytes" + server-response-bytes.instance.{{ .Release.Namespace }}: + kind: 3 # CUMULATIVE + value: 5 # DISTRIBUTION + buckets: + exponentialBuckets: + numFiniteBuckets: 20 + scale: 1 + growthFactor: 2 + metric_type: "istio.io/service/server/response_bytes" + server-response-latencies.instance.{{ .Release.Namespace }}: + kind: 3 # CUMULATIVE + value: 5 # DISTRIBUTION + buckets: + exponentialBuckets: + numFiniteBuckets: 20 + scale: 1 + growthFactor: 2 + metric_type: "istio.io/service/server/response_latencies" + server-received-bytes-count.instance.{{ .Release.Namespace }}: + kind: 3 # CUMULATIVE + value: 2 # INT64 + metric_type: "istio.io/service/server/received_bytes_count" + server-sent-bytes-count.instance.{{ .Release.Namespace }}: + kind: 3 # CUMULATIVE + value: 2 # INT64 + metric_type: "istio.io/service/server/sent_bytes_count" + client-request-count.instance.{{ .Release.Namespace }}: + kind: 3 # CUMULATIVE + value: 2 # INT64 + metric_type: "istio.io/service/client/request_count" + client-request-bytes.instance.{{ .Release.Namespace }}: + kind: 3 # CUMULATIVE + value: 5 # DISTRIBUTION + buckets: + exponentialBuckets: + numFiniteBuckets: 20 + scale: 1 + growthFactor: 2 + metric_type: "istio.io/service/client/request_bytes" + client-response-bytes.instance.{{ .Release.Namespace }}: + kind: 3 # CUMULATIVE + value: 5 # DISTRIBUTION + buckets: + exponentialBuckets: + numFiniteBuckets: 20 + scale: 1 + growthFactor: 2 + metric_type: "istio.io/service/client/response_bytes" + client-roundtrip-latencies.instance.{{ .Release.Namespace }}: + kind: 3 # CUMULATIVE + value: 5 # DISTRIBUTION + buckets: + exponentialBuckets: + numFiniteBuckets: 20 + scale: 1 + growthFactor: 2 + metric_type: "istio.io/service/client/roundtrip_latencies" + client-received-bytes-count.instance.{{ .Release.Namespace }}: + kind: 3 # CUMULATIVE + value: 2 # INT64 + metric_type: "istio.io/service/client/received_bytes_count" + client-sent-bytes-count.instance.{{ .Release.Namespace }}: + kind: 3 # CUMULATIVE + value: 2 # INT64 + metric_type: "istio.io/service/client/sent_bytes_count" + logInfo: + server-accesslog-stackdriver.instance.{{ .Release.Namespace }}: + labelNames: + - source_uid + - source_ip + - source_app + - source_principal + - source_name + - source_workload + - source_namespace + - source_owner + - destination_uid + - destination_app + - destination_ip + - destination_service_host + - destination_workload + - destination_name + - destination_namespace + - destination_owner + - destination_principal + - api_name + - api_version + - api_claims + - api_key + - request_operation + - protocol + - method + - url + - response_code + - response_size + - request_size + - request_id + - latency + - service_authentication_policy + - user_agent + - response_timestamp + - received_bytes + - sent_bytes + - referer + server-tcp-accesslog-stackdriver.instance.{{ .Release.Namespace }}: + labelNames: + - connection_id + - connection_event + - source_uid + - source_ip + - source_app + - source_principal + - source_name + - source_workload + - source_namespace + - source_owner + - destination_uid + - destination_app + - destination_ip + - destination_service_host + - destination_workload + - destination_name + - destination_namespace + - destination_owner + - destination_principal + - protocol + - connction_duration + - service_authentication_policy + - received_bytes + - sent_bytes + - total_received_bytes + - total_sent_bytes +--- +################################################# +############## Metric Config #################### +################################################# +apiVersion: "config.istio.io/v1alpha2" +kind: rule +metadata: + name: stackdriver-server + namespace: {{ .Release.Namespace }} + labels: + app: istio-telemetry + release: {{ .Release.Name }} +spec: + match: (context.protocol == "http" || context.protocol == "grpc") && (context.reporter.kind | "inbound" == "inbound") + actions: + - handler: stackdriver + instances: + - server-request-count + - server-request-bytes + - server-response-bytes + - server-response-latencies +--- +apiVersion: "config.istio.io/v1alpha2" +kind: rule +metadata: + name: stackdriver-client + namespace: {{ .Release.Namespace }} + labels: + app: istio-telemetry + release: {{ .Release.Name }} +spec: + match: (context.protocol == "http" || context.protocol == "grpc") && (context.reporter.kind | "inbound" == "outbound") + actions: + - handler: stackdriver + instances: + - client-request-count + - client-request-bytes + - client-response-bytes + - client-roundtrip-latencies +--- +apiVersion: "config.istio.io/v1alpha2" +kind: rule +metadata: + name: stackdriver-tcp-server + namespace: {{ .Release.Namespace }} + labels: + app: istio-telemetry + release: {{ .Release.Name }} +spec: + match: context.protocol == "tcp" && (context.reporter.kind | "inbound" == "inbound") + actions: + - handler: stackdriver + instances: + - server-received-bytes-count + - server-sent-bytes-count +--- +apiVersion: "config.istio.io/v1alpha2" +kind: rule +metadata: + name: stackdriver-tcp-client + namespace: {{ .Release.Namespace }} + labels: + app: istio-telemetry + release: {{ .Release.Name }} +spec: + match: context.protocol == "tcp" && (context.reporter.kind | "inbound" == "outbound") + actions: + - handler: stackdriver + instances: + - client-received-bytes-count + - client-sent-bytes-count +--- +apiVersion: "config.istio.io/v1alpha2" +kind: instance +metadata: + name: server-request-count + namespace: {{ .Release.Namespace }} + labels: + app: istio-telemetry + release: {{ .Release.Name }} +spec: + compiledTemplate: metric + params: + value: "1" + dimensions: + destination_service_name: destination.service.name | "unknown" + destination_service_namespace: destination.service.namespace | "unknown" + destination_port: destination.port | 0 + request_operation: conditional((context.protocol | "unknown") == "grpc", request.path | "unknown", request.method | "unknown") + request_protocol: context.protocol | "unknown" + api_version: api.version | "unknown" + api_name: api.service | "unknown" + response_code: response.code | 0 + service_authentication_policy: conditional((context.reporter.kind | "inbound") == "outbound", "unknown", conditional(connection.mtls | false, "mutual_tls", "none")) + source_workload_namespace: source.workload.namespace | "unknown" + source_workload_name: source.workload.name | "unknown" + source_owner: source.owner | "unknown" + destination_workload_namespace: destination.workload.namespace | "unknown" + destination_workload_name: destination.workload.name | "unknown" + destination_owner: destination.owner | "unknown" + destination_principal: destination.principal | "unknown" + source_principal: source.principal | "unknown" + monitoredResourceType: '"k8s_container"' + monitoredResourceDimensions: + project_id: '""' + cluster_name: '""' + namespace_name: destination.workload.namespace | "unknown" + location: '""' + container_name: conditional((destination.name | "unknown").startsWith("istio-telemetry") || (destination.name | "unknown").startsWith("istio-policy"), "mixer", destination.container.name | "unknown") + pod_name: destination.name | "unknown" +--- +apiVersion: "config.istio.io/v1alpha2" +kind: instance +metadata: + name: client-request-count + namespace: {{ .Release.Namespace }} + labels: + app: istio-telemetry + release: {{ .Release.Name }} +spec: + compiledTemplate: metric + params: + value: "1" + dimensions: + destination_service_name: destination.service.name | "unknown" + destination_service_namespace: destination.service.namespace | "unknown" + destination_port: destination.port | 0 + request_operation: conditional((context.protocol | "unknown") == "grpc", request.path | "unknown", request.method | "unknown") + request_protocol: context.protocol | "unknown" + api_version: api.version | "unknown" + api_name: api.service | "unknown" + response_code: response.code | 0 + service_authentication_policy: conditional((context.reporter.kind | "inbound") == "outbound", "unknown", conditional(connection.mtls | false, "mutual_tls", "none")) + source_workload_namespace: source.workload.namespace | "unknown" + source_workload_name: source.workload.name | "unknown" + source_owner: source.owner | "unknown" + destination_workload_namespace: destination.workload.namespace | "unknown" + destination_workload_name: destination.workload.name | "unknown" + destination_owner: destination.owner | "unknown" + destination_principal: destination.principal | "unknown" + source_principal: source.principal | "unknown" + monitoredResourceType: '"k8s_pod"' + monitoredResourceDimensions: + project_id: '""' + cluster_name: '""' + namespace_name: source.workload.namespace | "unknown" + location: '""' + pod_name: source.name | "unknown" +--- +apiVersion: "config.istio.io/v1alpha2" +kind: instance +metadata: + name: server-request-bytes + namespace: {{ .Release.Namespace }} + labels: + app: istio-telemetry + release: {{ .Release.Name }} +spec: + compiledTemplate: metric + params: + value: request.total_size + dimensions: + destination_service_name: destination.service.name | "unknown" + destination_service_namespace: destination.service.namespace | "unknown" + destination_port: destination.port | 0 + request_operation: conditional((context.protocol | "unknown") == "grpc", request.path | "unknown", request.method | "unknown") + request_protocol: context.protocol | "unknown" + api_version: api.version | "unknown" + api_name: api.service | "unknown" + response_code: response.code | 0 + service_authentication_policy: conditional((context.reporter.kind | "inbound") == "outbound", "unknown", conditional(connection.mtls | false, "mutual_tls", "none")) + source_workload_namespace: source.workload.namespace | "unknown" + source_workload_name: source.workload.name | "unknown" + source_owner: source.owner | "unknown" + destination_workload_namespace: destination.workload.namespace | "unknown" + destination_workload_name: destination.workload.name | "unknown" + destination_owner: destination.owner | "unknown" + destination_principal: destination.principal | "unknown" + source_principal: source.principal | "unknown" + monitoredResourceType: '"k8s_container"' + monitoredResourceDimensions: + project_id: '""' + cluster_name: '""' + namespace_name: destination.workload.namespace | "unknown" + location: '""' + container_name: conditional((destination.name | "unknown").startsWith("istio-telemetry") || (destination.name | "unknown").startsWith("istio-policy"), "mixer", destination.container.name | "unknown") + pod_name: destination.name | "unknown" +--- +apiVersion: "config.istio.io/v1alpha2" +kind: instance +metadata: + name: client-request-bytes + namespace: {{ .Release.Namespace }} + labels: + app: istio-telemetry + release: {{ .Release.Name }} +spec: + compiledTemplate: metric + params: + value: request.total_size + dimensions: + destination_service_name: destination.service.name | "unknown" + destination_service_namespace: destination.service.namespace | "unknown" + destination_port: destination.port | 0 + request_operation: conditional((context.protocol | "unknown") == "grpc", request.path | "unknown", request.method | "unknown") + request_protocol: context.protocol | "unknown" + api_version: api.version | "unknown" + api_name: api.service | "unknown" + response_code: response.code | 0 + service_authentication_policy: conditional((context.reporter.kind | "inbound") == "outbound", "unknown", conditional(connection.mtls | false, "mutual_tls", "none")) + source_workload_namespace: source.workload.namespace | "unknown" + source_workload_name: source.workload.name | "unknown" + source_owner: source.owner | "unknown" + destination_workload_namespace: destination.workload.namespace | "unknown" + destination_workload_name: destination.workload.name | "unknown" + destination_owner: destination.owner | "unknown" + destination_principal: destination.principal | "unknown" + source_principal: source.principal | "unknown" + monitoredResourceType: '"k8s_pod"' + monitoredResourceDimensions: + project_id: '""' + cluster_name: '""' + namespace_name: source.workload.namespace | "unknown" + location: '""' + pod_name: source.name | "unknown" +--- +apiVersion: "config.istio.io/v1alpha2" +kind: instance +metadata: + name: server-response-bytes + namespace: {{ .Release.Namespace }} + labels: + app: istio-telemetry + release: {{ .Release.Name }} +spec: + compiledTemplate: metric + params: + value: response.total_size + dimensions: + destination_service_name: destination.service.name | "unknown" + destination_service_namespace: destination.service.namespace | "unknown" + destination_port: destination.port | 0 + request_operation: conditional((context.protocol | "unknown") == "grpc", request.path | "unknown", request.method | "unknown") + request_protocol: context.protocol | "unknown" + api_version: api.version | "unknown" + api_name: api.service | "unknown" + response_code: response.code | 0 + service_authentication_policy: conditional((context.reporter.kind | "inbound") == "outbound", "unknown", conditional(connection.mtls | false, "mutual_tls", "none")) + source_workload_namespace: source.workload.namespace | "unknown" + source_workload_name: source.workload.name | "unknown" + source_owner: source.owner | "unknown" + destination_workload_namespace: destination.workload.namespace | "unknown" + destination_workload_name: destination.workload.name | "unknown" + destination_owner: destination.owner | "unknown" + destination_principal: destination.principal | "unknown" + source_principal: source.principal | "unknown" + monitoredResourceType: '"k8s_container"' + monitoredResourceDimensions: + project_id: '""' + cluster_name: '""' + namespace_name: destination.workload.namespace | "unknown" + location: '""' + container_name: conditional((destination.name | "unknown").startsWith("istio-telemetry") || (destination.name | "unknown").startsWith("istio-policy"), "mixer", destination.container.name | "unknown") + pod_name: destination.name | "unknown" +--- +apiVersion: "config.istio.io/v1alpha2" +kind: instance +metadata: + name: client-response-bytes + namespace: {{ .Release.Namespace }} + labels: + app: istio-telemetry + release: {{ .Release.Name }} +spec: + compiledTemplate: metric + params: + value: response.total_size + dimensions: + destination_service_name: destination.service.name | "unknown" + destination_service_namespace: destination.service.namespace | "unknown" + destination_port: destination.port | 0 + request_operation: conditional((context.protocol | "unknown") == "grpc", request.path | "unknown", request.method | "unknown") + request_protocol: context.protocol | "unknown" + api_version: api.version | "unknown" + api_name: api.service | "unknown" + response_code: response.code | 0 + service_authentication_policy: conditional((context.reporter.kind | "inbound") == "outbound", "unknown", conditional(connection.mtls | false, "mutual_tls", "none")) + source_workload_namespace: source.workload.namespace | "unknown" + source_workload_name: source.workload.name | "unknown" + source_owner: source.owner | "unknown" + destination_workload_namespace: destination.workload.namespace | "unknown" + destination_workload_name: destination.workload.name | "unknown" + destination_owner: destination.owner | "unknown" + destination_principal: destination.principal | "unknown" + source_principal: source.principal | "unknown" + monitoredResourceType: '"k8s_pod"' + monitoredResourceDimensions: + project_id: '""' + cluster_name: '""' + namespace_name: source.workload.namespace | "unknown" + location: '""' + pod_name: source.name | "unknown" +--- +apiVersion: "config.istio.io/v1alpha2" +kind: instance +metadata: + name: server-response-latencies + namespace: {{ .Release.Namespace }} + labels: + app: istio-telemetry + release: {{ .Release.Name }} +spec: + compiledTemplate: metric + params: + value: response.duration + dimensions: + destination_service_name: destination.service.name | "unknown" + destination_service_namespace: destination.service.namespace | "unknown" + destination_port: destination.port | 0 + request_operation: conditional((context.protocol | "unknown") == "grpc", request.path | "unknown", request.method | "unknown") + request_protocol: context.protocol | "unknown" + api_version: api.version | "unknown" + api_name: api.service | "unknown" + response_code: response.code | 0 + service_authentication_policy: conditional((context.reporter.kind | "inbound") == "outbound", "unknown", conditional(connection.mtls | false, "mutual_tls", "none")) + source_workload_namespace: source.workload.namespace | "unknown" + source_workload_name: source.workload.name | "unknown" + source_owner: source.owner | "unknown" + destination_workload_namespace: destination.workload.namespace | "unknown" + destination_workload_name: destination.workload.name | "unknown" + destination_owner: destination.owner | "unknown" + destination_principal: destination.principal | "unknown" + source_principal: source.principal | "unknown" + monitoredResourceType: '"k8s_container"' + monitoredResourceDimensions: + project_id: '""' + cluster_name: '""' + namespace_name: destination.workload.namespace | "unknown" + location: '""' + container_name: conditional((destination.name | "unknown").startsWith("istio-telemetry") || (destination.name | "unknown").startsWith("istio-policy"), "mixer", destination.container.name | "unknown") + pod_name: destination.name | "unknown" +--- +apiVersion: "config.istio.io/v1alpha2" +kind: instance +metadata: + name: client-roundtrip-latencies + namespace: {{ .Release.Namespace }} + labels: + app: istio-telemetry + release: {{ .Release.Name }} +spec: + compiledTemplate: metric + params: + value: response.duration + dimensions: + destination_service_name: destination.service.name | "unknown" + destination_service_namespace: destination.service.namespace | "unknown" + destination_port: destination.port | 0 + request_operation: conditional((context.protocol | "unknown") == "grpc", request.path | "unknown", request.method | "unknown") + request_protocol: context.protocol | "unknown" + api_version: api.version | "unknown" + api_name: api.service | "unknown" + response_code: response.code | 0 + service_authentication_policy: conditional((context.reporter.kind | "inbound") == "outbound", "unknown", conditional(connection.mtls | false, "mutual_tls", "none")) + source_workload_namespace: source.workload.namespace | "unknown" + source_workload_name: source.workload.name | "unknown" + source_owner: source.owner | "unknown" + destination_workload_namespace: destination.workload.namespace | "unknown" + destination_workload_name: destination.workload.name | "unknown" + destination_owner: destination.owner | "unknown" + destination_principal: destination.principal | "unknown" + source_principal: source.principal | "unknown" + monitoredResourceType: '"k8s_pod"' + monitoredResourceDimensions: + project_id: '""' + cluster_name: '""' + namespace_name: source.workload.namespace | "unknown" + location: '""' + pod_name: source.name | "unknown" +--- +apiVersion: "config.istio.io/v1alpha2" +kind: instance +metadata: + name: server-received-bytes-count + namespace: {{ .Release.Namespace }} + labels: + app: istio-telemetry + release: {{ .Release.Name }} +spec: + compiledTemplate: metric + params: + value: connection.received.bytes | 0 + dimensions: + destination_service_name: destination.service.name | "unknown" + destination_service_namespace: destination.service.namespace | "unknown" + destination_port: destination.port | 0 + request_protocol: context.protocol | "unknown" + service_authentication_policy: conditional((context.reporter.kind | "inbound") == "outbound", "unknown", conditional(connection.mtls | false, "mutual_tls", "none")) + source_workload_namespace: source.workload.namespace | "unknown" + source_workload_name: source.workload.name | "unknown" + source_owner: source.owner | "unknown" + destination_workload_namespace: destination.workload.namespace | "unknown" + destination_workload_name: destination.workload.name | "unknown" + destination_owner: destination.owner | "unknown" + destination_principal: destination.principal | "unknown" + source_principal: source.principal | "unknown" + monitoredResourceType: '"k8s_container"' + monitoredResourceDimensions: + project_id: '""' + cluster_name: '""' + namespace_name: destination.workload.namespace | "unknown" + location: '""' + container_name: conditional((destination.name | "unknown").startsWith("istio-telemetry") || (destination.name | "unknown").startsWith("istio-policy"), "mixer", destination.container.name | "unknown") + pod_name: destination.name | "unknown" +--- +apiVersion: "config.istio.io/v1alpha2" +kind: instance +metadata: + name: client-received-bytes-count + namespace: {{ .Release.Namespace }} + labels: + app: istio-telemetry + release: {{ .Release.Name }} +spec: + compiledTemplate: metric + params: + value: connection.received.bytes | 0 + dimensions: + destination_service_name: destination.service.name | "unknown" + destination_service_namespace: destination.service.namespace | "unknown" + destination_port: destination.port | 0 + request_protocol: context.protocol | "unknown" + service_authentication_policy: conditional((context.reporter.kind | "inbound") == "outbound", "unknown", conditional(connection.mtls | false, "mutual_tls", "none")) + source_workload_namespace: source.workload.namespace | "unknown" + source_workload_name: source.workload.name | "unknown" + source_owner: source.owner | "unknown" + destination_workload_namespace: destination.workload.namespace | "unknown" + destination_workload_name: destination.workload.name | "unknown" + destination_owner: destination.owner | "unknown" + destination_principal: destination.principal | "unknown" + source_principal: source.principal | "unknown" + monitoredResourceType: '"k8s_pod"' + monitoredResourceDimensions: + project_id: '""' + cluster_name: '""' + namespace_name: source.workload.namespace | "unknown" + location: '""' + pod_name: source.name | "unknown" +--- +apiVersion: "config.istio.io/v1alpha2" +kind: instance +metadata: + name: server-sent-bytes-count + namespace: {{ .Release.Namespace }} + labels: + app: istio-telemetry + release: {{ .Release.Name }} +spec: + compiledTemplate: metric + params: + value: connection.sent.bytes | 0 + dimensions: + destination_service_name: destination.service.name | "unknown" + destination_service_namespace: destination.service.namespace | "unknown" + destination_port: destination.port | 0 + request_protocol: context.protocol | "unknown" + service_authentication_policy: conditional((context.reporter.kind | "inbound") == "outbound", "unknown", conditional(connection.mtls | false, "mutual_tls", "none")) + source_workload_namespace: source.workload.namespace | "unknown" + source_workload_name: source.workload.name | "unknown" + source_owner: source.owner | "unknown" + destination_workload_namespace: destination.workload.namespace | "unknown" + destination_workload_name: destination.workload.name | "unknown" + destination_owner: destination.owner | "unknown" + destination_principal: destination.principal | "unknown" + source_principal: source.principal | "unknown" + monitoredResourceType: '"k8s_container"' + monitoredResourceDimensions: + project_id: '""' + cluster_name: '""' + namespace_name: destination.workload.namespace | "unknown" + location: '""' + container_name: conditional((destination.name | "unknown").startsWith("istio-telemetry") || (destination.name | "unknown").startsWith("istio-policy"), "mixer", destination.container.name | "unknown") + pod_name: destination.name | "unknown" +--- +apiVersion: "config.istio.io/v1alpha2" +kind: instance +metadata: + name: client-sent-bytes-count + namespace: {{ .Release.Namespace }} + labels: + app: istio-telemetry + release: {{ .Release.Name }} +spec: + compiledTemplate: metric + params: + value: connection.sent.bytes | 0 + dimensions: + destination_service_name: destination.service.name | "unknown" + destination_service_namespace: destination.service.namespace | "unknown" + destination_port: destination.port | 0 + request_protocol: context.protocol | "unknown" + service_authentication_policy: conditional((context.reporter.kind | "inbound") == "outbound", "unknown", conditional(connection.mtls | false, "mutual_tls", "none")) + source_workload_namespace: source.workload.namespace | "unknown" + source_workload_name: source.workload.name | "unknown" + source_owner: source.owner | "unknown" + destination_workload_namespace: destination.workload.namespace | "unknown" + destination_workload_name: destination.workload.name | "unknown" + destination_owner: destination.owner | "unknown" + destination_principal: destination.principal | "unknown" + source_principal: source.principal | "unknown" + monitoredResourceType: '"k8s_pod"' + monitoredResourceDimensions: + project_id: '""' + cluster_name: '""' + namespace_name: source.workload.namespace | "unknown" + location: '""' + pod_name: source.name | "unknown" +--- +apiVersion: "config.istio.io/v1alpha2" +kind: instance +metadata: + name: server-accesslog-stackdriver + namespace: {{ .Release.Namespace }} + labels: + app: istio-telemetry + release: {{ .Release.Name }} +spec: + compiledTemplate: logentry + params: + severity: '"Info"' + timestamp: request.time + variables: + source_uid: source.uid | "" + source_ip: source.ip | ip("0.0.0.0") + source_app: source.labels["app"] | "" + source_principal: source.principal | "" + source_name: source.name | "" + source_workload: source.workload.name | "" + source_namespace: source.namespace | "" + source_owner: source.owner | "" + destination_uid: destination.uid | "" + destination_app: destination.labels["app"] | "" + destination_ip: destination.ip | ip("0.0.0.0") + destination_service_host: destination.service.host | "" + destination_workload: destination.workload.name | "" + destination_name: destination.name | "" + destination_namespace: destination.namespace | "" + destination_owner: destination.owner | "" + destination_principal: destination.principal | "" + api_name: api.service | "" + api_version: api.version | "" + api_claims: request.auth.raw_claims | "" + api_key: request.api_key | request.headers["x-api-key"] | "" + request_operation: conditional((context.protocol | "unknown") == "grpc", request.path | "unknown", request.method | "unknown") + protocol: request.scheme | context.protocol | "http" + method: request.method | "" + url: request.path | "" + response_code: response.code | 0 + response_size: response.size | 0 + request_size: request.size | 0 + request_id: request.headers["x-request-id"] | "" + latency: response.duration | "0ms" + service_authentication_policy: conditional((context.reporter.kind | "inbound") == "outbound", "unknown", conditional(connection.mtls | false, "mutual_tls", "none")) + user_agent: request.useragent | "" + response_timestamp: response.time + received_bytes: request.total_size | 0 + sent_bytes: response.total_size | 0 + referer: request.referer | "" + monitored_resource_type: '"k8s_container"' + monitoredResourceDimensions: + project_id: '""' + cluster_name: '""' + namespace_name: destination.namespace | "unknown" + location: '""' + container_name: conditional((destination.name | "unknown").startsWith("istio-telemetry") || (destination.name | "unknown").startsWith("istio-policy"), "mixer", destination.container.name | "unknown") + pod_name: destination.name | "unknown" +--- +apiVersion: "config.istio.io/v1alpha2" +kind: instance +metadata: + name: server-tcp-accesslog-stackdriver + namespace: {{ .Release.Namespace }} + labels: + app: istio-telemetry + release: {{ .Release.Name }} +spec: + compiledTemplate: logentry + params: + severity: '"Info"' + timestamp: context.time | timestamp("2017-01-01T00:00:00Z") + variables: + source_uid: source.uid | "" + connection_id: connection.id | "" + connection_event: connection.event | "" + source_ip: source.ip | ip("0.0.0.0") + source_app: source.labels["app"] | "" + source_principal: source.principal | "" + source_name: source.name | "" + source_workload: source.workload.name | "" + source_namespace: source.namespace | "" + source_owner: source.owner | "" + destination_uid: destination.uid | "" + destination_app: destination.labels["app"] | "" + destination_ip: destination.ip | ip("0.0.0.0") + destination_service_host: destination.service.host | "" + destination_workload: destination.workload.name | "" + destination_name: destination.name | "" + destination_namespace: destination.namespace | "" + destination_owner: destination.owner | "" + destination_principal: destination.principal | "" + protocol: context.protocol | "tcp" + connction_duration: connection.duration | "0ms" + service_authentication_policy: conditional((context.reporter.kind | "inbound") == "outbound", "unknown", conditional(connection.mtls | false, "mutual_tls", "none")) + received_bytes: connection.received.bytes | 0 + sent_bytes: connection.sent.bytes | 0 + total_received_bytes: connection.received.bytes_total | 0 + total_sent_bytes: connection.sent.bytes_total | 0 + monitored_resource_type: '"k8s_container"' + monitoredResourceDimensions: + project_id: '""' + cluster_name: '""' + namespace_name: destination.namespace | "unknown" + location: '""' + container_name: conditional((destination.name | "unknown").startsWith("istio-telemetry") || (destination.name | "unknown").startsWith("istio-policy"), "mixer", destination.container.name | "unknown") + pod_name: destination.name | "unknown" +--- +apiVersion: "config.istio.io/v1alpha2" +kind: rule +metadata: + name: stackdriver-log + namespace: {{ .Release.Namespace }} + labels: + app: istio-telemetry + release: {{ .Release.Name }} +spec: + match: (context.protocol == "http" || context.protocol == "grpc") && (context.reporter.kind | "inbound" == "inbound") + actions: + - handler: stackdriver + instances: + - server-accesslog-stackdriver +--- +apiVersion: "config.istio.io/v1alpha2" +kind: rule +metadata: + name: stackdriver-log-tcp + namespace: {{ .Release.Namespace }} + labels: + app: istio-telemetry + release: {{ .Release.Name }} +spec: + match: (context.protocol == "tcp") && (context.reporter.kind | "inbound" == "inbound") + actions: + - handler: stackdriver + instances: + - server-tcp-accesslog-stackdriver +--- +{{- if .Values.mixer.adapters.stackdriver.tracer.enabled }} +apiVersion: "config.istio.io/v1alpha2" +kind: instance +metadata: + name: stackdriver-span + namespace: {{ .Release.Namespace }} + labels: + app: istio-telemetry + release: {{ .Release.Name }} +spec: + compiledTemplate: tracespan + params: + traceId: request.headers["x-b3-traceid"] + spanId: request.headers["x-b3-spanid"] | "" + parentSpanId: request.headers["x-b3-parentspanid"] | "" + spanName: destination.service.host | destination.service.name | destination.workload.name | "unknown" + startTime: request.time + endTime: response.time + clientSpan: (context.reporter.kind | "inbound") == "outbound" + rewriteClientSpanId: "true" + spanTags: + destination_service_name: destination.service.name | "unknown" + destination_service_namespace: destination.service.namespace | "unknown" + destination_port: destination.port | 0 + request_operation: conditional((context.protocol | "unknown") == "grpc", request.path | "unknown", request.method | "unknown") + request_protocol: context.protocol | "unknown" + api_version: api.version | "unknown" + api_name: api.service | "unknown" + response_code: response.code | 0 + service_authentication_policy: conditional((context.reporter.kind | "inbound") == "outbound", "unknown", conditional(connection.mtls | false, "mutual_tls", "none")) + source_workload_namespace: source.workload.namespace | "unknown" + source_workload_name: source.workload.name | "unknown" + source_owner: source.owner | "unknown" + destination_workload_namespace: destination.workload.namespace | "unknown" + destination_workload_name: destination.workload.name | "unknown" + destination_owner: destination.owner | "unknown" + http_url: request.path | "" + request_size: request.size | 0 + response_size: response.size | 0 + source_ip: source.ip | ip("0.0.0.0") +--- +apiVersion: "config.istio.io/v1alpha2" +kind: rule +metadata: + name: stackdriver-tracing-rule + namespace: {{ .Release.Namespace }} + labels: + app: istio-telemetry + release: {{ .Release.Name }} +spec: + match: (context.protocol == "http" || context.protocol == "grpc") && request.headers["x-b3-sampled"] == "1" && destination.workload.name != "istio-telemetry" && destination.workload.name != "istio-pilot" + actions: + - handler: stackdriver + instances: + - stackdriver-span +{{- end }} +{{- end }} diff --git a/istio-1.3.5/install/kubernetes/operator/charts/istio-telemetry/mixer-telemetry/values.yaml b/istio-1.3.5/install/kubernetes/operator/charts/istio-telemetry/mixer-telemetry/values.yaml new file mode 100644 index 0000000..372a7b0 --- /dev/null +++ b/istio-1.3.5/install/kubernetes/operator/charts/istio-telemetry/mixer-telemetry/values.yaml @@ -0,0 +1,102 @@ +mixer: + env: + GODEBUG: gctrace=1 + # max procs should be ceil(cpu limit + 1) + GOMAXPROCS: "6" + + adapters: + # stdio is a debug adapter in istio-telemetry, it is not recommended for production use. + stdio: + # If set to true, will add 'rule' and 'stdio' handler for access logs. + # If false, user will need to configure their own rules outside of installer. + enabled: false + outputAsJson: false + + prometheus: + enabled: true + metricsExpiryDuration: 10m + + kubernetesenv: + enabled: true + + stackdriver: + enabled: false + + auth: + appCredentials: false + apiKey: "" + serviceAccountPath: "" + + tracer: + enabled: false + sampleProbability: 1 + + # Setting this to false sets the useAdapterCRDs mixer startup argument to false + useAdapterCRDs: false + + telemetry: + image: mixer + enabled: true + replicaCount: 1 + rollingMaxSurge: 100% + rollingMaxUnavailable: 25% + autoscaleEnabled: true + autoscaleMin: 1 + autoscaleMax: 5 + cpu: + targetAverageUtilization: 80 + sessionAffinityEnabled: false + + # mixer load shedding configuration. + # When mixer detects that it is overloaded, it starts rejecting grpc requests. + loadshedding: + # disabled, logonly or enforce + mode: enforce + # based on measurements 100ms p50 translates to p99 of under 1s. This is ok for telemetry which is inherently async. + latencyThreshold: 100ms + resources: + requests: + cpu: 1000m + memory: 1G + limits: + # It is best to do horizontal scaling of mixer using moderate cpu allocation. + # We have experimentally found that these values work well. + cpu: 4800m + memory: 4G + + # Set reportBatchMaxEntries to 0 to use the default batching behavior (i.e., every 100 requests). + # A positive value indicates the number of requests that are batched before telemetry data + # is sent to the mixer server + reportBatchMaxEntries: 100 + + # Set reportBatchMaxTime to 0 to use the default batching behavior (i.e., every 1 second). + # A positive time value indicates the maximum wait time since the last request will telemetry data + # be batched before being sent to the mixer server + reportBatchMaxTime: 1s + + # Indicate if Galley is enabled to send MCP queries + useMCP: true + + nodeSelector: {} + tolerations: [] + + # Specify the pod anti-affinity that allows you to constrain which nodes + # your pod is eligible to be scheduled based on labels on pods that are + # already running on the node rather than based on labels on nodes. + # There are currently two types of anti-affinity: + # "requiredDuringSchedulingIgnoredDuringExecution" + # "preferredDuringSchedulingIgnoredDuringExecution" + # which denote "hard" vs. "soft" requirements, you can define your values + # in "podAntiAffinityLabelSelector" and "podAntiAffinityTermLabelSelector" + # correspondingly. + # For example: + # podAntiAffinityLabelSelector: + # - key: security + # operator: In + # values: S1,S2 + # topologyKey: "kubernetes.io/hostname" + # This pod anti-affinity rule says that the pod requires not to be scheduled + # onto a node if that node is already running a pod with label having key + # "security" and value "S1". + podAntiAffinityLabelSelector: [] + podAntiAffinityTermLabelSelector: [] diff --git a/istio-1.3.5/install/kubernetes/operator/charts/istio-telemetry/prometheus-operator/Chart.yaml b/istio-1.3.5/install/kubernetes/operator/charts/istio-telemetry/prometheus-operator/Chart.yaml new file mode 100644 index 0000000..2d1b8b1 --- /dev/null +++ b/istio-1.3.5/install/kubernetes/operator/charts/istio-telemetry/prometheus-operator/Chart.yaml @@ -0,0 +1,6 @@ +apiVersion: v1 +description: A Helm chart for Kubernetes +name: prometheus-operator +version: 1.1.0 +appVersion: 2.3.1 +tillerVersion: ">=2.7.2" diff --git a/istio-1.3.5/install/kubernetes/operator/charts/istio-telemetry/prometheus-operator/templates/_affinity.tpl b/istio-1.3.5/install/kubernetes/operator/charts/istio-telemetry/prometheus-operator/templates/_affinity.tpl new file mode 100644 index 0000000..8f29eeb --- /dev/null +++ b/istio-1.3.5/install/kubernetes/operator/charts/istio-telemetry/prometheus-operator/templates/_affinity.tpl @@ -0,0 +1,93 @@ +{{/* affinity - https://kubernetes.io/docs/concepts/configuration/assign-pod-node/ */}} + +{{- define "nodeaffinity" }} + nodeAffinity: + requiredDuringSchedulingIgnoredDuringExecution: + {{- include "nodeAffinityRequiredDuringScheduling" . }} + preferredDuringSchedulingIgnoredDuringExecution: + {{- include "nodeAffinityPreferredDuringScheduling" . }} +{{- end }} + +{{- define "nodeAffinityRequiredDuringScheduling" }} + nodeSelectorTerms: + - matchExpressions: + - key: beta.kubernetes.io/arch + operator: In + values: + {{- range $key, $val := .Values.global.arch }} + {{- if gt ($val | int) 0 }} + - {{ $key }} + {{- end }} + {{- end }} + {{- $nodeSelector := default .Values.global.defaultNodeSelector .Values.prometheus.nodeSelector -}} + {{- range $key, $val := $nodeSelector }} + - key: {{ $key }} + operator: In + values: + - {{ $val }} + {{- end }} +{{- end }} + +{{- define "nodeAffinityPreferredDuringScheduling" }} + {{- range $key, $val := .Values.global.arch }} + {{- if gt ($val | int) 0 }} + - weight: {{ $val | int }} + preference: + matchExpressions: + - key: beta.kubernetes.io/arch + operator: In + values: + - {{ $key }} + {{- end }} + {{- end }} +{{- end }} + +{{- define "podAntiAffinity" }} +{{- if or .Values.prometheus.podAntiAffinityLabelSelector .Values.prometheus.podAntiAffinityTermLabelSelector}} + podAntiAffinity: + {{- if .Values.prometheus.podAntiAffinityLabelSelector }} + requiredDuringSchedulingIgnoredDuringExecution: + {{- include "podAntiAffinityRequiredDuringScheduling" . }} + {{- end }} + {{- if .Values.prometheus.podAntiAffinityTermLabelSelector }} + preferredDuringSchedulingIgnoredDuringExecution: + {{- include "podAntiAffinityPreferredDuringScheduling" . }} + {{- end }} +{{- end }} +{{- end }} + +{{- define "podAntiAffinityRequiredDuringScheduling" }} + {{- range $index, $item := .Values.prometheus.podAntiAffinityLabelSelector }} + - labelSelector: + matchExpressions: + - key: {{ $item.key }} + operator: {{ $item.operator }} + {{- if $item.values }} + values: + {{- $vals := split "," $item.values }} + {{- range $i, $v := $vals }} + - {{ $v }} + {{- end }} + {{- end }} + topologyKey: {{ $item.topologyKey }} + {{- end }} +{{- end }} + +{{- define "podAntiAffinityPreferredDuringScheduling" }} + {{- range $index, $item := .Values.prometheus.podAntiAffinityTermLabelSelector }} + - podAffinityTerm: + labelSelector: + matchExpressions: + - key: {{ $item.key }} + operator: {{ $item.operator }} + {{- if $item.values }} + values: + {{- $vals := split "," $item.values }} + {{- range $i, $v := $vals }} + - {{ $v }} + {{- end }} + {{- end }} + topologyKey: {{ $item.topologyKey }} + weight: 100 + {{- end }} +{{- end }} diff --git a/istio-1.3.5/install/kubernetes/operator/charts/istio-telemetry/prometheus-operator/templates/prometheus.yaml b/istio-1.3.5/install/kubernetes/operator/charts/istio-telemetry/prometheus-operator/templates/prometheus.yaml new file mode 100644 index 0000000..438d510 --- /dev/null +++ b/istio-1.3.5/install/kubernetes/operator/charts/istio-telemetry/prometheus-operator/templates/prometheus.yaml @@ -0,0 +1,159 @@ +{{- if .Values.prometheus.createPrometheusResource }} +apiVersion: monitoring.coreos.com/v1 +kind: Prometheus +metadata: + name: prometheus + namespace: {{ .Release.Namespace }} + labels: + release: {{ .Release.Name }} +spec: + image: "{{ .Values.prometheus.hub }}/prometheus:{{ .Values.prometheus.tag }}" + version: {{ .Values.prometheus.tag }} + retention: {{ .Values.prometheus.retention }} + scrapeInterval: {{ .Values.prometheus.scrapeInterval }} + serviceAccountName: prometheus + serviceMonitorSelector: + any: true + serviceMonitorNamespaceSelector: + any: true + secrets: [ istio.prometheus ] + enableAdminAPI: false +{{- if .Values.global.priorityClassName }} + priorityClassName: "{{ .Values.global.priorityClassName }}" +{{- end }} + affinity: + {{- include "nodeaffinity" . | indent 2 }} + {{- include "podAntiAffinity" . | indent 2 }} +{{- if .Values.prometheus.tolerations }} + tolerations: +{{ toYaml .Values.prometheus.tolerations | indent 2 }} +{{- end }} + podMetadata: + labels: + app: prometheus + release: {{ .Release.Name }} + annotations: + sidecar.istio.io/inject: "false" + resources: + requests: + memory: 400Mi +--- +apiVersion: rbac.authorization.k8s.io/v1beta1 +kind: ClusterRole +metadata: + name: prometheus-{{ .Release.Namespace }} + labels: + app: prometheus + release: {{ .Release.Name }} +rules: +- apiGroups: [""] + resources: + - nodes + - services + - endpoints + - pods + - nodes/proxy + verbs: ["get", "list", "watch"] +- apiGroups: [""] + resources: + - configmaps + verbs: ["get"] +- nonResourceURLs: ["/metrics"] + verbs: ["get"] +--- +apiVersion: rbac.authorization.k8s.io/v1beta1 +kind: ClusterRoleBinding +metadata: + name: prometheus-{{ .Release.Namespace }} + labels: + app: prometheus + release: {{ .Release.Name }} +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: prometheus-{{ .Release.Namespace }} +subjects: +- kind: ServiceAccount + name: prometheus + namespace: {{ .Release.Namespace }} +--- +apiVersion: networking.istio.io/v1alpha3 +kind: DestinationRule +metadata: + name: prometheus + namespace: {{ .Release.Namespace }} +spec: + host: prometheus.{{ .Release.Namespace }} + trafficPolicy: + tls: + mode: DISABLE +--- +apiVersion: networking.istio.io/v1alpha3 +kind: DestinationRule +metadata: + name: prometheus-full + namespace: {{ .Release.Namespace }} +spec: + host: prometheus.{{ .Release.Namespace }}.svc.cluster.local + trafficPolicy: + tls: + mode: DISABLE +--- +{{- if not .Values.prometheus.service.nodePort.enabled }} +apiVersion: v1 +kind: Service +metadata: + name: prometheus + namespace: {{ .Release.Namespace }} + annotations: + prometheus.io/scrape: 'true' + {{- if .Values.service }} + {{- range $key, $val := .Values.prometheus.service.annotations }} + {{ $key }}: {{ $val | quote }} + {{- end }} + {{- end }} + labels: + app: prometheus + release: {{ .Release.Name }} +spec: + selector: + app: prometheus + ports: + - name: http-prometheus + protocol: TCP + port: 9090 +{{- else }} +# Using separate ingress for nodeport, to avoid conflict with pilot e2e test configs. +apiVersion: v1 +kind: Service +metadata: + name: prometheus-nodeport + namespace: {{ .Release.Namespace }} + labels: + app: prometheus + release: {{ .Release.Name }} +spec: + type: NodePort + ports: + - port: 9090 + nodePort: {{ .Values.prometheus.service.nodePort.port }} + name: http-prometheus + selector: + app: prometheus +{{- end }} +--- +apiVersion: v1 +kind: ServiceAccount +{{- if .Values.global.imagePullSecrets }} +imagePullSecrets: +{{- range .Values.global.imagePullSecrets }} + - name: {{ . }} +{{- end }} +{{- end }} +metadata: + name: prometheus + namespace: {{ .Release.Namespace }} + labels: + app: prometheus + release: {{ .Release.Name }} +{{- end }} diff --git a/istio-1.3.5/install/kubernetes/operator/charts/istio-telemetry/prometheus-operator/templates/servicemonitors.yaml b/istio-1.3.5/install/kubernetes/operator/charts/istio-telemetry/prometheus-operator/templates/servicemonitors.yaml new file mode 100644 index 0000000..aa0ab06 --- /dev/null +++ b/istio-1.3.5/install/kubernetes/operator/charts/istio-telemetry/prometheus-operator/templates/servicemonitors.yaml @@ -0,0 +1,314 @@ +apiVersion: monitoring.coreos.com/v1 +kind: ServiceMonitor +metadata: + name: istio-mesh-monitor + namespace: {{ .Release.Namespace }} + labels: + monitoring: istio-mesh + release: {{ .Release.Name }} +spec: + selector: + matchExpressions: + - {key: istio, operator: In, values: [mixer]} + namespaceSelector: + matchNames: + - {{ .Values.global.telemetryNamespace }} + endpoints: + - port: prometheus + interval: {{ .Values.prometheus.scrapeInterval }} +--- +apiVersion: monitoring.coreos.com/v1 +kind: ServiceMonitor +metadata: + name: istio-component-monitor + namespace: {{ .Release.Namespace }} + labels: + monitoring: istio-components + release: {{ .Release.Name }} +spec: + selector: + matchExpressions: + - {key: istio, operator: In, values: [mixer,pilot,galley,citadel]} + namespaceSelector: + any: true + endpoints: + - port: http-monitoring + interval: {{ .Values.prometheus.scrapeInterval }} + - port: http-policy-monitoring + interval: {{ .Values.prometheus.scrapeInterval }} +--- +apiVersion: monitoring.coreos.com/v1 +kind: ServiceMonitor +metadata: + name: envoy-stats-monitor + namespace: {{ .Release.Namespace }} + labels: + monitoring: istio-proxies + release: {{ .Release.Name }} +spec: + selector: + matchExpressions: + - {key: istio-prometheus-ignore, operator: DoesNotExist} + namespaceSelector: + any: true + jobLabel: envoy-stats + endpoints: + - path: /stats/prometheus + targetPort: 15090 + interval: {{ .Values.prometheus.scrapeInterval }} + relabelings: + - sourceLabels: [__meta_kubernetes_pod_container_port_name] + action: keep + regex: '.*-envoy-prom' + - action: labelmap + regex: "__meta_kubernetes_pod_label_(.+)" + - sourceLabels: [__meta_kubernetes_namespace] + action: replace + targetLabel: namespace + - sourceLabels: [__meta_kubernetes_pod_name] + action: replace + targetLabel: pod_name +--- +apiVersion: monitoring.coreos.com/v1 +kind: ServiceMonitor +metadata: + name: kubernetes-pods-monitor + namespace: {{ .Release.Namespace }} + labels: + monitoring: kube-pods + release: {{ .Release.Name }} +spec: + selector: + matchExpressions: + - {key: istio-prometheus-ignore, operator: DoesNotExist} + namespaceSelector: + any: true + jobLabel: kubernetes-pods + endpoints: + - interval: {{ .Values.prometheus.scrapeInterval }} + relabelings: + - sourceLabels: [__meta_kubernetes_pod_annotation_prometheus_io_scrape] + action: keep + regex: 'true' + - sourceLabels: [__meta_kubernetes_pod_annotation_sidecar_istio_io_status, __meta_kubernetes_pod_annotation_prometheus_io_scheme] + action: keep + regex: '((;.*)|(.*;http)|(.??))' + - sourceLabels: [__meta_kubernetes_pod_annotation_istio_mtls] + action: drop + regex: 'true' + - sourceLabels: [__meta_kubernetes_pod_annotation_prometheus_io_path] + action: replace + targetLabel: __metrics_path__ + regex: '(.+)' + - sourceLabels: [__address__, __meta_kubernetes_pod_annotation_prometheus_io_port] + action: replace + regex: '([^:]+)(?::\d+)?;(\d+)' + replacement: $1:$2 + targetLabel: __address__ + - action: labelmap + regex: '__meta_kubernetes_pod_label_(.+)' + - sourceLabels: [__meta_kubernetes_namespace] + action: replace + targetLabel: namespace + - sourceLabels: [__meta_kubernetes_pod_name] + action: replace + targetLabel: pod_name +--- +{{- if .Values.prometheus.security.enabled }} +apiVersion: monitoring.coreos.com/v1 +kind: ServiceMonitor +metadata: + name: kubernetes-pods-secure-monitor + namespace: {{ .Release.Namespace }} + labels: + monitoring: kube-pods-secure + release: {{ .Release.Name }} +spec: + selector: + matchExpressions: + - {key: istio-prometheus-ignore, operator: DoesNotExist} + namespaceSelector: + any: true + jobLabel: kubernetes-pods-secure + endpoints: + - interval: {{ .Values.prometheus.scrapeInterval }} + scheme: https + tlsConfig: + caFile: /etc/prometheus/secrets/istio.prometheus/root-cert.pem + certFile: /etc/prometheus/secrets/istio.prometheus/cert-chain.pem + keyFile: /etc/prometheus/secrets/istio.prometheus/key.pem + insecureSkipVerify: true # prometheus does not support secure naming. + relabelings: + - sourceLabels: [__meta_kubernetes_pod_annotation_prometheus_io_scrape] + action: keep + regex: 'true' + # sidecar status annotation is added by sidecar injector and + # istio_workload_mtls_ability can be specifically placed on a pod to indicate its ability to receive mtls traffic. + - sourceLabels: [__meta_kubernetes_pod_annotation_sidecar_istio_io_status, __meta_kubernetes_pod_annotation_istio_mtls] + action: keep + regex: '(([^;]+);([^;]*))|(([^;]*);(true))' + - sourceLabels: [__meta_kubernetes_pod_annotation_prometheus_io_scheme] + action: drop + regex: '(http)' + - sourceLabels: [__meta_kubernetes_pod_annotation_prometheus_io_path] + action: replace + targetLabel: __metrics_path__ + regex: '(.+)' + - sourceLabels: [__address__] # Only keep address that is host:port + action: keep # otherwise an extra target with ':443' is added for https scheme + regex: '([^:]+):(\d+)' + - sourceLabels: [__address__, __meta_kubernetes_pod_annotation_prometheus_io_port] + action: replace + regex: '([^:]+)(?::\d+)?;(\d+)' + replacement: $1:$2 + targetLabel: __address__ + - action: labelmap + regex: '__meta_kubernetes_pod_label_(.+)' + - sourceLabels: [__meta_kubernetes_namespace] + action: replace + targetLabel: namespace + - sourceLabels: [__meta_kubernetes_pod_name] + action: replace + targetLabel: pod_name +{{- end }} +--- +apiVersion: monitoring.coreos.com/v1 +kind: ServiceMonitor +metadata: + name: kubernetes-services-monitor + namespace: {{ .Release.Namespace }} + labels: + monitoring: kube-services + release: {{ .Release.Name }} +spec: + selector: + matchExpressions: + - {key: istio-prometheus-ignore, operator: DoesNotExist} + namespaceSelector: + any: true + jobLabel: kubernetes-services + endpoints: + - interval: {{ .Values.prometheus.scrapeInterval }} + relabelings: + - sourceLabels: [__meta_kubernetes_service_annotation_prometheus_io_scrape] + action: keep + regex: 'true' + - sourceLabels: [__meta_kubernetes_pod_annotation_sidecar_istio_io_status, __meta_kubernetes_service_annotation_prometheus_io_scheme] + action: keep + regex: '((;.*)|(.*;http)|(.??))' + - sourceLabels: [__meta_kubernetes_pod_annotation_istio_mtls] + action: drop + regex: 'true' + - sourceLabels: [__meta_kubernetes_service_annotation_prometheus_io_path] + action: replace + targetLabel: __metrics_path__ + regex: '(.+)' + - sourceLabels: [__address__, __meta_kubernetes_service_annotation_prometheus_io_port] + action: replace + regex: '([^:]+)(?::\d+)?;(\d+)' + replacement: $1:$2 + targetLabel: __address__ + - action: labelmap + regex: '__meta_kubernetes_pod_label_(.+)' + - sourceLabels: [__meta_kubernetes_namespace] + action: replace + targetLabel: namespace + - sourceLabels: [__meta_kubernetes_pod_name] + action: replace + targetLabel: pod_name +--- +{{- if .Values.prometheus.security.enabled }} +apiVersion: monitoring.coreos.com/v1 +kind: ServiceMonitor +metadata: + name: kubernetes-services-secure-monitor + namespace: {{ .Release.Namespace }} + labels: + monitoring: kube-services-secure + release: {{ .Release.Name }} +spec: + selector: + matchExpressions: + - {key: istio-prometheus-ignore, operator: DoesNotExist} + namespaceSelector: + any: true + jobLabel: kubernetes-services-secure + endpoints: + - interval: {{ .Values.prometheus.scrapeInterval }} + scheme: https + tlsConfig: + caFile: /etc/prometheus/secrets/istio.prometheus/root-cert.pem + certFile: /etc/prometheus/secrets/istio.prometheus/cert-chain.pem + keyFile: /etc/prometheus/secrets/istio.prometheus/key.pem + insecureSkipVerify: true # prometheus does not support secure naming. + relabelings: + - sourceLabels: [__meta_kubernetes_service_annotation_prometheus_io_scrape] + action: keep + regex: 'true' + # sidecar status annotation is added by sidecar injector and + # istio_workload_mtls_ability can be specifically placed on a pod to indicate its ability to receive mtls traffic. + - sourceLabels: [__meta_kubernetes_pod_annotation_sidecar_istio_io_status, __meta_kubernetes_pod_annotation_istio_mtls] + action: keep + regex: '(([^;]+);([^;]*))|(([^;]*);(true))' + - sourceLabels: [__meta_kubernetes_service_annotation_prometheus_io_scheme] + action: drop + regex: '(http)' + - sourceLabels: [__meta_kubernetes_service_annotation_prometheus_io_path] + action: replace + targetLabel: __metrics_path__ + regex: '(.+)' + - sourceLabels: [__address__] # Only keep address that is host:port + action: keep # otherwise an extra target with ':443' is added for https scheme + regex: '([^:]+):(\d+)' + - sourceLabels: [__address__, __meta_kubernetes_service_annotation_prometheus_io_port] + action: replace + regex: '([^:]+)(?::\d+)?;(\d+)' + replacement: $1:$2 + targetLabel: __address__ + - action: labelmap + regex: '__meta_kubernetes_pod_label_(.+)' + - sourceLabels: [__meta_kubernetes_namespace] + action: replace + targetLabel: namespace + - sourceLabels: [__meta_kubernetes_pod_name] + action: replace + targetLabel: pod_name +{{- end }} +--- +apiVersion: monitoring.coreos.com/v1 +kind: ServiceMonitor +metadata: + name: kubelet + namespace: {{ .Release.Namespace }} + labels: + monitoring: kubelet-monitor + release: {{ .Release.Name }} +spec: + endpoints: + - bearerTokenFile: /var/run/secrets/kubernetes.io/serviceaccount/token + honorLabels: true + interval: {{ .Values.prometheus.scrapeInterval }} + port: http-metrics + scheme: http + tlsConfig: + insecureSkipVerify: true + - bearerTokenFile: /var/run/secrets/kubernetes.io/serviceaccount/token + honorLabels: true + interval: {{ .Values.prometheus.scrapeInterval }} + metricRelabelings: + - action: drop + regex: container_(network_tcp_usage_total|network_udp_usage_total|tasks_state|cpu_load_average_10s) + sourceLabels: + - __name__ + path: /metrics/cadvisor + port: http-metrics + scheme: http + tlsConfig: + insecureSkipVerify: true + jobLabel: k8s-app + namespaceSelector: + matchNames: + - kube-system + selector: + matchLabels: + k8s-app: kubelet diff --git a/istio-1.3.5/install/kubernetes/operator/charts/istio-telemetry/prometheus-operator/values.yaml b/istio-1.3.5/install/kubernetes/operator/charts/istio-telemetry/prometheus-operator/values.yaml new file mode 100644 index 0000000..f295d90 --- /dev/null +++ b/istio-1.3.5/install/kubernetes/operator/charts/istio-telemetry/prometheus-operator/values.yaml @@ -0,0 +1,47 @@ +prometheus: + # Controls the default scrape interval used in the ServiceMonitors + scrapeInterval: 15s + + # Enabling this option will generate a Prometheus resource, causing the operator + # to create a prometheus deployment according to the generated spec. It will also + # create a service definition, destination rules, cluster roles and bindings, and + # a service account. Only use this option if you have not already created and configured + # a prometheus resource and/or you desire a distinct prometheus resource for Istio. + createPrometheusResource: false + hub: docker.io/prom + tag: v2.8.0 + retention: 6h + + service: + annotations: {} + nodePort: + enabled: false + port: 32090 + + # Indicate if Citadel is enabled, i.e., whether its generated certificates are available + security: + enabled: true + + nodeSelector: {} + tolerations: [] + + # Specify the pod anti-affinity that allows you to constrain which nodes + # your pod is eligible to be scheduled based on labels on pods that are + # already running on the node rather than based on labels on nodes. + # There are currently two types of anti-affinity: + # "requiredDuringSchedulingIgnoredDuringExecution" + # "preferredDuringSchedulingIgnoredDuringExecution" + # which denote "hard" vs. "soft" requirements, you can define your values + # in "podAntiAffinityLabelSelector" and "podAntiAffinityTermLabelSelector" + # correspondingly. + # For example: + # podAntiAffinityLabelSelector: + # - key: security + # operator: In + # values: S1,S2 + # topologyKey: "kubernetes.io/hostname" + # This pod anti-affinity rule says that the pod requires not to be scheduled + # onto a node if that node is already running a pod with label having key + # "security" and value "S1". + podAntiAffinityLabelSelector: [] + podAntiAffinityTermLabelSelector: [] diff --git a/istio-1.3.5/install/kubernetes/operator/charts/istio-telemetry/prometheus/Chart.yaml b/istio-1.3.5/install/kubernetes/operator/charts/istio-telemetry/prometheus/Chart.yaml new file mode 100644 index 0000000..6431a43 --- /dev/null +++ b/istio-1.3.5/install/kubernetes/operator/charts/istio-telemetry/prometheus/Chart.yaml @@ -0,0 +1,6 @@ +apiVersion: v1 +description: A Helm chart for Kubernetes +name: prometheus +version: 1.1.0 +appVersion: 2.8.0 +tillerVersion: ">=2.7.2" diff --git a/istio-1.3.5/install/kubernetes/operator/charts/istio-telemetry/prometheus/templates/_affinity.tpl b/istio-1.3.5/install/kubernetes/operator/charts/istio-telemetry/prometheus/templates/_affinity.tpl new file mode 100644 index 0000000..8f29eeb --- /dev/null +++ b/istio-1.3.5/install/kubernetes/operator/charts/istio-telemetry/prometheus/templates/_affinity.tpl @@ -0,0 +1,93 @@ +{{/* affinity - https://kubernetes.io/docs/concepts/configuration/assign-pod-node/ */}} + +{{- define "nodeaffinity" }} + nodeAffinity: + requiredDuringSchedulingIgnoredDuringExecution: + {{- include "nodeAffinityRequiredDuringScheduling" . }} + preferredDuringSchedulingIgnoredDuringExecution: + {{- include "nodeAffinityPreferredDuringScheduling" . }} +{{- end }} + +{{- define "nodeAffinityRequiredDuringScheduling" }} + nodeSelectorTerms: + - matchExpressions: + - key: beta.kubernetes.io/arch + operator: In + values: + {{- range $key, $val := .Values.global.arch }} + {{- if gt ($val | int) 0 }} + - {{ $key }} + {{- end }} + {{- end }} + {{- $nodeSelector := default .Values.global.defaultNodeSelector .Values.prometheus.nodeSelector -}} + {{- range $key, $val := $nodeSelector }} + - key: {{ $key }} + operator: In + values: + - {{ $val }} + {{- end }} +{{- end }} + +{{- define "nodeAffinityPreferredDuringScheduling" }} + {{- range $key, $val := .Values.global.arch }} + {{- if gt ($val | int) 0 }} + - weight: {{ $val | int }} + preference: + matchExpressions: + - key: beta.kubernetes.io/arch + operator: In + values: + - {{ $key }} + {{- end }} + {{- end }} +{{- end }} + +{{- define "podAntiAffinity" }} +{{- if or .Values.prometheus.podAntiAffinityLabelSelector .Values.prometheus.podAntiAffinityTermLabelSelector}} + podAntiAffinity: + {{- if .Values.prometheus.podAntiAffinityLabelSelector }} + requiredDuringSchedulingIgnoredDuringExecution: + {{- include "podAntiAffinityRequiredDuringScheduling" . }} + {{- end }} + {{- if .Values.prometheus.podAntiAffinityTermLabelSelector }} + preferredDuringSchedulingIgnoredDuringExecution: + {{- include "podAntiAffinityPreferredDuringScheduling" . }} + {{- end }} +{{- end }} +{{- end }} + +{{- define "podAntiAffinityRequiredDuringScheduling" }} + {{- range $index, $item := .Values.prometheus.podAntiAffinityLabelSelector }} + - labelSelector: + matchExpressions: + - key: {{ $item.key }} + operator: {{ $item.operator }} + {{- if $item.values }} + values: + {{- $vals := split "," $item.values }} + {{- range $i, $v := $vals }} + - {{ $v }} + {{- end }} + {{- end }} + topologyKey: {{ $item.topologyKey }} + {{- end }} +{{- end }} + +{{- define "podAntiAffinityPreferredDuringScheduling" }} + {{- range $index, $item := .Values.prometheus.podAntiAffinityTermLabelSelector }} + - podAffinityTerm: + labelSelector: + matchExpressions: + - key: {{ $item.key }} + operator: {{ $item.operator }} + {{- if $item.values }} + values: + {{- $vals := split "," $item.values }} + {{- range $i, $v := $vals }} + - {{ $v }} + {{- end }} + {{- end }} + topologyKey: {{ $item.topologyKey }} + weight: 100 + {{- end }} +{{- end }} diff --git a/istio-1.3.5/install/kubernetes/operator/charts/istio-telemetry/prometheus/templates/clusterrole.yaml b/istio-1.3.5/install/kubernetes/operator/charts/istio-telemetry/prometheus/templates/clusterrole.yaml new file mode 100644 index 0000000..ddf0c0d --- /dev/null +++ b/istio-1.3.5/install/kubernetes/operator/charts/istio-telemetry/prometheus/templates/clusterrole.yaml @@ -0,0 +1,22 @@ +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: prometheus-{{ .Release.Namespace }} + labels: + app: prometheus + release: {{ .Release.Name }} +rules: +- apiGroups: [""] + resources: + - nodes + - services + - endpoints + - pods + - nodes/proxy + verbs: ["get", "list", "watch"] +- apiGroups: [""] + resources: + - configmaps + verbs: ["get"] +- nonResourceURLs: ["/metrics"] + verbs: ["get"] diff --git a/istio-1.3.5/install/kubernetes/operator/charts/istio-telemetry/prometheus/templates/clusterrolebindings.yaml b/istio-1.3.5/install/kubernetes/operator/charts/istio-telemetry/prometheus/templates/clusterrolebindings.yaml new file mode 100644 index 0000000..5619efe --- /dev/null +++ b/istio-1.3.5/install/kubernetes/operator/charts/istio-telemetry/prometheus/templates/clusterrolebindings.yaml @@ -0,0 +1,15 @@ +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: prometheus-{{ .Release.Namespace }} + labels: + app: prometheus + release: {{ .Release.Name }} +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: prometheus-{{ .Release.Namespace }} +subjects: +- kind: ServiceAccount + name: prometheus + namespace: {{ .Release.Namespace }} diff --git a/istio-1.3.5/install/kubernetes/operator/charts/istio-telemetry/prometheus/templates/configmap.yaml b/istio-1.3.5/install/kubernetes/operator/charts/istio-telemetry/prometheus/templates/configmap.yaml new file mode 100644 index 0000000..59961cd --- /dev/null +++ b/istio-1.3.5/install/kubernetes/operator/charts/istio-telemetry/prometheus/templates/configmap.yaml @@ -0,0 +1,281 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: prometheus + namespace: {{ .Release.Namespace }} + labels: + app: prometheus + release: {{ .Release.Name }} +data: + prometheus.yml: |- + global: + scrape_interval: {{ .Values.prometheus.scrapeInterval }} + scrape_configs: + + # Mixer scrapping. Defaults to Prometheus and mixer on same namespace. + # + - job_name: 'istio-mesh' + kubernetes_sd_configs: + - role: endpoints + namespaces: + names: + - {{ .Release.Namespace }} + {{- range $key, $value := .Values.prometheus.datasources }} + - {{ $value }} + {{- end }} + relabel_configs: + - source_labels: [__meta_kubernetes_service_name, __meta_kubernetes_endpoint_port_name] + action: keep + regex: istio-telemetry;prometheus + + # Scrape config for envoy stats + - job_name: 'envoy-stats' + metrics_path: /stats/prometheus + kubernetes_sd_configs: + - role: pod + + relabel_configs: + - source_labels: [__meta_kubernetes_pod_container_port_name] + action: keep + regex: '.*-envoy-prom' + - source_labels: [__address__, __meta_kubernetes_pod_annotation_prometheus_io_port] + action: replace + regex: ([^:]+)(?::\d+)?;(\d+) + replacement: $1:15090 + target_label: __address__ + - action: labelmap + regex: __meta_kubernetes_pod_label_(.+) + - source_labels: [__meta_kubernetes_namespace] + action: replace + target_label: namespace + - source_labels: [__meta_kubernetes_pod_name] + action: replace + target_label: pod_name + + - job_name: 'istio-policy' + kubernetes_sd_configs: + - role: endpoints + namespaces: + names: + - {{ .Values.global.policyNamespace }} + + + relabel_configs: + - source_labels: [__meta_kubernetes_service_name, __meta_kubernetes_endpoint_port_name] + action: keep + regex: istio-policy;http-policy-monitoring + + - job_name: 'istio-telemetry' + kubernetes_sd_configs: + - role: endpoints + namespaces: + names: + - {{ .Release.Namespace }} + + relabel_configs: + - source_labels: [__meta_kubernetes_service_name, __meta_kubernetes_endpoint_port_name] + action: keep + regex: istio-telemetry;http-monitoring + + - job_name: 'pilot' + kubernetes_sd_configs: + - role: endpoints + namespaces: + names: + - {{ .Values.global.istioNamespace }} + + relabel_configs: + - source_labels: [__meta_kubernetes_service_name, __meta_kubernetes_endpoint_port_name] + action: keep + regex: istio-pilot;http-monitoring + + - job_name: 'galley' + kubernetes_sd_configs: + - role: endpoints + namespaces: + names: + - {{ .Values.global.configNamespace }} + + relabel_configs: + - source_labels: [__meta_kubernetes_service_name, __meta_kubernetes_endpoint_port_name] + action: keep + regex: istio-galley;http-monitoring + + - job_name: 'citadel' + kubernetes_sd_configs: + - role: endpoints + namespaces: + names: + - {{ .Release.Namespace }} + + relabel_configs: + - source_labels: [__meta_kubernetes_service_name, __meta_kubernetes_endpoint_port_name] + action: keep + regex: istio-citadel;http-monitoring + + # scrape config for API servers + - job_name: 'kubernetes-apiservers' + kubernetes_sd_configs: + - role: endpoints + namespaces: + names: + - default + scheme: https + tls_config: + ca_file: /var/run/secrets/kubernetes.io/serviceaccount/ca.crt + bearer_token_file: /var/run/secrets/kubernetes.io/serviceaccount/token + relabel_configs: + - source_labels: [__meta_kubernetes_service_name, __meta_kubernetes_endpoint_port_name] + action: keep + regex: kubernetes;https + + # scrape config for nodes (kubelet) + - job_name: 'kubernetes-nodes' + scheme: https + tls_config: + ca_file: /var/run/secrets/kubernetes.io/serviceaccount/ca.crt + bearer_token_file: /var/run/secrets/kubernetes.io/serviceaccount/token + kubernetes_sd_configs: + - role: node + relabel_configs: + - action: labelmap + regex: __meta_kubernetes_node_label_(.+) + - target_label: __address__ + replacement: kubernetes.default.svc:443 + - source_labels: [__meta_kubernetes_node_name] + regex: (.+) + target_label: __metrics_path__ + replacement: /api/v1/nodes/${1}/proxy/metrics + + # Scrape config for Kubelet cAdvisor. + # + # This is required for Kubernetes 1.7.3 and later, where cAdvisor metrics + # (those whose names begin with 'container_') have been removed from the + # Kubelet metrics endpoint. This job scrapes the cAdvisor endpoint to + # retrieve those metrics. + # + # In Kubernetes 1.7.0-1.7.2, these metrics are only exposed on the cAdvisor + # HTTP endpoint; use "replacement: /api/v1/nodes/${1}:4194/proxy/metrics" + # in that case (and ensure cAdvisor's HTTP server hasn't been disabled with + # the --cadvisor-port=0 Kubelet flag). + # + # This job is not necessary and should be removed in Kubernetes 1.6 and + # earlier versions, or it will cause the metrics to be scraped twice. + - job_name: 'kubernetes-cadvisor' + scheme: https + tls_config: + ca_file: /var/run/secrets/kubernetes.io/serviceaccount/ca.crt + bearer_token_file: /var/run/secrets/kubernetes.io/serviceaccount/token + kubernetes_sd_configs: + - role: node + relabel_configs: + - action: labelmap + regex: __meta_kubernetes_node_label_(.+) + - target_label: __address__ + replacement: kubernetes.default.svc:443 + - source_labels: [__meta_kubernetes_node_name] + regex: (.+) + target_label: __metrics_path__ + replacement: /api/v1/nodes/${1}/proxy/metrics/cadvisor + + # scrape config for service endpoints. + - job_name: 'kubernetes-service-endpoints' + kubernetes_sd_configs: + - role: endpoints + relabel_configs: + - source_labels: [__meta_kubernetes_service_annotation_prometheus_io_scrape] + action: keep + regex: true + - source_labels: [__meta_kubernetes_service_annotation_prometheus_io_scheme] + action: replace + target_label: __scheme__ + regex: (https?) + - source_labels: [__meta_kubernetes_service_annotation_prometheus_io_path] + action: replace + target_label: __metrics_path__ + regex: (.+) + - source_labels: [__address__, __meta_kubernetes_service_annotation_prometheus_io_port] + action: replace + target_label: __address__ + regex: ([^:]+)(?::\d+)?;(\d+) + replacement: $1:$2 + - action: labelmap + regex: __meta_kubernetes_service_label_(.+) + - source_labels: [__meta_kubernetes_namespace] + action: replace + target_label: kubernetes_namespace + - source_labels: [__meta_kubernetes_service_name] + action: replace + target_label: kubernetes_name + + - job_name: 'kubernetes-pods' + kubernetes_sd_configs: + - role: pod + relabel_configs: # If first two labels are present, pod should be scraped by the istio-secure job. + - source_labels: [__meta_kubernetes_pod_annotation_prometheus_io_scrape] + action: keep + regex: true + - source_labels: [__meta_kubernetes_pod_annotation_sidecar_istio_io_status] + action: drop + regex: (.+) + - source_labels: [__meta_kubernetes_pod_annotation_istio_mtls] + action: drop + regex: (true) + - source_labels: [__meta_kubernetes_pod_annotation_prometheus_io_path] + action: replace + target_label: __metrics_path__ + regex: (.+) + - source_labels: [__address__, __meta_kubernetes_pod_annotation_prometheus_io_port] + action: replace + regex: ([^:]+)(?::\d+)?;(\d+) + replacement: $1:$2 + target_label: __address__ + - action: labelmap + regex: __meta_kubernetes_pod_label_(.+) + - source_labels: [__meta_kubernetes_namespace] + action: replace + target_label: namespace + - source_labels: [__meta_kubernetes_pod_name] + action: replace + target_label: pod_name + +{{- if .Values.prometheus.security.enabled }} + - job_name: 'kubernetes-pods-istio-secure' + scheme: https + tls_config: + ca_file: /etc/istio-certs/root-cert.pem + cert_file: /etc/istio-certs/cert-chain.pem + key_file: /etc/istio-certs/key.pem + insecure_skip_verify: true # prometheus does not support secure naming. + kubernetes_sd_configs: + - role: pod + relabel_configs: + - source_labels: [__meta_kubernetes_pod_annotation_prometheus_io_scrape] + action: keep + regex: true + # sidecar status annotation is added by sidecar injector and + # istio_workload_mtls_ability can be specifically placed on a pod to indicate its ability to receive mtls traffic. + - source_labels: [__meta_kubernetes_pod_annotation_sidecar_istio_io_status, __meta_kubernetes_pod_annotation_istio_mtls] + action: keep + regex: (([^;]+);([^;]*))|(([^;]*);(true)) + - source_labels: [__meta_kubernetes_pod_annotation_prometheus_io_path] + action: replace + target_label: __metrics_path__ + regex: (.+) + - source_labels: [__address__] # Only keep address that is host:port + action: keep # otherwise an extra target with ':443' is added for https scheme + regex: ([^:]+):(\d+) + - source_labels: [__address__, __meta_kubernetes_pod_annotation_prometheus_io_port] + action: replace + regex: ([^:]+)(?::\d+)?;(\d+) + replacement: $1:$2 + target_label: __address__ + - action: labelmap + regex: __meta_kubernetes_pod_label_(.+) + - source_labels: [__meta_kubernetes_namespace] + action: replace + target_label: namespace + - source_labels: [__meta_kubernetes_pod_name] + action: replace + target_label: pod_name +{{- end }} diff --git a/istio-1.3.5/install/kubernetes/operator/charts/istio-telemetry/prometheus/templates/deployment.yaml b/istio-1.3.5/install/kubernetes/operator/charts/istio-telemetry/prometheus/templates/deployment.yaml new file mode 100644 index 0000000..4135880 --- /dev/null +++ b/istio-1.3.5/install/kubernetes/operator/charts/istio-telemetry/prometheus/templates/deployment.yaml @@ -0,0 +1,73 @@ +# TODO: the original template has service account, roles, etc +apiVersion: apps/v1 +kind: Deployment +metadata: + name: prometheus + namespace: {{ .Release.Namespace }} + labels: + app: prometheus + release: {{ .Release.Name }} +spec: + replicas: {{ .Values.prometheus.replicaCount }} + selector: + matchLabels: + app: prometheus + template: + metadata: + labels: + app: prometheus + release: {{ .Release.Name }} + annotations: + sidecar.istio.io/inject: "false" + spec: + serviceAccountName: prometheus +{{- if .Values.global.priorityClassName }} + priorityClassName: "{{ .Values.global.priorityClassName }}" +{{- end }} + containers: + - name: prometheus + image: "{{ .Values.prometheus.hub }}/{{ .Values.prometheus.image }}:{{ .Values.prometheus.tag }}" + imagePullPolicy: {{ .Values.global.imagePullPolicy | default "Always" }} + args: + - '--storage.tsdb.retention={{ .Values.prometheus.retention }}' + - '--config.file=/etc/prometheus/prometheus.yml' + ports: + - containerPort: 9090 + name: http + livenessProbe: + httpGet: + path: /-/healthy + port: 9090 + readinessProbe: + httpGet: + path: /-/ready + port: 9090 + resources: +{{- if .Values.prometheus.resources }} +{{ toYaml .Values.prometheus.resources | indent 12 }} +{{- else }} +{{ toYaml .Values.global.defaultResources | indent 12 }} +{{- end }} + volumeMounts: + - name: config-volume + mountPath: /etc/prometheus + - mountPath: /etc/istio-certs + name: istio-certs + volumes: + - name: config-volume + configMap: + name: prometheus + - name: istio-certs + secret: + defaultMode: 420 +{{- if not .Values.prometheus.security.enabled }} + optional: true +{{- end }} + secretName: istio.default + affinity: + {{- include "nodeaffinity" . | indent 6 }} + {{- include "podAntiAffinity" . | indent 6 }} +{{- if .Values.prometheus.tolerations }} + tolerations: +{{ toYaml .Values.prometheus.tolerations | indent 6 }} +{{- end }} diff --git a/istio-1.3.5/install/kubernetes/operator/charts/istio-telemetry/prometheus/templates/destination-rule.yaml b/istio-1.3.5/install/kubernetes/operator/charts/istio-telemetry/prometheus/templates/destination-rule.yaml new file mode 100644 index 0000000..b56e7bb --- /dev/null +++ b/istio-1.3.5/install/kubernetes/operator/charts/istio-telemetry/prometheus/templates/destination-rule.yaml @@ -0,0 +1,21 @@ +apiVersion: networking.istio.io/v1alpha3 +kind: DestinationRule +metadata: + name: prometheys + namespace: {{ .Release.Namespace }} +spec: + host: prometheus.{{ .Release.Namespace }} + trafficPolicy: + tls: + mode: DISABLE +--- +apiVersion: networking.istio.io/v1alpha3 +kind: DestinationRule +metadata: + name: prometheus-full + namespace: {{ .Release.Namespace }} +spec: + host: prometheus.{{ .Release.Namespace }}.svc.cluster.local + trafficPolicy: + tls: + mode: DISABLE diff --git a/istio-1.3.5/install/kubernetes/operator/charts/istio-telemetry/prometheus/templates/inrgess.yaml b/istio-1.3.5/install/kubernetes/operator/charts/istio-telemetry/prometheus/templates/inrgess.yaml new file mode 100644 index 0000000..8cd8721 --- /dev/null +++ b/istio-1.3.5/install/kubernetes/operator/charts/istio-telemetry/prometheus/templates/inrgess.yaml @@ -0,0 +1,38 @@ +{{- if .Values.prometheus.ingress.enabled -}} +apiVersion: extensions/v1beta1 +kind: Ingress +metadata: + name: prometheus + namespace: {{ .Release.Namespace }} + labels: + app: prometheus + release: {{ .Release.Name }} + annotations: + {{- range $key, $value := .Values.prometheus.ingress.annotations }} + {{ $key }}: {{ $value | quote }} + {{- end }} +spec: + rules: +{{- if .Values.prometheus.ingress.hosts }} + {{- range $host := .Values.prometheus.ingress.hosts }} + - host: {{ $host }} + http: + paths: + - path: {{ if $.Values.prometheus.contextPath }} {{ $.Values.prometheus.contextPath }} {{ else }} / {{ end }} + backend: + serviceName: prometheus + servicePort: 9090 + {{- end -}} +{{- else }} + - http: + paths: + - path: {{ if .Values.prometheus.contextPath }} {{ .Values.prometheus.contextPath }} {{ else }} / {{ end }} + backend: + serviceName: prometheus + servicePort: 9090 +{{- end }} + {{- if .Values.prometheus.ingress.tls }} + tls: +{{ toYaml .Values.prometheus.ingress.tls | indent 4 }} + {{- end -}} +{{- end -}} \ No newline at end of file diff --git a/istio-1.3.5/install/kubernetes/operator/charts/istio-telemetry/prometheus/templates/service.yaml b/istio-1.3.5/install/kubernetes/operator/charts/istio-telemetry/prometheus/templates/service.yaml new file mode 100644 index 0000000..321c4ff --- /dev/null +++ b/istio-1.3.5/install/kubernetes/operator/charts/istio-telemetry/prometheus/templates/service.yaml @@ -0,0 +1,43 @@ +apiVersion: v1 +kind: Service +metadata: + name: prometheus + namespace: {{ .Release.Namespace }} + annotations: + prometheus.io/scrape: 'true' + {{- if .Values.prometheus.service }} + {{- range $key, $val := .Values.prometheus.service.annotations }} + {{ $key }}: {{ $val | quote }} + {{- end }} + {{- end }} + labels: + app: prometheus + release: {{ .Release.Name }} +spec: + selector: + app: prometheus + ports: + - name: http-prometheus + protocol: TCP + port: 9090 + +{{- if .Values.prometheus.service }} +# Using separate ingress for nodeport, to avoid conflict with pilot e2e test configs. +--- +apiVersion: v1 +kind: Service +metadata: + name: prometheus-nodeport + namespace: {{ .Release.Namespace }} + labels: + app: prometheus + release: {{ .Release.Name }} +spec: + type: NodePort + ports: + - port: 9090 + nodePort: {{ .Values.prometheus.service.nodePort.port }} + name: http-prometheus + selector: + app: prometheus +{{- end }} diff --git a/istio-1.3.5/install/kubernetes/operator/charts/istio-telemetry/prometheus/templates/serviceaccount.yaml b/istio-1.3.5/install/kubernetes/operator/charts/istio-telemetry/prometheus/templates/serviceaccount.yaml new file mode 100644 index 0000000..095d1c7 --- /dev/null +++ b/istio-1.3.5/install/kubernetes/operator/charts/istio-telemetry/prometheus/templates/serviceaccount.yaml @@ -0,0 +1,14 @@ +apiVersion: v1 +kind: ServiceAccount +{{- if .Values.global.imagePullSecrets }} +imagePullSecrets: +{{- range .Values.global.imagePullSecrets }} + - name: {{ . }} +{{- end }} +{{- end }} +metadata: + name: prometheus + namespace: {{ .Release.Namespace }} + labels: + app: prometheus + release: {{ .Release.Name }} diff --git a/istio-1.3.5/install/kubernetes/operator/charts/istio-telemetry/prometheus/templates/tests/test-prometheus-connection.yaml b/istio-1.3.5/install/kubernetes/operator/charts/istio-telemetry/prometheus/templates/tests/test-prometheus-connection.yaml new file mode 100644 index 0000000..d41dc14 --- /dev/null +++ b/istio-1.3.5/install/kubernetes/operator/charts/istio-telemetry/prometheus/templates/tests/test-prometheus-connection.yaml @@ -0,0 +1,27 @@ +{{- if .Values.global.enableHelmTest }} +apiVersion: v1 +kind: Pod +metadata: + name: prometheus-test + namespace: {{ .Release.Namespace }} + labels: + app: prometheus-test + release: {{ .Release.Name }} + istio: prometheus + annotations: + sidecar.istio.io/inject: "false" + helm.sh/hook: test-success +spec: +{{- if .Values.global.priorityClassName }} + priorityClassName: "{{ .Values.global.priorityClassName }}" +{{- end }} + containers: + - name: "prometheus-test" + image: {{ .Values.global.hub }}/{{ .Values.global.proxy.image }}:{{ .Values.global.tag }} + imagePullPolicy: "{{ .Values.global.imagePullPolicy }}" + command: ['sh', '-c', 'for i in 1 2 3; do curl http://prometheus:9090/-/ready && exit 0 || sleep 15; done; exit 1'] + restartPolicy: Never + affinity: + {{- include "nodeaffinity" . | indent 4 }} + {{- include "podAntiAffinity" . | indent 4 }} +{{- end }} diff --git a/istio-1.3.5/install/kubernetes/operator/charts/istio-telemetry/prometheus/values.yaml b/istio-1.3.5/install/kubernetes/operator/charts/istio-telemetry/prometheus/values.yaml new file mode 100644 index 0000000..d391d3d --- /dev/null +++ b/istio-1.3.5/install/kubernetes/operator/charts/istio-telemetry/prometheus/values.yaml @@ -0,0 +1,62 @@ +prometheus: + enabled: true + replicaCount: 1 + hub: docker.io/prom + image: prometheus + tag: v2.8.0 + retention: 6h + + # Controls the frequency of prometheus scraping + scrapeInterval: 15s + + contextPath: /prometheus + + ingress: + enabled: false + ## Used to create an Ingress record. + hosts: + - prometheus.local + annotations: + # kubernetes.io/ingress.class: nginx + # kubernetes.io/tls-acme: "true" + tls: + # Secrets must be manually created in the namespace. + # - secretName: prometheus-tls + # hosts: + # - prometheus.local + + # 1.2 it is disabled by default - it can be enabled for special cases, but would create port + # conflicts. In general it is not recommended to use node ports for services, but use gateways instead. +# service: +# annotations: {} +# nodePort: +# enabled: false +# port: 32090 + + # Indicate if Citadel is enabled, i.e., whether its generated certificates are available + security: + enabled: true + + nodeSelector: {} + tolerations: [] + + # Specify the pod anti-affinity that allows you to constrain which nodes + # your pod is eligible to be scheduled based on labels on pods that are + # already running on the node rather than based on labels on nodes. + # There are currently two types of anti-affinity: + # "requiredDuringSchedulingIgnoredDuringExecution" + # "preferredDuringSchedulingIgnoredDuringExecution" + # which denote "hard" vs. "soft" requirements, you can define your values + # in "podAntiAffinityLabelSelector" and "podAntiAffinityTermLabelSelector" + # correspondingly. + # For example: + # podAntiAffinityLabelSelector: + # - key: security + # operator: In + # values: S1,S2 + # topologyKey: "kubernetes.io/hostname" + # This pod anti-affinity rule says that the pod requires not to be scheduled + # onto a node if that node is already running a pod with label having key + # "security" and value "S1". + podAntiAffinityLabelSelector: [] + podAntiAffinityTermLabelSelector: [] diff --git a/istio-1.3.5/install/kubernetes/operator/charts/istio-telemetry/tracing/Chart.yaml b/istio-1.3.5/install/kubernetes/operator/charts/istio-telemetry/tracing/Chart.yaml new file mode 100644 index 0000000..3fb213d --- /dev/null +++ b/istio-1.3.5/install/kubernetes/operator/charts/istio-telemetry/tracing/Chart.yaml @@ -0,0 +1,6 @@ +apiVersion: v1 +description: A Helm chart for tracing +name: tracing +version: 1.1.0 +appVersion: 1.5.1 +tillerVersion: ">=2.7.2" \ No newline at end of file diff --git a/istio-1.3.5/install/kubernetes/operator/charts/istio-telemetry/tracing/templates/_affinity.tpl b/istio-1.3.5/install/kubernetes/operator/charts/istio-telemetry/tracing/templates/_affinity.tpl new file mode 100644 index 0000000..a6cda34 --- /dev/null +++ b/istio-1.3.5/install/kubernetes/operator/charts/istio-telemetry/tracing/templates/_affinity.tpl @@ -0,0 +1,86 @@ +{{/* affinity - https://kubernetes.io/docs/concepts/configuration/assign-pod-node/ */}} + +{{- define "nodeaffinity" }} + nodeAffinity: + requiredDuringSchedulingIgnoredDuringExecution: + {{- include "nodeAffinityRequiredDuringScheduling" . }} + preferredDuringSchedulingIgnoredDuringExecution: + {{- include "nodeAffinityPreferredDuringScheduling" . }} +{{- end }} + +{{- define "nodeAffinityRequiredDuringScheduling" }} + nodeSelectorTerms: + - matchExpressions: + - key: beta.kubernetes.io/arch + operator: In + values: + {{- range $key, $val := .Values.global.arch }} + {{- if gt ($val | int) 0 }} + - {{ $key }} + {{- end }} + {{- end }} +{{- end }} + +{{- define "nodeAffinityPreferredDuringScheduling" }} + {{- range $key, $val := .Values.global.arch }} + {{- if gt ($val | int) 0 }} + - weight: {{ $val | int }} + preference: + matchExpressions: + - key: beta.kubernetes.io/arch + operator: In + values: + - {{ $key }} + {{- end }} + {{- end }} +{{- end }} + +{{- define "podAntiAffinity" }} +{{- if or .Values.podAntiAffinityLabelSelector .Values.podAntiAffinityTermLabelSelector}} + podAntiAffinity: + {{- if .Values.podAntiAffinityLabelSelector }} + requiredDuringSchedulingIgnoredDuringExecution: + {{- include "podAntiAffinityRequiredDuringScheduling" . }} + {{- end }} + {{- if or .Values.podAntiAffinityTermLabelSelector}} + preferredDuringSchedulingIgnoredDuringExecution: + {{- include "podAntiAffinityPreferredDuringScheduling" . }} + {{- end }} +{{- end }} +{{- end }} + +{{- define "podAntiAffinityRequiredDuringScheduling" }} + {{- range $index, $item := .Values.podAntiAffinityLabelSelector }} + - labelSelector: + matchExpressions: + - key: {{ $item.key }} + operator: {{ $item.operator }} + {{- if $item.values }} + values: + {{- $vals := split "," $item.values }} + {{- range $i, $v := $vals }} + - {{ $v }} + {{- end }} + {{- end }} + topologyKey: {{ $item.topologyKey }} + {{- end }} +{{- end }} + +{{- define "podAntiAffinityPreferredDuringScheduling" }} + {{- range $index, $item := .Values.podAntiAffinityTermLabelSelector }} + - podAffinityTerm: + labelSelector: + matchExpressions: + - key: {{ $item.key }} + operator: {{ $item.operator }} + {{- if $item.values }} + values: + {{- $vals := split "," $item.values }} + {{- range $i, $v := $vals }} + - {{ $v }} + {{- end }} + {{- end }} + topologyKey: {{ $item.topologyKey }} + weight: 100 + {{- end }} +{{- end }} \ No newline at end of file diff --git a/istio-1.3.5/install/kubernetes/operator/charts/istio-telemetry/tracing/templates/deployment-jaeger.yaml b/istio-1.3.5/install/kubernetes/operator/charts/istio-telemetry/tracing/templates/deployment-jaeger.yaml new file mode 100644 index 0000000..62174c4 --- /dev/null +++ b/istio-1.3.5/install/kubernetes/operator/charts/istio-telemetry/tracing/templates/deployment-jaeger.yaml @@ -0,0 +1,106 @@ +{{ if eq .Values.tracing.provider "jaeger" }} + +apiVersion: apps/v1 +kind: Deployment +metadata: + name: istio-tracing + namespace: {{ .Release.Namespace }} + labels: + app: jaeger + release: {{ .Release.Name }} +spec: + selector: + matchLabels: + app: jaeger + template: + metadata: + labels: + app: jaeger + release: {{ .Release.Name }} + annotations: + sidecar.istio.io/inject: "false" + prometheus.io/scrape: "true" + prometheus.io/port: "16686" +{{- if .Values.tracing.contextPath }} + prometheus.io/path: "{{ .Values.tracing.contextPath }}/metrics" +{{- else }} + prometheus.io/path: "/{{ .Values.tracing.provider }}/metrics" +{{- end }} + spec: +{{- if .Values.global.priorityClassName }} + priorityClassName: "{{ .Values.global.priorityClassName }}" +{{- end }} +{{- if .Values.global.imagePullSecrets }} + imagePullSecrets: +{{- range .Values.global.imagePullSecrets }} + - name: {{ . }} +{{- end }} +{{- end }} + containers: + - name: jaeger + image: "{{ .Values.tracing.jaeger.hub }}/{{ .Values.tracing.jaeger.image }}:{{ .Values.tracing.jaeger.tag }}" + imagePullPolicy: {{ .Values.global.imagePullPolicy | default "Always" }} + ports: + - containerPort: 9411 + - containerPort: 16686 + - containerPort: 5775 + protocol: UDP + - containerPort: 6831 + protocol: UDP + - containerPort: 6832 + protocol: UDP + env: + - name: POD_NAMESPACE + valueFrom: + fieldRef: + apiVersion: v1 + fieldPath: metadata.namespace + {{- if eq .Values.tracing.jaeger.spanStorageType "badger" }} + - name: BADGER_EPHEMERAL + value: "false" + - name: SPAN_STORAGE_TYPE + value: "badger" + - name: BADGER_DIRECTORY_VALUE + value: "/badger/data" + - name: BADGER_DIRECTORY_KEY + value: "/badger/key" + {{- end }} + - name: COLLECTOR_ZIPKIN_HTTP_PORT + value: "9411" + - name: MEMORY_MAX_TRACES + value: "{{ .Values.tracing.jaeger.memory.max_traces }}" + - name: QUERY_BASE_PATH + value: {{ if .Values.tracing.contextPath }} {{ .Values.tracing.contextPath }} {{ else }} /{{ .Values.tracing.provider }} {{ end }} + livenessProbe: + httpGet: + path: / + port: 16686 + readinessProbe: + httpGet: + path: / + port: 16686 +{{- if eq .Values.tracing.jaeger.spanStorageType "badger" }} + volumeMounts: + - name: data + mountPath: /badger +{{- end }} + resources: +{{- if .Values.tracing.jaeger.resources }} +{{ toYaml .Values.tracing.jaeger.resources | indent 12 }} +{{- else }} +{{ toYaml .Values.global.defaultResources | indent 12 }} +{{- end }} + affinity: + {{- include "nodeaffinity" . | indent 6 }} + {{- include "podAntiAffinity" . | indent 6 }} +{{- if eq .Values.tracing.jaeger.spanStorageType "badger" }} + volumes: + - name: data +{{- if .Values.tracing.jaeger.persist }} + persistentVolumeClaim: + claimName: istio-jaeger-pvc +{{- else }} + emptyDir: {} +{{- end }} +{{- end }} +{{ end }} diff --git a/istio-1.3.5/install/kubernetes/operator/charts/istio-telemetry/tracing/templates/deployment-opencensus.yaml b/istio-1.3.5/install/kubernetes/operator/charts/istio-telemetry/tracing/templates/deployment-opencensus.yaml new file mode 100644 index 0000000..d7510ec --- /dev/null +++ b/istio-1.3.5/install/kubernetes/operator/charts/istio-telemetry/tracing/templates/deployment-opencensus.yaml @@ -0,0 +1,94 @@ +{{ if eq .Values.tracing.provider "opencensus" }} +apiVersion: v1 +kind: ConfigMap +metadata: + name: oc-collector-config + labels: + app: opencensus + component: oc-collector-config +data: + oc-collector-config: | + receivers: + zipkin: + address: "127.0.0.1:9411" + exporters: +{{- if .Values.tracing.opencensus.exporters }} +{{ toYaml .Values.tracing.opencensus.exporters | indent 6 }} +{{- end }} +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: istio-tracing + namespace: {{ .Release.Namespace }} + labels: + app: opencensus + component: oc-collector + release: {{ .Release.Name }} +spec: + selector: + matchLabels: + app: opencensus + minReadySeconds: 5 + progressDeadlineSeconds: 120 + replicas: 1 + template: + metadata: + annotations: + sidecar.istio.io/inject: "false" + prometheus.io/path: "/metrics" + prometheus.io/port: "8888" + prometheus.io/scrape: "true" + labels: + app: opencensus + component: oc-collector + spec: +{{- if .Values.global.priorityClassName }} + priorityClassName: "{{ .Values.global.priorityClassName }}" +{{- end }} +{{- if .Values.global.imagePullSecrets }} + imagePullSecrets: +{{- range .Values.global.imagePullSecrets }} + - name: {{ . }} +{{- end }} +{{- end }} + containers: + - name: oc-collector + image: "{{ .Values.tracing.opencensus.hub }}/opencensus-collector:{{ .Values.tracing.opencensus.tag }}" + imagePullPolicy: {{ .Values.global.imagePullPolicy | default "Always" }} + command: + - "/occollector_linux" + - "--config=/conf/oc-collector-config.yaml" + ports: + - containerPort: 9411 + resources: +{{- if .Values.tracing.opencensus.resources }} +{{ toYaml .Values.tracing.opencensus.resources | indent 12 }} +{{- else }} +{{ toYaml .Values.global.defaultResources | indent 12 }} +{{- end }} + volumeMounts: + - name: oc-collector-config-vol + mountPath: /conf + livenessProbe: + httpGet: + path: / + port: 13133 + readinessProbe: + httpGet: + path: / + port: 13133 + env: + - name: GOGC + value: "80" + volumes: + - configMap: + name: oc-collector-config + items: + - key: oc-collector-config + path: oc-collector-config.yaml + name: oc-collector-config-vol + affinity: + {{- include "nodeaffinity" . | indent 6 }} + {{- include "podAntiAffinity" . | indent 6 }} +{{ end }} diff --git a/istio-1.3.5/install/kubernetes/operator/charts/istio-telemetry/tracing/templates/deployment-zipkin.yaml b/istio-1.3.5/install/kubernetes/operator/charts/istio-telemetry/tracing/templates/deployment-zipkin.yaml new file mode 100644 index 0000000..47a3552 --- /dev/null +++ b/istio-1.3.5/install/kubernetes/operator/charts/istio-telemetry/tracing/templates/deployment-zipkin.yaml @@ -0,0 +1,71 @@ +{{ if eq .Values.tracing.provider "zipkin" }} + +apiVersion: apps/v1 +kind: Deployment +metadata: + name: istio-tracing + namespace: {{ .Release.Namespace }} + labels: + app: zipkin + release: {{ .Release.Name }} +spec: + selector: + matchLabels: + app: zipkin + template: + metadata: + labels: + app: zipkin + release: {{ .Release.Name }} + annotations: + sidecar.istio.io/inject: "false" + scheduler.alpha.kubernetes.io/critical-pod: "" + spec: +{{- if .Values.global.priorityClassName }} + priorityClassName: "{{ .Values.global.priorityClassName }}" +{{- end }} +{{- if .Values.global.imagePullSecrets }} + imagePullSecrets: +{{- range .Values.global.imagePullSecrets }} + - name: {{ . }} +{{- end }} +{{- end }} + containers: + - name: zipkin + image: "{{ .Values.tracing.zipkin.hub }}/{{ .Values.tracing.zipkin.image }}:{{ .Values.tracing.zipkin.tag }}" + imagePullPolicy: {{ .Values.global.imagePullPolicy | default "Always" }} + ports: + - containerPort: {{ .Values.tracing.zipkin.queryPort }} + livenessProbe: + initialDelaySeconds: {{ .Values.tracing.zipkin.probeStartupDelay }} + tcpSocket: + port: {{ .Values.tracing.zipkin.queryPort }} + readinessProbe: + initialDelaySeconds: {{ .Values.tracing.zipkin.probeStartupDelay }} + httpGet: + path: /health + port: {{ .Values.tracing.zipkin.queryPort }} + resources: +{{- if .Values.tracing.zipkin.resources }} +{{ toYaml .Values.tracing.zipkin.resources | indent 12 }} +{{- else }} +{{ toYaml .Values.global.defaultResources | indent 12 }} +{{- end }} + env: + - name: POD_NAMESPACE + valueFrom: + fieldRef: + apiVersion: v1 + fieldPath: metadata.namespace + - name: QUERY_PORT + value: "{{ .Values.tracing.zipkin.queryPort }}" + - name: JAVA_OPTS + value: "-XX:ConcGCThreads={{ .Values.tracing.zipkin.node.cpus }} -XX:ParallelGCThreads={{ .Values.tracing.zipkin.node.cpus }} -Djava.util.concurrent.ForkJoinPool.common.parallelism={{ .Values.tracing.zipkin.node.cpus }} -Xms{{ .Values.tracing.zipkin.javaOptsHeap }}M -Xmx{{ .Values.tracing.zipkin.javaOptsHeap }}M -XX:+UseG1GC -server" + - name: STORAGE_METHOD + value: "mem" + - name: ZIPKIN_STORAGE_MEM_MAXSPANS + value: "{{ .Values.tracing.zipkin.maxSpans }}" + affinity: + {{- include "nodeaffinity" . | indent 6 }} + {{- include "podAntiAffinity" . | indent 6 }} +{{ end }} diff --git a/istio-1.3.5/install/kubernetes/operator/charts/istio-telemetry/tracing/templates/pvc.yaml b/istio-1.3.5/install/kubernetes/operator/charts/istio-telemetry/tracing/templates/pvc.yaml new file mode 100644 index 0000000..012cdd0 --- /dev/null +++ b/istio-1.3.5/install/kubernetes/operator/charts/istio-telemetry/tracing/templates/pvc.yaml @@ -0,0 +1,19 @@ +{{- if eq .Values.tracing.provider "jaeger" }} +{{- if .Values.tracing.jaeger.persist }} +kind: PersistentVolumeClaim +apiVersion: v1 +metadata: + name: istio-jaeger-pvc + namespace: {{ .Release.Namespace }} + labels: + app: {{ .Values.tracing.provider }} + release: {{ .Release.Name }} +spec: + storageClassName: {{ .Values.tracing.jaeger.storageClassName }} + accessModes: + - {{ .Values.tracing.jaeger.accessMode }} + resources: + requests: + storage: 5Gi +{{- end }} +{{- end }} \ No newline at end of file diff --git a/istio-1.3.5/install/kubernetes/operator/charts/istio-telemetry/tracing/templates/service-jaeger.yaml b/istio-1.3.5/install/kubernetes/operator/charts/istio-telemetry/tracing/templates/service-jaeger.yaml new file mode 100644 index 0000000..c1d6b47 --- /dev/null +++ b/istio-1.3.5/install/kubernetes/operator/charts/istio-telemetry/tracing/templates/service-jaeger.yaml @@ -0,0 +1,46 @@ +{{ if eq .Values.tracing.provider "jaeger" }} +apiVersion: v1 +kind: Service +metadata: + name: jaeger-query + namespace: {{ .Release.Namespace }} + annotations: + {{- range $key, $val := .Values.tracing.service.annotations }} + {{ $key }}: {{ $val | quote }} + {{- end }} + labels: + app: jaeger + jaeger-infra: jaeger-service + release: {{ .Release.Name }} +spec: + ports: + - name: query-http + port: 16686 + protocol: TCP + targetPort: 16686 + selector: + app: jaeger +--- +apiVersion: v1 +kind: Service +metadata: + name: jaeger-collector + namespace: {{ .Release.Namespace }} + labels: + app: jaeger + jaeger-infra: collector-service + release: {{ .Release.Name }} +spec: + ports: + - name: jaeger-collector-tchannel + port: 14267 + protocol: TCP + targetPort: 14267 + - name: jaeger-collector-http + port: 14268 + targetPort: 14268 + protocol: TCP + selector: + app: jaeger + type: ClusterIP +{{ end }} \ No newline at end of file diff --git a/istio-1.3.5/install/kubernetes/operator/charts/istio-telemetry/tracing/templates/service.yaml b/istio-1.3.5/install/kubernetes/operator/charts/istio-telemetry/tracing/templates/service.yaml new file mode 100644 index 0000000..25a4d10 --- /dev/null +++ b/istio-1.3.5/install/kubernetes/operator/charts/istio-telemetry/tracing/templates/service.yaml @@ -0,0 +1,44 @@ +apiVersion: v1 +kind: Service +metadata: + name: zipkin + namespace: {{ .Release.Namespace }} + labels: + app: {{ .Values.tracing.provider }} + release: {{ .Release.Name }} +spec: + type: {{ .Values.tracing.service.type }} + ports: + - port: {{ .Values.tracing.service.externalPort }} + targetPort: 9411 + protocol: TCP + name: {{ .Values.tracing.service.name }} + selector: + app: {{ .Values.tracing.provider }} +--- +{{- if ne .Values.tracing.provider "opencensus"}} +apiVersion: v1 +kind: Service +metadata: + name: tracing + namespace: {{ .Release.Namespace }} + annotations: + {{- range $key, $val := .Values.tracing.service.annotations }} + {{ $key }}: {{ $val | quote }} + {{- end }} + labels: + app: {{ .Values.tracing.provider }} + release: {{ .Release.Name }} +spec: + ports: + - name: http-query + port: 80 + protocol: TCP +{{ if eq .Values.tracing.provider "jaeger" }} + targetPort: 16686 +{{ else }} + targetPort: 9411 +{{ end}} + selector: + app: {{ .Values.tracing.provider }} +{{- end }} diff --git a/istio-1.3.5/install/kubernetes/operator/charts/istio-telemetry/tracing/values.yaml b/istio-1.3.5/install/kubernetes/operator/charts/istio-telemetry/tracing/values.yaml new file mode 100644 index 0000000..4d607b3 --- /dev/null +++ b/istio-1.3.5/install/kubernetes/operator/charts/istio-telemetry/tracing/values.yaml @@ -0,0 +1,98 @@ +# +# addon tracing configuration +# +tracing: + enabled: false + + provider: jaeger + nodeSelector: {} + + # Specify the pod anti-affinity that allows you to constrain which nodes + # your pod is eligible to be scheduled based on labels on pods that are + # already running on the node rather than based on labels on nodes. + # There are currently two types of anti-affinity: + # "requiredDuringSchedulingIgnoredDuringExecution" + # "preferredDuringSchedulingIgnoredDuringExecution" + # which denote "hard" vs. "soft" requirements, you can define your values + # in "podAntiAffinityLabelSelector" and "podAntiAffinityTermLabelSelector" + # correspondingly. + # For example: + # podAntiAffinityLabelSelector: + # - key: security + # operator: In + # values: S1,S2 + # topologyKey: "kubernetes.io/hostname" + # This pod anti-affinity rule says that the pod requires not to be scheduled + # onto a node if that node is already running a pod with label having key + # "security" and value "S1". + podAntiAffinityLabelSelector: [] + podAntiAffinityTermLabelSelector: [] + + jaeger: + hub: docker.io/jaegertracing + image: all-on-one + tag: 1.12 + memory: + max_traces: 50000 + # spanStorageType value can be "memory" and "badger" for all-in-one image + spanStorageType: badger + persist: false + storageClassName: "" + accessMode: ReadWriteMany + + zipkin: + hub: docker.io/openzipkin + image: zipkin + tag: 2.14.2 + probeStartupDelay: 200 + queryPort: 9411 + resources: + limits: + cpu: 300m + memory: 900Mi + requests: + cpu: 150m + memory: 900Mi + javaOptsHeap: 700 + # From: https://github.com/openzipkin/zipkin/blob/master/zipkin-server/src/main/resources/zipkin-server-shared.yml#L51 + # Maximum number of spans to keep in memory. When exceeded, oldest traces (and their spans) will be purged. + # A safe estimate is 1K of memory per span (each span with 2 annotations + 1 binary annotation), plus + # 100 MB for a safety buffer. You'll need to verify in your own environment. + maxSpans: 500000 + node: + cpus: 2 + + opencensus: + hub: docker.io/omnition + tag: 0.1.9 + resources: + limits: + cpu: 1 + memory: 2Gi + requests: + cpu: 200m + memory: 400Mi + exporters: + stackdriver: + enable_tracing: true + + service: + annotations: {} + name: http + type: ClusterIP + externalPort: 9411 + + ingress: + enabled: false + # Used to create an Ingress record. + hosts: + # - tracing.local + annotations: + # kubernetes.io/ingress.class: nginx + # kubernetes.io/tls-acme: "true" + tls: + # Secrets must be manually created in the namespace. + # - secretName: tracing-tls + # hosts: + # - tracing.local + diff --git a/istio-1.3.5/install/kubernetes/operator/charts/istiocoredns/Chart.yaml b/istio-1.3.5/install/kubernetes/operator/charts/istiocoredns/Chart.yaml new file mode 100644 index 0000000..fa04814 --- /dev/null +++ b/istio-1.3.5/install/kubernetes/operator/charts/istiocoredns/Chart.yaml @@ -0,0 +1,6 @@ +apiVersion: v1 +description: Istio CoreDNS provides DNS resolution for services in multicluster setups. +name: istiocoredns +version: 1.1.0 +appVersion: 0.1 +tillerVersion: ">=2.7.2" diff --git a/istio-1.3.5/install/kubernetes/operator/charts/istiocoredns/templates/_affinity.tpl b/istio-1.3.5/install/kubernetes/operator/charts/istiocoredns/templates/_affinity.tpl new file mode 100644 index 0000000..144b6f9 --- /dev/null +++ b/istio-1.3.5/install/kubernetes/operator/charts/istiocoredns/templates/_affinity.tpl @@ -0,0 +1,93 @@ +{{/* affinity - https://kubernetes.io/docs/concepts/configuration/assign-pod-node/ */}} + +{{- define "nodeaffinity" }} + nodeAffinity: + requiredDuringSchedulingIgnoredDuringExecution: + {{- include "nodeAffinityRequiredDuringScheduling" . }} + preferredDuringSchedulingIgnoredDuringExecution: + {{- include "nodeAffinityPreferredDuringScheduling" . }} +{{- end }} + +{{- define "nodeAffinityRequiredDuringScheduling" }} + nodeSelectorTerms: + - matchExpressions: + - key: beta.kubernetes.io/arch + operator: In + values: + {{- range $key, $val := .Values.global.arch }} + {{- if gt ($val | int) 0 }} + - {{ $key }} + {{- end }} + {{- end }} + {{- $nodeSelector := default .Values.global.defaultNodeSelector .Values.istiocoredns.nodeSelector -}} + {{- range $key, $val := $nodeSelector }} + - key: {{ $key }} + operator: In + values: + - {{ $val }} + {{- end }} +{{- end }} + +{{- define "nodeAffinityPreferredDuringScheduling" }} + {{- range $key, $val := .Values.global.arch }} + {{- if gt ($val | int) 0 }} + - weight: {{ $val | int }} + preference: + matchExpressions: + - key: beta.kubernetes.io/arch + operator: In + values: + - {{ $key }} + {{- end }} + {{- end }} +{{- end }} + +{{- define "podAntiAffinity" }} +{{- if or .Values.istiocoredns.podAntiAffinityLabelSelector .Values.istiocoredns.podAntiAffinityTermLabelSelector}} + podAntiAffinity: + {{- if .Values.istiocoredns.podAntiAffinityLabelSelector }} + requiredDuringSchedulingIgnoredDuringExecution: + {{- include "podAntiAffinityRequiredDuringScheduling" . }} + {{- end }} + {{- if .Values.istiocoredns.podAntiAffinityTermLabelSelector }} + preferredDuringSchedulingIgnoredDuringExecution: + {{- include "podAntiAffinityPreferredDuringScheduling" . }} + {{- end }} +{{- end }} +{{- end }} + +{{- define "podAntiAffinityRequiredDuringScheduling" }} + {{- range $index, $item := .Values.istiocoredns.podAntiAffinityLabelSelector }} + - labelSelector: + matchExpressions: + - key: {{ $item.key }} + operator: {{ $item.operator }} + {{- if $item.values }} + values: + {{- $vals := split "," $item.values }} + {{- range $i, $v := $vals }} + - {{ $v }} + {{- end }} + {{- end }} + topologyKey: {{ $item.topologyKey }} + {{- end }} +{{- end }} + +{{- define "podAntiAffinityPreferredDuringScheduling" }} + {{- range $index, $item := .Values.istiocoredns.podAntiAffinityTermLabelSelector }} + - podAffinityTerm: + labelSelector: + matchExpressions: + - key: {{ $item.key }} + operator: {{ $item.operator }} + {{- if $item.values }} + values: + {{- $vals := split "," $item.values }} + {{- range $i, $v := $vals }} + - {{ $v }} + {{- end }} + {{- end }} + topologyKey: {{ $item.topologyKey }} + weight: 100 + {{- end }} +{{- end }} diff --git a/istio-1.3.5/install/kubernetes/operator/charts/istiocoredns/templates/clusterrole.yaml b/istio-1.3.5/install/kubernetes/operator/charts/istiocoredns/templates/clusterrole.yaml new file mode 100644 index 0000000..160f564 --- /dev/null +++ b/istio-1.3.5/install/kubernetes/operator/charts/istiocoredns/templates/clusterrole.yaml @@ -0,0 +1,11 @@ +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: istiocoredns + labels: + app: istiocoredns + release: {{ .Release.Name }} +rules: +- apiGroups: ["networking.istio.io"] + resources: ["*"] + verbs: ["get", "watch", "list"] diff --git a/istio-1.3.5/install/kubernetes/operator/charts/istiocoredns/templates/clusterrolebinding.yaml b/istio-1.3.5/install/kubernetes/operator/charts/istiocoredns/templates/clusterrolebinding.yaml new file mode 100644 index 0000000..ccb594b --- /dev/null +++ b/istio-1.3.5/install/kubernetes/operator/charts/istiocoredns/templates/clusterrolebinding.yaml @@ -0,0 +1,15 @@ +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: istio-istiocoredns-role-binding-{{ .Release.Namespace }} + labels: + app: istiocoredns + release: {{ .Release.Name }} +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: istiocoredns +subjects: +- kind: ServiceAccount + name: istiocoredns-service-account + namespace: {{ .Release.Namespace }} diff --git a/istio-1.3.5/install/kubernetes/operator/charts/istiocoredns/templates/configmap.yaml b/istio-1.3.5/install/kubernetes/operator/charts/istiocoredns/templates/configmap.yaml new file mode 100644 index 0000000..ecb7695 --- /dev/null +++ b/istio-1.3.5/install/kubernetes/operator/charts/istiocoredns/templates/configmap.yaml @@ -0,0 +1,22 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: coredns + namespace: {{ .Release.Namespace }} + labels: + app: istiocoredns + release: {{ .Release.Name }} +data: + Corefile: | + .:53 { + errors + health + proxy global 127.0.0.1:8053 { + protocol grpc insecure + } + prometheus :9153 + proxy . /etc/resolv.conf + cache 30 + reload + } +--- diff --git a/istio-1.3.5/install/kubernetes/operator/charts/istiocoredns/templates/deployment.yaml b/istio-1.3.5/install/kubernetes/operator/charts/istiocoredns/templates/deployment.yaml new file mode 100644 index 0000000..099aa03 --- /dev/null +++ b/istio-1.3.5/install/kubernetes/operator/charts/istiocoredns/templates/deployment.yaml @@ -0,0 +1,93 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: istiocoredns + namespace: {{ .Release.Namespace }} + labels: + app: istiocoredns + release: {{ .Release.Name }} +spec: + replicas: {{ .Values.istiocoredns.replicaCount }} + selector: + matchLabels: + app: istiocoredns + strategy: + rollingUpdate: + maxSurge: {{ .Values.istiocoredns.rollingMaxSurge }} + maxUnavailable: {{ .Values.istiocoredns.rollingMaxUnavailable }} + template: + metadata: + name: istiocoredns + labels: + app: istiocoredns + release: {{ .Release.Name }} + annotations: + sidecar.istio.io/inject: "false" + spec: + serviceAccountName: istiocoredns-service-account +{{- if .Values.global.priorityClassName }} + priorityClassName: "{{ .Values.global.priorityClassName }}" +{{- end }} + containers: + - name: coredns + image: {{ .Values.istiocoredns.coreDNSImage }} + imagePullPolicy: {{ .Values.global.imagePullPolicy | default "Always" }} + args: [ "-conf", "/etc/coredns/Corefile" ] + volumeMounts: + - name: config-volume + mountPath: /etc/coredns + ports: + - containerPort: 53 + name: dns + protocol: UDP + - containerPort: 53 + name: dns-tcp + protocol: TCP + - containerPort: 9153 + name: metrics + protocol: TCP + livenessProbe: + httpGet: + path: /health + port: 8080 + scheme: HTTP + initialDelaySeconds: 60 + timeoutSeconds: 5 + successThreshold: 1 + failureThreshold: 5 + resources: +{{- if .Values.istiocoredns.resources }} +{{ toYaml .Values.istiocoredns.resources | indent 10 }} +{{- else }} +{{ toYaml .Values.global.defaultResources | indent 10 }} +{{- end }} + - name: istio-coredns-plugin + command: + - /usr/local/bin/plugin + image: {{ .Values.istiocoredns.coreDNSPluginImage }} + imagePullPolicy: {{ .Values.global.imagePullPolicy | default "Always" }} + ports: + - containerPort: 8053 + name: dns-grpc + protocol: TCP + resources: +{{- if .Values.istiocoredns.resources }} +{{ toYaml .Values.istiocorednsresources | indent 10 }} +{{- else }} +{{ toYaml .Values.global.defaultResources | indent 10 }} +{{- end }} + dnsPolicy: Default + volumes: + - name: config-volume + configMap: + name: coredns + items: + - key: Corefile + path: Corefile + affinity: + {{- include "nodeaffinity" . | indent 6 }} + {{- include "podAntiAffinity" . | indent 6 }} +{{- if .Values.istiocoredns.tolerations }} + tolerations: +{{ toYaml .Values.istiocoredns.tolerations | indent 6 }} +{{- end }} diff --git a/istio-1.3.5/install/kubernetes/operator/charts/istiocoredns/templates/service.yaml b/istio-1.3.5/install/kubernetes/operator/charts/istiocoredns/templates/service.yaml new file mode 100644 index 0000000..30251b5 --- /dev/null +++ b/istio-1.3.5/install/kubernetes/operator/charts/istiocoredns/templates/service.yaml @@ -0,0 +1,18 @@ +apiVersion: v1 +kind: Service +metadata: + name: istiocoredns + namespace: {{ .Release.Namespace }} + labels: + app: istiocoredns + release: {{ .Release.Name }} +spec: + selector: + app: istiocoredns + ports: + - name: dns + port: 53 + protocol: UDP + - name: dns-tcp + port: 53 + protocol: TCP diff --git a/istio-1.3.5/install/kubernetes/operator/charts/istiocoredns/templates/serviceaccount.yaml b/istio-1.3.5/install/kubernetes/operator/charts/istiocoredns/templates/serviceaccount.yaml new file mode 100644 index 0000000..3cec94a --- /dev/null +++ b/istio-1.3.5/install/kubernetes/operator/charts/istiocoredns/templates/serviceaccount.yaml @@ -0,0 +1,14 @@ +apiVersion: v1 +kind: ServiceAccount +{{- if .Values.global.imagePullSecrets }} +imagePullSecrets: +{{- range .Values.global.imagePullSecrets }} + - name: {{ . }} +{{- end }} +{{- end }} +metadata: + name: istiocoredns-service-account + namespace: {{ .Release.Namespace }} + labels: + app: istiocoredns + release: {{ .Release.Name }} diff --git a/istio-1.3.5/install/kubernetes/operator/charts/istiocoredns/values.yaml b/istio-1.3.5/install/kubernetes/operator/charts/istiocoredns/values.yaml new file mode 100644 index 0000000..bc7029e --- /dev/null +++ b/istio-1.3.5/install/kubernetes/operator/charts/istiocoredns/values.yaml @@ -0,0 +1,36 @@ +# +# addon istiocoredns tracing configuration +# +istiocoredns: + enabled: false + replicaCount: 1 + rollingMaxSurge: 100% + rollingMaxUnavailable: 25% + coreDNSImage: coredns/coredns:1.1.2 + # Source code for the plugin can be found at + # https://github.com/istio-ecosystem/istio-coredns-plugin + # The plugin listens for DNS requests from coredns server at 127.0.0.1:8053 + coreDNSPluginImage: istio/coredns-plugin:0.2-istio-1.1 + nodeSelector: {} + tolerations: [] + + # Specify the pod anti-affinity that allows you to constrain which nodes + # your pod is eligible to be scheduled based on labels on pods that are + # already running on the node rather than based on labels on nodes. + # There are currently two types of anti-affinity: + # "requiredDuringSchedulingIgnoredDuringExecution" + # "preferredDuringSchedulingIgnoredDuringExecution" + # which denote "hard" vs. "soft" requirements, you can define your values + # in "podAntiAffinityLabelSelector" and "podAntiAffinityTermLabelSelector" + # correspondingly. + # For example: + # podAntiAffinityLabelSelector: + # - key: security + # operator: In + # values: S1,S2 + # topologyKey: "kubernetes.io/hostname" + # This pod anti-affinity rule says that the pod requires not to be scheduled + # onto a node if that node is already running a pod with label having key + # "security" and value "S1". + podAntiAffinityLabelSelector: [] + podAntiAffinityTermLabelSelector: [] diff --git a/istio-1.3.5/install/kubernetes/operator/charts/security/certmanager/Chart.yaml b/istio-1.3.5/install/kubernetes/operator/charts/security/certmanager/Chart.yaml new file mode 100644 index 0000000..b83f4d1 --- /dev/null +++ b/istio-1.3.5/install/kubernetes/operator/charts/security/certmanager/Chart.yaml @@ -0,0 +1,6 @@ +apiVersion: v1 +description: A Helm chart for Kubernetes +name: certmanager +version: 1.1.0 +appVersion: 0.6.2 +tillerVersion: ">=2.7.2" diff --git a/istio-1.3.5/install/kubernetes/operator/charts/security/certmanager/templates/NOTES.txt b/istio-1.3.5/install/kubernetes/operator/charts/security/certmanager/templates/NOTES.txt new file mode 100644 index 0000000..0307ede --- /dev/null +++ b/istio-1.3.5/install/kubernetes/operator/charts/security/certmanager/templates/NOTES.txt @@ -0,0 +1,6 @@ +certmanager has been deployed successfully! + +More information on the different types of issuers and how to configure them +can be found in our documentation: + +https://cert-manager.readthedocs.io/en/latest/reference/issuers.html \ No newline at end of file diff --git a/istio-1.3.5/install/kubernetes/operator/charts/security/certmanager/templates/_affinity.tpl b/istio-1.3.5/install/kubernetes/operator/charts/security/certmanager/templates/_affinity.tpl new file mode 100644 index 0000000..cf5e09d --- /dev/null +++ b/istio-1.3.5/install/kubernetes/operator/charts/security/certmanager/templates/_affinity.tpl @@ -0,0 +1,93 @@ +{{/* affinity - https://kubernetes.io/docs/concepts/configuration/assign-pod-node/ */}} + +{{- define "nodeaffinity" }} + nodeAffinity: + requiredDuringSchedulingIgnoredDuringExecution: + {{- include "nodeAffinityRequiredDuringScheduling" . }} + preferredDuringSchedulingIgnoredDuringExecution: + {{- include "nodeAffinityPreferredDuringScheduling" . }} +{{- end }} + +{{- define "nodeAffinityRequiredDuringScheduling" }} + nodeSelectorTerms: + - matchExpressions: + - key: beta.kubernetes.io/arch + operator: In + values: + {{- range $key, $val := .Values.global.arch }} + {{- if gt ($val | int) 0 }} + - {{ $key }} + {{- end }} + {{- end }} + {{- $nodeSelector := default .Values.global.defaultNodeSelector .Values.certmanager.nodeSelector -}} + {{- range $key, $val := $nodeSelector }} + - key: {{ $key }} + operator: In + values: + - {{ $val }} + {{- end }} +{{- end }} + +{{- define "nodeAffinityPreferredDuringScheduling" }} + {{- range $key, $val := .Values.global.arch }} + {{- if gt ($val | int) 0 }} + - weight: {{ $val | int }} + preference: + matchExpressions: + - key: beta.kubernetes.io/arch + operator: In + values: + - {{ $key }} + {{- end }} + {{- end }} +{{- end }} + +{{- define "podAntiAffinity" }} +{{- if or .Values.certmanager.podAntiAffinityLabelSelector .Values.certmanager.podAntiAffinityTermLabelSelector}} + podAntiAffinity: + {{- if .Values.certmanager.podAntiAffinityLabelSelector }} + requiredDuringSchedulingIgnoredDuringExecution: + {{- include "podAntiAffinityRequiredDuringScheduling" . }} + {{- end }} + {{- if .Values.certmanager.podAntiAffinityTermLabelSelector }} + preferredDuringSchedulingIgnoredDuringExecution: + {{- include "podAntiAffinityPreferredDuringScheduling" . }} + {{- end }} +{{- end }} +{{- end }} + +{{- define "podAntiAffinityRequiredDuringScheduling" }} + {{- range $index, $item := .Values.certmanager.podAntiAffinityLabelSelector }} + - labelSelector: + matchExpressions: + - key: {{ $item.key }} + operator: {{ $item.operator }} + {{- if $item.values }} + values: + {{- $vals := split "," $item.values }} + {{- range $i, $v := $vals }} + - {{ $v }} + {{- end }} + {{- end }} + topologyKey: {{ $item.topologyKey }} + {{- end }} +{{- end }} + +{{- define "podAntiAffinityPreferredDuringScheduling" }} + {{- range $index, $item := .Values.certmanager.podAntiAffinityTermLabelSelector }} + - podAffinityTerm: + labelSelector: + matchExpressions: + - key: {{ $item.key }} + operator: {{ $item.operator }} + {{- if $item.values }} + values: + {{- $vals := split "," $item.values }} + {{- range $i, $v := $vals }} + - {{ $v }} + {{- end }} + {{- end }} + topologyKey: {{ $item.topologyKey }} + weight: 100 + {{- end }} +{{- end }} diff --git a/istio-1.3.5/install/kubernetes/operator/charts/security/certmanager/templates/deployment.yaml b/istio-1.3.5/install/kubernetes/operator/charts/security/certmanager/templates/deployment.yaml new file mode 100644 index 0000000..cc93cee --- /dev/null +++ b/istio-1.3.5/install/kubernetes/operator/charts/security/certmanager/templates/deployment.yaml @@ -0,0 +1,62 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: certmanager + namespace: {{ .Release.Namespace }} + labels: + app: certmanager + release: {{ .Release.Name }} +spec: + replicas: {{ .Values.certmanager.replicaCount }} + selector: + matchLabels: + app: certmanager + template: + metadata: + labels: + app: certmanager + release: {{ .Release.Name }} + {{- if .Values.certmanager.podLabels }} +{{ toYaml .Values.certmanager.podLabels | indent 8 }} + {{- end }} + annotations: + sidecar.istio.io/inject: "false" + {{- if .Values.certmanager.podAnnotations }} +{{ toYaml .Values.certmanager.podAnnotations | indent 8 }} + {{- end }} + spec: + serviceAccountName: certmanager +{{- if .Values.global.priorityClassName }} + priorityClassName: "{{ .Values.global.priorityClassName }}" +{{- end }} + containers: + - name: certmanager + image: "{{ .Values.certmanager.hub }}/{{ .Values.certmanager.image }}:{{ .Values.certmanager.tag }}" + imagePullPolicy: {{ .Values.global.imagePullPolicy | default "Always" }} + args: + - --cluster-resource-namespace=$(POD_NAMESPACE) + - --leader-election-namespace=$(POD_NAMESPACE) + {{- if .Values.certmanager.extraArgs }} +{{ toYaml .Values.certmanager.extraArgs | indent 8 }} + {{- end }} + env: + - name: POD_NAMESPACE + valueFrom: + fieldRef: + fieldPath: metadata.namespace + resources: +{{ toYaml .Values.certmanager.resources | indent 10 }} + {{- if .Values.certmanager.podDnsPolicy }} + dnsPolicy: {{ .Values.certmanager.podDnsPolicy }} + {{- end }} + {{- if .Values.certmanager.podDnsConfig }} + dnsConfig: +{{ toYaml .Values.certmanager.podDnsConfig | indent 8 }} + {{- end }} + affinity: + {{- include "nodeaffinity" . | indent 6 }} + {{- include "podAntiAffinity" . | indent 6 }} +{{- if .Values.certmanager.tolerations }} + tolerations: +{{ toYaml .Values.certmanager.tolerations | indent 6 }} +{{- end }} diff --git a/istio-1.3.5/install/kubernetes/operator/charts/security/certmanager/templates/issuer.yaml b/istio-1.3.5/install/kubernetes/operator/charts/security/certmanager/templates/issuer.yaml new file mode 100644 index 0000000..d0f0dbd --- /dev/null +++ b/istio-1.3.5/install/kubernetes/operator/charts/security/certmanager/templates/issuer.yaml @@ -0,0 +1,33 @@ +--- +apiVersion: certmanager.k8s.io/v1alpha1 +kind: ClusterIssuer +metadata: + name: letsencrypt-staging + namespace: {{ .Release.Namespace }} + labels: + app: certmanager + release: {{ .Release.Name }} +spec: + acme: + server: https://acme-staging-v02.api.letsencrypt.org/directory + email: {{ .Values.certmanager.email }} + # Name of a secret used to store the ACME account private key + privateKeySecretRef: + name: letsencrypt-staging + http01: {} +--- +apiVersion: certmanager.k8s.io/v1alpha1 +kind: ClusterIssuer +metadata: + name: letsencrypt + namespace: {{ .Release.Namespace }} + labels: + app: certmanager + release: {{ .Release.Name }} +spec: + acme: + server: https://acme-v02.api.letsencrypt.org/directory + email: {{ .Values.certmanager.email }} + privateKeySecretRef: + name: letsencrypt + http01: {} diff --git a/istio-1.3.5/install/kubernetes/operator/charts/security/certmanager/templates/poddisruptionbudget.yaml b/istio-1.3.5/install/kubernetes/operator/charts/security/certmanager/templates/poddisruptionbudget.yaml new file mode 100644 index 0000000..87b1f70 --- /dev/null +++ b/istio-1.3.5/install/kubernetes/operator/charts/security/certmanager/templates/poddisruptionbudget.yaml @@ -0,0 +1,19 @@ +{{- if .Values.global.defaultPodDisruptionBudget.enabled }} +apiVersion: policy/v1beta1 +kind: PodDisruptionBudget +metadata: + name: certmanager + namespace: {{ .Release.Namespace }} + labels: + app: certmanager + release: {{ .Release.Name }} + {{- if .Values.certmanager.podLabels }} +{{ toYaml .Values.certmanager.podLabels | indent 4 }} + {{- end }} +spec: + minAvailable: 1 + selector: + matchLabels: + app: certmanager + release: {{ .Release.Name }} +{{- end }} diff --git a/istio-1.3.5/install/kubernetes/operator/charts/security/certmanager/templates/rbac.yaml b/istio-1.3.5/install/kubernetes/operator/charts/security/certmanager/templates/rbac.yaml new file mode 100644 index 0000000..e2c37bd --- /dev/null +++ b/istio-1.3.5/install/kubernetes/operator/charts/security/certmanager/templates/rbac.yaml @@ -0,0 +1,33 @@ +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: certmanager + labels: + app: certmanager + release: {{ .Release.Name }} +rules: + - apiGroups: ["certmanager.k8s.io"] + resources: ["certificates", "certificates/finalizers", "issuers", "clusterissuers", "orders", "orders/finalizers", "challenges"] + verbs: ["*"] + - apiGroups: [""] + resources: ["configmaps", "secrets", "events", "services", "pods"] + verbs: ["*"] + - apiGroups: ["extensions"] + resources: ["ingresses"] + verbs: ["*"] +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: certmanager + labels: + app: certmanager + release: {{ .Release.Name }} +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: certmanager +subjects: + - name: certmanager + namespace: {{ .Release.Namespace }} + kind: ServiceAccount diff --git a/istio-1.3.5/install/kubernetes/operator/charts/security/certmanager/templates/serviceaccount.yaml b/istio-1.3.5/install/kubernetes/operator/charts/security/certmanager/templates/serviceaccount.yaml new file mode 100644 index 0000000..4f6b887 --- /dev/null +++ b/istio-1.3.5/install/kubernetes/operator/charts/security/certmanager/templates/serviceaccount.yaml @@ -0,0 +1,14 @@ +apiVersion: v1 +kind: ServiceAccount +{{- if .Values.global.imagePullSecrets }} +imagePullSecrets: +{{- range .Values.global.imagePullSecrets }} + - name: {{ . }} +{{- end }} +{{- end }} +metadata: + name: certmanager + namespace: {{ .Release.Namespace }} + labels: + app: certmanager + release: {{ .Release.Name }} diff --git a/istio-1.3.5/install/kubernetes/operator/charts/security/certmanager/values.yaml b/istio-1.3.5/install/kubernetes/operator/charts/security/certmanager/values.yaml new file mode 100644 index 0000000..08f10bc --- /dev/null +++ b/istio-1.3.5/install/kubernetes/operator/charts/security/certmanager/values.yaml @@ -0,0 +1,35 @@ +certmanager: + # Certmanager uses ACME to sign certificates. Since Istio gateways are + # mounting the TLS secrets the Certificate CRDs must be created in the + # istio-system namespace. Once the certificate has been created, the + # gateway must be updated by adding 'secretVolumes'. After the gateway + # restart, DestinationRules can be created using the ACME-signed certificates. + enabled: false + replicaCount: 1 + hub: quay.io/jetstack + image: cert-manager-controller + tag: v0.6.2 + resources: {} + nodeSelector: {} + tolerations: [] + + # Specify the pod anti-affinity that allows you to constrain which nodes + # your pod is eligible to be scheduled based on labels on pods that are + # already running on the node rather than based on labels on nodes. + # There are currently two types of anti-affinity: + # "requiredDuringSchedulingIgnoredDuringExecution" + # "preferredDuringSchedulingIgnoredDuringExecution" + # which denote "hard" vs. "soft" requirements, you can define your values + # in "podAntiAffinityLabelSelector" and "podAntiAffinityTermLabelSelector" + # correspondingly. + # For example: + # podAntiAffinityLabelSelector: + # - key: security + # operator: In + # values: S1,S2 + # topologyKey: "kubernetes.io/hostname" + # This pod anti-affinity rule says that the pod requires not to be scheduled + # onto a node if that node is already running a pod with label having key + # "security" and value "S1". + podAntiAffinityLabelSelector: [] + podAntiAffinityTermLabelSelector: [] diff --git a/istio-1.3.5/install/kubernetes/operator/charts/security/citadel/Chart.yaml b/istio-1.3.5/install/kubernetes/operator/charts/security/citadel/Chart.yaml new file mode 100644 index 0000000..58d547f --- /dev/null +++ b/istio-1.3.5/install/kubernetes/operator/charts/security/citadel/Chart.yaml @@ -0,0 +1,13 @@ +apiVersion: v1 +name: citadel +version: 1.1.0 +appVersion: 1.1.0 +tillerVersion: ">=2.7.2" +description: Helm chart for istio authentication +keywords: + - istio + - security +sources: + - http://github.com/istio/istio +engine: gotpl +icon: https://istio.io/favicons/android-192x192.png diff --git a/istio-1.3.5/install/kubernetes/operator/charts/security/citadel/templates/NOTES.txt b/istio-1.3.5/install/kubernetes/operator/charts/security/citadel/templates/NOTES.txt new file mode 100644 index 0000000..816d340 --- /dev/null +++ b/istio-1.3.5/install/kubernetes/operator/charts/security/citadel/templates/NOTES.txt @@ -0,0 +1,7 @@ +This template contains the 'singleton' part of Istio. + +All other components support multiple instances (profiles) running in parallel. + +For upgrade purpose, this component should run in istio-system - where the existing mesh certificates are stored. +Will install a new deployment of Citadel, using 1.1 - it can run in parallel with the old-style install of either 1.0 +or 1.1. diff --git a/istio-1.3.5/install/kubernetes/operator/charts/security/citadel/templates/_affinity.tpl b/istio-1.3.5/install/kubernetes/operator/charts/security/citadel/templates/_affinity.tpl new file mode 100644 index 0000000..1813859 --- /dev/null +++ b/istio-1.3.5/install/kubernetes/operator/charts/security/citadel/templates/_affinity.tpl @@ -0,0 +1,93 @@ +{{/* affinity - https://kubernetes.io/docs/concepts/configuration/assign-pod-node/ */}} + +{{- define "nodeaffinity" }} + nodeAffinity: + requiredDuringSchedulingIgnoredDuringExecution: + {{- include "nodeAffinityRequiredDuringScheduling" . }} + preferredDuringSchedulingIgnoredDuringExecution: + {{- include "nodeAffinityPreferredDuringScheduling" . }} +{{- end }} + +{{- define "nodeAffinityRequiredDuringScheduling" }} + nodeSelectorTerms: + - matchExpressions: + - key: beta.kubernetes.io/arch + operator: In + values: + {{- range $key, $val := .Values.global.arch }} + {{- if gt ($val | int) 0 }} + - {{ $key }} + {{- end }} + {{- end }} + {{- $nodeSelector := default .Values.global.defaultNodeSelector .Values.security.nodeSelector -}} + {{- range $key, $val := $nodeSelector }} + - key: {{ $key }} + operator: In + values: + - {{ $val }} + {{- end }} +{{- end }} + +{{- define "nodeAffinityPreferredDuringScheduling" }} + {{- range $key, $val := .Values.global.arch }} + {{- if gt ($val | int) 0 }} + - weight: {{ $val | int }} + preference: + matchExpressions: + - key: beta.kubernetes.io/arch + operator: In + values: + - {{ $key }} + {{- end }} + {{- end }} +{{- end }} + +{{- define "podAntiAffinity" }} +{{- if or .Values.security.podAntiAffinityLabelSelector .Values.security.podAntiAffinityTermLabelSelector}} + podAntiAffinity: + {{- if .Values.security.podAntiAffinityLabelSelector }} + requiredDuringSchedulingIgnoredDuringExecution: + {{- include "podAntiAffinityRequiredDuringScheduling" . }} + {{- end }} + {{- if .Values.security.podAntiAffinityTermLabelSelector }} + preferredDuringSchedulingIgnoredDuringExecution: + {{- include "podAntiAffinityPreferredDuringScheduling" . }} + {{- end }} +{{- end }} +{{- end }} + +{{- define "podAntiAffinityRequiredDuringScheduling" }} + {{- range $index, $item := .Values.security.podAntiAffinityLabelSelector }} + - labelSelector: + matchExpressions: + - key: {{ $item.key }} + operator: {{ $item.operator }} + {{- if $item.values }} + values: + {{- $vals := split "," $item.values }} + {{- range $i, $v := $vals }} + - {{ $v }} + {{- end }} + {{- end }} + topologyKey: {{ $item.topologyKey }} + {{- end }} +{{- end }} + +{{- define "podAntiAffinityPreferredDuringScheduling" }} + {{- range $index, $item := .Values.security.podAntiAffinityTermLabelSelector }} + - podAffinityTerm: + labelSelector: + matchExpressions: + - key: {{ $item.key }} + operator: {{ $item.operator }} + {{- if $item.values }} + values: + {{- $vals := split "," $item.values }} + {{- range $i, $v := $vals }} + - {{ $v }} + {{- end }} + {{- end }} + topologyKey: {{ $item.topologyKey }} + weight: 100 + {{- end }} +{{- end }} diff --git a/istio-1.3.5/install/kubernetes/operator/charts/security/citadel/templates/_helpers.tpl b/istio-1.3.5/install/kubernetes/operator/charts/security/citadel/templates/_helpers.tpl new file mode 100644 index 0000000..addbba1 --- /dev/null +++ b/istio-1.3.5/install/kubernetes/operator/charts/security/citadel/templates/_helpers.tpl @@ -0,0 +1,77 @@ +{{/* vim: set filetype=mustache: */}} +{{/* +Expand the name of the chart. +*/}} +{{- define "istio.name" -}} +{{- default .Chart.Name .Values.security.nameOverride | trunc 63 | trimSuffix "-" -}} +{{- end -}} + +{{/* +Create a default fully qualified app name. +We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). +If release name contains chart name it will be used as a full name. +*/}} +{{- define "istio.fullname" -}} +{{- if .Values.security.fullnameOverride -}} +{{- .Values.security.fullnameOverride | trunc 63 | trimSuffix "-" -}} +{{- else -}} +{{- $name := default .Chart.Name .Values.security.nameOverride -}} +{{- if contains $name .Release.Name -}} +{{- .Release.Name | trunc 63 | trimSuffix "-" -}} +{{- else -}} +{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" -}} +{{- end -}} +{{- end -}} +{{- end -}} + +{{/* +Create chart name and version as used by the chart label. +*/}} +{{- define "istio.chart" -}} +{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" -}} +{{- end -}} + +{{/* +Create a fully qualified configmap name. +*/}} +{{- define "istio.configmap.fullname" -}} +{{- printf "%s-%s" .Release.Name "istio-mesh-config" | trunc 63 | trimSuffix "-" -}} +{{- end -}} + +{{/* +Configmap checksum. +*/}} +{{- define "istio.configmap.checksum" -}} +{{- print $.Template.BasePath "/configmap.yaml" | sha256sum -}} +{{- end -}} +{{/* +Expand the name of the chart. +*/}} +{{- define "security.name" -}} +{{- default .Chart.Name .Values.security.nameOverride | trunc 63 | trimSuffix "-" -}} +{{- end -}} + +{{/* +Create a default fully qualified app name. +We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). +If release name contains chart name it will be used as a full name. +*/}} +{{- define "security.fullname" -}} +{{- if .Values.security.fullnameOverride -}} +{{- .Values.security.fullnameOverride | trunc 63 | trimSuffix "-" -}} +{{- else -}} +{{- $name := default .Chart.Name .Values.security.nameOverride -}} +{{- if contains $name .Release.Name -}} +{{- .Release.Name | trunc 63 | trimSuffix "-" -}} +{{- else -}} +{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" -}} +{{- end -}} +{{- end -}} +{{- end -}} + +{{/* +Create chart name and version as used by the chart label. +*/}} +{{- define "security.chart" -}} +{{- .Chart.Name | trunc 63 | trimSuffix "-" -}} +{{- end -}} diff --git a/istio-1.3.5/install/kubernetes/operator/charts/security/citadel/templates/clusterrole.yaml b/istio-1.3.5/install/kubernetes/operator/charts/security/citadel/templates/clusterrole.yaml new file mode 100644 index 0000000..06ffe49 --- /dev/null +++ b/istio-1.3.5/install/kubernetes/operator/charts/security/citadel/templates/clusterrole.yaml @@ -0,0 +1,24 @@ +{{ if .Values.clusterResources }} +apiVersion: rbac.authorization.k8s.io/v1beta1 +kind: ClusterRole +metadata: + name: istio-citadel-{{ .Release.Namespace }} + labels: + app: citadel + release: {{ .Release.Name }} +rules: +- apiGroups: [""] + resources: ["configmaps"] + verbs: ["create", "get", "update"] +- apiGroups: [""] + resources: ["secrets"] + verbs: ["create", "get", "watch", "list", "update", "delete"] +- apiGroups: [""] + resources: ["serviceaccounts", "services", "namespaces"] + verbs: ["get", "watch", "list"] +- apiGroups: ["authentication.k8s.io"] + resources: ["tokenreviews"] + verbs: ["create"] + +--- +{{ end }} diff --git a/istio-1.3.5/install/kubernetes/operator/charts/security/citadel/templates/clusterrolebinding.yaml b/istio-1.3.5/install/kubernetes/operator/charts/security/citadel/templates/clusterrolebinding.yaml new file mode 100644 index 0000000..06f402b --- /dev/null +++ b/istio-1.3.5/install/kubernetes/operator/charts/security/citadel/templates/clusterrolebinding.yaml @@ -0,0 +1,17 @@ +{{ if .Values.clusterResources }} +apiVersion: rbac.authorization.k8s.io/v1beta1 +kind: ClusterRoleBinding +metadata: + name: istio-citadel-{{ .Release.Namespace }} + labels: + release: {{ .Release.Name }} +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: istio-citadel-{{ .Release.Namespace }} +subjects: + - kind: ServiceAccount + name: istio-citadel-service-account + namespace: {{ .Release.Namespace }} +--- +{{- end}} diff --git a/istio-1.3.5/install/kubernetes/operator/charts/security/citadel/templates/deployment.yaml b/istio-1.3.5/install/kubernetes/operator/charts/security/citadel/templates/deployment.yaml new file mode 100644 index 0000000..522aac4 --- /dev/null +++ b/istio-1.3.5/install/kubernetes/operator/charts/security/citadel/templates/deployment.yaml @@ -0,0 +1,99 @@ +# istio CA watching all namespaces +apiVersion: apps/v1 +kind: Deployment +metadata: + name: istio-citadel + namespace: {{ .Release.Namespace }} + labels: + app: citadel + istio: citadel + release: {{ .Release.Name }} + +spec: + selector: + matchLabels: + istio: citadel + replicas: {{ .Values.security.replicaCount }} + strategy: + rollingUpdate: + maxSurge: {{ .Values.security.rollingMaxSurge }} + maxUnavailable: {{ .Values.security.rollingMaxUnavailable }} + template: + metadata: + labels: + app: citadel + istio: citadel + annotations: + sidecar.istio.io/inject: "false" + spec: + serviceAccountName: istio-citadel-service-account +{{- if .Values.global.priorityClassName }} + priorityClassName: "{{ .Values.global.priorityClassName }}" +{{- end }} + containers: + - name: citadel + image: "{{ .Values.global.hub }}/{{ .Values.security.image }}:{{ .Values.global.tag }}" + imagePullPolicy: {{ .Values.global.imagePullPolicy | default "Always" }} + args: + {{- if .Values.global.sds.enabled }} + - --sds-enabled=true + {{- end }} + - --append-dns-names=true + - --grpc-port=8060 + - --citadel-storage-namespace={{ .Release.Namespace }} + {{- if .Values.kustomize }} + - --custom-dns-names=$(CITADEL_DNS) + {{- else }} + - --custom-dns-names={{ range $k,$v := .Values.security.dnsCerts }}{{ $k }}:{{ $v }},{{ end }} + {{- end }} + {{- if .Values.security.selfSigned }} + - --self-signed-ca=true + {{- else }} + - --self-signed-ca=false + - --signing-cert=/etc/cacerts/ca-cert.pem + - --signing-key=/etc/cacerts/ca-key.pem + - --root-cert=/etc/cacerts/root-cert.pem + - --cert-chain=/etc/cacerts/cert-chain.pem + {{- end }} + {{- if .Values.security.trustDomain }} + - --trust-domain={{ .Values.security.trustDomain }} + {{- end }} + {{- if .Values.workloadCertTtl }} + - --workload-cert-ttl={{ .Values.workloadCertTtl }} + {{- end }} + {{- if .Values.global.logAsJson }} + - --log_as_json + {{- end }} + env: + - name: CITADEL_ENABLE_NAMESPACES_BY_DEFAULT + value: "{{ .Values.security.enableNamespacesByDefault }}" + livenessProbe: + httpGet: + path: /version + port: 15014 + initialDelaySeconds: 5 + periodSeconds: 5 + resources: +{{- if .Values.security.resources }} +{{ toYaml .Values.security.resources | indent 12 }} +{{- else }} +{{ toYaml .Values.global.defaultResources | indent 12 }} +{{- end }} +{{- if not .Values.security.selfSigned }} + volumeMounts: + - name: cacerts + mountPath: /etc/cacerts + readOnly: true + volumes: + - name: cacerts + secret: + secretName: cacerts + optional: true +{{- end }} + affinity: + {{- include "nodeaffinity" . | indent 6 }} + {{- include "podAntiAffinity" . | indent 6 }} +{{- if .Values.security.tolerations }} + tolerations: +{{ toYaml .Values.security.tolerations | indent 6 }} +{{- end }} diff --git a/istio-1.3.5/install/kubernetes/operator/charts/security/citadel/templates/poddisruptionbudget.yaml b/istio-1.3.5/install/kubernetes/operator/charts/security/citadel/templates/poddisruptionbudget.yaml new file mode 100644 index 0000000..6046f4c --- /dev/null +++ b/istio-1.3.5/install/kubernetes/operator/charts/security/citadel/templates/poddisruptionbudget.yaml @@ -0,0 +1,17 @@ +{{- if .Values.global.defaultPodDisruptionBudget.enabled }} +apiVersion: policy/v1beta1 +kind: PodDisruptionBudget +metadata: + name: istio-citadel + namespace: {{ .Release.Namespace }} + labels: + app: citadel + istio: citadel + release: {{ .Release.Name }} +spec: + minAvailable: 1 + selector: + matchLabels: + app: citadel + istio: citadel +{{- end }} diff --git a/istio-1.3.5/install/kubernetes/operator/charts/security/citadel/templates/service.yaml b/istio-1.3.5/install/kubernetes/operator/charts/security/citadel/templates/service.yaml new file mode 100644 index 0000000..794a8f8 --- /dev/null +++ b/istio-1.3.5/install/kubernetes/operator/charts/security/citadel/templates/service.yaml @@ -0,0 +1,21 @@ +apiVersion: v1 +kind: Service +metadata: + # Must match the certificate, this is used in the node agent in same namespace. + name: istio-citadel + namespace: {{ .Release.Namespace }} + labels: + app: citadel + istio: citadel + release: {{ .Release.Name }} + +spec: + ports: + - name: grpc-citadel + port: 8060 + targetPort: 8060 + protocol: TCP + - name: http-monitoring + port: 15014 + selector: + app: citadel diff --git a/istio-1.3.5/install/kubernetes/operator/charts/security/citadel/templates/serviceaccount.yaml b/istio-1.3.5/install/kubernetes/operator/charts/security/citadel/templates/serviceaccount.yaml new file mode 100644 index 0000000..a3a8424 --- /dev/null +++ b/istio-1.3.5/install/kubernetes/operator/charts/security/citadel/templates/serviceaccount.yaml @@ -0,0 +1,15 @@ +apiVersion: v1 +kind: ServiceAccount +{{- if .Values.global.imagePullSecrets }} +imagePullSecrets: +{{- range .Values.global.imagePullSecrets }} + - name: {{ . }} +{{- end }} +{{- end }} +metadata: + name: istio-citadel-service-account + namespace: {{ .Release.Namespace }} + + labels: + release: {{ .Release.Name }} + diff --git a/istio-1.3.5/install/kubernetes/operator/charts/security/citadel/values.yaml b/istio-1.3.5/install/kubernetes/operator/charts/security/citadel/values.yaml new file mode 100644 index 0000000..bfb47be --- /dev/null +++ b/istio-1.3.5/install/kubernetes/operator/charts/security/citadel/values.yaml @@ -0,0 +1,67 @@ +# +# security (citadel) configuration +# +security: + enabled: true + replicaCount: 1 + rollingMaxSurge: 100% + rollingMaxUnavailable: 25% + image: citadel + selfSigned: true # indicate if self-signed CA is used. + trustDomain: cluster.local # indicate the domain used in SPIFFE identity URL + + # 90*24hour = 2160h + workloadCertTtl: 2160h + + # Determines Citadel default behavior if the ca.istio.io/env or ca.istio.io/override + # labels are not found on a given namespace. + # + # For example: consider a namespace called "target", which has neither the "ca.istio.io/env" + # nor the "ca.istio.io/override" namespace labels. To decide whether or not to generate secrets + # for service accounts created in this "target" namespace, Citadel will defer to this option. If the value + # of this option is "true" in this case, secrets will be generated for the "target" namespace. + # If the value of this option is "false" Citadel will not generate secrets upon service account creation. + enableNamespacesByDefault: true + + # Galley, pilot in each 'profile' must have a DNS cert. + dnsCerts: + istio-pilot-service-account.istio-control: istio-pilot-service-account.istio-control + istio-pilot-service-account.istio-pilot11: istio-pilot-service-account.istio-system + + istio-sidecar-injector-service-account.istio-remote: istio-sidecar-injector.istio-remote.svc + istio-sidecar-injector-service-account.istio-pilot11: istio-sidecar-injector.istio-pilot11.svc + istio-sidecar-injector-service-account.istio-control: istio-sidecar-injector.istio-control.svc + istio-sidecar-injector-service-account.istio-master: istio-sidecar-injector.istio-master.svc + istio-sidecar-injector-service-account.istio-control-master: istio-sidecar-injector.istio-control-master.svc + + istio-galley-service-account.istio-pilot11: istio-galley.istio-pilot11.svc + istio-galley-service-account.istio-control: istio-galley.istio-control.svc + + istio-galley-service-account.istio-master: istio-galley.istio-master.svc + istio-galley-service-account.istio-control-master: istio-galley.istio-control-master.svc + + istio-galley-service-account.istio-config: istio-galley.istio-config.svc + + nodeSelector: {} + tolerations: [] + + # Specify the pod anti-affinity that allows you to constrain which nodes + # your pod is eligible to be scheduled based on labels on pods that are + # already running on the node rather than based on labels on nodes. + # There are currently two types of anti-affinity: + # "requiredDuringSchedulingIgnoredDuringExecution" + # "preferredDuringSchedulingIgnoredDuringExecution" + # which denote "hard" vs. "soft" requirements, you can define your values + # in "podAntiAffinityLabelSelector" and "podAntiAffinityTermLabelSelector" + # correspondingly. + # For example: + # podAntiAffinityLabelSelector: + # - key: security + # operator: In + # values: S1,S2 + # topologyKey: "kubernetes.io/hostname" + # This pod anti-affinity rule says that the pod requires not to be scheduled + # onto a node if that node is already running a pod with label having key + # "security" and value "S1". + podAntiAffinityLabelSelector: [] + podAntiAffinityTermLabelSelector: [] diff --git a/istio-1.3.5/install/kubernetes/operator/charts/security/nodeagent/Chart.yaml b/istio-1.3.5/install/kubernetes/operator/charts/security/nodeagent/Chart.yaml new file mode 100644 index 0000000..9ba4eeb --- /dev/null +++ b/istio-1.3.5/install/kubernetes/operator/charts/security/nodeagent/Chart.yaml @@ -0,0 +1,13 @@ +apiVersion: v1 +name: nodeagent +version: 1.1.0 +appVersion: 1.1.0 +tillerVersion: ">=2.7.2" +description: Helm chart for nodeagent deployment +keywords: + - istio + - nodeagent +sources: + - http://github.com/istio/istio +engine: gotpl +icon: https://istio.io/favicons/android-192x192.png diff --git a/istio-1.3.5/install/kubernetes/operator/charts/security/nodeagent/templates/_affinity.tpl b/istio-1.3.5/install/kubernetes/operator/charts/security/nodeagent/templates/_affinity.tpl new file mode 100644 index 0000000..c4dee1b --- /dev/null +++ b/istio-1.3.5/install/kubernetes/operator/charts/security/nodeagent/templates/_affinity.tpl @@ -0,0 +1,93 @@ +{{/* affinity - https://kubernetes.io/docs/concepts/configuration/assign-pod-node/ */}} + +{{- define "nodeaffinity" }} + nodeAffinity: + requiredDuringSchedulingIgnoredDuringExecution: + {{- include "nodeAffinityRequiredDuringScheduling" . }} + preferredDuringSchedulingIgnoredDuringExecution: + {{- include "nodeAffinityPreferredDuringScheduling" . }} +{{- end }} + +{{- define "nodeAffinityRequiredDuringScheduling" }} + nodeSelectorTerms: + - matchExpressions: + - key: beta.kubernetes.io/arch + operator: In + values: + {{- range $key, $val := .Values.global.arch }} + {{- if gt ($val | int) 0 }} + - {{ $key }} + {{- end }} + {{- end }} + {{- $nodeSelector := default .Values.global.defaultNodeSelector .Values.nodeagent.nodeSelector -}} + {{- range $key, $val := $nodeSelector }} + - key: {{ $key }} + operator: In + values: + - {{ $val }} + {{- end }} +{{- end }} + +{{- define "nodeAffinityPreferredDuringScheduling" }} + {{- range $key, $val := .Values.global.arch }} + {{- if gt ($val | int) 0 }} + - weight: {{ $val | int }} + preference: + matchExpressions: + - key: beta.kubernetes.io/arch + operator: In + values: + - {{ $key }} + {{- end }} + {{- end }} +{{- end }} + +{{- define "podAntiAffinity" }} +{{- if or .Values.nodeagent.podAntiAffinityLabelSelector .Values.nodeagent.podAntiAffinityTermLabelSelector}} + podAntiAffinity: + {{- if .Values.nodeagent.podAntiAffinityLabelSelector }} + requiredDuringSchedulingIgnoredDuringExecution: + {{- include "podAntiAffinityRequiredDuringScheduling" . }} + {{- end }} + {{- if .Values.nodeagent.podAntiAffinityTermLabelSelector }} + preferredDuringSchedulingIgnoredDuringExecution: + {{- include "podAntiAffinityPreferredDuringScheduling" . }} + {{- end }} +{{- end }} +{{- end }} + +{{- define "podAntiAffinityRequiredDuringScheduling" }} + {{- range $index, $item := .Values.nodeagent.podAntiAffinityLabelSelector }} + - labelSelector: + matchExpressions: + - key: {{ $item.key }} + operator: {{ $item.operator }} + {{- if $item.values }} + values: + {{- $vals := split "," $item.values }} + {{- range $i, $v := $vals }} + - {{ $v }} + {{- end }} + {{- end }} + topologyKey: {{ $item.topologyKey }} + {{- end }} +{{- end }} + +{{- define "podAntiAffinityPreferredDuringScheduling" }} + {{- range $index, $item := .Values.nodeagent.podAntiAffinityTermLabelSelector }} + - podAffinityTerm: + labelSelector: + matchExpressions: + - key: {{ $item.key }} + operator: {{ $item.operator }} + {{- if $item.values }} + values: + {{- $vals := split "," $item.values }} + {{- range $i, $v := $vals }} + - {{ $v }} + {{- end }} + {{- end }} + topologyKey: {{ $item.topologyKey }} + weight: 100 + {{- end }} +{{- end }} diff --git a/istio-1.3.5/install/kubernetes/operator/charts/security/nodeagent/templates/clusterrole.yaml b/istio-1.3.5/install/kubernetes/operator/charts/security/nodeagent/templates/clusterrole.yaml new file mode 100644 index 0000000..ac51632 --- /dev/null +++ b/istio-1.3.5/install/kubernetes/operator/charts/security/nodeagent/templates/clusterrole.yaml @@ -0,0 +1,11 @@ +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: istio-nodeagent-{{ .Release.Namespace }} + labels: + app: istio-nodeagent + release: {{ .Release.Name }} +rules: +- apiGroups: [""] + resources: ["configmaps"] + verbs: ["get"] diff --git a/istio-1.3.5/install/kubernetes/operator/charts/security/nodeagent/templates/clusterrolebinding.yaml b/istio-1.3.5/install/kubernetes/operator/charts/security/nodeagent/templates/clusterrolebinding.yaml new file mode 100644 index 0000000..33e923e --- /dev/null +++ b/istio-1.3.5/install/kubernetes/operator/charts/security/nodeagent/templates/clusterrolebinding.yaml @@ -0,0 +1,15 @@ +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: istio-nodeagent-{{ .Release.Namespace }} + labels: + app: istio-nodeagent + release: {{ .Release.Name }} +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: istio-nodeagent-{{ .Release.Namespace }} +subjects: + - kind: ServiceAccount + name: istio-nodeagent-service-account + namespace: {{ .Release.Namespace }} diff --git a/istio-1.3.5/install/kubernetes/operator/charts/security/nodeagent/templates/daemonset.yaml b/istio-1.3.5/install/kubernetes/operator/charts/security/nodeagent/templates/daemonset.yaml new file mode 100644 index 0000000..f3c3570 --- /dev/null +++ b/istio-1.3.5/install/kubernetes/operator/charts/security/nodeagent/templates/daemonset.yaml @@ -0,0 +1,67 @@ +apiVersion: apps/v1 +kind: DaemonSet +metadata: + name: istio-nodeagent + namespace: {{ .Release.Namespace }} + labels: + app: istio-nodeagent + istio: nodeagent + release: {{ .Release.Name }} +spec: + selector: + matchLabels: + istio: nodeagent + template: + metadata: + labels: + app: istio-nodeagent + istio: nodeagent + release: {{ .Release.Name }} + annotations: + sidecar.istio.io/inject: "false" + spec: + serviceAccountName: istio-nodeagent-service-account +{{- if .Values.global.priorityClassName }} + priorityClassName: "{{ .Values.global.priorityClassName }}" +{{- end }} + containers: + - name: nodeagent +{{- if contains "/" .Values.nodeagent.image }} + image: "{{ .Values.nodeagent.image }}" +{{- else }} + image: "{{ .Values.global.hub }}/{{ .Values.nodeagent.image }}:{{ .Values.global.tag }}" +{{- end }} + imagePullPolicy: {{ .Values.global.imagePullPolicy | default "Always" }} + args: + {{- if .Values.global.logAsJson }} + - --log_as_json + {{- end }} + volumeMounts: + - mountPath: /var/run/sds + name: sdsudspath + env: + {{- if .Values.nodeagent.env }} + {{- range $key, $val := .Values.nodeagent.env }} + - name: {{ $key }} + value: "{{ $val }}" + {{- end }} + {{- end }} + - name: "Trust_Domain" + value: "{{ .Values.global.trustDomain }}" + - name: NAMESPACE + valueFrom: + fieldRef: + fieldPath: metadata.namespace + volumes: + - name: sdsudspath + hostPath: + path: /var/run/sds + affinity: + {{- include "nodeaffinity" . | indent 6 }} + {{- include "podAntiAffinity" . | indent 6 }} +{{- if .Values.nodeagent.tolerations }} + tolerations: +{{ toYaml .Values.nodeagent.tolerations | indent 6 }} +{{- end }} + updateStrategy: + type: RollingUpdate \ No newline at end of file diff --git a/istio-1.3.5/install/kubernetes/operator/charts/security/nodeagent/templates/serviceaccount.yaml b/istio-1.3.5/install/kubernetes/operator/charts/security/nodeagent/templates/serviceaccount.yaml new file mode 100644 index 0000000..6f1f946 --- /dev/null +++ b/istio-1.3.5/install/kubernetes/operator/charts/security/nodeagent/templates/serviceaccount.yaml @@ -0,0 +1,14 @@ +apiVersion: v1 +kind: ServiceAccount +{{- if .Values.global.imagePullSecrets }} +imagePullSecrets: +{{- range .Values.global.imagePullSecrets }} + - name: {{ . }} +{{- end }} +{{- end }} +metadata: + name: istio-nodeagent-service-account + namespace: {{ .Release.Namespace }} + labels: + app: istio-nodeagent + release: {{ .Release.Name }} diff --git a/istio-1.3.5/install/kubernetes/operator/charts/security/nodeagent/values.yaml b/istio-1.3.5/install/kubernetes/operator/charts/security/nodeagent/values.yaml new file mode 100644 index 0000000..8223317 --- /dev/null +++ b/istio-1.3.5/install/kubernetes/operator/charts/security/nodeagent/values.yaml @@ -0,0 +1,37 @@ +# +# nodeagent configuration +# +nodeagent: + enabled: false + image: node-agent-k8s + env: + # name of authentication provider. + CA_PROVIDER: "" + # CA endpoint. + CA_ADDR: "" + # names of authentication provider's plugins. + Plugins: "" + + nodeSelector: {} + tolerations: [] + + # Specify the pod anti-affinity that allows you to constrain which nodes + # your pod is eligible to be scheduled based on labels on pods that are + # already running on the node rather than based on labels on nodes. + # There are currently two types of anti-affinity: + # "requiredDuringSchedulingIgnoredDuringExecution" + # "preferredDuringSchedulingIgnoredDuringExecution" + # which denote "hard" vs. "soft" requirements, you can define your values + # in "podAntiAffinityLabelSelector" and "podAntiAffinityTermLabelSelector" + # correspondingly. + # For example: + # podAntiAffinityLabelSelector: + # - key: security + # operator: In + # values: S1,S2 + # topologyKey: "kubernetes.io/hostname" + # This pod anti-affinity rule says that the pod requires not to be scheduled + # onto a node if that node is already running a pod with label having key + # "security" and value "S1". + podAntiAffinityLabelSelector: [] + podAntiAffinityTermLabelSelector: [] diff --git a/istio-1.3.5/install/kubernetes/operator/profiles/default.yaml b/istio-1.3.5/install/kubernetes/operator/profiles/default.yaml new file mode 100644 index 0000000..acffec3 --- /dev/null +++ b/istio-1.3.5/install/kubernetes/operator/profiles/default.yaml @@ -0,0 +1,701 @@ +apiVersion: install.istio.io/v1alpha2 +kind: IstioControlPlane +spec: + hub: gcr.io/istio-release + tag: release-1.3-latest-daily + defaultNamespace: istio-system + + # Traffic management feature + trafficManagement: + enabled: true + components: + pilot: + enabled: true + k8s: + env: + - name: POD_NAME + valueFrom: + fieldRef: + apiVersion: v1 + fieldPath: metadata.name + - name: POD_NAMESPACE + valueFrom: + fieldRef: + apiVersion: v1 + fieldPath: metadata.namespace + - name: GODEBUG + value: gctrace=1 + - name: PILOT_TRACE_SAMPLING + value: "1" + - name: CONFIG_NAMESPACE + value: istio-config + hpaSpec: + maxReplicas: 5 + minReplicas: 1 + scaleTargetRef: + apiVersion: apps/v1 + kind: Deployment + name: istio-pilot + metrics: + - type: Resource + resource: + name: cpu + targetAverageUtilization: 80 + readinessProbe: + httpGet: + path: /ready + port: 8080 + initialDelaySeconds: 5 + periodSeconds: 30 + timeoutSeconds: 5 + resources: + requests: + cpu: 500m + memory: 2048Mi + strategy: + rollingUpdate: + maxSurge: "100%" + maxUnavailable: "25%" + + # Policy feature + policy: + enabled: true + components: + policy: + enabled: true + k8s: + replicaCount: 1 + hpaSpec: + maxReplicas: 5 + minReplicas: 1 + scaleTargetRef: + apiVersion: apps/v1 + kind: Deployment + name: istio-policy + metrics: + - type: Resource + resource: + name: cpu + targetAverageUtilization: 80 + env: + - name: GODEBUG + value: "gctrace=1" + strategy: + rollingUpdate: + maxSurge: "100%" + maxUnavailable: "25%" + + # Telemetry feature + telemetry: + enabled: true + components: + telemetry: + enabled: true + k8s: + env: + - name: GODEBUG + value: "gctrace=1" + - name: GOMAXPROCS + value: "6" + hpaSpec: + maxReplicas: 5 + minReplicas: 1 + scaleTargetRef: + apiVersion: apps/v1 + kind: Deployment + name: istio-telemetry + metrics: + - type: Resource + resource: + name: cpu + targetAverageUtilization: 80 + replicaCount: 1 + resources: + requests: + cpu: 1000m + memory: 1G + limits: + cpu: 4800m + memory: 4G + strategy: + rollingUpdate: + maxSurge: "100%" + maxUnavailable: "25%" + + # Security feature + security: + enabled: true + components: + citadel: + enabled: true + k8s: + strategy: + rollingUpdate: + maxSurge: "100%" + maxUnavailable: "25%" + certManager: + enabled: false + nodeAgent: + enabled: false + + # Config management feature + configManagement: + enabled: true + components: + galley: + enabled: true + k8s: + replicaCount: 1 + resources: + requests: + cpu: 100m + strategy: + rollingUpdate: + maxSurge: "100%" + maxUnavailable: "25%" + + # Auto injection feature + autoInjection: + enabled: true + components: + injector: + enabled: true + k8s: + replicaCount: 1 + strategy: + rollingUpdate: + maxSurge: "100%" + maxUnavailable: "25%" + + # Istio Gateway feature + gateways: + enabled: true + components: + ingressGateway: + enabled: true + k8s: + hpaSpec: + maxReplicas: 5 + minReplicas: 1 + scaleTargetRef: + apiVersion: apps/v1 + kind: Deployment + name: istio-ingressgateway + metrics: + - type: Resource + resource: + name: cpu + targetAverageUtilization: 80 + resources: + requests: + cpu: 100m + memory: 128Mi + limits: + cpu: 2000m + memory: 1024Mi + strategy: + rollingUpdate: + maxSurge: "100%" + maxUnavailable: "25%" + + egressGateway: + enabled: false + k8s: + hpaSpec: + maxReplicas: 5 + minReplicas: 1 + scaleTargetRef: + apiVersion: apps/v1 + kind: Deployment + name: istio-egressgateway + metrics: + - type: Resource + resource: + name: cpu + targetAverageUtilization: 80 + resources: + requests: + cpu: 100m + memory: 128Mi + limits: + cpu: 2000m + memory: 256Mi + strategy: + rollingUpdate: + maxSurge: "100%" + maxUnavailable: "25%" + + # Global values passed through to helm global.yaml. + values: + global: + logging: + level: "default:info" + logAsJson: false + k8sIngress: + enabled: false + gatewayName: ingressgateway + enableHttps: false + proxy: + image: proxyv2 + clusterDomain: "cluster.local" + resources: + requests: + cpu: 100m + memory: 128Mi + limits: + cpu: 2000m + memory: 1024Mi + concurrency: 2 + accessLogFile: "" + accessLogFormat: "" + accessLogEncoding: TEXT + envoyAccessLogService: + enabled: false + host: # example: accesslog-service.istio-system + port: # example: 15000 + logLevel: warning + componentLogLevel: "misc:error" + dnsRefreshRate: 300s + protocolDetectionTimeout: 1s + privileged: false + enableCoreDump: false + statusPort: 15020 + readinessInitialDelaySeconds: 1 + readinessPeriodSeconds: 2 + readinessFailureThreshold: 30 + includeIPRanges: "*" + excludeIPRanges: "" + excludeOutboundPorts: "" + kubevirtInterfaces: "" + includeInboundPorts: "*" + excludeInboundPorts: "" + autoInject: enabled + envoyStatsd: + enabled: false + host: # example: statsd-svc.istio-system + port: # example: 9125 + envoyMetricsService: + enabled: false + host: # example: metrics-service.istio-system + port: # example: 15000 + tracer: "zipkin" + proxy_init: + image: proxy_init + resources: + limits: + cpu: 100m + memory: 50Mi + requests: + cpu: 10m + memory: 10Mi + imagePullPolicy: Always + controlPlaneSecurityEnabled: true + disablePolicyChecks: true + policyCheckFailOpen: false + enableTracing: true + tracer: + lightstep: + address: "" # example: lightstep-satellite:443 + accessToken: "" # example: abcdefg1234567 + secure: true # example: true|false + cacertPath: "" # example: /etc/lightstep/cacert.pem + zipkin: + address: "" + datadog: + address: "$(HOST_IP):8126" + mtls: + enabled: false + imagePullSecrets: [] + arch: + amd64: 2 + s390x: 2 + ppc64le: 2 + oneNamespace: false + defaultNodeSelector: {} + configValidation: true + meshExpansion: + enabled: false + useILB: false + multiCluster: + enabled: false + defaultResources: + requests: + cpu: 10m + defaultPodDisruptionBudget: + enabled: true + priorityClassName: "" + useMCP: true + trustDomain: "" + outboundTrafficPolicy: + mode: ALLOW_ANY + sds: + enabled: false + udsPath: "" + meshNetworks: {} + localityLbSetting: + enabled: true + enableHelmTest: false + + pilot: + autoscaleEnabled: true + autoscaleMin: 1 + autoscaleMax: 5 + replicaCount: 1 + image: pilot + traceSampling: 1.0 + configNamespace: istio-config + appNamespaces: [] + env: + GODEBUG: gctrace=1 + cpu: + targetAverageUtilization: 80 + nodeSelector: {} + tolerations: [] + podAntiAffinityLabelSelector: [] + podAntiAffinityTermLabelSelector: [] + keepaliveMaxServerConnectionAge: 30m + deploymentLabels: + meshNetworks: + networks: {} + configMap: true + ingress: + ingressService: istio-ingressgateway + ingressControllerMode: "OFF" + ingressClass: istio + telemetry: + enabled: true + policy: + enabled: false + useMCP: true + + mixer: + adapters: + stdio: + enabled: false + outputAsJson: false + prometheus: + enabled: true + metricsExpiryDuration: 10m + kubernetesenv: + enabled: true + stackdriver: + enabled: false + auth: + appCredentials: false + apiKey: "" + serviceAccountPath: "" + tracer: + enabled: false + sampleProbability: 1 + useAdapterCRDs: false + + telemetry: + image: mixer + replicaCount: 1 + autoscaleEnabled: true + sessionAffinityEnabled: false + loadshedding: + mode: enforce + latencyThreshold: 100ms + reportBatchMaxEntries: 100 + reportBatchMaxTime: 1s + useMCP: true + nodeSelector: {} + tolerations: [] + podAntiAffinityLabelSelector: [] + podAntiAffinityTermLabelSelector: [] + + policy: + image: mixer + adapters: + kubernetesenv: + enabled: true + + galley: + + citadel: + image: citadel + selfSigned: true # indicate if self-signed CA is used. + trustDomain: cluster.local # indicate the domain used in SPIFFE identity URL + enableNamespacesByDefault: true + dnsCerts: + istio-pilot-service-account.istio-system: istio-pilot.istio-system + + certmanager: + hub: quay.io/jetstack + tag: v0.6.2 + image: cert-manager-controller + + nodeagent: + image: node-agent-k8s + + gateways: + istio-egressgateway: + autoscaleEnabled: true + zvpn: + suffix: global + enabled: true + drainDuration: 45s + connectTimeout: 10s + env: + ISTIO_META_ROUTER_MODE: "sni-dnat" + ports: + - port: 80 + name: http2 + - port: 443 + name: https + - port: 15443 + targetPort: 15443 + name: tls + secretVolumes: + - name: egressgateway-certs + secretName: istio-egressgateway-certs + mountPath: /etc/istio/egressgateway-certs + - name: egressgateway-ca-certs + secretName: istio-egressgateway-ca-certs + mountPath: /etc/istio/egressgateway-ca-certs + + istio-ingressgateway: + autoscaleEnabled: true + applicationPorts: "" + debug: info + domain: "" + zvpn: + enabled: true + suffix: global + telemetry_domain_name: "" + env: + ISTIO_META_ROUTER_MODE: "sni-dnat" + ports: + - port: 15020 + targetPort: 15020 + name: status-port + - port: 80 + targetPort: 80 + name: http2 + - port: 443 + name: https + - port: 15029 + targetPort: 15029 + name: kiali + - port: 15030 + targetPort: 15030 + name: prometheus + - port: 15031 + targetPort: 15031 + name: grafana + - port: 15032 + targetPort: 15032 + name: tracing + - port: 15443 + targetPort: 15443 + name: tls + meshExpansionPorts: + - port: 15011 + targetPort: 15011 + name: tcp-pilot-grpc-tls + - port: 8060 + targetPort: 8060 + name: tcp-citadel-grpc-tls + - port: 853 + targetPort: 853 + name: tcp-dns-tls + secretVolumes: + - name: ingressgateway-certs + secretName: istio-ingressgateway-certs + mountPath: /etc/istio/ingressgateway-certs + - name: ingressgateway-ca-certs + secretName: istio-ingressgateway-ca-certs + mountPath: /etc/istio/ingressgateway-ca-certs + telemetry_addon_gateways: + tracing_gateway: + name: tracing + port: 15032 + desPort: 80 + enabled: false + tls: false + kiali_gateway: + name: kiali + port: 15029 + desPort: 20001 + enabled: false + tls: false + grafana_gateway: + name: grafana + port: 15031 + desPort: 3000 + enabled: false + tls: false + prometheus_gateway: + name: prometheus + port: 15030 + desPort: 9090 + enabled: false + tls: false + + sidecarInjectorWebhook: + image: sidecar_injector + enableNamespacesByDefault: false + rewriteAppHTTPProbe: false + selfSigned: false + injectLabel: istio-injection + + prometheus: + enabled: true + replicaCount: 1 + hub: docker.io/prom + tag: v2.8.0 + retention: 6h + scrapeInterval: 15s + contextPath: /prometheus + ingress: + enabled: false + hosts: + - prometheus.local + annotations: + tls: + security: + enabled: true + nodeSelector: {} + tolerations: [] + podAntiAffinityLabelSelector: [] + podAntiAffinityTermLabelSelector: [] + + grafana: + enabled: false + replicaCount: 1 + image: + repository: grafana/grafana + tag: 6.1.6 + persist: false + storageClassName: "" + accessMode: ReadWriteMany + security: + enabled: false + secretName: grafana + usernameKey: username + passphraseKey: passphrase + + contextPath: /grafana + service: + annotations: {} + name: http + type: ClusterIP + externalPort: 3000 + loadBalancerIP: + loadBalancerSourceRanges: + ingress: + enabled: false + hosts: + - grafana.local + annotations: + tls: + datasources: + datasources.yaml: + apiVersion: 1 + datasources: + dashboardProviders: + dashboardproviders.yaml: + apiVersion: 1 + providers: + - name: 'istio' + orgId: 1 + folder: 'istio' + type: file + disableDeletion: false + options: + path: /var/lib/grafana/dashboards/istio + nodeSelector: {} + tolerations: [] + podAntiAffinityLabelSelector: [] + podAntiAffinityTermLabelSelector: [] + env: {} + envSecrets: {} + + tracing: + enabled: false + provider: jaeger + nodeSelector: {} + podAntiAffinityLabelSelector: [] + podAntiAffinityTermLabelSelector: [] + jaeger: + hub: docker.io/jaegertracing + tag: 1.12 + memory: + max_traces: 50000 + spanStorageType: badger + persist: false + storageClassName: "" + accessMode: ReadWriteMany + zipkin: + hub: docker.io/openzipkin + tag: 2.14.2 + probeStartupDelay: 200 + queryPort: 9411 + resources: + limits: + cpu: 300m + memory: 900Mi + requests: + cpu: 150m + memory: 900Mi + javaOptsHeap: 700 + maxSpans: 500000 + node: + cpus: 2 + opencensus: + hub: docker.io/omnition + tag: 0.1.9 + resources: + limits: + cpu: 1 + memory: 2Gi + requests: + cpu: 200m + memory: 400Mi + exporters: + stackdriver: + enable_tracing: true + service: + annotations: {} + name: http + type: ClusterIP + externalPort: 9411 + ingress: + enabled: false + hosts: + annotations: + tls: + + kiali: + enabled: false + replicaCount: 1 + hub: docker.io/kiali + tag: v1.1.0 + contextPath: /kiali + nodeSelector: {} + podAntiAffinityLabelSelector: [] + podAntiAffinityTermLabelSelector: [] + ingress: + enabled: false + hosts: + - kiali.local + annotations: + tls: + dashboard: + secretName: kiali + usernameKey: username + passphraseKey: passphrase + viewOnlyMode: false + grafanaURL: + jaegerURL: + prometheusNamespace: + createDemoSecret: true + security: + enabled: true + cert_file: /kiali-cert/cert-chain.pem + private_key_file: /kiali-cert/key.pem + + # TODO: derive from operator API + version: "" + clusterResources: true diff --git a/istio-1.3.5/install/kubernetes/operator/profiles/demo-auth.yaml b/istio-1.3.5/install/kubernetes/operator/profiles/demo-auth.yaml new file mode 100644 index 0000000..6fa2a87 --- /dev/null +++ b/istio-1.3.5/install/kubernetes/operator/profiles/demo-auth.yaml @@ -0,0 +1,112 @@ +apiVersion: install.istio.io/v1alpha2 +kind: IstioControlPlane +spec: + gateways: + components: + egressGateway: + enabled: true + k8s: + resources: + requests: + cpu: 10m + memory: 40Mi + ingressGateway: + enabled: true + k8s: + resources: + requests: + cpu: 10m + memory: 40Mi + policy: + components: + policy: + k8s: + resources: + requests: + cpu: 10m + memory: 100Mi + + telemetry: + components: + telemetry: + k8s: + resources: + requests: + cpu: 50m + memory: 100Mi + + + trafficManagement: + components: + pilot: + k8s: + env: + - name: POD_NAME + valueFrom: + fieldRef: + apiVersion: v1 + fieldPath: metadata.name + - name: POD_NAMESPACE + valueFrom: + fieldRef: + apiVersion: v1 + fieldPath: metadata.namespace + - name: GODEBUG + value: gctrace=1 + - name: PILOT_TRACE_SAMPLING + value: "100" + - name: CONFIG_NAMESPACE + value: istio-config + resources: + requests: + cpu: 10m + memory: 100Mi + + values: + global: + disablePolicyChecks: false + mtls: + enabled: true + proxy: + accessLogFile: /dev/stdout + resources: + requests: + cpu: 10m + memory: 40Mi + + pilot: + autoscaleEnabled: false + + mixer: + adapters: + useAdapterCRDs: false + kubernetesenv: + enabled: true + prometheus: + enabled: true + metricsExpiryDuration: 10m + stackdriver: + enabled: false + stdio: + enabled: true + outputAsJson: false + policy: + autoscaleEnabled: false + telemetry: + autoscaleEnabled: false + + gateways: + istio-egressgateway: + autoscaleEnabled: false + istio-ingressgateway: + autoscaleEnabled: false + + grafana: + enabled: true + + tracing: + enabled: true + + kiali: + enabled: true + createDemoSecret: true diff --git a/istio-1.3.5/install/kubernetes/operator/profiles/demo.yaml b/istio-1.3.5/install/kubernetes/operator/profiles/demo.yaml new file mode 100644 index 0000000..0bd7a4a --- /dev/null +++ b/istio-1.3.5/install/kubernetes/operator/profiles/demo.yaml @@ -0,0 +1,112 @@ +apiVersion: install.istio.io/v1alpha2 +kind: IstioControlPlane +spec: + gateways: + components: + egressGateway: + enabled: true + k8s: + resources: + requests: + cpu: 10m + memory: 40Mi + + ingressGateway: + enabled: true + k8s: + resources: + requests: + cpu: 10m + memory: 40Mi + + policy: + components: + policy: + k8s: + resources: + requests: + cpu: 10m + memory: 100Mi + + telemetry: + components: + telemetry: + k8s: + resources: + requests: + cpu: 50m + memory: 100Mi + + trafficManagement: + components: + pilot: + k8s: + env: + - name: POD_NAME + valueFrom: + fieldRef: + apiVersion: v1 + fieldPath: metadata.name + - name: POD_NAMESPACE + valueFrom: + fieldRef: + apiVersion: v1 + fieldPath: metadata.namespace + - name: GODEBUG + value: gctrace=1 + - name: PILOT_TRACE_SAMPLING + value: "100" + - name: CONFIG_NAMESPACE + value: istio-config + resources: + requests: + cpu: 10m + memory: 100Mi + + values: + global: + disablePolicyChecks: false + controlPlaneSecurityEnabled: false + proxy: + accessLogFile: /dev/stdout + resources: + requests: + cpu: 10m + memory: 40Mi + + pilot: + autoscaleEnabled: false + + mixer: + adapters: + useAdapterCRDs: false + kubernetesenv: + enabled: true + prometheus: + enabled: true + metricsExpiryDuration: 10m + stackdriver: + enabled: false + stdio: + enabled: true + outputAsJson: false + policy: + autoscaleEnabled: false + telemetry: + autoscaleEnabled: false + + gateways: + istio-egressgateway: + autoscaleEnabled: false + istio-ingressgateway: + autoscaleEnabled: false + + grafana: + enabled: true + + tracing: + enabled: true + + kiali: + enabled: true + createDemoSecret: true diff --git a/istio-1.3.5/install/kubernetes/operator/profiles/minimal.yaml b/istio-1.3.5/install/kubernetes/operator/profiles/minimal.yaml new file mode 100644 index 0000000..e982124 --- /dev/null +++ b/istio-1.3.5/install/kubernetes/operator/profiles/minimal.yaml @@ -0,0 +1,36 @@ +apiVersion: install.istio.io/v1alpha2 +kind: IstioControlPlane +spec: + policy: + enabled: false + + telemetry: + enabled: false + + security: + enabled: false + + configManagement: + enabled: false + + autoInjection: + enabled: false + + gateways: + enabled: false + + values: + global: + useMCP: false + + pilot: + sidecar: false + + proxy: + envoyStatsd: + enabled: false + host: + port: + + prometheus: + enabled: false diff --git a/istio-1.3.5/install/kubernetes/operator/profiles/sds.yaml b/istio-1.3.5/install/kubernetes/operator/profiles/sds.yaml new file mode 100644 index 0000000..0e80a3c --- /dev/null +++ b/istio-1.3.5/install/kubernetes/operator/profiles/sds.yaml @@ -0,0 +1,24 @@ +apiVersion: install.istio.io/v1alpha2 +kind: IstioControlPlane +spec: + security: + components: + nodeAgent: + enabled: true + values: + global: + controlPlaneSecurityEnabled: false + mtls: + enabled: true + sds: + enabled: true + udsPath: "unix:/var/run/sds/uds_path" + useNormalJwt: false + useTrustworthyJwt: true + nodeagent: + image: node-agent-k8s + env: + CA_PROVIDER: "Citadel" + CA_ADDR: "istio-citadel:8060" + VALID_TOKEN: true + diff --git a/istio-1.3.5/install/kubernetes/operator/version.yaml b/istio-1.3.5/install/kubernetes/operator/version.yaml new file mode 100644 index 0000000..f0bb29e --- /dev/null +++ b/istio-1.3.5/install/kubernetes/operator/version.yaml @@ -0,0 +1 @@ +1.3.0 diff --git a/istio-1.3.5/install/kubernetes/operator/versions.yaml b/istio-1.3.5/install/kubernetes/operator/versions.yaml new file mode 100644 index 0000000..7d5107d --- /dev/null +++ b/istio-1.3.5/install/kubernetes/operator/versions.yaml @@ -0,0 +1,4 @@ +- operatorVersion: 1.3.0 + supportedIstioVersions: 1.3.0 + recommendedIstioVersions: 1.3.0 + diff --git a/istio-1.3.5/install/tools/setupIstioVM.sh b/istio-1.3.5/install/tools/setupIstioVM.sh new file mode 100755 index 0000000..3ab5729 --- /dev/null +++ b/istio-1.3.5/install/tools/setupIstioVM.sh @@ -0,0 +1,112 @@ +#!/bin/bash +# +# Copyright 2017 Istio Authors. All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +################################################################################ + +# Script to install istio components for the raw VM. + +# Environment variable pointing to the generated Istio configs and binaries. +# TODO: use curl or tar to fetch the artifacts. +ISTIO_STAGING=${ISTIO_STAGING:-.} + +function istioVersionSource() { + echo "Sourced ${ISTIO_STAGING}/istio.VERSION" + cat "${ISTIO_STAGING}/istio.VERSION" + # shellcheck disable=SC1090 + source "${ISTIO_STAGING}/istio.VERSION" +} + +# Configure network for istio use, using DNSMasq. +# Will use the generated "kubedns" file. +function istioNetworkInit() { + if [[ ! -r /etc/dnsmasq.d ]] ; then + echo "*** Running apt-get update..." + apt-get update > /dev/null + echo "*** Running apt-get install dnsmasq..." + apt-get --no-install-recommends -y install dnsmasq + fi + + # Copy config files for DNS + chmod go+r "${ISTIO_STAGING}/kubedns" + cp "${ISTIO_STAGING}/kubedns" /etc/dnsmasq.d + systemctl restart dnsmasq + + # Update DHCP - if needed + if ! grep "^prepend domain-name-servers 127.0.0.1;" /etc/dhcp/dhclient.conf > /dev/null; then + echo 'prepend domain-name-servers 127.0.0.1;' >> /etc/dhcp/dhclient.conf + # TODO: find a better way to re-trigger dhclient + dhclient -v -1 + fi +} + +# Install istio components and certificates. The admin (directly or using tools like ansible) +# will generate and copy the files and install the packages on each machine. +function istioInstall() { + echo "*** Fetching istio packages..." + # Current URL for the debian files artifacts. Will be replaced by a proper apt repo. + rm -f istio-sidecar.deb + echo "curl -f -L ${PILOT_DEBIAN_URL}/istio-sidecar.deb > ${ISTIO_STAGING}/istio-sidecar.deb" + curl -f -L "${PILOT_DEBIAN_URL}/istio-sidecar.deb" > "${ISTIO_STAGING}/istio-sidecar.deb" + + # Install istio binaries + dpkg -i "${ISTIO_STAGING}/istio-sidecar.deb" + + mkdir -p /etc/certs + + # shellcheck disable=SC2086 + cp ${ISTIO_STAGING}/*.pem /etc/certs + + # Cluster settings - the CIDR in particular. + cp "${ISTIO_STAGING}/cluster.env" /var/lib/istio/envoy + + chown -R istio-proxy /etc/certs + chown -R istio-proxy /var/lib/istio/envoy + + # Useful to test VM extension to istio + apt-get --no-install-recommends -y install host +} + +function istioRestart() { + echo "*** Restarting istio proxy..." + # Node agent + if systemctl status istio-auth-node-agent > /dev/null; then + systemctl restart istio-auth-node-agent + else + systemctl start istio-auth-node-agent + fi + # Start or restart istio envoy + if systemctl status istio > /dev/null; then + systemctl restart istio + else + systemctl start istio + fi +} + +if [[ ${1:-} == "initNetwork" ]] ; then + istioNetworkInit +elif [[ ${1:-} == "istioInstall" ]] ; then + istioVersionSource + istioInstall + istioRestart +elif [[ ${1:-} == "help" ]] ; then + echo "$0 initNetwork: Configure DNS" + echo "$0 istioInstall: Install istio components" +else + istioVersionSource + istioNetworkInit + istioInstall + istioRestart +fi diff --git a/istio-1.3.5/install/tools/setupMeshEx.sh b/istio-1.3.5/install/tools/setupMeshEx.sh new file mode 100755 index 0000000..7228843 --- /dev/null +++ b/istio-1.3.5/install/tools/setupMeshEx.sh @@ -0,0 +1,274 @@ +#!/bin/bash +# +# Copyright 2017 Istio Authors. All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +################################################################################ + + +# Helper functions for extending the mesh with external VMs. + +# Script can be sourced in other files or used from tools like ansible. +# Currently the script include helpers for GKE, other providers will be added as +# they are contributed and we test them. + +# Environment variables used: +# +# ISTIO_NAMESPACE - control plane namespace, defaults to istio-system, only +# needs to be set for custom deployments +# K8S_CLUSTER - name of the K8S cluster. +# SERVICE_ACCOUNT - what account to provision on the VM. Defaults to default. +# SERVICE_NAMESPACE- namespace where the service account and service are +# running. Defaults to the current workspace in kube config. +# ISTIO_SECRET_PREFIX - prefix where the istio CA generates secrets for each +# service account. defaults to "istio." +# TODO: read MeshConfig to get the value of control plane auth policy, for now assume mTLS +# CONTROL_PLANE_AUTH_POLICY - control plane auth policy, defaults to "MUTUAL_TLS", only +# needs to be set when "NONE" is desired + +# GCP_OPTS - optional parameters for gcloud command, for example +# "--project P --zone Z". +# If not set, defaults are used. +# ISTIO_CP - command to use to copy files to the VM. +# ISTIO_RUN - command to use to run a command on the VM. + +# Generate a 'kubedns' Dnsmasq config file using the internal load balancer. +# It will need to be installed on each machine expanding the mesh. +function istioDnsmasq() { + local NS=${ISTIO_NAMESPACE:-istio-system} + # Multiple tries, it may take some time until the controllers generate the IPs + for _ in {1..20}; do + PILOT_IP=$(kubectl get -n "$NS" service istio-pilot-ilb -o jsonpath='{.status.loadBalancer.ingress[0].ip}') + ISTIO_DNS=$(kubectl get -n kube-system service dns-ilb -o jsonpath='{.status.loadBalancer.ingress[0].ip}') + MIXER_IP=$(kubectl get -n "$NS" service mixer-ilb -o jsonpath='{.status.loadBalancer.ingress[0].ip}') + CITADEL_IP=$(kubectl get -n "$NS" service citadel-ilb -o jsonpath='{.status.loadBalancer.ingress[0].ip}') + + if [ "${PILOT_IP}" == "" ] || [ "${ISTIO_DNS}" == "" ] || [ "${MIXER_IP}" == "" ] || [ "${CITADEL_IP}" == "" ] ; then + echo "Waiting for ILBs, pilot=$PILOT_IP, MIXER_IP=$MIXER_IP, CITADEL_IP=$CITADEL_IP, DNS=$ISTIO_DNS - kubectl get -n $NS service: $(kubectl get -n "$NS" service)" + sleep 30 + else + break + fi + done + + if [ "${PILOT_IP}" == "" ] || [ "${ISTIO_DNS}" == "" ] || [ "${MIXER_IP}" == "" ] || [ "${CITADEL_IP}" == "" ] ; then + echo "Failed to create ILBs" + exit 1 + fi + + #/etc/dnsmasq.d/kubedns + { + echo "server=/svc.cluster.local/$ISTIO_DNS" + echo "address=/istio-policy/$MIXER_IP" + echo "address=/istio-telemetry/$MIXER_IP" + echo "address=/istio-pilot/$PILOT_IP" + echo "address=/istio-citadel/$CITADEL_IP" + echo "address=/istio-ca/$CITADEL_IP" # Deprecated. For backward compatibility + # Also generate host entries for the istio-system. The generated config will work with both + # 'cluster-wide' and 'per-namespace'. + echo "address=/istio-policy.$NS/$MIXER_IP" + echo "address=/istio-telemetry.$NS/$MIXER_IP" + echo "address=/istio-pilot.$NS/$PILOT_IP" + echo "address=/istio-citadel.$NS/$CITADEL_IP" + echo "address=/istio-ca.$NS/$CITADEL_IP" # Deprecated. For backward compatibility + } > kubedns + + echo "Generated Dnsmaq config file 'kubedns'. Install it in /etc/dnsmasq.d and restart dnsmasq." + echo "$0 machineSetup does this for you." +} + +# Generate a cluster.env config file. +# Parameters: +# - name of the k8s cluster. +function istioClusterEnv() { + local K8S_CLUSTER=${1:-${K8S_CLUSTER}} + local ISTIO_NS=${ISTIO_NAMESPACE:-istio-system} + local CP_AUTH_POLICY=${CONTROL_PLANE_AUTH_POLICY:-MUTUAL_TLS} + + # TODO: parse it all from $(kubectl config current-context) + # shellcheck disable=SC2086 + CIDR=$(gcloud container clusters describe "${K8S_CLUSTER}" ${GCP_OPTS:-} --format "value(servicesIpv4Cidr)") + echo "ISTIO_SERVICE_CIDR=$CIDR" > cluster.env + echo "ISTIO_SYSTEM_NAMESPACE=$ISTIO_NS" >> cluster.env + echo "ISTIO_CP_AUTH=$CP_AUTH_POLICY" >> cluster.env + + echo "Generated cluster.env, needs to be installed in each VM as /var/lib/istio/envoy/cluster.env" + echo "the /var/lib/istio/envoy/ directory and files must be readable by 'istio-proxy' user" + echo "$0 machineSetup does this for you." +} + + +# Get an istio service account secret, extract it to files to be provisioned on a raw VM +# Params: +# - service account - defaults to istio.default or SERVICE_ACCOUNT env +# - service namespace - defaults to current namespace. +function istio_provision_certs() { + local SA=${1:-${SERVICE_ACCOUNT:-default}} + local NS=${2:-${SERVICE_NAMESPACE:-}} + local ALL=${3} + local CERT_NAME=${ISTIO_SECRET_PREFIX:-istio.}${SA} + + if [[ -n "$NS" ]] ; then + NS="-n $NS" + fi + local B64_DECODE=${BASE64_DECODE:-base64 --decode} + # shellcheck disable=SC2086 + kubectl get $NS secret "$CERT_NAME" -o jsonpath='{.data.root-cert\.pem}' | $B64_DECODE > root-cert.pem + echo "Generated root-cert.pem. It should be installed on /etc/certs" + if [ "$ALL" == "all" ] ; then + # shellcheck disable=SC2086 + kubectl get $NS secret "$CERT_NAME" -o jsonpath='{.data.cert-chain\.pem}' | $B64_DECODE > cert-chain.pem + # shellcheck disable=SC2086 + kubectl get $NS secret "$CERT_NAME" -o jsonpath='{.data.key\.pem}' | $B64_DECODE > key.pem + echo "Generated cert-chain.pem and key.pem. It should be installed on /etc/certs" + fi + + echo "the directory and files must be owned by 'istio-proxy' user" + echo "$0 machineSetup does this for you." +} + +# Install required files on a VM and run the setup script. +# This is an example to help integrating the steps into the admin automation tools. +# +# Must be run for each VM added to the cluster +# Params: +# - name of the VM - used to copy files over. +# - optional service account to be provisioned (defaults to istio.default) +# - optional namespace of the service account and VM services, defaults to SERVICE_NAMESPACE env +# or kube config. +# +# Expected to be run from the release directory (ie istio-0.2.8/ or istio/) +function istioBootstrapGCE() { + local DESTINATION=${1} + local SA=${2:-${SERVICE_ACCOUNT:-default}} + local NS=${3:-${SERVICE_NAMESPACE:-}} + + DEFAULT_SCRIPT="install/tools/setupIstioVM.sh" + SETUP_ISTIO_VM_SCRIPT=${SETUP_ISTIO_VM_SCRIPT:-${DEFAULT_SCRIPT}} + echo "Making certs for service account $SA (namespace $NS)" + istio_provision_certs "$SA" "$NS" "root-cert-only" + + for _ in {1..10}; do + # Copy deb, helper and config files + if ! istioCopy "$DESTINATION" \ + kubedns \ + ./*.pem \ + cluster.env \ + istio.VERSION \ + "${SETUP_ISTIO_VM_SCRIPT}"; then + echo "scp failed, retry in 10 sec" + sleep 10 + else + echo "scp succeeded" + break + fi + done + + istioRun "$DESTINATION" "ls -a" + + # Run the setup script. + istioRun "$DESTINATION" "sudo bash -c -x ./setupIstioVM.sh" +} + +# Install required files on a VM and run the setup script. +# This is an example to help integrating the steps into the admin automation tools. +# +# Must be run for each VM added to the cluster +# Params: +# - name of the VM - used to copy files over. +# - optional service account to be provisioned (defaults to istio.default) +# - optional namespace of the service account and VM services, defaults to SERVICE_NAMESPACE env +# or kube config. +# +# Expected to be run from the release directory (ie istio-0.2.8/ or istio/) +function istioBootstrapVM() { + local DESTINATION=${1} + local SA=${2:-${SERVICE_ACCOUNT:-default}} + local NS=${3:-${SERVICE_NAMESPACE:-}} + + DEFAULT_SCRIPT="install/tools/setupIstioVM.sh" + SETUP_ISTIO_VM_SCRIPT=${SETUP_ISTIO_VM_SCRIPT:-${DEFAULT_SCRIPT}} + echo "Making certs for service account $SA (namespace $NS)" + istio_provision_certs "$SA" "$NS" "all" + + for _ in {1..10}; do + # Copy deb, helper and config files + if ! istioCopy "$DESTINATION" \ + kubedns \ + ./*.pem \ + cluster.env \ + istio.VERSION \ + "${SETUP_ISTIO_VM_SCRIPT}"; then + echo "scp failed, retry in 10 sec" + sleep 10 + else + echo "scp succeeded" + break + fi + done + + istioRun "$DESTINATION" "ls -a" + + # Run the setup script. + istioRun "$DESTINATION" "sudo bash -c -x ./setupIstioVM.sh" +} + + +# Helper functions for the main script + +# Copy files to the VM. +# - VM name - required, destination where files will be copied +# - list of files and directories to be copied +function istioCopy() { + # TODO: based on some env variable, use different commands for other clusters or for testing with + # bare-metal machines. + local NAME=$1 + shift + local FILES=$* + + # shellcheck disable=SC2086 + ${ISTIO_CP:-gcloud compute scp --recurse ${GCP_OPTS:-}} $FILES "${NAME}:" +} + +# Run a command in a VM. +# - VM name +# - command to run, as one parameter. +function istioRun() { + local NAME=$1 + local CMD=$2 + + ${ISTIO_RUN:-gcloud compute ssh ${GCP_OPTS:-}} "$NAME" --command "$CMD" +} + +if [[ ${1:-} == "generateDnsmasq" ]] ; then + istioDnsmasq +elif [[ ${1:-} == "generateClusterEnv" ]] ; then + shift + istioClusterEnv "$1" +elif [[ ${1:-} == "machineCerts" ]] ; then + shift + istio_provision_certs "$1" "$2" "$3" +elif [[ ${1:-} == "machineSetup" ]] ; then + shift + istioBootstrapVM "$1" +elif [[ ${1:-} == "gceMachineSetup" ]] ; then + shift + istioBootstrapGCE "$1" +else + echo "$0 generateDnsmasq: Generate dnsmasq config files (one time)" + echo "GCP_OPTS=\"--project P --zone Z\" $0 generateClusterEnv K8S_CLUSTER_NAME: Generate cluster range config files (one time)" + echo "$0 machineCerts SERVICE_ACCOUNT: Generate bootstrap machine certs. Uses 'default' account if no parameters (one time per host)" + echo "$0 machineSetup HOST: Copy files to HOST, and run the setup script (one time per host)" + echo "$0 gceMachineSetup HOST: Copy files to a GCE HOST, and run the setup script (one time per host)" +fi diff --git a/istio-1.3.5/istio.VERSION b/istio-1.3.5/istio.VERSION new file mode 100644 index 0000000..a25cc0a --- /dev/null +++ b/istio-1.3.5/istio.VERSION @@ -0,0 +1,16 @@ +# DO NOT EDIT THIS FILE MANUALLY instead use +# install/updateVersion.sh (see install/README.md) +export GALLEY_HUB="docker.io/istio" +export GALLEY_TAG="1.3.5" +export CITADEL_HUB="docker.io/istio" +export CITADEL_TAG="1.3.5" +export MIXER_HUB="docker.io/istio" +export MIXER_TAG="1.3.5" +export PILOT_HUB="docker.io/istio" +export PILOT_TAG="1.3.5" +export PROXY_HUB="docker.io/istio" +export PROXY_TAG="1.3.5" +export ISTIO_NAMESPACE="istio-system" +export PILOT_DEBIAN_URL="https://storage.googleapis.com/istio-release/releases/1.3.5/deb" +export FORTIO_HUB="docker.io/fortio" +export FORTIO_TAG="latest_release" diff --git a/istio-1.3.5/samples/README.md b/istio-1.3.5/samples/README.md new file mode 100644 index 0000000..4e1d644 --- /dev/null +++ b/istio-1.3.5/samples/README.md @@ -0,0 +1,4 @@ +# Istio Samples + +This directory contains sample applications highlighting Istio's various +features. To run these samples, check out the tutorials [here](https://istio.io/docs/examples/). diff --git a/istio-1.3.5/samples/bookinfo/README.md b/istio-1.3.5/samples/bookinfo/README.md new file mode 100644 index 0000000..92e3b17 --- /dev/null +++ b/istio-1.3.5/samples/bookinfo/README.md @@ -0,0 +1,25 @@ +# Bookinfo Sample +See https://istio.io/docs/examples/bookinfo/ + +## Build docker images without pushing +``` +src/build-services.sh +``` + +The bookinfo versions are different from Istio versions since the sample should work with any version of Istio. + +## Update docker images in the yaml files +``` +sed -i "s/\(istio\/examples-bookinfo-.*\):[[:digit:]]\.[[:digit:]]\.[[:digit:]]//g" */bookinfo*.yaml +``` + +## Push docker images to docker hub +One script to build the docker images, push them to docker hub and to update the yaml files +``` +build_push_update_images.sh +``` + +## Tests +Bookinfo is tested by e2e smoke test on every PR. The Bookinfo e2e test is in [tests/e2e/tests/bookinfo](https://github.com/istio/istio/tree/master/tests/e2e/tests/bookinfo), make target `e2e_bookinfo`. + +The reference productpage HTML files are in [tests/apps/bookinfo/output](https://github.com/istio/istio/tree/master/tests/apps/bookinfo/output). If the productpage HTML produced by the app is changed, remember to regenerate the reference HTML files and commit them with the same PR. diff --git a/istio-1.3.5/samples/bookinfo/networking/ROUTING_RULE_MIGRATION.md b/istio-1.3.5/samples/bookinfo/networking/ROUTING_RULE_MIGRATION.md new file mode 100644 index 0000000..027ed64 --- /dev/null +++ b/istio-1.3.5/samples/bookinfo/networking/ROUTING_RULE_MIGRATION.md @@ -0,0 +1,32 @@ +## Routing Config Model Changes + +The routing configuration resources in `v1alpha3` have changed as follows: + +1. `RouteRule` -> `VirtualService` +2. `DestinationPolicy` -> `DestinationRule` +3. `EgressRule` -> `ServiceEntry` +4. `Ingress` -> `Gateway` (recommended to use) + +A `VirtualService` configures the set of routes to a particular traffic destination host. +A `DestinationRule` configures the set of policies to be applied at a destination after routing has occurred. + +Note that the `apiVersion` of these resources is also changed: + +`apiVersion: config.istio.io/v1alpha2` -> `apiVersion: networking.istio.io/v1alpha3` + +### Creating and deleting Route Rules + +In the previous config model there could be many `RouteRule` resources for the same destination, where a `precedence` field was used +to control the order of evaluation. In `v1alpha3`, all rules for a given destination are stored together as an ordered +list in a single `VirtualService` resource. Therefore, adding a second and subsequent rules for a particular destination +is no longer done by creating a new `RouteRule` resource, but instead by updating the one-and-only `VirtualService` resource +for the destination. + +old routing rules: +``` +kubectl apply -f my-second-rule-for-destination-abc.yaml +``` +v1alpha3 routing rules: +``` +kubectl apply -f my-updated-rules-for-destination-abc.yaml +``` diff --git a/istio-1.3.5/samples/bookinfo/networking/bookinfo-gateway.yaml b/istio-1.3.5/samples/bookinfo/networking/bookinfo-gateway.yaml new file mode 100644 index 0000000..951f069 --- /dev/null +++ b/istio-1.3.5/samples/bookinfo/networking/bookinfo-gateway.yaml @@ -0,0 +1,41 @@ +apiVersion: networking.istio.io/v1alpha3 +kind: Gateway +metadata: + name: bookinfo-gateway +spec: + selector: + istio: ingressgateway # use istio default controller + servers: + - port: + number: 80 + name: http + protocol: HTTP + hosts: + - "*" +--- +apiVersion: networking.istio.io/v1alpha3 +kind: VirtualService +metadata: + name: bookinfo +spec: + hosts: + - "*" + gateways: + - bookinfo-gateway + http: + - match: + - uri: + exact: /productpage + - uri: + prefix: /static + - uri: + exact: /login + - uri: + exact: /logout + - uri: + prefix: /api/v1/products + route: + - destination: + host: productpage + port: + number: 9080 diff --git a/istio-1.3.5/samples/bookinfo/networking/certmanager-gateway.yaml b/istio-1.3.5/samples/bookinfo/networking/certmanager-gateway.yaml new file mode 100644 index 0000000..3fa6537 --- /dev/null +++ b/istio-1.3.5/samples/bookinfo/networking/certmanager-gateway.yaml @@ -0,0 +1,35 @@ +apiVersion: networking.istio.io/v1alpha3 +kind: Gateway +metadata: + name: cert-manager-gateway + namespace: istio-system +spec: + selector: + istio: ingressgateway + servers: + - port: + number: 80 + name: http + protocol: HTTP + hosts: + - "*" +--- +apiVersion: networking.istio.io/v1alpha3 +kind: VirtualService +metadata: + name: cert-manager + namespace: istio-system +spec: + hosts: + - "*" + gateways: + - cert-manager-gateway + http: + - match: + - uri: + prefix: /.well-known/acme-challenge/ + route: + - destination: + host: cert-manager-resolver + port: + number: 8089 diff --git a/istio-1.3.5/samples/bookinfo/networking/destination-rule-all-mtls.yaml b/istio-1.3.5/samples/bookinfo/networking/destination-rule-all-mtls.yaml new file mode 100644 index 0000000..2a19c3f --- /dev/null +++ b/istio-1.3.5/samples/bookinfo/networking/destination-rule-all-mtls.yaml @@ -0,0 +1,74 @@ +apiVersion: networking.istio.io/v1alpha3 +kind: DestinationRule +metadata: + name: productpage +spec: + host: productpage + trafficPolicy: + tls: + mode: ISTIO_MUTUAL + subsets: + - name: v1 + labels: + version: v1 +--- +apiVersion: networking.istio.io/v1alpha3 +kind: DestinationRule +metadata: + name: reviews +spec: + host: reviews + trafficPolicy: + tls: + mode: ISTIO_MUTUAL + subsets: + - name: v1 + labels: + version: v1 + - name: v2 + labels: + version: v2 + - name: v3 + labels: + version: v3 +--- +apiVersion: networking.istio.io/v1alpha3 +kind: DestinationRule +metadata: + name: ratings +spec: + host: ratings + trafficPolicy: + tls: + mode: ISTIO_MUTUAL + subsets: + - name: v1 + labels: + version: v1 + - name: v2 + labels: + version: v2 + - name: v2-mysql + labels: + version: v2-mysql + - name: v2-mysql-vm + labels: + version: v2-mysql-vm +--- +apiVersion: networking.istio.io/v1alpha3 +kind: DestinationRule +metadata: + name: details +spec: + host: details + trafficPolicy: + tls: + mode: ISTIO_MUTUAL + subsets: + - name: v1 + labels: + version: v1 + - name: v2 + labels: + version: v2 +--- diff --git a/istio-1.3.5/samples/bookinfo/networking/destination-rule-all.yaml b/istio-1.3.5/samples/bookinfo/networking/destination-rule-all.yaml new file mode 100644 index 0000000..96be699 --- /dev/null +++ b/istio-1.3.5/samples/bookinfo/networking/destination-rule-all.yaml @@ -0,0 +1,62 @@ +apiVersion: networking.istio.io/v1alpha3 +kind: DestinationRule +metadata: + name: productpage +spec: + host: productpage + subsets: + - name: v1 + labels: + version: v1 +--- +apiVersion: networking.istio.io/v1alpha3 +kind: DestinationRule +metadata: + name: reviews +spec: + host: reviews + subsets: + - name: v1 + labels: + version: v1 + - name: v2 + labels: + version: v2 + - name: v3 + labels: + version: v3 +--- +apiVersion: networking.istio.io/v1alpha3 +kind: DestinationRule +metadata: + name: ratings +spec: + host: ratings + subsets: + - name: v1 + labels: + version: v1 + - name: v2 + labels: + version: v2 + - name: v2-mysql + labels: + version: v2-mysql + - name: v2-mysql-vm + labels: + version: v2-mysql-vm +--- +apiVersion: networking.istio.io/v1alpha3 +kind: DestinationRule +metadata: + name: details +spec: + host: details + subsets: + - name: v1 + labels: + version: v1 + - name: v2 + labels: + version: v2 +--- diff --git a/istio-1.3.5/samples/bookinfo/networking/destination-rule-reviews.yaml b/istio-1.3.5/samples/bookinfo/networking/destination-rule-reviews.yaml new file mode 100644 index 0000000..69f30f1 --- /dev/null +++ b/istio-1.3.5/samples/bookinfo/networking/destination-rule-reviews.yaml @@ -0,0 +1,19 @@ +apiVersion: networking.istio.io/v1alpha3 +kind: DestinationRule +metadata: + name: reviews +spec: + host: reviews + trafficPolicy: + loadBalancer: + simple: RANDOM + subsets: + - name: v1 + labels: + version: v1 + - name: v2 + labels: + version: v2 + - name: v3 + labels: + version: v3 diff --git a/istio-1.3.5/samples/bookinfo/networking/egress-rule-google-apis.yaml b/istio-1.3.5/samples/bookinfo/networking/egress-rule-google-apis.yaml new file mode 100644 index 0000000..d35e3ac --- /dev/null +++ b/istio-1.3.5/samples/bookinfo/networking/egress-rule-google-apis.yaml @@ -0,0 +1,46 @@ +apiVersion: networking.istio.io/v1alpha3 +kind: ServiceEntry +metadata: + name: googleapis +spec: + hosts: + - www.googleapis.com + ports: + - number: 80 + name: http + protocol: HTTP + - number: 443 + name: https + protocol: HTTPS + resolution: DNS +--- +apiVersion: networking.istio.io/v1alpha3 +kind: VirtualService +metadata: + name: rewrite-port-for-googleapis +spec: + hosts: + - www.googleapis.com + http: + - match: + - port: 80 + route: + - destination: + host: www.googleapis.com + port: + number: 443 +--- +apiVersion: networking.istio.io/v1alpha3 +kind: DestinationRule +metadata: + name: originate-tls-for-googleapis +spec: + host: www.googleapis.com + trafficPolicy: + loadBalancer: + simple: ROUND_ROBIN + portLevelSettings: + - port: + number: 443 + tls: + mode: SIMPLE # initiates HTTPS when accessing www.googleapis.com diff --git a/istio-1.3.5/samples/bookinfo/networking/fault-injection-details-v1.yaml b/istio-1.3.5/samples/bookinfo/networking/fault-injection-details-v1.yaml new file mode 100644 index 0000000..689ac40 --- /dev/null +++ b/istio-1.3.5/samples/bookinfo/networking/fault-injection-details-v1.yaml @@ -0,0 +1,31 @@ +apiVersion: networking.istio.io/v1alpha3 +kind: VirtualService +metadata: + name: details +spec: + hosts: + - details + http: + - fault: + abort: + httpStatus: 555 + percent: 100 + route: + - destination: + host: details + subset: v1 + - route: + - destination: + host: details + subset: v1 +--- +apiVersion: networking.istio.io/v1alpha3 +kind: DestinationRule +metadata: + name: details +spec: + host: details + subsets: + - name: v1 + labels: + version: v1 \ No newline at end of file diff --git a/istio-1.3.5/samples/bookinfo/networking/virtual-service-all-v1.yaml b/istio-1.3.5/samples/bookinfo/networking/virtual-service-all-v1.yaml new file mode 100644 index 0000000..6811e31 --- /dev/null +++ b/istio-1.3.5/samples/bookinfo/networking/virtual-service-all-v1.yaml @@ -0,0 +1,52 @@ +apiVersion: networking.istio.io/v1alpha3 +kind: VirtualService +metadata: + name: productpage +spec: + hosts: + - productpage + http: + - route: + - destination: + host: productpage + subset: v1 +--- +apiVersion: networking.istio.io/v1alpha3 +kind: VirtualService +metadata: + name: reviews +spec: + hosts: + - reviews + http: + - route: + - destination: + host: reviews + subset: v1 +--- +apiVersion: networking.istio.io/v1alpha3 +kind: VirtualService +metadata: + name: ratings +spec: + hosts: + - ratings + http: + - route: + - destination: + host: ratings + subset: v1 +--- +apiVersion: networking.istio.io/v1alpha3 +kind: VirtualService +metadata: + name: details +spec: + hosts: + - details + http: + - route: + - destination: + host: details + subset: v1 +--- diff --git a/istio-1.3.5/samples/bookinfo/networking/virtual-service-details-v2.yaml b/istio-1.3.5/samples/bookinfo/networking/virtual-service-details-v2.yaml new file mode 100644 index 0000000..5f21fa5 --- /dev/null +++ b/istio-1.3.5/samples/bookinfo/networking/virtual-service-details-v2.yaml @@ -0,0 +1,12 @@ +apiVersion: networking.istio.io/v1alpha3 +kind: VirtualService +metadata: + name: details +spec: + hosts: + - details + http: + - route: + - destination: + host: details + subset: v2 diff --git a/istio-1.3.5/samples/bookinfo/networking/virtual-service-ratings-db.yaml b/istio-1.3.5/samples/bookinfo/networking/virtual-service-ratings-db.yaml new file mode 100644 index 0000000..1698ec2 --- /dev/null +++ b/istio-1.3.5/samples/bookinfo/networking/virtual-service-ratings-db.yaml @@ -0,0 +1,26 @@ +apiVersion: networking.istio.io/v1alpha3 +kind: VirtualService +metadata: + name: reviews +spec: + hosts: + - reviews + http: + - route: + - destination: + host: reviews + subset: v3 +--- +apiVersion: networking.istio.io/v1alpha3 +kind: VirtualService +metadata: + name: ratings +spec: + hosts: + - ratings + http: + - route: + - destination: + host: ratings + subset: v2 +--- diff --git a/istio-1.3.5/samples/bookinfo/networking/virtual-service-ratings-mysql-vm.yaml b/istio-1.3.5/samples/bookinfo/networking/virtual-service-ratings-mysql-vm.yaml new file mode 100644 index 0000000..fdf8827 --- /dev/null +++ b/istio-1.3.5/samples/bookinfo/networking/virtual-service-ratings-mysql-vm.yaml @@ -0,0 +1,26 @@ +apiVersion: networking.istio.io/v1alpha3 +kind: VirtualService +metadata: + name: reviews +spec: + hosts: + - reviews + http: + - route: + - destination: + host: reviews + subset: v3 +--- +apiVersion: networking.istio.io/v1alpha3 +kind: VirtualService +metadata: + name: ratings +spec: + hosts: + - ratings + http: + - route: + - destination: + host: ratings + subset: v2-mysql-vm +--- diff --git a/istio-1.3.5/samples/bookinfo/networking/virtual-service-ratings-mysql.yaml b/istio-1.3.5/samples/bookinfo/networking/virtual-service-ratings-mysql.yaml new file mode 100644 index 0000000..03a700e --- /dev/null +++ b/istio-1.3.5/samples/bookinfo/networking/virtual-service-ratings-mysql.yaml @@ -0,0 +1,26 @@ +apiVersion: networking.istio.io/v1alpha3 +kind: VirtualService +metadata: + name: reviews +spec: + hosts: + - reviews + http: + - route: + - destination: + host: reviews + subset: v3 +--- +apiVersion: networking.istio.io/v1alpha3 +kind: VirtualService +metadata: + name: ratings +spec: + hosts: + - ratings + http: + - route: + - destination: + host: ratings + subset: v2-mysql +--- diff --git a/istio-1.3.5/samples/bookinfo/networking/virtual-service-ratings-test-abort.yaml b/istio-1.3.5/samples/bookinfo/networking/virtual-service-ratings-test-abort.yaml new file mode 100644 index 0000000..51c6fe9 --- /dev/null +++ b/istio-1.3.5/samples/bookinfo/networking/virtual-service-ratings-test-abort.yaml @@ -0,0 +1,25 @@ +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 diff --git a/istio-1.3.5/samples/bookinfo/networking/virtual-service-ratings-test-delay.yaml b/istio-1.3.5/samples/bookinfo/networking/virtual-service-ratings-test-delay.yaml new file mode 100644 index 0000000..6c4e19d --- /dev/null +++ b/istio-1.3.5/samples/bookinfo/networking/virtual-service-ratings-test-delay.yaml @@ -0,0 +1,25 @@ +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 diff --git a/istio-1.3.5/samples/bookinfo/networking/virtual-service-reviews-50-v3.yaml b/istio-1.3.5/samples/bookinfo/networking/virtual-service-reviews-50-v3.yaml new file mode 100644 index 0000000..aad8c31 --- /dev/null +++ b/istio-1.3.5/samples/bookinfo/networking/virtual-service-reviews-50-v3.yaml @@ -0,0 +1,17 @@ +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 diff --git a/istio-1.3.5/samples/bookinfo/networking/virtual-service-reviews-80-20.yaml b/istio-1.3.5/samples/bookinfo/networking/virtual-service-reviews-80-20.yaml new file mode 100644 index 0000000..7304d86 --- /dev/null +++ b/istio-1.3.5/samples/bookinfo/networking/virtual-service-reviews-80-20.yaml @@ -0,0 +1,17 @@ +apiVersion: networking.istio.io/v1alpha3 +kind: VirtualService +metadata: + name: reviews +spec: + hosts: + - reviews + http: + - route: + - destination: + host: reviews + subset: v1 + weight: 80 + - destination: + host: reviews + subset: v2 + weight: 20 diff --git a/istio-1.3.5/samples/bookinfo/networking/virtual-service-reviews-90-10.yaml b/istio-1.3.5/samples/bookinfo/networking/virtual-service-reviews-90-10.yaml new file mode 100644 index 0000000..d211dd1 --- /dev/null +++ b/istio-1.3.5/samples/bookinfo/networking/virtual-service-reviews-90-10.yaml @@ -0,0 +1,17 @@ +apiVersion: networking.istio.io/v1alpha3 +kind: VirtualService +metadata: + name: reviews +spec: + hosts: + - reviews + http: + - route: + - destination: + host: reviews + subset: v1 + weight: 90 + - destination: + host: reviews + subset: v2 + weight: 10 diff --git a/istio-1.3.5/samples/bookinfo/networking/virtual-service-reviews-jason-v2-v3.yaml b/istio-1.3.5/samples/bookinfo/networking/virtual-service-reviews-jason-v2-v3.yaml new file mode 100644 index 0000000..fb35713 --- /dev/null +++ b/istio-1.3.5/samples/bookinfo/networking/virtual-service-reviews-jason-v2-v3.yaml @@ -0,0 +1,20 @@ +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: v3 diff --git a/istio-1.3.5/samples/bookinfo/networking/virtual-service-reviews-test-v2.yaml b/istio-1.3.5/samples/bookinfo/networking/virtual-service-reviews-test-v2.yaml new file mode 100644 index 0000000..ea07efb --- /dev/null +++ b/istio-1.3.5/samples/bookinfo/networking/virtual-service-reviews-test-v2.yaml @@ -0,0 +1,20 @@ +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 diff --git a/istio-1.3.5/samples/bookinfo/networking/virtual-service-reviews-v2-v3.yaml b/istio-1.3.5/samples/bookinfo/networking/virtual-service-reviews-v2-v3.yaml new file mode 100644 index 0000000..7ae7b80 --- /dev/null +++ b/istio-1.3.5/samples/bookinfo/networking/virtual-service-reviews-v2-v3.yaml @@ -0,0 +1,17 @@ +apiVersion: networking.istio.io/v1alpha3 +kind: VirtualService +metadata: + name: reviews +spec: + hosts: + - reviews + http: + - route: + - destination: + host: reviews + subset: v2 + weight: 50 + - destination: + host: reviews + subset: v3 + weight: 50 diff --git a/istio-1.3.5/samples/bookinfo/networking/virtual-service-reviews-v3.yaml b/istio-1.3.5/samples/bookinfo/networking/virtual-service-reviews-v3.yaml new file mode 100644 index 0000000..5da999d --- /dev/null +++ b/istio-1.3.5/samples/bookinfo/networking/virtual-service-reviews-v3.yaml @@ -0,0 +1,12 @@ +apiVersion: networking.istio.io/v1alpha3 +kind: VirtualService +metadata: + name: reviews +spec: + hosts: + - reviews + http: + - route: + - destination: + host: reviews + subset: v3 diff --git a/istio-1.3.5/samples/bookinfo/platform/consul/README.md b/istio-1.3.5/samples/bookinfo/platform/consul/README.md new file mode 100644 index 0000000..8863ca1 --- /dev/null +++ b/istio-1.3.5/samples/bookinfo/platform/consul/README.md @@ -0,0 +1,69 @@ +# Consul Adapter for Istio on Docker + +Make Istio run in docker environment by integrating Consul as a service registry. + +## Design Principle + +The key issue is how to implement the ServiceDiscovery interface functions in Istio. +This platform adapter uses Consul Server to help Istio monitor service instances running in the underlying platform. +When a service instance is brought up in docker, the [Registrator](http://gliderlabs.github.io/registrator/latest/) +automatically registers the service in Consul. + +Note that Istio pilot is running inside each app container so as to coordinate Envoy and the service mesh. + +## Prerequisites + + * Clone Istio Pilot [repo](https://github.com/istio/pilot) (required only if building images locally) + + * Download istioctl from Istio's [releases page](https://github.com/istio/istio/releases) or build from + source in Istio Pilot repository + +## Bookinfo Demo + +The ingress controller is still under construction, routing functionalities can be tested by curling a service container directly. + +To build all images for the bookinfo sample for the consul adapter, run: + + ``` + samples/bookinfo/src/build-docker-services.sh + ``` + +For Linux users, configure the `DOCKER_GATEWAY` environment variable + + ```bash + export DOCKER_GATEWAY=172.28.0.1: + ``` + +To bring up the control plane containers directly, from the root repository directory run + + ``` + docker-compose -f install/consul/istio.yaml up -d + ``` + +This will pull images from docker hub to your local computing space. + +Now you can see all the containers in the mesh by running `docker ps -a`. + +If the webpage is not displaying properly, you may need to run the previous command once more to resolve a timing issue during start up. + + +To bring up the app containers, from the `samples/bookinfo/consul` directory run + + ``` + docker-compose -f bookinfo.yaml up -d + ``` + + +To view the productpage webpage, open a web browser and enter `localhost:9081/productpage`. + +If you refresh the page several times, you should see different versions of reviews shown in productpage presented in a round robin style (red stars, black stars, no stars). + +Configure `kubectl` to use the locally mapped port for the Istio api server + +``` +kubectl config set-context istio --cluster=istio +kubectl config set-cluster istio --server=http://localhost:8080 +kubectl config use-context istio +``` + +If you are an advanced consul and docker network user, you may choose to configure your own envoymesh network dns and consul port mapping and istio-apiserver ipv4_address in the `istio.yaml` file. diff --git a/istio-1.3.5/samples/bookinfo/platform/consul/bookinfo.sidecars.yaml b/istio-1.3.5/samples/bookinfo/platform/consul/bookinfo.sidecars.yaml new file mode 100644 index 0000000..0b06d34 --- /dev/null +++ b/istio-1.3.5/samples/bookinfo/platform/consul/bookinfo.sidecars.yaml @@ -0,0 +1,163 @@ +# GENERATED FILE. Use with Docker-Compose and consul +# TO UPDATE, modify files in samples/bookinfo/platform/consul/templates and run install/updateVersion.sh +# Copyright 2017 Istio Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +############################################################################ +version: '2' +services: + details-v1-init: + image: docker.io/istio/proxy_init:1.3.5 + cap_add: + - NET_ADMIN + network_mode: "container:consul_details-v1_1" + command: + - -p + - "15001" + - -u + - "1337" + - -m + - REDIRECT + - -i + - "*" + - -b + - "9080" + details-v1-sidecar: + image: docker.io/istio/proxy_debug:1.3.5 + network_mode: "container:consul_details-v1_1" + entrypoint: + - su + - istio-proxy + - -c + - "/usr/local/bin/pilot-agent proxy --serviceregistry Consul --serviceCluster details-v1 --zipkinAddress zipkin:9411 --configPath /var/lib/istio >/tmp/envoy.log" + ratings-v1-init: + image: docker.io/istio/proxy_init:1.3.5 + cap_add: + - NET_ADMIN + network_mode: "container:consul_ratings-v1_1" + command: + - -p + - "15001" + - -u + - "1337" + - -m + - REDIRECT + - -i + - "*" + - -b + - "9080" + ratings-v1-sidecar: + image: docker.io/istio/proxy_debug:1.3.5 + network_mode: "container:consul_ratings-v1_1" + entrypoint: + - su + - istio-proxy + - -c + - "/usr/local/bin/pilot-agent proxy --serviceregistry Consul --serviceCluster ratings-v1 --zipkinAddress zipkin:9411 --configPath /var/lib/istio >/tmp/envoy.log" + productpage-v1-init: + image: docker.io/istio/proxy_init:1.3.5 + cap_add: + - NET_ADMIN + network_mode: "container:consul_productpage-v1_1" + command: + - -p + - "15001" + - -u + - "1337" + - -m + - REDIRECT + - -i + - "*" + - -b + - "9080" + productpage-v1-sidecar: + image: docker.io/istio/proxy_debug:1.3.5 + network_mode: "container:consul_productpage-v1_1" + entrypoint: + - su + - istio-proxy + - -c + - "/usr/local/bin/pilot-agent proxy --serviceregistry Consul --serviceCluster productpage-v1 --zipkinAddress zipkin:9411 --configPath /var/lib/istio >/tmp/envoy.log" + reviews-v1-init: + image: docker.io/istio/proxy_init:1.3.5 + cap_add: + - NET_ADMIN + network_mode: "container:consul_reviews-v1_1" + command: + - -p + - "15001" + - -u + - "1337" + - -m + - REDIRECT + - -i + - "*" + - -b + - "9080" + reviews-v1-sidecar: + image: docker.io/istio/proxy_debug:1.3.5 + network_mode: "container:consul_reviews-v1_1" + entrypoint: + - su + - istio-proxy + - -c + - "/usr/local/bin/pilot-agent proxy --serviceregistry Consul --serviceCluster reviews-v1 --zipkinAddress zipkin:9411 --configPath /var/lib/istio >/tmp/envoy.log" + reviews-v2-init: + image: docker.io/istio/proxy_init:1.3.5 + cap_add: + - NET_ADMIN + network_mode: "container:consul_reviews-v2_1" + command: + - -p + - "15001" + - -u + - "1337" + - -m + - REDIRECT + - -i + - "*" + - -b + - "9080" + reviews-v2-sidecar: + image: docker.io/istio/proxy_debug:1.3.5 + network_mode: "container:consul_reviews-v2_1" + entrypoint: + - su + - istio-proxy + - -c + - "/usr/local/bin/pilot-agent proxy --serviceregistry Consul --serviceCluster reviews-v2 --zipkinAddress zipkin:9411 --configPath /var/lib/istio >/tmp/envoy.log" + reviews-v3-init: + image: docker.io/istio/proxy_init:1.3.5 + cap_add: + - NET_ADMIN + network_mode: "container:consul_reviews-v3_1" + command: + - -p + - "15001" + - -u + - "1337" + - -m + - REDIRECT + - -i + - "*" + - -b + - "9080" + reviews-v3-sidecar: + image: docker.io/istio/proxy_debug:1.3.5 + network_mode: "container:consul_reviews-v3_1" + entrypoint: + - su + - istio-proxy + - -c + - "/usr/local/bin/pilot-agent proxy --serviceregistry Consul --serviceCluster reviews-v3 --zipkinAddress zipkin:9411 --configPath /var/lib/istio >/tmp/envoy.log" diff --git a/istio-1.3.5/samples/bookinfo/platform/consul/bookinfo.yaml b/istio-1.3.5/samples/bookinfo/platform/consul/bookinfo.yaml new file mode 100644 index 0000000..c78ae3d --- /dev/null +++ b/istio-1.3.5/samples/bookinfo/platform/consul/bookinfo.yaml @@ -0,0 +1,128 @@ +# Copyright 2017 Istio Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +############################################################################ +version: '2' +services: + details-v1: + image: istio/examples-bookinfo-details-v1:1.15.0 + networks: + istiomesh: + dns: + - 172.28.0.1 + - 8.8.8.8 + dns_search: + - service.consul + environment: + - SERVICE_NAME=details + - SERVICE_TAGS=version|v1 + - SERVICE_PROTOCOL=http + - SERVICE_VERSION=v1 + expose: + - "9080" + + ratings-v1: + image: istio/examples-bookinfo-ratings-v1:1.15.0 + networks: + istiomesh: + dns: + - 172.28.0.1 + - 8.8.8.8 + dns_search: + - service.consul + environment: + - SERVICE_NAME=ratings + - SERVICE_TAGS=version|v1 + - SERVICE_PROTOCOL=http + - SERVICE_VERSION=v1 + expose: + - "9080" + + reviews-v1: + image: istio/examples-bookinfo-reviews-v1:1.15.0 + networks: + istiomesh: + dns: + - 172.28.0.1 + - 8.8.8.8 + dns_search: + - service.consul + environment: + - SERVICE_9080_NAME=reviews + - SERVICE_TAGS=version|v1 + - SERVICE_PROTOCOL=http + - SERVICE_9443_IGNORE=1 + - SERVICE_VERSION=v1 + expose: + - "9080" + + reviews-v2: + image: istio/examples-bookinfo-reviews-v2:1.15.0 + networks: + istiomesh: + dns: + - 172.28.0.1 + - 8.8.8.8 + dns_search: + - service.consul + environment: + - SERVICE_9080_NAME=reviews + - SERVICE_TAGS=version|v2 + - SERVICE_PROTOCOL=http + - SERVICE_9443_IGNORE=1 + - SERVICE_VERSION=v2 + expose: + - "9080" + + reviews-v3: + image: istio/examples-bookinfo-reviews-v3:1.15.0 + networks: + istiomesh: + dns: + - 172.28.0.1 + - 8.8.8.8 + dns_search: + - service.consul + environment: + - SERVICE_9080_NAME=reviews + - SERVICE_TAGS=version|v3 + - SERVICE_PROTOCOL=http + - SERVICE_9443_IGNORE=1 + - SERVICE_VERSION=v3 + expose: + - "9080" + + productpage-v1: + image: istio/examples-bookinfo-productpage-v1:1.15.0 + networks: + istiomesh: + ipv4_address: 172.28.0.14 + dns: + - 172.28.0.1 + - 8.8.8.8 + dns_search: + - service.consul + environment: + - SERVICE_NAME=productpage + - SERVICE_TAGS=version|v1 + - SERVICE_PROTOCOL=http + - SERVICE_VERSION=v1 + ports: + - "9081:9080" + expose: + - "9080" +networks: + istiomesh: + external: + name: consul_istiomesh diff --git a/istio-1.3.5/samples/bookinfo/platform/consul/cleanup.sh b/istio-1.3.5/samples/bookinfo/platform/consul/cleanup.sh new file mode 100755 index 0000000..2120b94 --- /dev/null +++ b/istio-1.3.5/samples/bookinfo/platform/consul/cleanup.sh @@ -0,0 +1,61 @@ +#!/bin/bash +# +# Copyright 2017 Istio Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +SCRIPTDIR=$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd ) + +# only ask if in interactive mode +if [[ -t 0 ]];then + echo -n "namespace ? [default] " + read -r NAMESPACE +fi + +if [[ -z ${NAMESPACE} ]];then + NAMESPACE=default +fi + +echo "using NAMESPACE=${NAMESPACE}" + +protos=( destinationrules virtualservices gateways ) +for proto in "${protos[@]}"; do + for resource in $(kubectl get -n ${NAMESPACE} "$proto" -o name); do + kubectl delete -n ${NAMESPACE} "$resource"; + done +done + +OUTPUT=$(mktemp) +export OUTPUT +echo "Application cleanup may take up to one minute" +docker-compose -f "$SCRIPTDIR/bookinfo.sidecars.yaml" down > "${OUTPUT}" 2>&1 +docker-compose -f "$SCRIPTDIR/bookinfo.yaml" down > "${OUTPUT}" 2>&1 +ret=$? +function cleanup() { + rm -f "${OUTPUT}" +} + +trap cleanup EXIT + +if [[ ${ret} -eq 0 ]];then + cat "${OUTPUT}" +else + # ignore NotFound errors + OUT2=$(grep -v NotFound "${OUTPUT}") + if [[ -n ${OUT2} ]];then + cat "${OUTPUT}" + exit ${ret} + fi +fi + +echo "Application cleanup successful" diff --git a/istio-1.3.5/samples/bookinfo/platform/consul/destination-rule-all.yaml b/istio-1.3.5/samples/bookinfo/platform/consul/destination-rule-all.yaml new file mode 100644 index 0000000..e28055a --- /dev/null +++ b/istio-1.3.5/samples/bookinfo/platform/consul/destination-rule-all.yaml @@ -0,0 +1,53 @@ +apiVersion: networking.istio.io/v1alpha3 +kind: DestinationRule +metadata: + name: productpage +spec: + host: productpage.service.consul + subsets: + - name: v1 + labels: + version: v1 +--- +apiVersion: networking.istio.io/v1alpha3 +kind: DestinationRule +metadata: + name: reviews +spec: + host: reviews.service.consul + subsets: + - name: v1 + labels: + version: v1 + - name: v2 + labels: + version: v2 + - name: v3 + labels: + version: v3 +--- +apiVersion: networking.istio.io/v1alpha3 +kind: DestinationRule +metadata: + name: ratings +spec: + host: ratings.service.consul + subsets: + - name: v1 + labels: + version: v1 +--- +apiVersion: networking.istio.io/v1alpha3 +kind: DestinationRule +metadata: + name: details +spec: + host: details.service.consul + subsets: + - name: v1 + labels: + version: v1 + - name: v2 + labels: + version: v2 +--- diff --git a/istio-1.3.5/samples/bookinfo/platform/consul/virtual-service-all-v1.yaml b/istio-1.3.5/samples/bookinfo/platform/consul/virtual-service-all-v1.yaml new file mode 100644 index 0000000..19b4772 --- /dev/null +++ b/istio-1.3.5/samples/bookinfo/platform/consul/virtual-service-all-v1.yaml @@ -0,0 +1,52 @@ +apiVersion: networking.istio.io/v1alpha3 +kind: VirtualService +metadata: + name: productpage +spec: + hosts: + - productpage.service.consul + http: + - route: + - destination: + host: productpage.service.consul + subset: v1 +--- +apiVersion: networking.istio.io/v1alpha3 +kind: VirtualService +metadata: + name: reviews +spec: + hosts: + - reviews.service.consul + http: + - route: + - destination: + host: reviews.service.consul + subset: v1 +--- +apiVersion: networking.istio.io/v1alpha3 +kind: VirtualService +metadata: + name: ratings +spec: + hosts: + - ratings.service.consul + http: + - route: + - destination: + host: ratings.service.consul + subset: v1 +--- +apiVersion: networking.istio.io/v1alpha3 +kind: VirtualService +metadata: + name: details +spec: + hosts: + - details.service.consul + http: + - route: + - destination: + host: details.service.consul + subset: v1 +--- diff --git a/istio-1.3.5/samples/bookinfo/platform/consul/virtual-service-ratings-test-abort.yaml b/istio-1.3.5/samples/bookinfo/platform/consul/virtual-service-ratings-test-abort.yaml new file mode 100644 index 0000000..f0c8f6d --- /dev/null +++ b/istio-1.3.5/samples/bookinfo/platform/consul/virtual-service-ratings-test-abort.yaml @@ -0,0 +1,25 @@ +apiVersion: networking.istio.io/v1alpha3 +kind: VirtualService +metadata: + name: ratings +spec: + hosts: + - ratings.service.consul + http: + - match: + - headers: + end-user: + exact: jason + fault: + abort: + percentage: + value: 100.0 + httpStatus: 500 + route: + - destination: + host: ratings.service.consul + subset: v1 + - route: + - destination: + host: ratings.service.consul + subset: v1 diff --git a/istio-1.3.5/samples/bookinfo/platform/consul/virtual-service-ratings-test-delay.yaml b/istio-1.3.5/samples/bookinfo/platform/consul/virtual-service-ratings-test-delay.yaml new file mode 100644 index 0000000..1978632 --- /dev/null +++ b/istio-1.3.5/samples/bookinfo/platform/consul/virtual-service-ratings-test-delay.yaml @@ -0,0 +1,25 @@ +apiVersion: networking.istio.io/v1alpha3 +kind: VirtualService +metadata: + name: ratings +spec: + hosts: + - ratings.service.consul + http: + - match: + - headers: + end-user: + exact: jason + fault: + delay: + percentage: + value: 100.0 + fixedDelay: 7s + route: + - destination: + host: ratings.service.consul + subset: v1 + - route: + - destination: + host: ratings.service.consul + subset: v1 diff --git a/istio-1.3.5/samples/bookinfo/platform/consul/virtual-service-reviews-50-v3.yaml b/istio-1.3.5/samples/bookinfo/platform/consul/virtual-service-reviews-50-v3.yaml new file mode 100644 index 0000000..7e91c8c --- /dev/null +++ b/istio-1.3.5/samples/bookinfo/platform/consul/virtual-service-reviews-50-v3.yaml @@ -0,0 +1,17 @@ +apiVersion: networking.istio.io/v1alpha3 +kind: VirtualService +metadata: + name: reviews +spec: + hosts: + - reviews.service.consul + http: + - route: + - destination: + host: reviews.service.consul + subset: v1 + weight: 50 + - destination: + host: reviews.service.consul + subset: v3 + weight: 50 diff --git a/istio-1.3.5/samples/bookinfo/platform/consul/virtual-service-reviews-test-v2.yaml b/istio-1.3.5/samples/bookinfo/platform/consul/virtual-service-reviews-test-v2.yaml new file mode 100644 index 0000000..92fa461 --- /dev/null +++ b/istio-1.3.5/samples/bookinfo/platform/consul/virtual-service-reviews-test-v2.yaml @@ -0,0 +1,20 @@ +apiVersion: networking.istio.io/v1alpha3 +kind: VirtualService +metadata: + name: reviews +spec: + hosts: + - reviews.service.consul + http: + - match: + - headers: + end-user: + exact: jason + route: + - destination: + host: reviews.service.consul + subset: v2 + - route: + - destination: + host: reviews.service.consul + subset: v1 diff --git a/istio-1.3.5/samples/bookinfo/platform/consul/virtual-service-reviews-v2-v3.yaml b/istio-1.3.5/samples/bookinfo/platform/consul/virtual-service-reviews-v2-v3.yaml new file mode 100644 index 0000000..60271c0 --- /dev/null +++ b/istio-1.3.5/samples/bookinfo/platform/consul/virtual-service-reviews-v2-v3.yaml @@ -0,0 +1,17 @@ +apiVersion: networking.istio.io/v1alpha3 +kind: VirtualService +metadata: + name: reviews +spec: + hosts: + - reviews.service.consul + http: + - route: + - destination: + host: reviews.service.consul + subset: v2 + weight: 50 + - destination: + host: reviews.service.consul + subset: v3 + weight: 50 diff --git a/istio-1.3.5/samples/bookinfo/platform/consul/virtual-service-reviews-v3.yaml b/istio-1.3.5/samples/bookinfo/platform/consul/virtual-service-reviews-v3.yaml new file mode 100644 index 0000000..da9440c --- /dev/null +++ b/istio-1.3.5/samples/bookinfo/platform/consul/virtual-service-reviews-v3.yaml @@ -0,0 +1,12 @@ +apiVersion: networking.istio.io/v1alpha3 +kind: VirtualService +metadata: + name: reviews +spec: + hosts: + - reviews.service.consul + http: + - route: + - destination: + host: reviews.service.consul + subset: v3 diff --git a/istio-1.3.5/samples/bookinfo/platform/kube/README.md b/istio-1.3.5/samples/bookinfo/platform/kube/README.md new file mode 100644 index 0000000..d1189be --- /dev/null +++ b/istio-1.3.5/samples/bookinfo/platform/kube/README.md @@ -0,0 +1,2 @@ +See the [Bookinfo guide](https://istio.io/docs/guides/bookinfo.html) in Istio +docs for instructions on how to run this demo application. diff --git a/istio-1.3.5/samples/bookinfo/platform/kube/bookinfo-certificate.yaml b/istio-1.3.5/samples/bookinfo/platform/kube/bookinfo-certificate.yaml new file mode 100644 index 0000000..bce874d --- /dev/null +++ b/istio-1.3.5/samples/bookinfo/platform/kube/bookinfo-certificate.yaml @@ -0,0 +1,37 @@ +--- +apiVersion: certmanager.k8s.io/v1alpha1 +kind: ClusterIssuer +metadata: + name: letsencrypt-staging + namespace: istio-system +spec: + acme: + # The ACME server URL + server: https://acme-staging-v02.api.letsencrypt.org/directory + # Email address used for ACME registration + email: stage@istio.io + # Name of a secret used to store the ACME account private key + privateKeySecretRef: + name: letsencrypt-staging + # Enable the HTTP-01 challenge provider + http01: {} +--- +apiVersion: certmanager.k8s.io/v1alpha1 +kind: Certificate +metadata: + name: istio-ingressgateway-certs + namespace: istio-system +spec: + secretName: istio-ingressgateway-certs + issuerRef: + name: letsencrypt-staging + kind: ClusterIssuer + commonName: bookinfo.example.com + dnsNames: + - bookinfo.example.com + acme: + config: + - http01: + ingressClass: none + domains: + - bookinfo.example.com diff --git a/istio-1.3.5/samples/bookinfo/platform/kube/bookinfo-db.yaml b/istio-1.3.5/samples/bookinfo/platform/kube/bookinfo-db.yaml new file mode 100644 index 0000000..e6ab9c1 --- /dev/null +++ b/istio-1.3.5/samples/bookinfo/platform/kube/bookinfo-db.yaml @@ -0,0 +1,53 @@ +# Copyright 2017 Istio Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +apiVersion: v1 +kind: Service +metadata: + name: mongodb + labels: + app: mongodb +spec: + ports: + - port: 27017 + name: mongo + selector: + app: mongodb +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: mongodb-v1 + labels: + app: mongodb + version: v1 +spec: + replicas: 1 + selector: + matchLabels: + app: mongodb + version: v1 + template: + metadata: + labels: + app: mongodb + version: v1 + spec: + containers: + - name: mongodb + image: istio/examples-bookinfo-mongodb:1.15.0 + imagePullPolicy: IfNotPresent + ports: + - containerPort: 27017 +--- diff --git a/istio-1.3.5/samples/bookinfo/platform/kube/bookinfo-details-v2.yaml b/istio-1.3.5/samples/bookinfo/platform/kube/bookinfo-details-v2.yaml new file mode 100644 index 0000000..e6fb123 --- /dev/null +++ b/istio-1.3.5/samples/bookinfo/platform/kube/bookinfo-details-v2.yaml @@ -0,0 +1,46 @@ +# Copyright 2017 Istio Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +################################################################################################## +# Details service v2 +################################################################################################## +apiVersion: apps/v1 +kind: Deployment +metadata: + name: details-v2 + labels: + app: details + version: v2 +spec: + replicas: 1 + selector: + matchLabels: + app: details + version: v2 + template: + metadata: + labels: + app: details + version: v2 + spec: + containers: + - name: details + image: docker.io/istio/examples-bookinfo-details-v2:1.15.0 + imagePullPolicy: IfNotPresent + ports: + - containerPort: 9080 + env: + - name: DO_NOT_ENCRYPT + value: "true" +--- diff --git a/istio-1.3.5/samples/bookinfo/platform/kube/bookinfo-details.yaml b/istio-1.3.5/samples/bookinfo/platform/kube/bookinfo-details.yaml new file mode 100644 index 0000000..bffaae2 --- /dev/null +++ b/istio-1.3.5/samples/bookinfo/platform/kube/bookinfo-details.yaml @@ -0,0 +1,56 @@ +# Copyright 2017 Istio Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +################################################################################################## +# Details service +################################################################################################## +apiVersion: v1 +kind: Service +metadata: + name: details + labels: + app: details +spec: + ports: + - port: 9080 + name: http + selector: + app: details +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: details-v1 + labels: + app: details + version: v1 +spec: + replicas: 1 + selector: + matchLabels: + app: details + version: v1 + template: + metadata: + labels: + app: details + version: v1 + spec: + containers: + - name: details + image: docker.io/istio/examples-bookinfo-details-v1:1.15.0 + imagePullPolicy: IfNotPresent + ports: + - containerPort: 9080 +--- diff --git a/istio-1.3.5/samples/bookinfo/platform/kube/bookinfo-ingress.yaml b/istio-1.3.5/samples/bookinfo/platform/kube/bookinfo-ingress.yaml new file mode 100644 index 0000000..0dd6561 --- /dev/null +++ b/istio-1.3.5/samples/bookinfo/platform/kube/bookinfo-ingress.yaml @@ -0,0 +1,44 @@ +# Copyright 2017 Istio Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +########################################################################### +# Ingress resource (gateway) +########################################################################## +apiVersion: extensions/v1beta1 +kind: Ingress +metadata: + name: gateway + annotations: + kubernetes.io/ingress.class: "istio" +spec: + rules: + - http: + paths: + - path: /productpage + backend: + serviceName: productpage + servicePort: 9080 + - path: /login + backend: + serviceName: productpage + servicePort: 9080 + - path: /logout + backend: + serviceName: productpage + servicePort: 9080 + - path: /api/v1/products.* + backend: + serviceName: productpage + servicePort: 9080 +--- diff --git a/istio-1.3.5/samples/bookinfo/platform/kube/bookinfo-mysql.yaml b/istio-1.3.5/samples/bookinfo/platform/kube/bookinfo-mysql.yaml new file mode 100644 index 0000000..9a8edd7 --- /dev/null +++ b/istio-1.3.5/samples/bookinfo/platform/kube/bookinfo-mysql.yaml @@ -0,0 +1,72 @@ +# Copyright 2017 Istio Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +################################################################################################## +# Mysql db services +# credentials: root/password +################################################################################################## +apiVersion: v1 +kind: Secret +metadata: + name: mysql-credentials +type: Opaque +data: + rootpasswd: cGFzc3dvcmQ= +--- +apiVersion: v1 +kind: Service +metadata: + name: mysqldb + labels: + app: mysqldb +spec: + ports: + - port: 3306 + name: tcp + selector: + app: mysqldb +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: mysqldb-v1 + labels: + app: mysqldb + version: v1 +spec: + replicas: 1 + selector: + matchLabels: + app: mysqldb + version: v1 + template: + metadata: + labels: + app: mysqldb + version: v1 + spec: + containers: + - name: mysqldb + image: docker.io/istio/examples-bookinfo-mysqldb:1.15.0 + imagePullPolicy: IfNotPresent + ports: + - containerPort: 3306 + env: + - name: MYSQL_ROOT_PASSWORD + valueFrom: + secretKeyRef: + name: mysql-credentials + key: rootpasswd + args: ["--default-authentication-plugin","mysql_native_password"] +--- diff --git a/istio-1.3.5/samples/bookinfo/platform/kube/bookinfo-ratings-discovery.yaml b/istio-1.3.5/samples/bookinfo/platform/kube/bookinfo-ratings-discovery.yaml new file mode 100644 index 0000000..fa63eb2 --- /dev/null +++ b/istio-1.3.5/samples/bookinfo/platform/kube/bookinfo-ratings-discovery.yaml @@ -0,0 +1,30 @@ +# Copyright 2017 Istio Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +################################################################################################## +# Ratings service +################################################################################################## +apiVersion: v1 +kind: Service +metadata: + name: ratings + labels: + app: ratings +spec: + ports: + - port: 9080 + name: http + selector: + app: ratings +--- diff --git a/istio-1.3.5/samples/bookinfo/platform/kube/bookinfo-ratings-v2-mysql-vm.yaml b/istio-1.3.5/samples/bookinfo/platform/kube/bookinfo-ratings-v2-mysql-vm.yaml new file mode 100644 index 0000000..364e7af --- /dev/null +++ b/istio-1.3.5/samples/bookinfo/platform/kube/bookinfo-ratings-v2-mysql-vm.yaml @@ -0,0 +1,53 @@ +# Copyright 2017 Istio Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +apiVersion: apps/v1 +kind: Deployment +metadata: + name: ratings-v2-mysql-vm + labels: + app: ratings + version: v2-mysql-vm +spec: + replicas: 1 + selector: + matchLabels: + app: ratings + version: v2-mysql-vm + template: + metadata: + labels: + app: ratings + version: v2-mysql-vm + spec: + containers: + - name: ratings + image: docker.io/istio/examples-bookinfo-ratings-v2:1.15.0 + imagePullPolicy: IfNotPresent + env: + # This assumes you registered your mysql vm as + # istioctl register -n vm mysqldb 1.2.3.4 3306 + - name: DB_TYPE + value: "mysql" + - name: MYSQL_DB_HOST + value: mysqldb.vm.svc.cluster.local + - name: MYSQL_DB_PORT + value: "3306" + - name: MYSQL_DB_USER + value: root + - name: MYSQL_DB_PASSWORD + value: password + ports: + - containerPort: 9080 +--- diff --git a/istio-1.3.5/samples/bookinfo/platform/kube/bookinfo-ratings-v2-mysql.yaml b/istio-1.3.5/samples/bookinfo/platform/kube/bookinfo-ratings-v2-mysql.yaml new file mode 100644 index 0000000..0a7745c --- /dev/null +++ b/istio-1.3.5/samples/bookinfo/platform/kube/bookinfo-ratings-v2-mysql.yaml @@ -0,0 +1,56 @@ +# Copyright 2017 Istio Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +apiVersion: apps/v1 +kind: Deployment +metadata: + name: ratings-v2-mysql + labels: + app: ratings + version: v2-mysql +spec: + replicas: 1 + selector: + matchLabels: + app: ratings + version: v2-mysql + template: + metadata: + labels: + app: ratings + version: v2-mysql + spec: + containers: + - name: ratings + image: docker.io/istio/examples-bookinfo-ratings-v2:1.15.0 + imagePullPolicy: IfNotPresent + env: + # ratings-v2 will use mongodb as the default db backend. + # if you would like to use mysqldb then you can use this file + # which sets DB_TYPE = 'mysql' and the rest of the parameters shown + # here and also create the # mysqldb service using bookinfo-mysql.yaml + # NOTE: This file is mutually exclusive to bookinfo-ratings-v2.yaml + - name: DB_TYPE + value: "mysql" + - name: MYSQL_DB_HOST + value: mysqldb + - name: MYSQL_DB_PORT + value: "3306" + - name: MYSQL_DB_USER + value: root + - name: MYSQL_DB_PASSWORD + value: password + ports: + - containerPort: 9080 +--- diff --git a/istio-1.3.5/samples/bookinfo/platform/kube/bookinfo-ratings-v2.yaml b/istio-1.3.5/samples/bookinfo/platform/kube/bookinfo-ratings-v2.yaml new file mode 100644 index 0000000..569bb1f --- /dev/null +++ b/istio-1.3.5/samples/bookinfo/platform/kube/bookinfo-ratings-v2.yaml @@ -0,0 +1,63 @@ +# Copyright 2017 Istio Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +apiVersion: v1 +kind: ServiceAccount +metadata: + name: bookinfo-ratings-v2 +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: ratings-v2 + labels: + app: ratings + version: v2 +spec: + replicas: 1 + selector: + matchLabels: + app: ratings + version: v2 + template: + metadata: + labels: + app: ratings + version: v2 + spec: + serviceAccountName: bookinfo-ratings-v2 + containers: + - name: ratings + image: docker.io/istio/examples-bookinfo-ratings-v2:1.15.0 + imagePullPolicy: IfNotPresent + env: + # ratings-v2 will use mongodb as the default db backend. + # if you would like to use mysqldb then set DB_TYPE = 'mysql', set + # the rest of the parameters shown here and also create the + # mysqldb service using bookinfo-mysql.yaml + # - name: DB_TYPE #default to + # value: "mysql" + # - name: MYSQL_DB_HOST + # value: mysqldb + # - name: MYSQL_DB_PORT + # value: "3306" + # - name: MYSQL_DB_USER + # value: root + # - name: MYSQL_DB_PASSWORD + # value: password + - name: MONGO_DB_URL + value: mongodb://mongodb:27017/test + ports: + - containerPort: 9080 +--- diff --git a/istio-1.3.5/samples/bookinfo/platform/kube/bookinfo-ratings.yaml b/istio-1.3.5/samples/bookinfo/platform/kube/bookinfo-ratings.yaml new file mode 100644 index 0000000..dab1c1f --- /dev/null +++ b/istio-1.3.5/samples/bookinfo/platform/kube/bookinfo-ratings.yaml @@ -0,0 +1,56 @@ +# Copyright 2017 Istio Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +################################################################################################## +# Ratings service +################################################################################################## +apiVersion: v1 +kind: Service +metadata: + name: ratings + labels: + app: ratings +spec: + ports: + - port: 9080 + name: http + selector: + app: ratings +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: ratings-v1 + labels: + app: ratings + version: v1 +spec: + replicas: 1 + selector: + matchLabels: + app: ratings + version: v1 + template: + metadata: + labels: + app: ratings + version: v1 + spec: + containers: + - name: ratings + image: docker.io/istio/examples-bookinfo-ratings-v1:1.15.0 + imagePullPolicy: IfNotPresent + ports: + - containerPort: 9080 +--- diff --git a/istio-1.3.5/samples/bookinfo/platform/kube/bookinfo-reviews-v2.yaml b/istio-1.3.5/samples/bookinfo/platform/kube/bookinfo-reviews-v2.yaml new file mode 100644 index 0000000..beadc15 --- /dev/null +++ b/istio-1.3.5/samples/bookinfo/platform/kube/bookinfo-reviews-v2.yaml @@ -0,0 +1,43 @@ +# Copyright 2017 Istio Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +################################################################################################## +# Reviews service v2 +################################################################################################## +apiVersion: apps/v1 +kind: Deployment +metadata: + name: reviews-v2 + labels: + app: reviews + version: v2 +spec: + replicas: 1 + selector: + matchLabels: + app: reviews + version: v2 + template: + metadata: + labels: + app: reviews + version: v2 + spec: + containers: + - name: reviews + image: docker.io/istio/examples-bookinfo-reviews-v2:1.15.0 + imagePullPolicy: IfNotPresent + ports: + - containerPort: 9080 +--- diff --git a/istio-1.3.5/samples/bookinfo/platform/kube/bookinfo.yaml b/istio-1.3.5/samples/bookinfo/platform/kube/bookinfo.yaml new file mode 100644 index 0000000..eff003f --- /dev/null +++ b/istio-1.3.5/samples/bookinfo/platform/kube/bookinfo.yaml @@ -0,0 +1,264 @@ +# Copyright 2017 Istio Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +################################################################################################## +# Details service +################################################################################################## +apiVersion: v1 +kind: Service +metadata: + name: details + labels: + app: details + service: details +spec: + ports: + - port: 9080 + name: http + selector: + app: details +--- +apiVersion: v1 +kind: ServiceAccount +metadata: + name: bookinfo-details +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: details-v1 + labels: + app: details + version: v1 +spec: + replicas: 1 + selector: + matchLabels: + app: details + version: v1 + template: + metadata: + labels: + app: details + version: v1 + spec: + serviceAccountName: bookinfo-details + containers: + - name: details + image: docker.io/istio/examples-bookinfo-details-v1:1.15.0 + imagePullPolicy: IfNotPresent + ports: + - containerPort: 9080 +--- +################################################################################################## +# Ratings service +################################################################################################## +apiVersion: v1 +kind: Service +metadata: + name: ratings + labels: + app: ratings + service: ratings +spec: + ports: + - port: 9080 + name: http + selector: + app: ratings +--- +apiVersion: v1 +kind: ServiceAccount +metadata: + name: bookinfo-ratings +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: ratings-v1 + labels: + app: ratings + version: v1 +spec: + replicas: 1 + selector: + matchLabels: + app: ratings + version: v1 + template: + metadata: + labels: + app: ratings + version: v1 + spec: + serviceAccountName: bookinfo-ratings + containers: + - name: ratings + image: docker.io/istio/examples-bookinfo-ratings-v1:1.15.0 + imagePullPolicy: IfNotPresent + ports: + - containerPort: 9080 +--- +################################################################################################## +# Reviews service +################################################################################################## +apiVersion: v1 +kind: Service +metadata: + name: reviews + labels: + app: reviews + service: reviews +spec: + ports: + - port: 9080 + name: http + selector: + app: reviews +--- +apiVersion: v1 +kind: ServiceAccount +metadata: + name: bookinfo-reviews +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: reviews-v1 + labels: + app: reviews + version: v1 +spec: + replicas: 1 + selector: + matchLabels: + app: reviews + version: v1 + template: + metadata: + labels: + app: reviews + version: v1 + spec: + serviceAccountName: bookinfo-reviews + containers: + - name: reviews + image: docker.io/istio/examples-bookinfo-reviews-v1:1.15.0 + imagePullPolicy: IfNotPresent + ports: + - containerPort: 9080 +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: reviews-v2 + labels: + app: reviews + version: v2 +spec: + replicas: 1 + selector: + matchLabels: + app: reviews + version: v2 + template: + metadata: + labels: + app: reviews + version: v2 + spec: + serviceAccountName: bookinfo-reviews + containers: + - name: reviews + image: docker.io/istio/examples-bookinfo-reviews-v2:1.15.0 + imagePullPolicy: IfNotPresent + ports: + - containerPort: 9080 +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: reviews-v3 + labels: + app: reviews + version: v3 +spec: + replicas: 1 + selector: + matchLabels: + app: reviews + version: v3 + template: + metadata: + labels: + app: reviews + version: v3 + spec: + serviceAccountName: bookinfo-reviews + containers: + - name: reviews + image: docker.io/istio/examples-bookinfo-reviews-v3:1.15.0 + imagePullPolicy: IfNotPresent + ports: + - containerPort: 9080 +--- +################################################################################################## +# Productpage services +################################################################################################## +apiVersion: v1 +kind: Service +metadata: + name: productpage + labels: + app: productpage + service: productpage +spec: + ports: + - port: 9080 + name: http + selector: + app: productpage +--- +apiVersion: v1 +kind: ServiceAccount +metadata: + name: bookinfo-productpage +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: productpage-v1 + labels: + app: productpage + version: v1 +spec: + replicas: 1 + selector: + matchLabels: + app: productpage + version: v1 + template: + metadata: + labels: + app: productpage + version: v1 + spec: + serviceAccountName: bookinfo-productpage + containers: + - name: productpage + image: docker.io/istio/examples-bookinfo-productpage-v1:1.15.0 + imagePullPolicy: IfNotPresent + ports: + - containerPort: 9080 +--- diff --git a/istio-1.3.5/samples/bookinfo/platform/kube/cleanup.sh b/istio-1.3.5/samples/bookinfo/platform/kube/cleanup.sh new file mode 100755 index 0000000..1930237 --- /dev/null +++ b/istio-1.3.5/samples/bookinfo/platform/kube/cleanup.sh @@ -0,0 +1,60 @@ +#!/bin/bash +# +# Copyright 2017 Istio Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +SCRIPTDIR=$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd ) + +# only ask if in interactive mode +if [[ -t 0 && -z ${NAMESPACE} ]];then + echo -n "namespace ? [default] " + read -r NAMESPACE +fi + +if [[ -z ${NAMESPACE} ]];then + NAMESPACE=default +fi + +echo "using NAMESPACE=${NAMESPACE}" + +protos=( destinationrules virtualservices gateways ) +for proto in "${protos[@]}"; do + for resource in $(kubectl get -n ${NAMESPACE} "$proto" -o name); do + kubectl delete -n ${NAMESPACE} "$resource"; + done +done + +OUTPUT=$(mktemp) +export OUTPUT +echo "Application cleanup may take up to one minute" +kubectl delete -n ${NAMESPACE} -f "$SCRIPTDIR/bookinfo.yaml" > "${OUTPUT}" 2>&1 +ret=$? +function cleanup() { + rm -f "${OUTPUT}" +} + +trap cleanup EXIT + +if [[ ${ret} -eq 0 ]];then + cat "${OUTPUT}" +else + # ignore NotFound errors + OUT2=$(grep -v NotFound "${OUTPUT}") + if [[ -n ${OUT2} ]];then + cat "${OUTPUT}" + exit ${ret} + fi +fi + +echo "Application cleanup successful" diff --git a/istio-1.3.5/samples/bookinfo/platform/kube/productpage-nodeport.yaml b/istio-1.3.5/samples/bookinfo/platform/kube/productpage-nodeport.yaml new file mode 100644 index 0000000..00aa249 --- /dev/null +++ b/istio-1.3.5/samples/bookinfo/platform/kube/productpage-nodeport.yaml @@ -0,0 +1,32 @@ +# Copyright 2017 Istio Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +################################################################################################## +# Productpage services +################################################################################################## +apiVersion: v1 +kind: Service +metadata: + name: productpage + labels: + app: productpage + service: productpage +spec: + type: NodePort + ports: + - port: 9080 + name: http + selector: + app: productpage +--- diff --git a/istio-1.3.5/samples/bookinfo/platform/kube/rbac/details-reviews-policy-permissive.yaml b/istio-1.3.5/samples/bookinfo/platform/kube/rbac/details-reviews-policy-permissive.yaml new file mode 100644 index 0000000..24a7de4 --- /dev/null +++ b/istio-1.3.5/samples/bookinfo/platform/kube/rbac/details-reviews-policy-permissive.yaml @@ -0,0 +1,22 @@ +apiVersion: "rbac.istio.io/v1alpha1" +kind: ServiceRole +metadata: + name: details-reviews-viewer + namespace: default +spec: + rules: + - services: ["details.default.svc.cluster.local", "reviews.default.svc.cluster.local"] + methods: ["GET"] +--- +apiVersion: "rbac.istio.io/v1alpha1" +kind: ServiceRoleBinding +metadata: + name: bind-details-reviews + namespace: default +spec: + subjects: + - user: "cluster.local/ns/default/sa/bookinfo-productpage" + roleRef: + kind: ServiceRole + name: "details-reviews-viewer" + mode: PERMISSIVE diff --git a/istio-1.3.5/samples/bookinfo/platform/kube/rbac/details-reviews-policy.yaml b/istio-1.3.5/samples/bookinfo/platform/kube/rbac/details-reviews-policy.yaml new file mode 100644 index 0000000..7957714 --- /dev/null +++ b/istio-1.3.5/samples/bookinfo/platform/kube/rbac/details-reviews-policy.yaml @@ -0,0 +1,21 @@ +apiVersion: "rbac.istio.io/v1alpha1" +kind: ServiceRole +metadata: + name: details-reviews-viewer + namespace: default +spec: + rules: + - services: ["details.default.svc.cluster.local", "reviews.default.svc.cluster.local"] + methods: ["GET"] +--- +apiVersion: "rbac.istio.io/v1alpha1" +kind: ServiceRoleBinding +metadata: + name: bind-details-reviews + namespace: default +spec: + subjects: + - user: "cluster.local/ns/default/sa/bookinfo-productpage" + roleRef: + kind: ServiceRole + name: "details-reviews-viewer" diff --git a/istio-1.3.5/samples/bookinfo/platform/kube/rbac/mongodb-policy.yaml b/istio-1.3.5/samples/bookinfo/platform/kube/rbac/mongodb-policy.yaml new file mode 100644 index 0000000..03ff0a8 --- /dev/null +++ b/istio-1.3.5/samples/bookinfo/platform/kube/rbac/mongodb-policy.yaml @@ -0,0 +1,24 @@ +apiVersion: "rbac.istio.io/v1alpha1" +kind: ServiceRole +metadata: + name: mongodb-viewer + namespace: default +spec: + rules: + - services: ["mongodb.default.svc.cluster.local"] + constraints: + - key: "destination.port" + values: ["27017"] +--- +apiVersion: "rbac.istio.io/v1alpha1" +kind: ServiceRoleBinding +metadata: + name: bind-mongodb-viewer + namespace: default +spec: + subjects: + - user: "cluster.local/ns/default/sa/bookinfo-ratings-v2" + roleRef: + kind: ServiceRole + name: "mongodb-viewer" +--- diff --git a/istio-1.3.5/samples/bookinfo/platform/kube/rbac/namespace-policy.yaml b/istio-1.3.5/samples/bookinfo/platform/kube/rbac/namespace-policy.yaml new file mode 100644 index 0000000..ac6e4a7 --- /dev/null +++ b/istio-1.3.5/samples/bookinfo/platform/kube/rbac/namespace-policy.yaml @@ -0,0 +1,27 @@ +apiVersion: "rbac.istio.io/v1alpha1" +kind: ServiceRole +metadata: + name: service-viewer + namespace: default +spec: + rules: + - services: ["*"] + methods: ["GET"] + constraints: + - key: "destination.labels[app]" + values: ["productpage", "details", "reviews", "ratings"] +--- +apiVersion: "rbac.istio.io/v1alpha1" +kind: ServiceRoleBinding +metadata: + name: bind-service-viewer + namespace: default +spec: + subjects: + - properties: + source.namespace: "istio-system" + - properties: + source.namespace: "default" + roleRef: + kind: ServiceRole + name: "service-viewer" diff --git a/istio-1.3.5/samples/bookinfo/platform/kube/rbac/productpage-policy.yaml b/istio-1.3.5/samples/bookinfo/platform/kube/rbac/productpage-policy.yaml new file mode 100644 index 0000000..6758ef2 --- /dev/null +++ b/istio-1.3.5/samples/bookinfo/platform/kube/rbac/productpage-policy.yaml @@ -0,0 +1,21 @@ +apiVersion: "rbac.istio.io/v1alpha1" +kind: ServiceRole +metadata: + name: productpage-viewer + namespace: default +spec: + rules: + - services: ["productpage.default.svc.cluster.local"] + methods: ["GET"] +--- +apiVersion: "rbac.istio.io/v1alpha1" +kind: ServiceRoleBinding +metadata: + name: bind-productpage-viewer + namespace: default +spec: + subjects: + - user: "*" + roleRef: + kind: ServiceRole + name: "productpage-viewer" diff --git a/istio-1.3.5/samples/bookinfo/platform/kube/rbac/ratings-policy.yaml b/istio-1.3.5/samples/bookinfo/platform/kube/rbac/ratings-policy.yaml new file mode 100644 index 0000000..d0e4f2b --- /dev/null +++ b/istio-1.3.5/samples/bookinfo/platform/kube/rbac/ratings-policy.yaml @@ -0,0 +1,21 @@ +apiVersion: "rbac.istio.io/v1alpha1" +kind: ServiceRole +metadata: + name: ratings-viewer + namespace: default +spec: + rules: + - services: ["ratings.default.svc.cluster.local"] + methods: ["GET"] +--- +apiVersion: "rbac.istio.io/v1alpha1" +kind: ServiceRoleBinding +metadata: + name: bind-ratings + namespace: default +spec: + subjects: + - user: "cluster.local/ns/default/sa/bookinfo-reviews" + roleRef: + kind: ServiceRole + name: "ratings-viewer" diff --git a/istio-1.3.5/samples/bookinfo/platform/kube/rbac/rbac-config-ON.yaml b/istio-1.3.5/samples/bookinfo/platform/kube/rbac/rbac-config-ON.yaml new file mode 100644 index 0000000..534a500 --- /dev/null +++ b/istio-1.3.5/samples/bookinfo/platform/kube/rbac/rbac-config-ON.yaml @@ -0,0 +1,8 @@ +apiVersion: "rbac.istio.io/v1alpha1" +kind: ClusterRbacConfig +metadata: + name: default +spec: + mode: 'ON_WITH_INCLUSION' + inclusion: + namespaces: ["default"] diff --git a/istio-1.3.5/samples/bookinfo/platform/kube/rbac/rbac-config-on-mongodb.yaml b/istio-1.3.5/samples/bookinfo/platform/kube/rbac/rbac-config-on-mongodb.yaml new file mode 100644 index 0000000..9c22675 --- /dev/null +++ b/istio-1.3.5/samples/bookinfo/platform/kube/rbac/rbac-config-on-mongodb.yaml @@ -0,0 +1,9 @@ +apiVersion: "rbac.istio.io/v1alpha1" +kind: ClusterRbacConfig +metadata: + name: default +spec: + mode: 'ON_WITH_INCLUSION' + inclusion: + services: ["mongodb.default.svc.cluster.local"] +--- diff --git a/istio-1.3.5/samples/bookinfo/platform/kube/rbac/rbac-config-on-permissive.yaml b/istio-1.3.5/samples/bookinfo/platform/kube/rbac/rbac-config-on-permissive.yaml new file mode 100644 index 0000000..3b52651 --- /dev/null +++ b/istio-1.3.5/samples/bookinfo/platform/kube/rbac/rbac-config-on-permissive.yaml @@ -0,0 +1,9 @@ +apiVersion: "rbac.istio.io/v1alpha1" +kind: ClusterRbacConfig +metadata: + name: default +spec: + mode: 'ON_WITH_INCLUSION' + inclusion: + namespaces: ["default"] + enforcement_mode: PERMISSIVE diff --git a/istio-1.3.5/samples/bookinfo/platform/kube/rbac/rbac-permissive-telemetry.yaml b/istio-1.3.5/samples/bookinfo/platform/kube/rbac/rbac-permissive-telemetry.yaml new file mode 100644 index 0000000..1da9508 --- /dev/null +++ b/istio-1.3.5/samples/bookinfo/platform/kube/rbac/rbac-permissive-telemetry.yaml @@ -0,0 +1,47 @@ +# Configuration for logentry instances +apiVersion: "config.istio.io/v1alpha2" +kind: instance +metadata: + name: rbacsamplelog + namespace: istio-system +spec: + compiledTemplate: logentry + params: + severity: '"warning"' + timestamp: request.time + variables: + source: source.labels["app"] | source.workload.name | "unknown" + user: source.user | "unknown" + destination: destination.labels["app"] | destination.workload.name | "unknown" + responseCode: response.code | 0 + responseSize: response.size | 0 + latency: response.duration | "0ms" + permissiveResponseCode: rbac.permissive.response_code | "" + permissiveResponsePolicyID: rbac.permissive.effective_policy_id | "" + monitored_resource_type: '"UNSPECIFIED"' +--- +# Configuration for a stdio handler +apiVersion: "config.istio.io/v1alpha2" +kind: handler +metadata: + name: rbacsamplehandler + namespace: istio-system +spec: + compiledAdapter: stdio + params: + severity_levels: + warning: 1 # Params.Level.WARNING + outputAsJson: true +--- +# Rule to send logentry instances to a stdio handler +apiVersion: "config.istio.io/v1alpha2" +kind: rule +metadata: + name: rabcsamplestdio + namespace: istio-system +spec: + actions: + - handler: rbacsamplehandler + instances: [ rbacsamplelog ] +--- + diff --git a/istio-1.3.5/samples/bookinfo/policy/mixer-rule-deny-ip-crd.yaml b/istio-1.3.5/samples/bookinfo/policy/mixer-rule-deny-ip-crd.yaml new file mode 100644 index 0000000..63fc5e6 --- /dev/null +++ b/istio-1.3.5/samples/bookinfo/policy/mixer-rule-deny-ip-crd.yaml @@ -0,0 +1,29 @@ +apiVersion: config.istio.io/v1alpha2 +kind: listchecker +metadata: + name: whitelistip +spec: + # providerUrl: ordinarily black and white lists are maintained + # externally and fetched asynchronously using the providerUrl. + overrides: ["10.57.0.0/16"] # overrides provide a static list + blacklist: false + entryType: IP_ADDRESSES +--- +apiVersion: config.istio.io/v1alpha2 +kind: listentry +metadata: + name: sourceip +spec: + value: source.ip | ip("0.0.0.0") +--- +apiVersion: config.istio.io/v1alpha2 +kind: rule +metadata: + name: checkip +spec: + match: source.labels["istio"] == "ingressgateway" + actions: + - handler: whitelistip.listchecker + instances: + - sourceip.listentry +--- diff --git a/istio-1.3.5/samples/bookinfo/policy/mixer-rule-deny-ip.yaml b/istio-1.3.5/samples/bookinfo/policy/mixer-rule-deny-ip.yaml new file mode 100644 index 0000000..b771fd6 --- /dev/null +++ b/istio-1.3.5/samples/bookinfo/policy/mixer-rule-deny-ip.yaml @@ -0,0 +1,32 @@ +apiVersion: config.istio.io/v1alpha2 +kind: handler +metadata: + name: whitelistip +spec: + compiledAdapter: listchecker + params: + # providerUrl: ordinarily black and white lists are maintained + # externally and fetched asynchronously using the providerUrl. + overrides: ["10.57.0.0/16"] # overrides provide a static list + blacklist: false + entryType: IP_ADDRESSES +--- +apiVersion: config.istio.io/v1alpha2 +kind: instance +metadata: + name: sourceip +spec: + compiledTemplate: listentry + params: + value: source.ip | ip("0.0.0.0") +--- +apiVersion: config.istio.io/v1alpha2 +kind: rule +metadata: + name: checkip +spec: + match: source.labels["istio"] == "ingressgateway" + actions: + - handler: whitelistip + instances: [ sourceip ] +--- diff --git a/istio-1.3.5/samples/bookinfo/policy/mixer-rule-deny-label-crd.yaml b/istio-1.3.5/samples/bookinfo/policy/mixer-rule-deny-label-crd.yaml new file mode 100644 index 0000000..249d505 --- /dev/null +++ b/istio-1.3.5/samples/bookinfo/policy/mixer-rule-deny-label-crd.yaml @@ -0,0 +1,24 @@ +apiVersion: "config.istio.io/v1alpha2" +kind: denier +metadata: + name: denyreviewsv3handler +spec: + status: + code: 7 + message: Not allowed +--- +apiVersion: "config.istio.io/v1alpha2" +kind: checknothing +metadata: + name: denyreviewsv3request +spec: +--- +apiVersion: "config.istio.io/v1alpha2" +kind: rule +metadata: + name: denyreviewsv3 +spec: + match: destination.labels["app"] == "ratings" && source.labels["app"]=="reviews" && source.labels["version"] == "v3" + actions: + - handler: denyreviewsv3handler.denier + instances: [ denyreviewsv3request.checknothing ] diff --git a/istio-1.3.5/samples/bookinfo/policy/mixer-rule-deny-label.yaml b/istio-1.3.5/samples/bookinfo/policy/mixer-rule-deny-label.yaml new file mode 100644 index 0000000..0d1e85e --- /dev/null +++ b/istio-1.3.5/samples/bookinfo/policy/mixer-rule-deny-label.yaml @@ -0,0 +1,27 @@ +apiVersion: "config.istio.io/v1alpha2" +kind: handler +metadata: + name: denyreviewsv3handler +spec: + compiledAdapter: denier + params: + status: + code: 7 + message: Not allowed +--- +apiVersion: "config.istio.io/v1alpha2" +kind: instance +metadata: + name: denyreviewsv3request +spec: + compiledTemplate: checknothing +--- +apiVersion: "config.istio.io/v1alpha2" +kind: rule +metadata: + name: denyreviewsv3 +spec: + match: destination.labels["app"] == "ratings" && source.labels["app"]=="reviews" && source.labels["version"] == "v3" + actions: + - handler: denyreviewsv3handler + instances: [ denyreviewsv3request ] diff --git a/istio-1.3.5/samples/bookinfo/policy/mixer-rule-deny-serviceaccount.yaml b/istio-1.3.5/samples/bookinfo/policy/mixer-rule-deny-serviceaccount.yaml new file mode 100644 index 0000000..c7b91c1 --- /dev/null +++ b/istio-1.3.5/samples/bookinfo/policy/mixer-rule-deny-serviceaccount.yaml @@ -0,0 +1,27 @@ +apiVersion: "config.istio.io/v1alpha2" +kind: handler +metadata: + name: denyproductpagehandler +spec: + compiledAdapter: denier + params: + status: + code: 7 + message: Not allowed +--- +apiVersion: "config.istio.io/v1alpha2" +kind: instance +metadata: + name: denyproductpagerequest +spec: + compiledTemplate: checknothing +--- +apiVersion: "config.istio.io/v1alpha2" +kind: rule +metadata: + name: denyproductpage +spec: + match: destination.labels["app"] == "details" && source.user == "cluster.local/ns/default/sa/bookinfo-productpage" + actions: + - handler: denyproductpagehandler + instances: [ denyproductpagerequest ] diff --git a/istio-1.3.5/samples/bookinfo/policy/mixer-rule-deny-whitelist-crd.yaml b/istio-1.3.5/samples/bookinfo/policy/mixer-rule-deny-whitelist-crd.yaml new file mode 100644 index 0000000..7486e6e --- /dev/null +++ b/istio-1.3.5/samples/bookinfo/policy/mixer-rule-deny-whitelist-crd.yaml @@ -0,0 +1,28 @@ +apiVersion: config.istio.io/v1alpha2 +kind: listchecker +metadata: + name: whitelist +spec: + # providerUrl: ordinarily black and white lists are maintained + # externally and fetched asynchronously using the providerUrl. + overrides: ["v1", "v2"] # overrides provide a static list + blacklist: false +--- +apiVersion: config.istio.io/v1alpha2 +kind: listentry +metadata: + name: appversion +spec: + value: source.labels["version"] +--- +apiVersion: config.istio.io/v1alpha2 +kind: rule +metadata: + name: checkversion +spec: + match: destination.labels["app"] == "ratings" + actions: + - handler: whitelist.listchecker + instances: + - appversion.listentry +--- diff --git a/istio-1.3.5/samples/bookinfo/policy/mixer-rule-deny-whitelist.yaml b/istio-1.3.5/samples/bookinfo/policy/mixer-rule-deny-whitelist.yaml new file mode 100644 index 0000000..4c51279 --- /dev/null +++ b/istio-1.3.5/samples/bookinfo/policy/mixer-rule-deny-whitelist.yaml @@ -0,0 +1,31 @@ +apiVersion: config.istio.io/v1alpha2 +kind: handler +metadata: + name: whitelist +spec: + compiledAdapter: listchecker + params: + # providerUrl: ordinarily black and white lists are maintained + # externally and fetched asynchronously using the providerUrl. + overrides: ["v1", "v2"] # overrides provide a static list + blacklist: false +--- +apiVersion: config.istio.io/v1alpha2 +kind: instance +metadata: + name: appversion +spec: + compiledTemplate: listentry + params: + value: source.labels["version"] +--- +apiVersion: config.istio.io/v1alpha2 +kind: rule +metadata: + name: checkversion +spec: + match: destination.labels["app"] == "ratings" + actions: + - handler: whitelist + instances: [ appversion ] +--- diff --git a/istio-1.3.5/samples/bookinfo/policy/mixer-rule-ingress-denial.yaml b/istio-1.3.5/samples/bookinfo/policy/mixer-rule-ingress-denial.yaml new file mode 100644 index 0000000..0199373 --- /dev/null +++ b/istio-1.3.5/samples/bookinfo/policy/mixer-rule-ingress-denial.yaml @@ -0,0 +1,30 @@ +apiVersion: "config.istio.io/v1alpha2" +kind: handler +metadata: + name: handler + namespace: istio-system +spec: + compiledAdapter: denier + params: + status: + code: 7 + message: Not allowed +--- +apiVersion: "config.istio.io/v1alpha2" +kind: instance +metadata: + name: denyrequest + namespace: istio-system +spec: + compiledTemplate: checknothing +--- +apiVersion: "config.istio.io/v1alpha2" +kind: rule +metadata: + name: denyingress + namespace: istio-system +spec: + match: (source.labels["istio"] | "") == "ingressgateway" && (request.headers["x-user"] | "") == "john" + actions: + - handler: handler + instances: [ denyrequest ] diff --git a/istio-1.3.5/samples/bookinfo/policy/mixer-rule-kubernetesenv-telemetry.yaml b/istio-1.3.5/samples/bookinfo/policy/mixer-rule-kubernetesenv-telemetry.yaml new file mode 100644 index 0000000..10c2c95 --- /dev/null +++ b/istio-1.3.5/samples/bookinfo/policy/mixer-rule-kubernetesenv-telemetry.yaml @@ -0,0 +1,56 @@ +apiVersion: "config.istio.io/v1alpha2" +kind: handler +metadata: + name: kubeenvhandler + namespace: istio-system +spec: + compiledAdapter: prometheus + params: + metrics: + - name: kube_request_count + instance_name: kubeenvrequestcount.instance.istio-system + kind: COUNTER + label_names: + - response_code + - source_pod + - source_workload_uid + - source_workload + - source_owner + - destination_pod + - destination_workload_uid + - destination_workload + - destination_owner + - destination_container +--- +apiVersion: "config.istio.io/v1alpha2" +kind: instance +metadata: + name: kubeenvrequestcount + namespace: istio-system +spec: + compiledTemplate: metric + params: + value: "1" + dimensions: + response_code: response.code | 200 + source_pod: source.name | "unknown" + source_workload_uid: source.workload.uid | "unknown" + source_workload: source.workload.name | "unknown" + source_owner: source.owner | "unknown" + destination_pod: destination.name | "unknown" + destination_workload: destination.workload.name | "unknown" + destination_workload_uid: destination.workload.uid | "unknown" + destination_owner: destination.owner | "unknown" + destination_container: destination.container.name | "unknown" + monitored_resource_type: '"UNSPECIFIED"' +--- +apiVersion: "config.istio.io/v1alpha2" +kind: rule +metadata: + name: promkubeenv + namespace: istio-system +spec: + match: "true" + actions: + - handler: kubeenvhandler + instances: [ kubeenvrequestcount ] diff --git a/istio-1.3.5/samples/bookinfo/policy/mixer-rule-productpage-ratelimit-crd.yaml b/istio-1.3.5/samples/bookinfo/policy/mixer-rule-productpage-ratelimit-crd.yaml new file mode 100644 index 0000000..2262035 --- /dev/null +++ b/istio-1.3.5/samples/bookinfo/policy/mixer-rule-productpage-ratelimit-crd.yaml @@ -0,0 +1,81 @@ +apiVersion: config.istio.io/v1alpha2 +kind: memquota +metadata: + name: handler + namespace: istio-system +spec: + quotas: + - name: requestcount.quota.istio-system + maxAmount: 500 + validDuration: 1s + # The first matching override is applied. + # A requestcount instance is checked against override dimensions. + overrides: + # The following override applies to 'reviews' regardless + # of the source. + - dimensions: + destination: reviews + maxAmount: 1 + validDuration: 5s + # The following override applies to 'productpage' when + # the source is a specific ip address. + - dimensions: + destination: productpage + source: "10.28.11.20" + maxAmount: 500 + validDuration: 1s + # The following override applies to 'productpage' regardless + # of the source. + - dimensions: + destination: productpage + maxAmount: 2 + validDuration: 5s +--- +apiVersion: config.istio.io/v1alpha2 +kind: quota +metadata: + name: requestcount + namespace: istio-system +spec: + dimensions: + source: request.headers["x-forwarded-for"] | "unknown" + destination: destination.labels["app"] | destination.service.name | "unknown" + destinationVersion: destination.labels["version"] | "unknown" +--- +apiVersion: config.istio.io/v1alpha2 +kind: QuotaSpec +metadata: + name: request-count + namespace: istio-system +spec: + rules: + - quotas: + - charge: 1 + quota: requestcount +--- +apiVersion: config.istio.io/v1alpha2 +kind: QuotaSpecBinding +metadata: + name: request-count + namespace: istio-system +spec: + quotaSpecs: + - name: request-count + namespace: istio-system + services: + - name: productpage + namespace: default + # - service: '*' # Uncomment this to bind *all* services to request-count +--- +apiVersion: config.istio.io/v1alpha2 +kind: rule +metadata: + name: quota + namespace: istio-system +spec: + # quota only applies if you are not logged in. + # match: match(request.headers["cookie"], "user=*") == false + actions: + - handler: handler.memquota + instances: + - requestcount.quota diff --git a/istio-1.3.5/samples/bookinfo/policy/mixer-rule-productpage-ratelimit.yaml b/istio-1.3.5/samples/bookinfo/policy/mixer-rule-productpage-ratelimit.yaml new file mode 100644 index 0000000..5b2233b --- /dev/null +++ b/istio-1.3.5/samples/bookinfo/policy/mixer-rule-productpage-ratelimit.yaml @@ -0,0 +1,85 @@ +apiVersion: config.istio.io/v1alpha2 +kind: handler +metadata: + name: quotahandler + namespace: istio-system +spec: + compiledAdapter: memquota + params: + quotas: + - name: requestcountquota.instance.istio-system + maxAmount: 500 + validDuration: 1s + # The first matching override is applied. + # A requestcount instance is checked against override dimensions. + overrides: + # The following override applies to 'reviews' regardless + # of the source. + - dimensions: + destination: reviews + maxAmount: 1 + validDuration: 5s + # The following override applies to 'productpage' when + # the source is a specific ip address. + - dimensions: + destination: productpage + source: "10.28.11.20" + maxAmount: 500 + validDuration: 1s + # The following override applies to 'productpage' regardless + # of the source. + - dimensions: + destination: productpage + maxAmount: 2 + validDuration: 5s +--- +apiVersion: config.istio.io/v1alpha2 +kind: instance +metadata: + name: requestcountquota + namespace: istio-system +spec: + compiledTemplate: quota + params: + dimensions: + source: request.headers["x-forwarded-for"] | "unknown" + destination: destination.labels["app"] | destination.service.name | "unknown" + destinationVersion: destination.labels["version"] | "unknown" +--- +apiVersion: config.istio.io/v1alpha2 +kind: QuotaSpec +metadata: + name: request-count + namespace: istio-system +spec: + rules: + - quotas: + - charge: 1 + quota: requestcountquota +--- +apiVersion: config.istio.io/v1alpha2 +kind: QuotaSpecBinding +metadata: + name: request-count + namespace: istio-system +spec: + quotaSpecs: + - name: request-count + namespace: istio-system + services: + - name: productpage + namespace: default + # - service: '*' # Uncomment this to bind *all* services to request-count +--- +apiVersion: config.istio.io/v1alpha2 +kind: rule +metadata: + name: quota + namespace: istio-system +spec: + # quota only applies if you are not logged in. + # match: match(request.headers["cookie"], "user=*") == false + actions: + - handler: quotahandler + instances: + - requestcountquota diff --git a/istio-1.3.5/samples/bookinfo/policy/mixer-rule-productpage-redis-quota-fixed-window.yaml b/istio-1.3.5/samples/bookinfo/policy/mixer-rule-productpage-redis-quota-fixed-window.yaml new file mode 100644 index 0000000..85787a2 --- /dev/null +++ b/istio-1.3.5/samples/bookinfo/policy/mixer-rule-productpage-redis-quota-fixed-window.yaml @@ -0,0 +1,83 @@ +apiVersion: config.istio.io/v1alpha2 +kind: handler +metadata: + name: redishandler + namespace: istio-system +spec: + compiledAdapter: redisquota + params: + redisServerUrl: redis-release-master:6379 + connectionPoolSize: 10 + quotas: + - name: requestcountquota.instance.istio-system + maxAmount: 1 + validDuration: 30s + rateLimitAlgorithm: FIXED_WINDOW + # The first matching override is applied. + # A requestquotacount instance is checked against override dimensions. + overrides: + # The following override applies to 'productpage' when + # the source is 'istio-ingressgateway'. + - dimensions: + destination: productpage + source: istio-ingressgateway + maxAmount: 50 +--- +apiVersion: config.istio.io/v1alpha2 +kind: instance +metadata: + name: requestcountquota + namespace: istio-system +spec: + compiledTemplate: quota + params: + dimensions: + source: source.labels["app"] | "unknown" + sourceVersion: source.labels["version"] | "unknown" + destination: destination.labels["app"] | "unknown" + destinationVersion: destination.labels["version"] | "unknown" +--- +apiVersion: config.istio.io/v1alpha2 +kind: QuotaSpec +metadata: + name: request-count + namespace: istio-system +spec: + rules: + - quotas: + - charge: 1 + quota: requestcountquota +--- +# Note: change the default namespace to the namespace of the bookinfo app +apiVersion: config.istio.io/v1alpha2 +kind: QuotaSpecBinding +metadata: + name: request-count + namespace: istio-system +spec: + quotaSpecs: + - name: request-count + namespace: istio-system + services: + - name: ratings + namespace: default + - name: reviews + namespace: default + - name: details + namespace: default + - name: productpage + namespace: default + - name: istio-ingressgateway + namespace: istio-system +--- +apiVersion: config.istio.io/v1alpha2 +kind: rule +metadata: + name: quota + namespace: istio-system +spec: + match: (destination.labels["app"]|"unknown") == "productpage" + actions: + - handler: redishandler + instances: + - requestcountquota diff --git a/istio-1.3.5/samples/bookinfo/policy/mixer-rule-productpage-redis-quota-rolling-window.yaml b/istio-1.3.5/samples/bookinfo/policy/mixer-rule-productpage-redis-quota-rolling-window.yaml new file mode 100644 index 0000000..ec524b9 --- /dev/null +++ b/istio-1.3.5/samples/bookinfo/policy/mixer-rule-productpage-redis-quota-rolling-window.yaml @@ -0,0 +1,87 @@ +apiVersion: config.istio.io/v1alpha2 +kind: handler +metadata: + name: redishandler + namespace: istio-system +spec: + compiledAdapter: redisquota + params: + redisServerUrl: redis-release-master:6379 + connectionPoolSize: 10 + quotas: + - name: requestcountquota.instance.istio-system + maxAmount: 500 + validDuration: 1s + bucketDuration: 500ms + rateLimitAlgorithm: ROLLING_WINDOW + # The first matching override is applied. + # A requestcount instance is checked against override dimensions. + overrides: + # The following override applies to 'reviews' regardless + # of the source. + - dimensions: + destination: reviews + maxAmount: 1 + # The following override applies to 'productpage' when + # the source is a specific ip address. + - dimensions: + destination: productpage + source: "10.28.11.20" + maxAmount: 500 + # The following override applies to 'productpage' regardless + # of the source. + - dimensions: + destination: productpage + maxAmount: 2 +--- +apiVersion: config.istio.io/v1alpha2 +kind: instance +metadata: + name: requestcountquota + namespace: istio-system +spec: + compiledTemplate: quota + params: + dimensions: + source: request.headers["x-forwarded-for"] | "unknown" + destination: destination.labels["app"] | destination.workload.name | "unknown" + destinationVersion: destination.labels["version"] | "unknown" +--- +apiVersion: config.istio.io/v1alpha2 +kind: QuotaSpec +metadata: + name: request-count + namespace: istio-system +spec: + rules: + - quotas: + - charge: 1 + quota: requestcountquota +--- +apiVersion: config.istio.io/v1alpha2 +kind: QuotaSpecBinding +metadata: + name: request-count + namespace: istio-system +spec: + quotaSpecs: + - name: request-count + namespace: istio-system + services: + - name: productpage + namespace: default + # - service: '*' # Uncomment this to bind *all* services to request-count +--- +apiVersion: config.istio.io/v1alpha2 +kind: rule +metadata: + name: quota + namespace: istio-system +spec: + # quota only applies if you are not logged in. + # match: match(request.headers["cookie"], "session=*") == false + actions: + - handler: redishandler + instances: + - requestcountquota +--- diff --git a/istio-1.3.5/samples/bookinfo/policy/mixer-rule-ratings-denial.yaml b/istio-1.3.5/samples/bookinfo/policy/mixer-rule-ratings-denial.yaml new file mode 100644 index 0000000..4239b03 --- /dev/null +++ b/istio-1.3.5/samples/bookinfo/policy/mixer-rule-ratings-denial.yaml @@ -0,0 +1,31 @@ +apiVersion: "config.istio.io/v1alpha2" +kind: handler +metadata: + name: denierhandler + namespace: istio-system +spec: + compiledAdapter: denier + params: + status: + code: 7 + message: Not allowed +--- +apiVersion: "config.istio.io/v1alpha2" +kind: instance +metadata: + name: denyrequest + namespace: istio-system +spec: + compiledTemplate: checknothing +--- +apiVersion: "config.istio.io/v1alpha2" +kind: rule +metadata: + name: denyreviewsv3 + namespace: istio-system +spec: + #FIXME match: destination.labels["app"]=="productpage" && request.headers["x-user"] == "" + match: (request.headers["x-user"] | "") == "john" + actions: + - handler: denierhandler + instances: [ denyrequest ] diff --git a/istio-1.3.5/samples/bookinfo/policy/mixer-rule-ratings-ratelimit.yaml b/istio-1.3.5/samples/bookinfo/policy/mixer-rule-ratings-ratelimit.yaml new file mode 100644 index 0000000..4989262 --- /dev/null +++ b/istio-1.3.5/samples/bookinfo/policy/mixer-rule-ratings-ratelimit.yaml @@ -0,0 +1,81 @@ +apiVersion: "config.istio.io/v1alpha2" +kind: handler +metadata: + name: quotahandler + namespace: istio-system +spec: + compiledAdapter: memquota + params: + quotas: + - name: requestcountquota.instance.istio-system + maxAmount: 5000 + validDuration: 1s + # The first matching override is applied. + # A requestcount instance is checked against override dimensions. + overrides: + # The following override applies to 'ratings' when + # the source is 'reviews'. + - dimensions: + destination: ratings + source: reviews + maxAmount: 1 + validDuration: 1s + # The following override applies to 'ratings' regardless + # of the source. + - dimensions: + destination: ratings + maxAmount: 100 + validDuration: 1s + +--- +apiVersion: "config.istio.io/v1alpha2" +kind: instance +metadata: + name: requestcountquota + namespace: istio-system +spec: + compiledTemplate: quota + params: + dimensions: + source: source.labels["app"] | "unknown" + sourceVersion: source.labels["version"] | "unknown" + destination: destination.labels["app"] | destination.service.name | "unknown" + destinationVersion: destination.labels["version"] | "unknown" +--- +apiVersion: "config.istio.io/v1alpha2" +kind: rule +metadata: + name: quota + namespace: istio-system +spec: + actions: + - handler: quotahandler + instances: + - requestcountquota +--- +apiVersion: config.istio.io/v1alpha2 +kind: QuotaSpec +metadata: + name: request-count + namespace: istio-system +spec: + rules: + - quotas: + - charge: 1 + quota: requestcountquota +--- +apiVersion: config.istio.io/v1alpha2 +kind: QuotaSpecBinding +metadata: + name: request-count + namespace: istio-system +spec: + quotaSpecs: + - name: request-count + namespace: istio-system + services: + - name: ratings + - name: reviews + - name: details + - name: productpage + diff --git a/istio-1.3.5/samples/bookinfo/policy/mixer-rule-ratings-redis-quota-fixed-window.yaml b/istio-1.3.5/samples/bookinfo/policy/mixer-rule-ratings-redis-quota-fixed-window.yaml new file mode 100644 index 0000000..a8bce7c --- /dev/null +++ b/istio-1.3.5/samples/bookinfo/policy/mixer-rule-ratings-redis-quota-fixed-window.yaml @@ -0,0 +1,87 @@ +apiVersion: config.istio.io/v1alpha2 +kind: handler +metadata: + name: redishandler + namespace: istio-system +spec: + compiledAdapter: redisquota + params: + redisServerUrl: redis-release-master:6379 + connectionPoolSize: 10 + quotas: + - name: requestcountquota.instance.istio-system + maxAmount: 5000 + validDuration: 30s + rateLimitAlgorithm: FIXED_WINDOW + # The first matching override is applied. + # A requestcount instance is checked against override dimensions. + overrides: + # The following override applies to 'ratings' when + # the source is 'reviews'. + - dimensions: + destination: ratings + source: reviews + maxAmount: 50 + # The following override applies to 'ratings' regardless + # of the source. + - dimensions: + destination: ratings + maxAmount: 100 +--- +apiVersion: config.istio.io/v1alpha2 +kind: instance +metadata: + name: requestcountquota + namespace: istio-system +spec: + compiledTemplate: quota + params: + dimensions: + source: source.labels["app"] | "unknown" + sourceVersion: source.labels["version"] | "unknown" + destination: destination.labels["app"] | "unknown" + destinationVersion: destination.labels["version"] | "unknown" +--- +apiVersion: config.istio.io/v1alpha2 +kind: QuotaSpec +metadata: + name: request-count + namespace: istio-system +spec: + rules: + - quotas: + - charge: 1 + quota: requestcountquota +--- +# Note: change the default namespace to the namespace of the bookinfo app +apiVersion: config.istio.io/v1alpha2 +kind: QuotaSpecBinding +metadata: + name: request-count + namespace: istio-system +spec: + quotaSpecs: + - name: request-count + namespace: istio-system + services: + - name: ratings + namespace: default + - name: reviews + namespace: default + - name: details + namespace: default + - name: productpage + namespace: default +--- +apiVersion: config.istio.io/v1alpha2 +kind: rule +metadata: + name: quota + namespace: istio-system +spec: + match: (destination.labels["app"]|"unknown") == "ratings" + actions: + - handler: redishandler + instances: + - requestcountquota +--- diff --git a/istio-1.3.5/samples/bookinfo/policy/mixer-rule-ratings-redis-quota-rolling-window.yaml b/istio-1.3.5/samples/bookinfo/policy/mixer-rule-ratings-redis-quota-rolling-window.yaml new file mode 100644 index 0000000..b713637 --- /dev/null +++ b/istio-1.3.5/samples/bookinfo/policy/mixer-rule-ratings-redis-quota-rolling-window.yaml @@ -0,0 +1,88 @@ +apiVersion: config.istio.io/v1alpha2 +kind: handler +metadata: + name: redishandler + namespace: istio-system +spec: + compiledAdapter: redisquota + params: + redisServerUrl: redis-release-master:6379 + connectionPoolSize: 10 + quotas: + - name: requestcountquota.instance.istio-system + maxAmount: 5000 + validDuration: 30s + bucketDuration: 9s + rateLimitAlgorithm: ROLLING_WINDOW + # The first matching override is applied. + # A requestcount instance is checked against override dimensions. + overrides: + # The following override applies to 'ratings' when + # the source is 'reviews'. + - dimensions: + destination: ratings + source: reviews + maxAmount: 50 + # The following override applies to 'ratings' regardless + # of the source. + - dimensions: + destination: ratings + maxAmount: 100 +--- +apiVersion: config.istio.io/v1alpha2 +kind: instance +metadata: + name: requestcountquota + namespace: istio-system +spec: + compiledTemplate: quota + params: + dimensions: + source: source.labels["app"] | "unknown" + sourceVersion: source.labels["version"] | "unknown" + destination: destination.labels["app"] | "unknown" + destinationVersion: destination.labels["version"] | "unknown" +--- +apiVersion: config.istio.io/v1alpha2 +kind: QuotaSpec +metadata: + name: request-count + namespace: istio-system +spec: + rules: + - quotas: + - charge: 1 + quota: requestcountquota +--- +# Note: change the default namespace to the namespace of the bookinfo app +apiVersion: config.istio.io/v1alpha2 +kind: QuotaSpecBinding +metadata: + name: request-count + namespace: istio-system +spec: + quotaSpecs: + - name: request-count + namespace: istio-system + services: + - name: ratings + namespace: default + - name: reviews + namespace: default + - name: details + namespace: default + - name: productpage + namespace: default +--- +apiVersion: config.istio.io/v1alpha2 +kind: rule +metadata: + name: quota + namespace: istio-system +spec: + match: (destination.labels["app"]|"unknown") == "ratings" + actions: + - handler: redishandler + instances: + - requestcountquota +--- diff --git a/istio-1.3.5/samples/bookinfo/policy/prometheus-adapter-deployment.yaml b/istio-1.3.5/samples/bookinfo/policy/prometheus-adapter-deployment.yaml new file mode 100644 index 0000000..f744947 --- /dev/null +++ b/istio-1.3.5/samples/bookinfo/policy/prometheus-adapter-deployment.yaml @@ -0,0 +1,44 @@ +apiVersion: v1 +kind: Service +metadata: + name: prometheusadapter + namespace: istio-system + labels: + app: prometheusadapter +spec: + ports: + - name: http + port: 8080 + - name: prometheus + port: 42422 + selector: + app: prometheusadapter +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: prometheusadapter + namespace: istio-system +spec: + replicas: 1 + selector: + matchLabels: + app: prometheusadapter + version: v1 + template: + metadata: + labels: + app: prometheusadapter + version: v1 + annotations: + prometheus.io/scrape: "true" + prometheus.io/port: "42422" + spec: + containers: + - image: gcr.io/istio-testing/prometheusadapter:release-1.1 + imagePullPolicy: Always + name: prometheusadapter + ports: + - containerPort: 8080 + - containerPort: 42422 +--- diff --git a/istio-1.3.5/samples/bookinfo/policy/prometheus-oop-rule.yaml b/istio-1.3.5/samples/bookinfo/policy/prometheus-oop-rule.yaml new file mode 100644 index 0000000..059d067 --- /dev/null +++ b/istio-1.3.5/samples/bookinfo/policy/prometheus-oop-rule.yaml @@ -0,0 +1,78 @@ +apiVersion: "config.istio.io/v1alpha2" +kind: instance +metadata: + name: requestcount-oop + namespace: istio-system +spec: + template: metric + params: + value: "1" + dimensions: + reporter: conditional((context.reporter.kind | "inbound") == "outbound", "source", "destination") + source_workload: source.workload.name | "unknown" + source_workload_namespace: source.workload.namespace | "unknown" + source_principal: source.principal | "unknown" + source_app: source.labels["app"] | "unknown" + source_version: source.labels["version"] | "unknown" + destination_workload: destination.workload.name | "unknown" + destination_workload_namespace: destination.workload.namespace | "unknown" + destination_principal: destination.principal | "unknown" + destination_app: destination.labels["app"] | "unknown" + destination_version: destination.labels["version"] | "unknown" + destination_service: destination.service.host | "unknown" + destination_service_name: destination.service.name | "unknown" + destination_service_namespace: destination.service.namespace | "unknown" + request_protocol: api.protocol | context.protocol | "unknown" + response_code: response.code | 200 + response_flags: context.proxy_error_code | "-" + permissive_response_code: rbac.permissive.response_code | "none" + permissive_response_policyid: rbac.permissive.effective_policy_id | "none" + connection_security_policy: conditional((context.reporter.kind | "inbound") == "outbound", "unknown", conditional(connection.mtls | false, "mutual_tls", "none")) + monitored_resource_type: '"UNSPECIFIED"' +--- +apiVersion: "config.istio.io/v1alpha2" +kind: handler +metadata: + name: prometheus-handler + namespace: istio-system +spec: + adapter: prometheus-nosession + connection: + address: "prometheusadapter:8080" + params: + metrics: + - name: request_count_oop + instance_name: requestcount-oop.instance.istio-system + kind: COUNTER + label_names: + - reporter + - source_workload + - source_workload_namespace + - source_principal + - source_app + - source_version + - destination_workload + - destination_workload_namespace + - destination_principal + - destination_app + - destination_version + - destination_service + - destination_service_name + - destination_service_namespace + - request_protocol + - response_code + - response_flags + - permissive_response_code + - permissive_response_policyid + - connection_security_policy +--- +apiVersion: "config.istio.io/v1alpha2" +kind: rule +metadata: + name: promhttp-oop + namespace: istio-system +spec: + actions: + - handler: prometheus-handler + instances: [ requestcount-oop ] +--- diff --git a/istio-1.3.5/samples/bookinfo/src/mongodb/ratings_data.json b/istio-1.3.5/samples/bookinfo/src/mongodb/ratings_data.json new file mode 100644 index 0000000..b4563b5 --- /dev/null +++ b/istio-1.3.5/samples/bookinfo/src/mongodb/ratings_data.json @@ -0,0 +1,2 @@ +{rating: 5} +{rating: 4} diff --git a/istio-1.3.5/samples/bookinfo/src/productpage/requirements.txt b/istio-1.3.5/samples/bookinfo/src/productpage/requirements.txt new file mode 100644 index 0000000..ae8cd93 --- /dev/null +++ b/istio-1.3.5/samples/bookinfo/src/productpage/requirements.txt @@ -0,0 +1,31 @@ +certifi==2019.3.9 +chardet==3.0.4 +Click==7.0 +contextlib2==0.5.5 +dominate==2.3.5 +Flask==1.0.2 +Flask-Bootstrap==3.3.7.1 +Flask-JSON==0.3.3 +future==0.17.1 +futures==3.1.1 +gevent==1.4.0 +greenlet==0.4.15 +idna==2.8 +itsdangerous==1.1.0 +jaeger-client==3.13.0 +Jinja2==2.10.1 +json2html==1.2.1 +MarkupSafe==0.23 +nose==1.3.7 +opentracing==1.2.2 +opentracing-instrumentation==2.4.3 +requests==2.21.0 +simplejson==3.16.0 +six==1.12.0 +threadloop==1.0.2 +thrift==0.11.0 +tornado==4.5.3 +urllib3==1.24.2 +visitor==0.1.3 +Werkzeug==0.14.1 +wrapt==1.11.1 diff --git a/istio-1.3.5/samples/bookinfo/src/productpage/test-requirements.txt b/istio-1.3.5/samples/bookinfo/src/productpage/test-requirements.txt new file mode 100644 index 0000000..f756640 --- /dev/null +++ b/istio-1.3.5/samples/bookinfo/src/productpage/test-requirements.txt @@ -0,0 +1 @@ +requests-mock==1.5.2 diff --git a/istio-1.3.5/samples/bookinfo/src/ratings/package.json b/istio-1.3.5/samples/bookinfo/src/ratings/package.json new file mode 100644 index 0000000..9093980 --- /dev/null +++ b/istio-1.3.5/samples/bookinfo/src/ratings/package.json @@ -0,0 +1,10 @@ +{ + "scripts": { + "start": "node ratings.js" + }, + "dependencies": { + "httpdispatcher": "1.0.0", + "mongodb": "^2.2.31", + "mysql": "^2.15.0" + } +} diff --git a/istio-1.3.5/samples/bookinfo/swagger.yaml b/istio-1.3.5/samples/bookinfo/swagger.yaml new file mode 100644 index 0000000..6782e73 --- /dev/null +++ b/istio-1.3.5/samples/bookinfo/swagger.yaml @@ -0,0 +1,248 @@ +swagger: "2.0" +info: + description: "This is the API of the Istio BookInfo sample application." + version: "1.0.0" + title: "BookInfo API" + termsOfService: "https://istio.io/" + license: + name: "Apache 2.0" + url: "http://www.apache.org/licenses/LICENSE-2.0.html" +basePath: "/api/v1" +tags: +- name: "product" + description: "Information about a product (in this case a book)" +- name: "review" + description: "Review information for a product" +- name: "rating" + description: "Rating information for a product" +externalDocs: + description: "Learn more about the Istio BookInfo application" + url: "https://istio.io/docs/samples/bookinfo.html" +paths: + /products: + get: + tags: + - "product" + summary: "List all products" + description: "List all products available in the application with a minimum amount of information." + operationId: "getProducts" + consumes: + - "application/json" + produces: + - "application/json" + responses: + 200: + description: "successful operation" + schema: + type: "array" + items: + $ref: "#/definitions/Product" + /products/{id}: + get: + tags: + - "product" + summary: "Get individual product" + description: "Get detailed information about an individual product with the given id." + operationId: "getProduct" + consumes: + - "application/json" + produces: + - "application/json" + parameters: + - name: "id" + in: "path" + description: "Product id" + required: true + type: "integer" + format: "int32" + responses: + 200: + description: "successful operation" + schema: + $ref: "#/definitions/ProductDetails" + 400: + description: "Invalid product id" + /products/{id}/reviews: + get: + tags: + - "review" + summary: "Get reviews for a product" + description: "Get reviews for a product, including review text and possibly ratings information." + operationId: "getProductReviews" + consumes: + - "application/json" + produces: + - "application/json" + parameters: + - name: "id" + in: "path" + description: "Product id" + required: true + type: "integer" + format: "int32" + responses: + 200: + description: "successful operation" + schema: + $ref: "#/definitions/ProductReviews" + 400: + description: "Invalid product id" + /products/{id}/ratings: + get: + tags: + - "rating" + summary: "Get ratings for a product" + description: "Get ratings for a product, including stars and their color." + operationId: "getProductRatings" + consumes: + - "application/json" + produces: + - "application/json" + parameters: + - name: "id" + in: "path" + description: "Product id" + required: true + type: "integer" + format: "int32" + responses: + 200: + description: "successful operation" + schema: + $ref: "#/definitions/ProductRatings" + 400: + description: "Invalid product id" + + +definitions: + Product: + type: "object" + description: "Basic information about a product" + properties: + id: + type: "integer" + format: "int32" + description: "Product id" + title: + type: "string" + description: "Title of the book" + descriptionHtml: + type: "string" + description: "Description of the book - may contain HTML tags" + required: + - "id" + - "title" + - "descriptionHtml" + ProductDetails: + type: "object" + description: "Detailed information about a product" + properties: + id: + type: "integer" + format: "int32" + description: "Product id" + publisher: + type: "string" + description: "Publisher of the book" + language: + type: "string" + description: "Language of the book" + author: + type: "string" + description: "Author of the book" + ISBN-10: + type: "string" + description: "ISBN-10 of the book" + ISBN-13: + type: "string" + description: "ISBN-13 of the book" + year: + type: "integer" + format: "int32" + description: "Year the book was first published in" + type: + type: "string" + enum: + - "paperback" + - "hardcover" + description: "Type of the book" + pages: + type: "integer" + format: "int32" + description: "Number of pages of the book" + required: + - "id" + - "publisher" + - "language" + - "author" + - "ISBN-10" + - "ISBN-13" + - "year" + - "type" + - "pages" + ProductReviews: + type: "object" + description: "Object containing reviews for a product" + properties: + id: + type: "integer" + format: "int32" + description: "Product id" + reviews: + type: "array" + description: "List of reviews" + items: + $ref: "#/definitions/Review" + required: + - "id" + - "reviews" + Review: + type: "object" + description: "Review of a product" + properties: + reviewer: + type: "string" + description: "Name of the reviewer" + text: + type: "string" + description: "Review text" + rating: + $ref: "#/definitions/Rating" + required: + - "reviewer" + - "text" + Rating: + type: "object" + description: "Rating of a product" + properties: + stars: + type: "integer" + format: "int32" + minimum: 1 + maximum: 5 + description: "Number of stars" + color: + type: "string" + enum: + - "red" + - "black" + description: "Color in which stars should be displayed" + required: + - "stars" + - "color" + ProductRatings: + type: "object" + description: "Object containing ratings of a product" + properties: + id: + type: "integer" + format: "int32" + description: "Product id" + ratings: + type: "object" + description: "A hashmap where keys are reviewer names, values are number of stars" + additionalProperties: + type: "string" + required: + - "id" + - "ratings" \ No newline at end of file diff --git a/istio-1.3.5/samples/bookinfo/telemetry/fluentd-istio-crd.yaml b/istio-1.3.5/samples/bookinfo/telemetry/fluentd-istio-crd.yaml new file mode 100644 index 0000000..4df061e --- /dev/null +++ b/istio-1.3.5/samples/bookinfo/telemetry/fluentd-istio-crd.yaml @@ -0,0 +1,40 @@ +# Configuration for logentry instances +apiVersion: "config.istio.io/v1alpha2" +kind: logentry +metadata: + name: newlog + namespace: istio-system +spec: + severity: '"info"' + timestamp: request.time + variables: + source: source.labels["app"] | source.workload.name | "unknown" + user: source.user | "unknown" + destination: destination.labels["app"] | destination.workload.name | "unknown" + responseCode: response.code | 0 + responseSize: response.size | 0 + latency: response.duration | "0ms" + monitored_resource_type: '"UNSPECIFIED"' +--- +# Configuration for a Fluentd handler +apiVersion: "config.istio.io/v1alpha2" +kind: fluentd +metadata: + name: handler + namespace: istio-system +spec: + address: "fluentd-es.logging:24224" +--- +# Rule to send logentry instances to the Fluentd handler +apiVersion: "config.istio.io/v1alpha2" +kind: rule +metadata: + name: newlogtofluentd + namespace: istio-system +spec: + match: "true" # match for all requests + actions: + - handler: handler.fluentd + instances: + - newlog.logentry +--- diff --git a/istio-1.3.5/samples/bookinfo/telemetry/fluentd-istio.yaml b/istio-1.3.5/samples/bookinfo/telemetry/fluentd-istio.yaml new file mode 100644 index 0000000..c416f31 --- /dev/null +++ b/istio-1.3.5/samples/bookinfo/telemetry/fluentd-istio.yaml @@ -0,0 +1,44 @@ +# Configuration for logentry instances +apiVersion: config.istio.io/v1alpha2 +kind: instance +metadata: + name: newlog + namespace: istio-system +spec: + compiledTemplate: logentry + params: + severity: '"info"' + timestamp: request.time + variables: + source: source.labels["app"] | source.workload.name | "unknown" + user: source.user | "unknown" + destination: destination.labels["app"] | destination.workload.name | "unknown" + responseCode: response.code | 0 + responseSize: response.size | 0 + latency: response.duration | "0ms" + monitored_resource_type: '"UNSPECIFIED"' +--- +# Configuration for a Fluentd handler +apiVersion: config.istio.io/v1alpha2 +kind: handler +metadata: + name: handler + namespace: istio-system +spec: + compiledAdapter: fluentd + params: + address: "fluentd-es.logging:24224" +--- +# Rule to send logentry instances to the Fluentd handler +apiVersion: config.istio.io/v1alpha2 +kind: rule +metadata: + name: newlogtofluentd + namespace: istio-system +spec: + match: "true" # match for all requests + actions: + - handler: handler + instances: + - newlog +--- diff --git a/istio-1.3.5/samples/bookinfo/telemetry/log-entry-crd.yaml b/istio-1.3.5/samples/bookinfo/telemetry/log-entry-crd.yaml new file mode 100644 index 0000000..d439676 --- /dev/null +++ b/istio-1.3.5/samples/bookinfo/telemetry/log-entry-crd.yaml @@ -0,0 +1,42 @@ +# Configuration for logentry instances +apiVersion: "config.istio.io/v1alpha2" +kind: logentry +metadata: + name: newlog + namespace: istio-system +spec: + severity: '"warning"' + timestamp: request.time + variables: + source: source.labels["app"] | source.workload.name | "unknown" + user: source.user | "unknown" + destination: destination.labels["app"] | destination.workload.name | "unknown" + responseCode: response.code | 0 + responseSize: response.size | 0 + latency: response.duration | "0ms" + monitored_resource_type: '"UNSPECIFIED"' +--- +# Configuration for a stdio handler +apiVersion: "config.istio.io/v1alpha2" +kind: stdio +metadata: + name: newloghandler + namespace: istio-system +spec: + severity_levels: + warning: 1 # Params.Level.WARNING + outputAsJson: true +--- +# Rule to send logentry instances to a stdio handler +apiVersion: "config.istio.io/v1alpha2" +kind: rule +metadata: + name: newlogstdio + namespace: istio-system +spec: + match: "true" # match for all requests + actions: + - handler: newloghandler.stdio + instances: + - newlog.logentry +--- diff --git a/istio-1.3.5/samples/bookinfo/telemetry/log-entry.yaml b/istio-1.3.5/samples/bookinfo/telemetry/log-entry.yaml new file mode 100644 index 0000000..43f47e7 --- /dev/null +++ b/istio-1.3.5/samples/bookinfo/telemetry/log-entry.yaml @@ -0,0 +1,46 @@ +# Configuration for logentry instances +apiVersion: config.istio.io/v1alpha2 +kind: instance +metadata: + name: newlog + namespace: istio-system +spec: + compiledTemplate: logentry + params: + severity: '"warning"' + timestamp: request.time + variables: + source: source.labels["app"] | source.workload.name | "unknown" + user: source.user | "unknown" + destination: destination.labels["app"] | destination.workload.name | "unknown" + responseCode: response.code | 0 + responseSize: response.size | 0 + latency: response.duration | "0ms" + monitored_resource_type: '"UNSPECIFIED"' +--- +# Configuration for a stdio handler +apiVersion: config.istio.io/v1alpha2 +kind: handler +metadata: + name: newloghandler + namespace: istio-system +spec: + compiledAdapter: stdio + params: + severity_levels: + warning: 1 # Params.Level.WARNING + outputAsJson: true +--- +# Rule to send logentry instances to a stdio handler +apiVersion: config.istio.io/v1alpha2 +kind: rule +metadata: + name: newlogstdio + namespace: istio-system +spec: + match: "true" # match for all requests + actions: + - handler: newloghandler + instances: + - newlog +--- diff --git a/istio-1.3.5/samples/bookinfo/telemetry/metrics-crd.yaml b/istio-1.3.5/samples/bookinfo/telemetry/metrics-crd.yaml new file mode 100644 index 0000000..9ee2f5f --- /dev/null +++ b/istio-1.3.5/samples/bookinfo/telemetry/metrics-crd.yaml @@ -0,0 +1,45 @@ +# Configuration for metric instances +apiVersion: "config.istio.io/v1alpha2" +kind: instance +metadata: + name: doublerequestcount + namespace: istio-system +spec: + compiledTemplate: metric + params: + value: "2" # count each request twice + dimensions: + reporter: conditional((context.reporter.kind | "inbound") == "outbound", "client", "server") + source: source.workload.name | "unknown" + destination: destination.workload.name | "unknown" + message: '"twice the fun!"' + monitored_resource_type: '"UNSPECIFIED"' +--- +# Configuration for a Prometheus handler +apiVersion: "config.istio.io/v1alpha2" +kind: prometheus +metadata: + name: doublehandler + namespace: istio-system +spec: + metrics: + - name: double_request_count # Prometheus metric name + instance_name: doublerequestcount.instance.istio-system # Mixer instance name (fully-qualified) + kind: COUNTER + label_names: + - reporter + - source + - destination + - message +--- +# Rule to send metric instances to a Prometheus handler +apiVersion: "config.istio.io/v1alpha2" +kind: rule +metadata: + name: doubleprom + namespace: istio-system +spec: + actions: + - handler: doublehandler.prometheus + instances: + - doublerequestcount diff --git a/istio-1.3.5/samples/bookinfo/telemetry/metrics.yaml b/istio-1.3.5/samples/bookinfo/telemetry/metrics.yaml new file mode 100644 index 0000000..45d9877 --- /dev/null +++ b/istio-1.3.5/samples/bookinfo/telemetry/metrics.yaml @@ -0,0 +1,46 @@ +# Configuration for metric instances +apiVersion: config.istio.io/v1alpha2 +kind: instance +metadata: + name: doublerequestcount + namespace: istio-system +spec: + compiledTemplate: metric + params: + value: "2" # count each request twice + dimensions: + reporter: conditional((context.reporter.kind | "inbound") == "outbound", "client", "server") + source: source.workload.name | "unknown" + destination: destination.workload.name | "unknown" + message: '"twice the fun!"' + monitored_resource_type: '"UNSPECIFIED"' +--- +# Configuration for a Prometheus handler +apiVersion: config.istio.io/v1alpha2 +kind: handler +metadata: + name: doublehandler + namespace: istio-system +spec: + compiledAdapter: prometheus + params: + metrics: + - name: double_request_count # Prometheus metric name + instance_name: doublerequestcount.instance.istio-system # Mixer instance name (fully-qualified) + kind: COUNTER + label_names: + - reporter + - source + - destination + - message +--- +# Rule to send metric instances to a Prometheus handler +apiVersion: config.istio.io/v1alpha2 +kind: rule +metadata: + name: doubleprom + namespace: istio-system +spec: + actions: + - handler: doublehandler + instances: [ doublerequestcount ] diff --git a/istio-1.3.5/samples/bookinfo/telemetry/tcp-metrics-crd.yaml b/istio-1.3.5/samples/bookinfo/telemetry/tcp-metrics-crd.yaml new file mode 100644 index 0000000..36ba5ec --- /dev/null +++ b/istio-1.3.5/samples/bookinfo/telemetry/tcp-metrics-crd.yaml @@ -0,0 +1,67 @@ +# Configuration for a metric measuring bytes sent from a server +# to a client +apiVersion: "config.istio.io/v1alpha2" +kind: metric +metadata: + name: mongosentbytes + namespace: default +spec: + value: connection.sent.bytes | 0 # uses a TCP-specific attribute + dimensions: + source_service: source.workload.name | "unknown" + source_version: source.labels["version"] | "unknown" + destination_version: destination.labels["version"] | "unknown" + monitoredResourceType: '"UNSPECIFIED"' +--- +# Configuration for a metric measuring bytes sent from a client +# to a server +apiVersion: "config.istio.io/v1alpha2" +kind: metric +metadata: + name: mongoreceivedbytes + namespace: default +spec: + value: connection.received.bytes | 0 # uses a TCP-specific attribute + dimensions: + source_service: source.workload.name | "unknown" + source_version: source.labels["version"] | "unknown" + destination_version: destination.labels["version"] | "unknown" + monitoredResourceType: '"UNSPECIFIED"' +--- +# Configuration for a Prometheus handler +apiVersion: "config.istio.io/v1alpha2" +kind: prometheus +metadata: + name: mongohandler + namespace: default +spec: + metrics: + - name: mongo_sent_bytes # Prometheus metric name + instance_name: mongosentbytes.metric.default # Mixer instance name (fully-qualified) + kind: COUNTER + label_names: + - source_service + - source_version + - destination_version + - name: mongo_received_bytes # Prometheus metric name + instance_name: mongoreceivedbytes.metric.default # Mixer instance name (fully-qualified) + kind: COUNTER + label_names: + - source_service + - source_version + - destination_version +--- +# Rule to send metric instances to a Prometheus handler +apiVersion: "config.istio.io/v1alpha2" +kind: rule +metadata: + name: mongoprom + namespace: default +spec: + match: context.protocol == "tcp" + && destination.service.host == "mongodb.default.svc.cluster.local" + actions: + - handler: mongohandler.prometheus + instances: + - mongoreceivedbytes.metric + - mongosentbytes.metric diff --git a/istio-1.3.5/samples/bookinfo/telemetry/tcp-metrics.yaml b/istio-1.3.5/samples/bookinfo/telemetry/tcp-metrics.yaml new file mode 100644 index 0000000..817507b --- /dev/null +++ b/istio-1.3.5/samples/bookinfo/telemetry/tcp-metrics.yaml @@ -0,0 +1,73 @@ +# Configuration for a metric measuring bytes sent from a server +# to a client +apiVersion: config.istio.io/v1alpha2 +kind: instance +metadata: + name: mongosentbytes + namespace: default +spec: + compiledTemplate: metric + params: + value: connection.sent.bytes | 0 # uses a TCP-specific attribute + dimensions: + source_service: source.workload.name | "unknown" + source_version: source.labels["version"] | "unknown" + destination_version: destination.labels["version"] | "unknown" + monitoredResourceType: '"UNSPECIFIED"' +--- +# Configuration for a metric measuring bytes sent from a client +# to a server +apiVersion: config.istio.io/v1alpha2 +kind: instance +metadata: + name: mongoreceivedbytes + namespace: default +spec: + compiledTemplate: metric + params: + value: connection.received.bytes | 0 # uses a TCP-specific attribute + dimensions: + source_service: source.workload.name | "unknown" + source_version: source.labels["version"] | "unknown" + destination_version: destination.labels["version"] | "unknown" + monitoredResourceType: '"UNSPECIFIED"' +--- +# Configuration for a Prometheus handler +apiVersion: config.istio.io/v1alpha2 +kind: handler +metadata: + name: mongohandler + namespace: default +spec: + compiledAdapter: prometheus + params: + metrics: + - name: mongo_sent_bytes # Prometheus metric name + instance_name: mongosentbytes.instance.default # Mixer instance name (fully-qualified) + kind: COUNTER + label_names: + - source_service + - source_version + - destination_version + - name: mongo_received_bytes # Prometheus metric name + instance_name: mongoreceivedbytes.instance.default # Mixer instance name (fully-qualified) + kind: COUNTER + label_names: + - source_service + - source_version + - destination_version +--- +# Rule to send metric instances to a Prometheus handler +apiVersion: config.istio.io/v1alpha2 +kind: rule +metadata: + name: mongoprom + namespace: default +spec: + match: context.protocol == "tcp" + && destination.service.host == "mongodb.default.svc.cluster.local" + actions: + - handler: mongohandler + instances: + - mongoreceivedbytes + - mongosentbytes diff --git a/istio-1.3.5/samples/certs/README.md b/istio-1.3.5/samples/certs/README.md new file mode 100644 index 0000000..af87ec4 --- /dev/null +++ b/istio-1.3.5/samples/certs/README.md @@ -0,0 +1,37 @@ +# Sample Certificates for Citadel CA + +This directory contains sample pre-generated certificate and keys to demonstrate how an operator could configure Citadel with an existing root certificate, signing certificates and keys. In such +a deployment, Citadel acts as an intermediate certificate authority (CA), under the given root CA. +Instructions are available [here](https://istio.io/docs/tasks/security/plugin-ca-cert/). + +The included sample files are: + +- `root-cert.pem`: root CA certificate. +- `ca-cert.pem` and `ca-cert.key`: Citadel intermediate certificate and corresponding private key. +- `cert-chain.pem`: certificate trust chain. + +## Generating Certificates for Bootstrapping Multicluster Chain of Trust + +Using the sample certificates to establish trust between multiple clusters is not recommended. +Since the directory is missing the root CA's private key, we're unable to create new certificates +for the clusters. Our only workable option is to use the **same** files for all clusters. +A better alternative would be to assign a different intermediate CA to each cluster, all signed by +a shared root CA. This will enable trust between workloads from different clusters as long as +they share a common root CA. + +The directory contains a `Makefile` for generating new root and intermediate certificates. +The following `make` targets are defined: + +- `make root-ca`: this will generate a new root CA key and certificate. +- `make $NAME-certs`: this will generate all needed files to bootstrap a new Citadel for cluster `$NAME` (e.g., `us-east`, `cluster01`, etc.). + +The intermediate CA files used for cluster `$NAME` are created under a directory named +`$NAME`. By creating files under a directory, we can create them using the naming convention +expected by Citadel's command line options. To differentiate between clusters, we include a +`Location` (`L`) designation in the certificates `Subject` field, with the cluster's name. +Similarly, we set the `Subject Alternate Name` field to include the cluster name as part +of the SPIFFE identity. + +Note that the Makefile generates long lived intermediate certificates. While this might be +acceptable for demonstration purposes, a more realistic and secure deployment would use short +lived and automatically renewed certificates for the intermediate Citadels. \ No newline at end of file diff --git a/istio-1.3.5/samples/certs/ca-cert.pem b/istio-1.3.5/samples/certs/ca-cert.pem new file mode 100644 index 0000000..a460e03 --- /dev/null +++ b/istio-1.3.5/samples/certs/ca-cert.pem @@ -0,0 +1,22 @@ +-----BEGIN CERTIFICATE----- +MIIDnzCCAoegAwIBAgIJAON1ifrBZ2/BMA0GCSqGSIb3DQEBCwUAMIGLMQswCQYD +VQQGEwJVUzETMBEGA1UECAwKQ2FsaWZvcm5pYTESMBAGA1UEBwwJU3Vubnl2YWxl +MQ4wDAYDVQQKDAVJc3RpbzENMAsGA1UECwwEVGVzdDEQMA4GA1UEAwwHUm9vdCBD +QTEiMCAGCSqGSIb3DQEJARYTdGVzdHJvb3RjYUBpc3Rpby5pbzAgFw0xODAxMjQx +OTE1NTFaGA8yMTE3MTIzMTE5MTU1MVowWTELMAkGA1UEBhMCVVMxEzARBgNVBAgT +CkNhbGlmb3JuaWExEjAQBgNVBAcTCVN1bm55dmFsZTEOMAwGA1UEChMFSXN0aW8x +ETAPBgNVBAMTCElzdGlvIENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKC +AQEAyzCxr/xu0zy5rVBiso9ffgl00bRKvB/HF4AX9/ytmZ6Hqsy13XIQk8/u/By9 +iCvVwXIMvyT0CbiJq/aPEj5mJUy0lzbrUs13oneXqrPXf7ir3HzdRw+SBhXlsh9z +APZJXcF93DJU3GabPKwBvGJ0IVMJPIFCuDIPwW4kFAI7R/8A5LSdPrFx6EyMXl7K +M8jekC0y9DnTj83/fY72WcWX7YTpgZeBHAeeQOPTZ2KYbFal2gLsar69PgFS0Tom +ESO9M14Yit7mzB1WDK2z9g3r+zLxENdJ5JG/ZskKe+TO4Diqi5OJt/h8yspS1ck8 +LJtCole9919umByg5oruflqIlQIDAQABozUwMzALBgNVHQ8EBAMCAgQwDAYDVR0T +BAUwAwEB/zAWBgNVHREEDzANggtjYS5pc3Rpby5pbzANBgkqhkiG9w0BAQsFAAOC +AQEAltHEhhyAsve4K4bLgBXtHwWzo6SpFzdAfXpLShpOJNtQNERb3qg6iUGQdY+w +A2BpmSkKr3Rw/6ClP5+cCG7fGocPaZh+c+4Nxm9suMuZBZCtNOeYOMIfvCPcCS+8 +PQ/0hC4/0J3WJKzGBssaaMufJxzgFPPtDJ998kY8rlROghdSaVt423/jXIAYnP3Y +05n8TGERBj7TLdtIVbtUIx3JHAo3PWJywA6mEDovFMJhJERp9sDHIr1BbhXK1TFN +Z6HNH6gInkSSMtvC4Ptejb749PTaePRPF7ID//eq/3AH8UK50F3TQcLjEqWUsJUn +aFKltOc+RAjzDklcUPeG4Y6eMA== +-----END CERTIFICATE----- diff --git a/istio-1.3.5/samples/certs/ca-key.pem b/istio-1.3.5/samples/certs/ca-key.pem new file mode 100644 index 0000000..faa77f3 --- /dev/null +++ b/istio-1.3.5/samples/certs/ca-key.pem @@ -0,0 +1,27 @@ +-----BEGIN RSA PRIVATE KEY----- +MIIEpAIBAAKCAQEAyzCxr/xu0zy5rVBiso9ffgl00bRKvB/HF4AX9/ytmZ6Hqsy1 +3XIQk8/u/By9iCvVwXIMvyT0CbiJq/aPEj5mJUy0lzbrUs13oneXqrPXf7ir3Hzd +Rw+SBhXlsh9zAPZJXcF93DJU3GabPKwBvGJ0IVMJPIFCuDIPwW4kFAI7R/8A5LSd +PrFx6EyMXl7KM8jekC0y9DnTj83/fY72WcWX7YTpgZeBHAeeQOPTZ2KYbFal2gLs +ar69PgFS0TomESO9M14Yit7mzB1WDK2z9g3r+zLxENdJ5JG/ZskKe+TO4Diqi5OJ +t/h8yspS1ck8LJtCole9919umByg5oruflqIlQIDAQABAoIBAGZI8fnUinmd5R6B +C941XG3XFs6GAuUm3hNPcUFuGnntmv/5I0gBpqSyFO0nDqYg4u8Jma8TTCIkmnFN +ogIeFU+LiJFinR3GvwWzTE8rTz1FWoaY+M9P4ENd/I4pVLxUPuSKhfA2ChAVOupU +8F7D9Q/dfBXQQCT3VoUaC+FiqjL4HvIhji1zIqaqpK7fChGPraC/4WHwLMNzI0Zg +oDdAanwVygettvm6KD7AeKzhK94gX1PcnsOi3KuzQYvkenQE1M6/K7YtEc5qXCYf +QETj0UCzB55btgdF36BGoZXf0LwHqxys9ubfHuhwKBpY0xg2z4/4RXZNhfIDih3w +J3mihcECgYEA6FtQ0cfh0Zm03OPDpBGc6sdKxTw6aBDtE3KztfI2hl26xHQoeFqp +FmV/TbnExnppw+gWJtwx7IfvowUD8uRR2P0M2wGctWrMpnaEYTiLAPhXsj69HSM/ +CYrh54KM0YWyjwNhtUzwbOTrh1jWtT9HV5e7ay9Atk3UWljuR74CFMUCgYEA392e +DVoDLE0XtbysmdlfSffhiQLP9sT8+bf/zYnr8Eq/4LWQoOtjEARbuCj3Oq7bP8IE +Vz45gT1mEE3IacC9neGwuEa6icBiuQi86NW8ilY/ZbOWrRPLOhk3zLiZ+yqkt+sN +cqWx0JkIh7IMKWI4dVQgk4I0jcFP7vNG/So4AZECgYEA426eSPgxHQwqcBuwn6Nt +yJCRq0UsljgbFfIr3Wfb3uFXsntQMZ3r67QlS1sONIgVhmBhbmARrcfQ0+xQ1SqO +wqnOL4AAd8K11iojoVXLGYP7ssieKysYxKpgPE8Yru0CveE9fkx0+OGJeM2IO5hY +qHAoTt3NpaPAuz5Y3XgqaVECgYA0TONS/TeGjxA9/jFY1Cbl8gp35vdNEKKFeM5D +Z7h+cAg56FE8tyFyqYIAGVoBFL7WO26mLzxiDEUfA/0Rb90c2JBfzO5hpleqIPd5 +cg3VR+cRzI4kK16sWR3nLy2SN1k6OqjuovVS5Z3PjfI3bOIBz0C5FY9Pmt0g1yc7 +mDRzcQKBgQCXWCZStbdjewaLd5u5Hhbw8tIWImMVfcfs3H1FN669LLpbARM8RtAa +8dYwDVHmWmevb/WX03LiSE+GCjCBO79fa1qc5RKAalqH/1OYxTuvYOeTUebSrg8+ +lQFlP2OC4GGolKrN6HVWdxtf+F+SdjwX6qGCfYkXJRLYXIFSFjFeuw== +-----END RSA PRIVATE KEY----- diff --git a/istio-1.3.5/samples/certs/cert-chain.pem b/istio-1.3.5/samples/certs/cert-chain.pem new file mode 100644 index 0000000..a460e03 --- /dev/null +++ b/istio-1.3.5/samples/certs/cert-chain.pem @@ -0,0 +1,22 @@ +-----BEGIN CERTIFICATE----- +MIIDnzCCAoegAwIBAgIJAON1ifrBZ2/BMA0GCSqGSIb3DQEBCwUAMIGLMQswCQYD +VQQGEwJVUzETMBEGA1UECAwKQ2FsaWZvcm5pYTESMBAGA1UEBwwJU3Vubnl2YWxl +MQ4wDAYDVQQKDAVJc3RpbzENMAsGA1UECwwEVGVzdDEQMA4GA1UEAwwHUm9vdCBD +QTEiMCAGCSqGSIb3DQEJARYTdGVzdHJvb3RjYUBpc3Rpby5pbzAgFw0xODAxMjQx +OTE1NTFaGA8yMTE3MTIzMTE5MTU1MVowWTELMAkGA1UEBhMCVVMxEzARBgNVBAgT +CkNhbGlmb3JuaWExEjAQBgNVBAcTCVN1bm55dmFsZTEOMAwGA1UEChMFSXN0aW8x +ETAPBgNVBAMTCElzdGlvIENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKC +AQEAyzCxr/xu0zy5rVBiso9ffgl00bRKvB/HF4AX9/ytmZ6Hqsy13XIQk8/u/By9 +iCvVwXIMvyT0CbiJq/aPEj5mJUy0lzbrUs13oneXqrPXf7ir3HzdRw+SBhXlsh9z +APZJXcF93DJU3GabPKwBvGJ0IVMJPIFCuDIPwW4kFAI7R/8A5LSdPrFx6EyMXl7K +M8jekC0y9DnTj83/fY72WcWX7YTpgZeBHAeeQOPTZ2KYbFal2gLsar69PgFS0Tom +ESO9M14Yit7mzB1WDK2z9g3r+zLxENdJ5JG/ZskKe+TO4Diqi5OJt/h8yspS1ck8 +LJtCole9919umByg5oruflqIlQIDAQABozUwMzALBgNVHQ8EBAMCAgQwDAYDVR0T +BAUwAwEB/zAWBgNVHREEDzANggtjYS5pc3Rpby5pbzANBgkqhkiG9w0BAQsFAAOC +AQEAltHEhhyAsve4K4bLgBXtHwWzo6SpFzdAfXpLShpOJNtQNERb3qg6iUGQdY+w +A2BpmSkKr3Rw/6ClP5+cCG7fGocPaZh+c+4Nxm9suMuZBZCtNOeYOMIfvCPcCS+8 +PQ/0hC4/0J3WJKzGBssaaMufJxzgFPPtDJ998kY8rlROghdSaVt423/jXIAYnP3Y +05n8TGERBj7TLdtIVbtUIx3JHAo3PWJywA6mEDovFMJhJERp9sDHIr1BbhXK1TFN +Z6HNH6gInkSSMtvC4Ptejb749PTaePRPF7ID//eq/3AH8UK50F3TQcLjEqWUsJUn +aFKltOc+RAjzDklcUPeG4Y6eMA== +-----END CERTIFICATE----- diff --git a/istio-1.3.5/samples/certs/root-cert.pem b/istio-1.3.5/samples/certs/root-cert.pem new file mode 100644 index 0000000..64c3fd5 --- /dev/null +++ b/istio-1.3.5/samples/certs/root-cert.pem @@ -0,0 +1,24 @@ +-----BEGIN CERTIFICATE----- +MIID7TCCAtWgAwIBAgIJAOIRDhOcxsx6MA0GCSqGSIb3DQEBCwUAMIGLMQswCQYD +VQQGEwJVUzETMBEGA1UECAwKQ2FsaWZvcm5pYTESMBAGA1UEBwwJU3Vubnl2YWxl +MQ4wDAYDVQQKDAVJc3RpbzENMAsGA1UECwwEVGVzdDEQMA4GA1UEAwwHUm9vdCBD +QTEiMCAGCSqGSIb3DQEJARYTdGVzdHJvb3RjYUBpc3Rpby5pbzAgFw0xODAxMjQx +OTE1NTFaGA8yMTE3MTIzMTE5MTU1MVowgYsxCzAJBgNVBAYTAlVTMRMwEQYDVQQI +DApDYWxpZm9ybmlhMRIwEAYDVQQHDAlTdW5ueXZhbGUxDjAMBgNVBAoMBUlzdGlv +MQ0wCwYDVQQLDARUZXN0MRAwDgYDVQQDDAdSb290IENBMSIwIAYJKoZIhvcNAQkB +FhN0ZXN0cm9vdGNhQGlzdGlvLmlvMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB +CgKCAQEA38uEfAatzQYqbaLou1nxJ348VyNzumYMmDDt5pbLYRrCo2pS3ki1ZVDN +8yxIENJFkpKw9UctTGdbNGuGCiSDP7uqF6BiVn+XKAU/3pnPFBbTd0S33NqbDEQu +IYraHSl/tSk5rARbC1DrQRdZ6nYD2KrapC4g0XbjY6Pu5l4y7KnFwSunnp9uqpZw +uERv/BgumJ5QlSeSeCmhnDhLxooG8w5tC2yVr1yDpsOHGimP/mc8Cds4V0zfIhQv +YzfIHphhE9DKjmnjBYLOdj4aycv44jHnOGc+wvA1Jqsl60t3wgms+zJTiWwABLdw +zgMAa7yxLyoV0+PiVQud6k+8ZoIFcwIDAQABo1AwTjAdBgNVHQ4EFgQUOUYGtUyh +euxO4lGe4Op1y8NVoagwHwYDVR0jBBgwFoAUOUYGtUyheuxO4lGe4Op1y8NVoagw +DAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAQEANXLyfAs7J9rmBamGJvPZ +ltx390WxzzLFQsBRAaH6rgeipBq3dR9qEjAwb6BTF+ROmtQzX+fjstCRrJxCto9W +tC8KvXTdRfIjfCCZjhtIOBKqRxE4KJV/RBfv9xD5lyjtCPCQl3Ia6MSf42N+abAK +WCdU6KCojA8WB9YhSCzza3aQbPTzd26OC/JblJpVgtus5f8ILzCsz+pbMimgTkhy +AuhYRppJaQ24APijsEC9+GIaVKPg5IwWroiPoj+QXNpshuvqVQQXvGaRiq4zoSnx +xAJz+w8tjrDWcf826VN14IL+/Cmqlg/rIfB5CHdwVIfWwpuGB66q/UiPegZMNs8a +3g== +-----END CERTIFICATE----- diff --git a/istio-1.3.5/samples/custom-bootstrap/README.md b/istio-1.3.5/samples/custom-bootstrap/README.md new file mode 100644 index 0000000..81d1084 --- /dev/null +++ b/istio-1.3.5/samples/custom-bootstrap/README.md @@ -0,0 +1,52 @@ +# Custom Envoy Bootstrap Configuration + +This sample creates a simple helloworld service that bootstraps the Envoy proxy with a custom configuration file. + +## Starting the service + +First, we need to create a `ConfigMap` resource with our bootstrap configuration. + +```bash +kubectl apply -f custom-bootstrap.yaml +``` + +Next, we can create a service that uses this bootstrap configuration. + +To do this, we need to add an annotation, `sidecar.istio.io/bootstrapOverride`, with the name of our ConfigMap as the value. + +We can create our helloworld app, using the custom config, with: + +```bash +kubectl apply -f example-app.yaml +``` + +If you don't have [automatic sidecar injection](https://istio.io/docs/setup/kubernetes/sidecar-injection.html#automatic-sidecar-injection) +set in your cluster you will need to manually inject it to the services instead: + +```bash +istioctl kube-inject -f example-app.yaml -o example-app-istio.yaml +kubectl apply -f example-app-istio.yaml +``` + +## Checking the Bootstrap Configuration + +To see what bootstrap configuration a pod is using: + +```bash +istioctl proxy-config bootstrap +``` + +## Customizing the Bootstrap + +The configuration provided will be passed to envoy using the [`--config-yaml`](https://www.envoyproxy.io/docs/envoy/v1.7.1/operations/cli#cmdoption-config-yaml) flag. + +This will merge the passed in configuration with the default configuration. Singular values will replace the default values, while repeated values will be appended. + +For reference, [the default bootstrap configuration](/tools/packaging/common/envoy_bootstrap_v2.json) and Envoy's [configuration reference](https://www.envoyproxy.io/docs/envoy/latest/configuration/configuration#config) may be useful + +## Cleanup + +```bash +kubectl delete -f custom-bootstrap.yaml +kubectl delete -f example-app.yaml +``` \ No newline at end of file diff --git a/istio-1.3.5/samples/custom-bootstrap/custom-bootstrap.yaml b/istio-1.3.5/samples/custom-bootstrap/custom-bootstrap.yaml new file mode 100644 index 0000000..7ef8d1d --- /dev/null +++ b/istio-1.3.5/samples/custom-bootstrap/custom-bootstrap.yaml @@ -0,0 +1,19 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: istio-custom-bootstrap-config + namespace: default +data: + custom_bootstrap.json: | + { + "tracing": { + "http": { + "name": "envoy.zipkin", + "config": { + "collector_cluster": "zipkin", + "collector_endpoint": "/api/v1/spans/custom", + "trace_id_128bit": "true" + } + } + } + } diff --git a/istio-1.3.5/samples/custom-bootstrap/example-app.yaml b/istio-1.3.5/samples/custom-bootstrap/example-app.yaml new file mode 100644 index 0000000..24b4fdc --- /dev/null +++ b/istio-1.3.5/samples/custom-bootstrap/example-app.yaml @@ -0,0 +1,27 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: helloworld-v1 +spec: + replicas: 1 + selector: + matchLabels: + app: helloworld + version: v1 + template: + metadata: + annotations: + sidecar.istio.io/bootstrapOverride: "istio-custom-bootstrap-config" + labels: + app: helloworld + version: v1 + spec: + containers: + - name: helloworld + image: docker.io/istio/examples-helloworld-v1 + resources: + requests: + cpu: "100m" + imagePullPolicy: IfNotPresent + ports: + - containerPort: 5000 diff --git a/istio-1.3.5/samples/external/README.md b/istio-1.3.5/samples/external/README.md new file mode 100644 index 0000000..e17198b --- /dev/null +++ b/istio-1.3.5/samples/external/README.md @@ -0,0 +1,34 @@ +# External Services + +By default Istio-enabled services are unable to access services and URLs outside of the cluster. Pods use iptables to transparently redirect all outbound traffic to the sidecar proxy, which only handles intra-cluster destinations. + +See [the Egress Task](https://istio.io/docs/tasks/traffic-management/egress/) for +information on configuring Istio to contact external services. + +This directory contains samples showing how to enable pods to contact a few well +known services. + +If Istio is not configured to allow pods to contact external services, the pods will +see errors such as 404s, HTTPS connection problems, and TCP connection problems. If +ServiceEntries are misconfigured pods may see problems with server names. + +## Try it out + +After an operator runs `kubectl create -f aptget.yaml` pods will be able to +succeed with `apt-get update` and `apt-get install`. + +After an operator runs `kubectl create -f github.yaml` pods will be able to +succeed with `git clone https://github.com/fortio/fortio.git`. + +Running `kubectl create -f pypi.yaml` allows pods to update Python libraries using `pip`. + +It is not a best practice to enable pods to update libraries dynamically. +We are providing these samples +because they have proven to be helpful with interactive troubleshooting. Security minded clusters should only allow traffic to service dependencies such as cloud +services. + +### Enable communication by default + +Note that [this note](https://istio.io/docs/tasks/traffic-management/egress/#install-istio-with-access-to-all-external-services-by-default) shows how to configure Istio to contact services by default. The technique +discussed there does not allow HTTP on port 80 or SSH on port 22. These examples will +allow external communication for ports 80 and 22. diff --git a/istio-1.3.5/samples/external/aptget.yaml b/istio-1.3.5/samples/external/aptget.yaml new file mode 100644 index 0000000..fa24fa4 --- /dev/null +++ b/istio-1.3.5/samples/external/aptget.yaml @@ -0,0 +1,20 @@ +# This ServiceEntry exposes the hosts needed for installing packages with apt-get. +# After applying this file, Istio-enabled pods (configured apt-get) be able to execute +# `apt-get upgrade` and `apt-get install`. If this is not installed you may get +# "404 Not Found" + +apiVersion: networking.istio.io/v1alpha3 +kind: ServiceEntry +metadata: + name: make-aptget-work +spec: + hosts: + - deb.debian.org + - cdn-fastly.deb.debian.org + - security.debian.org + - archive.ubuntu.com + - security.ubuntu.com + ports: + - number: 80 + name: http + protocol: HTTP diff --git a/istio-1.3.5/samples/external/github.yaml b/istio-1.3.5/samples/external/github.yaml new file mode 100644 index 0000000..832cbc3 --- /dev/null +++ b/istio-1.3.5/samples/external/github.yaml @@ -0,0 +1,53 @@ +# This ServiceEntry exposes the hosts needed for github.com. +# After applying this file, Istio-enabled pods will be able to execute +# `git clone https://github.com/istio/api.git` and (with local identification +# config and certificate) `git clone git@github.com:istio/api.git` + +# HTTP and TLS, the host must be specified +# See https://istio.io/docs/tasks/traffic-management/egress/ +apiVersion: networking.istio.io/v1alpha3 +kind: ServiceEntry +metadata: + name: github-https +spec: + hosts: + - github.com + ports: + - number: 443 + name: https + protocol: HTTPS +--- +# For TCP services the IP ranges SHOULD be specified to avoid problems +# if multiple SEs use the same port number. +# See https://istio.io/blog/2018/egress-tcp/#mesh-external-service-entry-for-an-external-mysql-instance +apiVersion: networking.istio.io/v1alpha3 +kind: ServiceEntry +metadata: + name: github-tcp +spec: + hosts: + - dummy.github.com # not used + addresses: # from https://help.github.com/articles/about-github-s-ip-addresses/ + - "13.229.188.59/32" + - "13.250.177.223/32" + - "140.82.112.0/20" + - "18.194.104.89/32" + - "18.195.85.27/32" + - "185.199.108.0/22" + - "185.199.108.153/32" + - "185.199.109.153/32" + - "185.199.110.153/32" + - "185.199.111.153/32" + - "192.30.252.0/22" + - "192.30.252.153/32" + - "192.30.252.154/32" + - "23.20.92.3/32" + - "35.159.8.160/32" + - "52.74.223.119/32" + - "54.166.52.62/32" + - "54.87.5.173/32" + ports: + - name: tcp + number: 22 + protocol: tcp + location: MESH_EXTERNAL diff --git a/istio-1.3.5/samples/external/pypi.yaml b/istio-1.3.5/samples/external/pypi.yaml new file mode 100644 index 0000000..7f457a5 --- /dev/null +++ b/istio-1.3.5/samples/external/pypi.yaml @@ -0,0 +1,44 @@ +# This ServiceEntry exposes the hosts needed for Python `pip`. +# After applying this file, Istio-enabled pods will be able to execute +# `pip search istio`. + +# HTTP and TLS, the host must be specified +# See https://istio.io/docs/tasks/traffic-management/egress/ + +apiVersion: networking.istio.io/v1alpha3 +kind: ServiceEntry +metadata: + name: python-https +spec: + hosts: + - pypi.python.org + ports: + - number: 443 + name: https + protocol: HTTPS +--- +# pypi.python.org may 301 redirect to pypi.org, so we need this too. +apiVersion: networking.istio.io/v1alpha3 +kind: ServiceEntry +metadata: + name: pypi-https +spec: + hosts: + - pypi.org + ports: + - number: 443 + name: https + protocol: HTTPS +--- +# pip install may fetch files from files.pythonhosted.org +apiVersion: networking.istio.io/v1alpha3 +kind: ServiceEntry +metadata: + name: pythonhosted-https +spec: + hosts: + - files.pythonhosted.org + ports: + - number: 443 + name: https + protocol: HTTPS diff --git a/istio-1.3.5/samples/fortio/stackdriver.yaml b/istio-1.3.5/samples/fortio/stackdriver.yaml new file mode 100644 index 0000000..2bc93dc --- /dev/null +++ b/istio-1.3.5/samples/fortio/stackdriver.yaml @@ -0,0 +1,245 @@ +apiVersion: "config.istio.io/v1alpha2" +kind: handler +metadata: + name: stackdriver +spec: + compiledAdapter: stackdriver + params: + appCredentials: y + pushInterval: 5s + metricInfo: + server-request-count.instance.{{.Namespace}}: + kind: 3 # CUMULATIVE + value: 2 # INT64 + metric_type: "istio.io/service/server/request_count" + logInfo: + server-accesslog-stackdriver.instance.{{.Namespace}}: + labelNames: + - source_uid + - source_ip + - source_app + - source_principal + - source_name + - source_workload + - source_namespace + - source_owner + - destination_uid + - destination_app + - destination_ip + - destination_service_host + - destination_workload + - destination_name + - destination_namespace + - destination_owner + - destination_principal + - api_name + - api_version + - api_claims + - api_key + - request_operation + - protocol + - method + - url + - response_code + - response_size + - request_size + - request_id + - client_trace_id + - latency + - service_authentication_policy + - user_agent + - response_timestamp + - received_bytes + - sent_bytes + - referer + trace: + sampleProbability: 1.0 +--- +# For future Context Graph test. +# apiVersion: "config.istio.io/v1alpha2" +# kind: edge +# metadata: +# name: default +# spec: +# timestamp: request.time | context.time +# sourceUid: source.uid | "Unknown" +# sourceOwner: source.owner | "Unknown" +# sourceWorkloadName: source.workload.name | "Unknown" +# sourceWorkloadNamespace: source.workload.namespace | "Unknown" +# destinationUid: destination.uid | "Unknown" +# destinationOwner: destination.owner | "Unknown" +# destinationWorkloadName: destination.workload.name | "Unknown" +# destinationWorkloadNamespace: destination.workload.namespace | "Unknown" +# contextProtocol: context.protocol | "Unknown" +# apiProtocol: api.protocol | "Unknown" +--- +apiVersion: "config.istio.io/v1alpha2" +kind: instance +metadata: + name: server-accesslog-stackdriver +spec: + compiledTemplate: logentry + params: + severity: '"Info"' + timestamp: request.time + variables: + source_uid: source.uid | "" + source_ip: source.ip | ip("0.0.0.0") + source_app: source.labels["app"] | "" + source_principal: source.principal | "" + source_name: source.name | "" + source_workload: source.workload.name | "" + source_namespace: source.namespace | "" + source_owner: source.owner | "" + destination_uid: destination.uid | "" + destination_app: destination.labels["app"] | "" + destination_ip: destination.ip | ip("0.0.0.0") + destination_service_host: destination.service.host | "" + destination_workload: destination.workload.name | "" + destination_name: destination.name | "" + destination_namespace: destination.namespace | "" + destination_owner: destination.owner | "" + destination_principal: destination.principal | "" + api_name: api.service | "" + api_version: api.version | "" + api_claims: request.auth.raw_claims | "" + api_key: request.api_key | request.headers["x-api-key"] | "" + request_operation: conditional((context.protocol | "unknown") == "grpc", request.path | "unknown", request.method | "unknown") + protocol: request.scheme | context.protocol | "http" + method: request.method | "" + url: request.path | "" + response_code: response.code | 0 + response_size: response.size | 0 + request_size: request.size | 0 + request_id: request.headers["x-request-id"] | "" + client_trace_id: request.headers["x-client-trace-id"] | "" + latency: response.duration | "0ms" + service_authentication_policy: conditional((context.reporter.kind | "inbound") == "outbound", "unknown", conditional(connection.mtls | false, "mutual_tls", "none")) + user_agent: request.useragent | "" + response_timestamp: response.time + received_bytes: request.total_size | 0 + sent_bytes: response.total_size | 0 + referer: request.referer | "" + monitored_resource_type: '"k8s_container"' + monitoredResourceDimensions: + project_id: '""' + cluster_name: '""' + namespace_name: destination.namespace | "unknown" + location: '""' + container_name: destination.container.name | "unknown" + pod_name: destination.name | "unknown" +--- +apiVersion: "config.istio.io/v1alpha2" +kind: instance +metadata: + name: server-request-count +spec: + compiledTemplate: metric + params: + value: "1" + dimensions: + destination_service_name: destination.service.name | "unknown" + destination_service_namespace: destination.service.namespace | "unknown" + destination_port: destination.port | 0 + request_operation: conditional((context.protocol | "unknown") == "grpc", request.path | "unknown", request.method | "unknown") + request_protocol: context.protocol | "unknown" + api_version: api.version | "unknown" + api_name: api.service | "unknown" + response_code: response.code | 0 + service_authentication_policy: conditional((context.reporter.kind | "inbound") == "outbound", "unknown", conditional(connection.mtls | false, "mutual_tls", "none")) + source_workload_namespace: source.workload.namespace | "unknown" + source_workload_name: source.workload.name | "unknown" + source_owner: source.owner | "unknown" + destination_workload_namespace: destination.workload.namespace | "unknown" + destination_workload_name: destination.workload.name | "unknown" + destination_owner: destination.owner | "unknown" + monitoredResourceType: '"k8s_container"' + monitoredResourceDimensions: + project_id: '""' + cluster_name: '""' + namespace_name: destination.workload.namespace | "unknown" + location: '""' + container_name: destination.container.name | "unknown" + pod_name: destination.name | "unknown" +--- +apiVersion: "config.istio.io/v1alpha2" +kind: instance +metadata: + name: stackdriver-span +spec: + compiledTemplate: tracespan + params: + traceId: request.headers["x-b3-traceid"] + spanId: request.headers["x-b3-spanid"] | "" + parentSpanId: request.headers["x-b3-parentspanid"] | "" + spanName: destination.service.host | destination.service.name | destination.workload.name | "unknown" + startTime: request.time + endTime: response.time + clientSpan: (context.reporter.kind | "inbound") == "outbound" + rewriteClientSpanId: "true" + spanTags: + destination_service_name: destination.service.name | "unknown" + destination_service_namespace: destination.service.namespace | "unknown" + destination_port: destination.port | 0 + request_operation: conditional((context.protocol | "unknown") == "grpc", request.path | "unknown", request.method | "unknown") + request_protocol: context.protocol | "unknown" + api_version: api.version | "unknown" + api_name: api.service | "unknown" + response_code: response.code | 0 + service_authentication_policy: conditional((context.reporter.kind | "inbound") == "outbound", "unknown", conditional(connection.mtls | false, "mutual_tls", "none")) + source_workload_namespace: source.workload.namespace | "unknown" + source_workload_name: source.workload.name | "unknown" + source_owner: source.owner | "unknown" + destination_workload_namespace: destination.workload.namespace | "unknown" + destination_workload_name: destination.workload.name | "unknown" + destination_owner: destination.owner | "unknown" + http_url: request.path | "" + request_size: request.size | 0 + response_size: response.size | 0 + source_ip: source.ip | ip("0.0.0.0") +--- +apiVersion: "config.istio.io/v1alpha2" +kind: rule +metadata: + name: stackdriver-log +spec: + match: (context.protocol == "http" || context.protocol == "grpc") && (context.reporter.kind | "inbound" == "inbound") + actions: + - handler: stackdriver.handler + instances: + - server-accesslog-stackdriver +--- +apiVersion: "config.istio.io/v1alpha2" +kind: rule +metadata: + name: stackdriver-server +spec: + match: (context.protocol == "http" || context.protocol == "grpc") && (context.reporter.kind | "inbound" == "inbound") + actions: + - handler: stackdriver.handler + instances: + - server-request-count +--- +apiVersion: "config.istio.io/v1alpha2" +kind: rule +metadata: + name: stackdriver-tracing-rule +spec: + match: context.protocol == "http" || context.protocol == "grpc" # If omitted match is true. + actions: + - handler: stackdriver.handler + instances: + - stackdriver-span +--- +# For future Context Graph test. +# apiVersion: "config.istio.io/v1alpha2" +# kind: rule +# metadata: +# name: edgetosd +# spec: +# match: (context.reporter.kind | "inbound" == "inbound") && (context.protocol | "unknown" != "unknown") +# actions: +# - handler: stackdriver.handler +# instances: +# - default.edge +--- diff --git a/istio-1.3.5/samples/health-check/liveness-command.yaml b/istio-1.3.5/samples/health-check/liveness-command.yaml new file mode 100644 index 0000000..9ea9fe7 --- /dev/null +++ b/istio-1.3.5/samples/health-check/liveness-command.yaml @@ -0,0 +1,57 @@ +# Copyright 2017 Istio Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +################################################################################################## +# Liveness service +################################################################################################## +apiVersion: v1 +kind: Service +metadata: + name: liveness + labels: + app: liveness +spec: + ports: + - port: 80 + name: http + selector: + app: liveness +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: liveness +spec: + selector: + matchLabels: + app: liveness + template: + metadata: + labels: + app: liveness + spec: + containers: + - name: liveness + image: k8s.gcr.io/busybox + args: + - /bin/sh + - -c + - touch /tmp/healthy; sleep 3600 + livenessProbe: + exec: + command: + - cat + - /tmp/healthy + initialDelaySeconds: 5 + periodSeconds: 5 diff --git a/istio-1.3.5/samples/health-check/liveness-http-same-port.yaml b/istio-1.3.5/samples/health-check/liveness-http-same-port.yaml new file mode 100644 index 0000000..39c98a2 --- /dev/null +++ b/istio-1.3.5/samples/health-check/liveness-http-same-port.yaml @@ -0,0 +1,39 @@ +apiVersion: v1 +kind: Service +metadata: + name: liveness-http + labels: + app: liveness-http +spec: + ports: + - name: http + port: 8001 + selector: + app: liveness-http +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: liveness-http +spec: + template: + selector: + matchLabels: + app: liveness-http + version: v1 + metadata: + labels: + app: liveness-http + version: v1 + spec: + containers: + - name: liveness-http + image: docker.io/istio/health:example + ports: + - containerPort: 8001 + livenessProbe: + httpGet: + path: /foo + port: 8001 + initialDelaySeconds: 5 + periodSeconds: 5 diff --git a/istio-1.3.5/samples/health-check/liveness-http.yaml b/istio-1.3.5/samples/health-check/liveness-http.yaml new file mode 100644 index 0000000..bf76daf --- /dev/null +++ b/istio-1.3.5/samples/health-check/liveness-http.yaml @@ -0,0 +1,39 @@ +apiVersion: v1 +kind: Service +metadata: + name: liveness-http + labels: + app: liveness-http +spec: + ports: + - name: http + port: 8001 + selector: + app: liveness-http +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: liveness-http +spec: + template: + selector: + matchLabels: + app: liveness-http + version: v1 + metadata: + labels: + app: liveness-http + version: v1 + spec: + containers: + - name: liveness-http + image: docker.io/istio/health:example + ports: + - containerPort: 8001 + livenessProbe: + httpGet: + path: /foo + port: 8002 + initialDelaySeconds: 5 + periodSeconds: 5 diff --git a/istio-1.3.5/samples/helloworld/README.md b/istio-1.3.5/samples/helloworld/README.md new file mode 100644 index 0000000..c4fc552 --- /dev/null +++ b/istio-1.3.5/samples/helloworld/README.md @@ -0,0 +1,69 @@ +# Helloworld service + +This sample runs two versions of a simple helloworld service that return their +version and instance (hostname) when called. It's used to demonstrate canary deployments +working in conjunction with autoscaling. +See [Canary deployments using Istio](https://istio.io/blog/2017/0.1-canary.html). + +## Start the services + +If you don't have [automatic sidecar injection](https://istio.io/docs/setup/kubernetes/sidecar-injection.html#automatic-sidecar-injection) +set in your cluster you will need to manually inject it to the services: + +```bash +istioctl kube-inject -f helloworld.yaml -o helloworld-istio.yaml +``` + +Note that Kubernetes [Horizontal Pod Autoscaler](https://kubernetes.io/docs/tasks/run-application/horizontal-pod-autoscale/) +only work if all containers in the pods requests cpu. In this sample the deployment +containers within the `helloworld.yaml` are pre-defined with the request. The (manually/automatically) +injected istio-proxy containers also have the requests cpu therefore making the `helloworld` +ready for autoscaling. + +Now create the deployment using the updated yaml file and create the gateway configuration: + +```bash +kubectl create -f helloworld-istio.yaml +kubectl create -f helloworld-gateway.yaml +``` + +Follow the [instructions](https://preliminary.istio.io/docs/tasks/traffic-management/ingress.html#determining-the-ingress-ip-and-ports) to set the INGRESS_HOST and INGRESS_PORT variables then confirm it's running using curl. + +```bash +export GATEWAY_URL=$INGRESS_HOST:$INGRESS_PORT +curl http://$GATEWAY_URL/hello +``` + +## Autoscale the services + +Enable autoscale on both services: + +```bash +kubectl autoscale deployment helloworld-v1 --cpu-percent=50 --min=1 --max=10 +kubectl autoscale deployment helloworld-v2 --cpu-percent=50 --min=1 --max=10 +kubectl get hpa +``` + +## Generate load + +```bash +./loadgen.sh & +./loadgen.sh & # run it twice to generate lots of load +``` + +Wait for about 2min and check the number of replicas: + +```bash +kubectl get hpa +``` + +If autoscaler is functioning correctly the `REPLICAS` column should have a +value > 1. + +## Cleanup + +```bash +kubectl delete -f helloworld-istio.yaml +kubectl delete -f helloworld-gateway.yaml +kubectl delete hpa helloworld-v1 helloworld-v2 +``` diff --git a/istio-1.3.5/samples/helloworld/helloworld-gateway.yaml b/istio-1.3.5/samples/helloworld/helloworld-gateway.yaml new file mode 100644 index 0000000..43afc14 --- /dev/null +++ b/istio-1.3.5/samples/helloworld/helloworld-gateway.yaml @@ -0,0 +1,33 @@ +apiVersion: networking.istio.io/v1alpha3 +kind: Gateway +metadata: + name: helloworld-gateway +spec: + selector: + istio: ingressgateway # use istio default controller + servers: + - port: + number: 80 + name: http + protocol: HTTP + hosts: + - "*" +--- +apiVersion: networking.istio.io/v1alpha3 +kind: VirtualService +metadata: + name: helloworld +spec: + hosts: + - "*" + gateways: + - helloworld-gateway + http: + - match: + - uri: + exact: /hello + route: + - destination: + host: helloworld + port: + number: 5000 diff --git a/istio-1.3.5/samples/helloworld/helloworld.yaml b/istio-1.3.5/samples/helloworld/helloworld.yaml new file mode 100644 index 0000000..2563918 --- /dev/null +++ b/istio-1.3.5/samples/helloworld/helloworld.yaml @@ -0,0 +1,68 @@ +apiVersion: v1 +kind: Service +metadata: + name: helloworld + labels: + app: helloworld +spec: + ports: + - port: 5000 + name: http + selector: + app: helloworld +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: helloworld-v1 + labels: + version: v1 +spec: + replicas: 1 + selector: + matchLabels: + app: helloworld + version: v1 + template: + metadata: + labels: + app: helloworld + version: v1 + spec: + containers: + - name: helloworld + image: docker.io/istio/examples-helloworld-v1 + resources: + requests: + cpu: "100m" + imagePullPolicy: IfNotPresent #Always + ports: + - containerPort: 5000 +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: helloworld-v2 + labels: + version: v2 +spec: + replicas: 1 + selector: + matchLabels: + app: helloworld + version: v2 + template: + metadata: + labels: + app: helloworld + version: v2 + spec: + containers: + - name: helloworld + image: docker.io/istio/examples-helloworld-v2 + resources: + requests: + cpu: "100m" + imagePullPolicy: IfNotPresent #Always + ports: + - containerPort: 5000 diff --git a/istio-1.3.5/samples/helloworld/src/requirements.txt b/istio-1.3.5/samples/helloworld/src/requirements.txt new file mode 100644 index 0000000..ac286ea --- /dev/null +++ b/istio-1.3.5/samples/helloworld/src/requirements.txt @@ -0,0 +1,7 @@ +requests +flask +flask_json +flask_bootstrap +json2html +simplejson +gevent diff --git a/istio-1.3.5/samples/httpbin/README.md b/istio-1.3.5/samples/httpbin/README.md new file mode 100644 index 0000000..85d82be --- /dev/null +++ b/istio-1.3.5/samples/httpbin/README.md @@ -0,0 +1,38 @@ +# Httpbin service + +This sample runs [httpbin](https://httpbin.org) as an Istio service. +Httpbin is a well known HTTP testing service that can be used for experimenting +with all kinds of Istio features. + +To use it: + +1. Install Istio by following the [istio install instructions](https://istio.io/docs/setup/kubernetes/). + +2. Start the httpbin service inside the Istio service mesh: + + If you have [automatic sidecar injection](https://istio.io/docs/setup/kubernetes/additional-setup/sidecar-injection/#automatic-sidecar-injection) enabled: + + ```bash + kubectl apply -f httpbin.yaml + ``` + + Otherwise manually inject the sidecars before applying: + + ```bash + kubectl apply -f <(istioctl kube-inject -f httpbin.yaml) + ``` + +Because the httpbin service is not exposed outside of the cluster +we cannot _curl_ it directly, however we can verify that it is working correctly using +a _curl_ command against `httpbin:8000` *from inside the cluster* using the public _dockerqa/curl_ +image from the Docker hub: + +```bash +kubectl run -i --rm --restart=Never dummy --image=dockerqa/curl:ubuntu-trusty --command -- curl --silent httpbin:8000/html +kubectl run -i --rm --restart=Never dummy --image=dockerqa/curl:ubuntu-trusty --command -- curl --silent --head httpbin:8000/status/500 +time kubectl run -i --rm --restart=Never dummy --image=dockerqa/curl:ubuntu-trusty --command -- curl --silent httpbin:8000/delay/5 +``` + +You can also test the httpbin service by starting the [sleep service](../sleep) and calling httpbin from it. + +A third option is to access the service from outside of the mesh through an Ingress Gateway. The [Ingress Gateways](https://istio.io/docs/tasks/traffic-management/ingress/ingress-control/) task explains how to do it. diff --git a/istio-1.3.5/samples/httpbin/httpbin-gateway.yaml b/istio-1.3.5/samples/httpbin/httpbin-gateway.yaml new file mode 100644 index 0000000..99ac6ee --- /dev/null +++ b/istio-1.3.5/samples/httpbin/httpbin-gateway.yaml @@ -0,0 +1,30 @@ +apiVersion: networking.istio.io/v1alpha3 +kind: Gateway +metadata: + name: httpbin-gateway +spec: + selector: + istio: ingressgateway + servers: + - port: + number: 80 + name: http + protocol: HTTP + hosts: + - "*" +--- +apiVersion: networking.istio.io/v1alpha3 +kind: VirtualService +metadata: + name: httpbin +spec: + hosts: + - "*" + gateways: + - httpbin-gateway + http: + - route: + - destination: + host: httpbin + port: + number: 8000 diff --git a/istio-1.3.5/samples/httpbin/httpbin-nodeport.yaml b/istio-1.3.5/samples/httpbin/httpbin-nodeport.yaml new file mode 100644 index 0000000..a42b55c --- /dev/null +++ b/istio-1.3.5/samples/httpbin/httpbin-nodeport.yaml @@ -0,0 +1,54 @@ +# Copyright 2017 Istio Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +################################################################################################## +# httpbin service +################################################################################################## +apiVersion: v1 +kind: Service +metadata: + name: httpbin + labels: + app: httpbin +spec: + type: NodePort + ports: + - name: http + port: 8000 + targetPort: 80 + selector: + app: httpbin +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: httpbin +spec: + replicas: 1 + selector: + matchLabels: + app: httpbin + version: v1 + template: + metadata: + labels: + app: httpbin + version: v1 + spec: + containers: + - image: docker.io/kennethreitz/httpbin + imagePullPolicy: IfNotPresent + name: httpbin + ports: + - containerPort: 80 diff --git a/istio-1.3.5/samples/httpbin/httpbin-vault.yaml b/istio-1.3.5/samples/httpbin/httpbin-vault.yaml new file mode 100644 index 0000000..d05e954 --- /dev/null +++ b/istio-1.3.5/samples/httpbin/httpbin-vault.yaml @@ -0,0 +1,54 @@ +# Copyright 2019 Istio Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +################################################################################################## +# httpbin service +################################################################################################## +apiVersion: v1 +kind: Service +metadata: + name: httpbin + labels: + app: httpbin +spec: + ports: + - name: http + port: 8000 + targetPort: 80 + selector: + app: httpbin +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: httpbin +spec: + replicas: 1 + selector: + matchLabels: + app: httpbin + version: v1 + template: + metadata: + labels: + app: httpbin + version: v1 + spec: + serviceAccountName: vault-citadel-sa + containers: + - image: docker.io/kennethreitz/httpbin + imagePullPolicy: IfNotPresent + name: httpbin + ports: + - containerPort: 80 diff --git a/istio-1.3.5/samples/httpbin/httpbin.yaml b/istio-1.3.5/samples/httpbin/httpbin.yaml new file mode 100644 index 0000000..bd2880f --- /dev/null +++ b/istio-1.3.5/samples/httpbin/httpbin.yaml @@ -0,0 +1,53 @@ +# Copyright 2017 Istio Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +################################################################################################## +# httpbin service +################################################################################################## +apiVersion: v1 +kind: Service +metadata: + name: httpbin + labels: + app: httpbin +spec: + ports: + - name: http + port: 8000 + targetPort: 80 + selector: + app: httpbin +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: httpbin +spec: + replicas: 1 + selector: + matchLabels: + app: httpbin + version: v1 + template: + metadata: + labels: + app: httpbin + version: v1 + spec: + containers: + - image: docker.io/kennethreitz/httpbin + imagePullPolicy: IfNotPresent + name: httpbin + ports: + - containerPort: 80 diff --git a/istio-1.3.5/samples/httpbin/policy/keyval-template.yaml b/istio-1.3.5/samples/httpbin/policy/keyval-template.yaml new file mode 100644 index 0000000..c194bc5 --- /dev/null +++ b/istio-1.3.5/samples/httpbin/policy/keyval-template.yaml @@ -0,0 +1,10 @@ +# this config is created through command +# mixgen template -d $GOPATH/src/istio.io/istio/mixer/test/keyval/template_handler_service.descriptor_set -o $GOPATH/src/istio.io/istio/mixer/test/keyval/template.yaml -n keyval +apiVersion: "config.istio.io/v1alpha2" +kind: template +metadata: + name: keyval + namespace: istio-system +spec: + descriptor: "CvD6AgogZ29vZ2xlL3Byb3RvYnVmL2Rlc2NyaXB0b3IucHJvdG8SD2dvb2dsZS5wcm90b2J1ZiJNChFGaWxlRGVzY3JpcHRvclNldBI4CgRmaWxlGAEgAygLMiQuZ29vZ2xlLnByb3RvYnVmLkZpbGVEZXNjcmlwdG9yUHJvdG9SBGZpbGUi5AQKE0ZpbGVEZXNjcmlwdG9yUHJvdG8SEgoEbmFtZRgBIAEoCVIEbmFtZRIYCgdwYWNrYWdlGAIgASgJUgdwYWNrYWdlEh4KCmRlcGVuZGVuY3kYAyADKAlSCmRlcGVuZGVuY3kSKwoRcHVibGljX2RlcGVuZGVuY3kYCiADKAVSEHB1YmxpY0RlcGVuZGVuY3kSJwoPd2Vha19kZXBlbmRlbmN5GAsgAygFUg53ZWFrRGVwZW5kZW5jeRJDCgxtZXNzYWdlX3R5cGUYBCADKAsyIC5nb29nbGUucHJvdG9idWYuRGVzY3JpcHRvclByb3RvUgttZXNzYWdlVHlwZRJBCgllbnVtX3R5cGUYBSADKAsyJC5nb29nbGUucHJvdG9idWYuRW51bURlc2NyaXB0b3JQcm90b1IIZW51bVR5cGUSQQoHc2VydmljZRgGIAMoCzInLmdvb2dsZS5wcm90b2J1Zi5TZXJ2aWNlRGVzY3JpcHRvclByb3RvUgdzZXJ2aWNlEkMKCWV4dGVuc2lvbhgHIAMoCzIlLmdvb2dsZS5wcm90b2J1Zi5GaWVsZERlc2NyaXB0b3JQcm90b1IJZXh0ZW5zaW9uEjYKB29wdGlvbnMYCCABKAsyHC5nb29nbGUucHJvdG9idWYuRmlsZU9wdGlvbnNSB29wdGlvbnMSSQoQc291cmNlX2NvZGVfaW5mbxgJIAEoCzIfLmdvb2dsZS5wcm90b2J1Zi5Tb3VyY2VDb2RlSW5mb1IOc291cmNlQ29kZUluZm8SFgoGc3ludGF4GAwgASgJUgZzeW50YXgiuQYKD0Rlc2NyaXB0b3JQcm90bxISCgRuYW1lGAEgASgJUgRuYW1lEjsKBWZpZWxkGAIgAygLMiUuZ29vZ2xlLnByb3RvYnVmLkZpZWxkRGVzY3JpcHRvclByb3RvUgVmaWVsZBJDCglleHRlbnNpb24YBiADKAsyJS5nb29nbGUucHJvdG9idWYuRmllbGREZXNjcmlwdG9yUHJvdG9SCWV4dGVuc2lvbhJBCgtuZXN0ZWRfdHlwZRgDIAMoCzIgLmdvb2dsZS5wcm90b2J1Zi5EZXNjcmlwdG9yUHJvdG9SCm5lc3RlZFR5cGUSQQoJZW51bV90eXBlGAQgAygLMiQuZ29vZ2xlLnByb3RvYnVmLkVudW1EZXNjcmlwdG9yUHJvdG9SCGVudW1UeXBlElgKD2V4dGVuc2lvbl9yYW5nZRgFIAMoCzIvLmdvb2dsZS5wcm90b2J1Zi5EZXNjcmlwdG9yUHJvdG8uRXh0ZW5zaW9uUmFuZ2VSDmV4dGVuc2lvblJhbmdlEkQKCm9uZW9mX2RlY2wYCCADKAsyJS5nb29nbGUucHJvdG9idWYuT25lb2ZEZXNjcmlwdG9yUHJvdG9SCW9uZW9mRGVjbBI5CgdvcHRpb25zGAcgASgLMh8uZ29vZ2xlLnByb3RvYnVmLk1lc3NhZ2VPcHRpb25zUgdvcHRpb25zElUKDnJlc2VydmVkX3JhbmdlGAkgAygLMi4uZ29vZ2xlLnByb3RvYnVmLkRlc2NyaXB0b3JQcm90by5SZXNlcnZlZFJhbmdlUg1yZXNlcnZlZFJhbmdlEiMKDXJlc2VydmVkX25hbWUYCiADKAlSDHJlc2VydmVkTmFtZRp6Cg5FeHRlbnNpb25SYW5nZRIUCgVzdGFydBgBIAEoBVIFc3RhcnQSEAoDZW5kGAIgASgFUgNlbmQSQAoHb3B0aW9ucxgDIAEoCzImLmdvb2dsZS5wcm90b2J1Zi5FeHRlbnNpb25SYW5nZU9wdGlvbnNSB29wdGlvbnMaNwoNUmVzZXJ2ZWRSYW5nZRIUCgVzdGFydBgBIAEoBVIFc3RhcnQSEAoDZW5kGAIgASgFUgNlbmQifAoVRXh0ZW5zaW9uUmFuZ2VPcHRpb25zElgKFHVuaW50ZXJwcmV0ZWRfb3B0aW9uGOcHIAMoCzIkLmdvb2dsZS5wcm90b2J1Zi5VbmludGVycHJldGVkT3B0aW9uUhN1bmludGVycHJldGVkT3B0aW9uKgkI6AcQgICAgAIimAYKFEZpZWxkRGVzY3JpcHRvclByb3RvEhIKBG5hbWUYASABKAlSBG5hbWUSFgoGbnVtYmVyGAMgASgFUgZudW1iZXISQQoFbGFiZWwYBCABKA4yKy5nb29nbGUucHJvdG9idWYuRmllbGREZXNjcmlwdG9yUHJvdG8uTGFiZWxSBWxhYmVsEj4KBHR5cGUYBSABKA4yKi5nb29nbGUucHJvdG9idWYuRmllbGREZXNjcmlwdG9yUHJvdG8uVHlwZVIEdHlwZRIbCgl0eXBlX25hbWUYBiABKAlSCHR5cGVOYW1lEhoKCGV4dGVuZGVlGAIgASgJUghleHRlbmRlZRIjCg1kZWZhdWx0X3ZhbHVlGAcgASgJUgxkZWZhdWx0VmFsdWUSHwoLb25lb2ZfaW5kZXgYCSABKAVSCm9uZW9mSW5kZXgSGwoJanNvbl9uYW1lGAogASgJUghqc29uTmFtZRI3CgdvcHRpb25zGAggASgLMh0uZ29vZ2xlLnByb3RvYnVmLkZpZWxkT3B0aW9uc1IHb3B0aW9ucyK2AgoEVHlwZRIPCgtUWVBFX0RPVUJMRRABEg4KClRZUEVfRkxPQVQQAhIOCgpUWVBFX0lOVDY0EAMSDwoLVFlQRV9VSU5UNjQQBBIOCgpUWVBFX0lOVDMyEAUSEAoMVFlQRV9GSVhFRDY0EAYSEAoMVFlQRV9GSVhFRDMyEAcSDQoJVFlQRV9CT09MEAgSDwoLVFlQRV9TVFJJTkcQCRIOCgpUWVBFX0dST1VQEAoSEAoMVFlQRV9NRVNTQUdFEAsSDgoKVFlQRV9CWVRFUxAMEg8KC1RZUEVfVUlOVDMyEA0SDQoJVFlQRV9FTlVNEA4SEQoNVFlQRV9TRklYRUQzMhAPEhEKDVRZUEVfU0ZJWEVENjQQEBIPCgtUWVBFX1NJTlQzMhAREg8KC1RZUEVfU0lOVDY0EBIiQwoFTGFiZWwSEgoOTEFCRUxfT1BUSU9OQUwQARISCg5MQUJFTF9SRVFVSVJFRBACEhIKDkxBQkVMX1JFUEVBVEVEEAMiYwoUT25lb2ZEZXNjcmlwdG9yUHJvdG8SEgoEbmFtZRgBIAEoCVIEbmFtZRI3CgdvcHRpb25zGAIgASgLMh0uZ29vZ2xlLnByb3RvYnVmLk9uZW9mT3B0aW9uc1IHb3B0aW9ucyLjAgoTRW51bURlc2NyaXB0b3JQcm90bxISCgRuYW1lGAEgASgJUgRuYW1lEj8KBXZhbHVlGAIgAygLMikuZ29vZ2xlLnByb3RvYnVmLkVudW1WYWx1ZURlc2NyaXB0b3JQcm90b1IFdmFsdWUSNgoHb3B0aW9ucxgDIAEoCzIcLmdvb2dsZS5wcm90b2J1Zi5FbnVtT3B0aW9uc1IHb3B0aW9ucxJdCg5yZXNlcnZlZF9yYW5nZRgEIAMoCzI2Lmdvb2dsZS5wcm90b2J1Zi5FbnVtRGVzY3JpcHRvclByb3RvLkVudW1SZXNlcnZlZFJhbmdlUg1yZXNlcnZlZFJhbmdlEiMKDXJlc2VydmVkX25hbWUYBSADKAlSDHJlc2VydmVkTmFtZRo7ChFFbnVtUmVzZXJ2ZWRSYW5nZRIUCgVzdGFydBgBIAEoBVIFc3RhcnQSEAoDZW5kGAIgASgFUgNlbmQigwEKGEVudW1WYWx1ZURlc2NyaXB0b3JQcm90bxISCgRuYW1lGAEgASgJUgRuYW1lEhYKBm51bWJlchgCIAEoBVIGbnVtYmVyEjsKB29wdGlvbnMYAyABKAsyIS5nb29nbGUucHJvdG9idWYuRW51bVZhbHVlT3B0aW9uc1IHb3B0aW9ucyKnAQoWU2VydmljZURlc2NyaXB0b3JQcm90bxISCgRuYW1lGAEgASgJUgRuYW1lEj4KBm1ldGhvZBgCIAMoCzImLmdvb2dsZS5wcm90b2J1Zi5NZXRob2REZXNjcmlwdG9yUHJvdG9SBm1ldGhvZBI5CgdvcHRpb25zGAMgASgLMh8uZ29vZ2xlLnByb3RvYnVmLlNlcnZpY2VPcHRpb25zUgdvcHRpb25zIokCChVNZXRob2REZXNjcmlwdG9yUHJvdG8SEgoEbmFtZRgBIAEoCVIEbmFtZRIdCgppbnB1dF90eXBlGAIgASgJUglpbnB1dFR5cGUSHwoLb3V0cHV0X3R5cGUYAyABKAlSCm91dHB1dFR5cGUSOAoHb3B0aW9ucxgEIAEoCzIeLmdvb2dsZS5wcm90b2J1Zi5NZXRob2RPcHRpb25zUgdvcHRpb25zEjAKEGNsaWVudF9zdHJlYW1pbmcYBSABKAg6BWZhbHNlUg9jbGllbnRTdHJlYW1pbmcSMAoQc2VydmVyX3N0cmVhbWluZxgGIAEoCDoFZmFsc2VSD3NlcnZlclN0cmVhbWluZyK5CAoLRmlsZU9wdGlvbnMSIQoMamF2YV9wYWNrYWdlGAEgASgJUgtqYXZhUGFja2FnZRIwChRqYXZhX291dGVyX2NsYXNzbmFtZRgIIAEoCVISamF2YU91dGVyQ2xhc3NuYW1lEjUKE2phdmFfbXVsdGlwbGVfZmlsZXMYCiABKAg6BWZhbHNlUhFqYXZhTXVsdGlwbGVGaWxlcxJECh1qYXZhX2dlbmVyYXRlX2VxdWFsc19hbmRfaGFzaBgUIAEoCEICGAFSGWphdmFHZW5lcmF0ZUVxdWFsc0FuZEhhc2gSOgoWamF2YV9zdHJpbmdfY2hlY2tfdXRmOBgbIAEoCDoFZmFsc2VSE2phdmFTdHJpbmdDaGVja1V0ZjgSUwoMb3B0aW1pemVfZm9yGAkgASgOMikuZ29vZ2xlLnByb3RvYnVmLkZpbGVPcHRpb25zLk9wdGltaXplTW9kZToFU1BFRURSC29wdGltaXplRm9yEh0KCmdvX3BhY2thZ2UYCyABKAlSCWdvUGFja2FnZRI1ChNjY19nZW5lcmljX3NlcnZpY2VzGBAgASgIOgVmYWxzZVIRY2NHZW5lcmljU2VydmljZXMSOQoVamF2YV9nZW5lcmljX3NlcnZpY2VzGBEgASgIOgVmYWxzZVITamF2YUdlbmVyaWNTZXJ2aWNlcxI1ChNweV9nZW5lcmljX3NlcnZpY2VzGBIgASgIOgVmYWxzZVIRcHlHZW5lcmljU2VydmljZXMSNwoUcGhwX2dlbmVyaWNfc2VydmljZXMYKiABKAg6BWZhbHNlUhJwaHBHZW5lcmljU2VydmljZXMSJQoKZGVwcmVjYXRlZBgXIAEoCDoFZmFsc2VSCmRlcHJlY2F0ZWQSLwoQY2NfZW5hYmxlX2FyZW5hcxgfIAEoCDoFZmFsc2VSDmNjRW5hYmxlQXJlbmFzEioKEW9iamNfY2xhc3NfcHJlZml4GCQgASgJUg9vYmpjQ2xhc3NQcmVmaXgSKQoQY3NoYXJwX25hbWVzcGFjZRglIAEoCVIPY3NoYXJwTmFtZXNwYWNlEiEKDHN3aWZ0X3ByZWZpeBgnIAEoCVILc3dpZnRQcmVmaXgSKAoQcGhwX2NsYXNzX3ByZWZpeBgoIAEoCVIOcGhwQ2xhc3NQcmVmaXgSIwoNcGhwX25hbWVzcGFjZRgpIAEoCVIMcGhwTmFtZXNwYWNlElgKFHVuaW50ZXJwcmV0ZWRfb3B0aW9uGOcHIAMoCzIkLmdvb2dsZS5wcm90b2J1Zi5VbmludGVycHJldGVkT3B0aW9uUhN1bmludGVycHJldGVkT3B0aW9uIjoKDE9wdGltaXplTW9kZRIJCgVTUEVFRBABEg0KCUNPREVfU0laRRACEhAKDExJVEVfUlVOVElNRRADKgkI6AcQgICAgAJKBAgmECci0QIKDk1lc3NhZ2VPcHRpb25zEjwKF21lc3NhZ2Vfc2V0X3dpcmVfZm9ybWF0GAEgASgIOgVmYWxzZVIUbWVzc2FnZVNldFdpcmVGb3JtYXQSTAofbm9fc3RhbmRhcmRfZGVzY3JpcHRvcl9hY2Nlc3NvchgCIAEoCDoFZmFsc2VSHG5vU3RhbmRhcmREZXNjcmlwdG9yQWNjZXNzb3ISJQoKZGVwcmVjYXRlZBgDIAEoCDoFZmFsc2VSCmRlcHJlY2F0ZWQSGwoJbWFwX2VudHJ5GAcgASgIUghtYXBFbnRyeRJYChR1bmludGVycHJldGVkX29wdGlvbhjnByADKAsyJC5nb29nbGUucHJvdG9idWYuVW5pbnRlcnByZXRlZE9wdGlvblITdW5pbnRlcnByZXRlZE9wdGlvbioJCOgHEICAgIACSgQICBAJSgQICRAKIuIDCgxGaWVsZE9wdGlvbnMSQQoFY3R5cGUYASABKA4yIy5nb29nbGUucHJvdG9idWYuRmllbGRPcHRpb25zLkNUeXBlOgZTVFJJTkdSBWN0eXBlEhYKBnBhY2tlZBgCIAEoCFIGcGFja2VkEkcKBmpzdHlwZRgGIAEoDjIkLmdvb2dsZS5wcm90b2J1Zi5GaWVsZE9wdGlvbnMuSlNUeXBlOglKU19OT1JNQUxSBmpzdHlwZRIZCgRsYXp5GAUgASgIOgVmYWxzZVIEbGF6eRIlCgpkZXByZWNhdGVkGAMgASgIOgVmYWxzZVIKZGVwcmVjYXRlZBIZCgR3ZWFrGAogASgIOgVmYWxzZVIEd2VhaxJYChR1bmludGVycHJldGVkX29wdGlvbhjnByADKAsyJC5nb29nbGUucHJvdG9idWYuVW5pbnRlcnByZXRlZE9wdGlvblITdW5pbnRlcnByZXRlZE9wdGlvbiIvCgVDVHlwZRIKCgZTVFJJTkcQABIICgRDT1JEEAESEAoMU1RSSU5HX1BJRUNFEAIiNQoGSlNUeXBlEg0KCUpTX05PUk1BTBAAEg0KCUpTX1NUUklORxABEg0KCUpTX05VTUJFUhACKgkI6AcQgICAgAJKBAgEEAUicwoMT25lb2ZPcHRpb25zElgKFHVuaW50ZXJwcmV0ZWRfb3B0aW9uGOcHIAMoCzIkLmdvb2dsZS5wcm90b2J1Zi5VbmludGVycHJldGVkT3B0aW9uUhN1bmludGVycHJldGVkT3B0aW9uKgkI6AcQgICAgAIiwAEKC0VudW1PcHRpb25zEh8KC2FsbG93X2FsaWFzGAIgASgIUgphbGxvd0FsaWFzEiUKCmRlcHJlY2F0ZWQYAyABKAg6BWZhbHNlUgpkZXByZWNhdGVkElgKFHVuaW50ZXJwcmV0ZWRfb3B0aW9uGOcHIAMoCzIkLmdvb2dsZS5wcm90b2J1Zi5VbmludGVycHJldGVkT3B0aW9uUhN1bmludGVycHJldGVkT3B0aW9uKgkI6AcQgICAgAJKBAgFEAYingEKEEVudW1WYWx1ZU9wdGlvbnMSJQoKZGVwcmVjYXRlZBgBIAEoCDoFZmFsc2VSCmRlcHJlY2F0ZWQSWAoUdW5pbnRlcnByZXRlZF9vcHRpb24Y5wcgAygLMiQuZ29vZ2xlLnByb3RvYnVmLlVuaW50ZXJwcmV0ZWRPcHRpb25SE3VuaW50ZXJwcmV0ZWRPcHRpb24qCQjoBxCAgICAAiKcAQoOU2VydmljZU9wdGlvbnMSJQoKZGVwcmVjYXRlZBghIAEoCDoFZmFsc2VSCmRlcHJlY2F0ZWQSWAoUdW5pbnRlcnByZXRlZF9vcHRpb24Y5wcgAygLMiQuZ29vZ2xlLnByb3RvYnVmLlVuaW50ZXJwcmV0ZWRPcHRpb25SE3VuaW50ZXJwcmV0ZWRPcHRpb24qCQjoBxCAgICAAiLgAgoNTWV0aG9kT3B0aW9ucxIlCgpkZXByZWNhdGVkGCEgASgIOgVmYWxzZVIKZGVwcmVjYXRlZBJxChFpZGVtcG90ZW5jeV9sZXZlbBgiIAEoDjIvLmdvb2dsZS5wcm90b2J1Zi5NZXRob2RPcHRpb25zLklkZW1wb3RlbmN5TGV2ZWw6E0lERU1QT1RFTkNZX1VOS05PV05SEGlkZW1wb3RlbmN5TGV2ZWwSWAoUdW5pbnRlcnByZXRlZF9vcHRpb24Y5wcgAygLMiQuZ29vZ2xlLnByb3RvYnVmLlVuaW50ZXJwcmV0ZWRPcHRpb25SE3VuaW50ZXJwcmV0ZWRPcHRpb24iUAoQSWRlbXBvdGVuY3lMZXZlbBIXChNJREVNUE9URU5DWV9VTktOT1dOEAASEwoPTk9fU0lERV9FRkZFQ1RTEAESDgoKSURFTVBPVEVOVBACKgkI6AcQgICAgAIimgMKE1VuaW50ZXJwcmV0ZWRPcHRpb24SQQoEbmFtZRgCIAMoCzItLmdvb2dsZS5wcm90b2J1Zi5VbmludGVycHJldGVkT3B0aW9uLk5hbWVQYXJ0UgRuYW1lEikKEGlkZW50aWZpZXJfdmFsdWUYAyABKAlSD2lkZW50aWZpZXJWYWx1ZRIsChJwb3NpdGl2ZV9pbnRfdmFsdWUYBCABKARSEHBvc2l0aXZlSW50VmFsdWUSLAoSbmVnYXRpdmVfaW50X3ZhbHVlGAUgASgDUhBuZWdhdGl2ZUludFZhbHVlEiEKDGRvdWJsZV92YWx1ZRgGIAEoAVILZG91YmxlVmFsdWUSIQoMc3RyaW5nX3ZhbHVlGAcgASgMUgtzdHJpbmdWYWx1ZRInCg9hZ2dyZWdhdGVfdmFsdWUYCCABKAlSDmFnZ3JlZ2F0ZVZhbHVlGkoKCE5hbWVQYXJ0EhsKCW5hbWVfcGFydBgBIAIoCVIIbmFtZVBhcnQSIQoMaXNfZXh0ZW5zaW9uGAIgAigIUgtpc0V4dGVuc2lvbiKnAgoOU291cmNlQ29kZUluZm8SRAoIbG9jYXRpb24YASADKAsyKC5nb29nbGUucHJvdG9idWYuU291cmNlQ29kZUluZm8uTG9jYXRpb25SCGxvY2F0aW9uGs4BCghMb2NhdGlvbhIWCgRwYXRoGAEgAygFQgIQAVIEcGF0aBIWCgRzcGFuGAIgAygFQgIQAVIEc3BhbhIpChBsZWFkaW5nX2NvbW1lbnRzGAMgASgJUg9sZWFkaW5nQ29tbWVudHMSKwoRdHJhaWxpbmdfY29tbWVudHMYBCABKAlSEHRyYWlsaW5nQ29tbWVudHMSOgoZbGVhZGluZ19kZXRhY2hlZF9jb21tZW50cxgGIAMoCVIXbGVhZGluZ0RldGFjaGVkQ29tbWVudHMi0QEKEUdlbmVyYXRlZENvZGVJbmZvEk0KCmFubm90YXRpb24YASADKAsyLS5nb29nbGUucHJvdG9idWYuR2VuZXJhdGVkQ29kZUluZm8uQW5ub3RhdGlvblIKYW5ub3RhdGlvbhptCgpBbm5vdGF0aW9uEhYKBHBhdGgYASADKAVCAhABUgRwYXRoEh8KC3NvdXJjZV9maWxlGAIgASgJUgpzb3VyY2VGaWxlEhQKBWJlZ2luGAMgASgFUgViZWdpbhIQCgNlbmQYBCABKAVSA2VuZEKPAQoTY29tLmdvb2dsZS5wcm90b2J1ZkIQRGVzY3JpcHRvclByb3Rvc0gBWj5naXRodWIuY29tL2dvbGFuZy9wcm90b2J1Zi9wcm90b2MtZ2VuLWdvL2Rlc2NyaXB0b3I7ZGVzY3JpcHRvcvgBAaICA0dQQqoCGkdvb2dsZS5Qcm90b2J1Zi5SZWZsZWN0aW9uSqrAAgoHEgUnAOcGAQqqDwoBDBIDJwASMsEMIFByb3RvY29sIEJ1ZmZlcnMgLSBHb29nbGUncyBkYXRhIGludGVyY2hhbmdlIGZvcm1hdAogQ29weXJpZ2h0IDIwMDggR29vZ2xlIEluYy4gIEFsbCByaWdodHMgcmVzZXJ2ZWQuCiBodHRwczovL2RldmVsb3BlcnMuZ29vZ2xlLmNvbS9wcm90b2NvbC1idWZmZXJzLwoKIFJlZGlzdHJpYnV0aW9uIGFuZCB1c2UgaW4gc291cmNlIGFuZCBiaW5hcnkgZm9ybXMsIHdpdGggb3Igd2l0aG91dAogbW9kaWZpY2F0aW9uLCBhcmUgcGVybWl0dGVkIHByb3ZpZGVkIHRoYXQgdGhlIGZvbGxvd2luZyBjb25kaXRpb25zIGFyZQogbWV0OgoKICAgICAqIFJlZGlzdHJpYnV0aW9ucyBvZiBzb3VyY2UgY29kZSBtdXN0IHJldGFpbiB0aGUgYWJvdmUgY29weXJpZ2h0CiBub3RpY2UsIHRoaXMgbGlzdCBvZiBjb25kaXRpb25zIGFuZCB0aGUgZm9sbG93aW5nIGRpc2NsYWltZXIuCiAgICAgKiBSZWRpc3RyaWJ1dGlvbnMgaW4gYmluYXJ5IGZvcm0gbXVzdCByZXByb2R1Y2UgdGhlIGFib3ZlCiBjb3B5cmlnaHQgbm90aWNlLCB0aGlzIGxpc3Qgb2YgY29uZGl0aW9ucyBhbmQgdGhlIGZvbGxvd2luZyBkaXNjbGFpbWVyCiBpbiB0aGUgZG9jdW1lbnRhdGlvbiBhbmQvb3Igb3RoZXIgbWF0ZXJpYWxzIHByb3ZpZGVkIHdpdGggdGhlCiBkaXN0cmlidXRpb24uCiAgICAgKiBOZWl0aGVyIHRoZSBuYW1lIG9mIEdvb2dsZSBJbmMuIG5vciB0aGUgbmFtZXMgb2YgaXRzCiBjb250cmlidXRvcnMgbWF5IGJlIHVzZWQgdG8gZW5kb3JzZSBvciBwcm9tb3RlIHByb2R1Y3RzIGRlcml2ZWQgZnJvbQogdGhpcyBzb2Z0d2FyZSB3aXRob3V0IHNwZWNpZmljIHByaW9yIHdyaXR0ZW4gcGVybWlzc2lvbi4KCiBUSElTIFNPRlRXQVJFIElTIFBST1ZJREVEIEJZIFRIRSBDT1BZUklHSFQgSE9MREVSUyBBTkQgQ09OVFJJQlVUT1JTCiAiQVMgSVMiIEFORCBBTlkgRVhQUkVTUyBPUiBJTVBMSUVEIFdBUlJBTlRJRVMsIElOQ0xVRElORywgQlVUIE5PVAogTElNSVRFRCBUTywgVEhFIElNUExJRUQgV0FSUkFOVElFUyBPRiBNRVJDSEFOVEFCSUxJVFkgQU5EIEZJVE5FU1MgRk9SCiBBIFBBUlRJQ1VMQVIgUFVSUE9TRSBBUkUgRElTQ0xBSU1FRC4gSU4gTk8gRVZFTlQgU0hBTEwgVEhFIENPUFlSSUdIVAogT1dORVIgT1IgQ09OVFJJQlVUT1JTIEJFIExJQUJMRSBGT1IgQU5ZIERJUkVDVCwgSU5ESVJFQ1QsIElOQ0lERU5UQUwsCiBTUEVDSUFMLCBFWEVNUExBUlksIE9SIENPTlNFUVVFTlRJQUwgREFNQUdFUyAoSU5DTFVESU5HLCBCVVQgTk9UCiBMSU1JVEVEIFRPLCBQUk9DVVJFTUVOVCBPRiBTVUJTVElUVVRFIEdPT0RTIE9SIFNFUlZJQ0VTOyBMT1NTIE9GIFVTRSwKIERBVEEsIE9SIFBST0ZJVFM7IE9SIEJVU0lORVNTIElOVEVSUlVQVElPTikgSE9XRVZFUiBDQVVTRUQgQU5EIE9OIEFOWQogVEhFT1JZIE9GIExJQUJJTElUWSwgV0hFVEhFUiBJTiBDT05UUkFDVCwgU1RSSUNUIExJQUJJTElUWSwgT1IgVE9SVAogKElOQ0xVRElORyBORUdMSUdF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bm5vdAogc3RvcmUgdGhlIHZhbHVlcyBpbiB0aGVtLiAgSW5zdGVhZCBpdCBzdG9yZXMgdGhlbSBpbiBhIGZpZWxkIGluIHRoZSAqT3B0aW9ucwogbWVzc2FnZSBjYWxsZWQgdW5pbnRlcnByZXRlZF9vcHRpb24uIFRoaXMgZmllbGQgbXVzdCBoYXZlIHRoZSBzYW1lIG5hbWUKIGFjcm9zcyBhbGwgKk9wdGlvbnMgbWVzc2FnZXMuIFdlIHRoZW4gdXNlIHRoaXMgZmllbGQgdG8gcG9wdWxhdGUgdGhlCiBleHRlbnNpb25zIHdoZW4gd2UgYnVpbGQgYSBkZXNjcmlwdG9yLCBhdCB3aGljaCBwb2ludCBhbGwgcHJvdG9zIGhhdmUgYmVlbgogcGFyc2VkIGFuZCBzbyBhbGwgZXh0ZW5zaW9ucyBhcmUga25vd24uCgogRXh0ZW5zaW9uIG51bWJlcnMgZm9yIGN1c3RvbSBvcHRpb25zIG1heSBiZSBjaG9zZW4gYXMgZm9sbG93czoKICogRm9yIG9wdGlvbnMgd2hpY2ggd2lsbCBvbmx5IGJlIHVzZWQgd2l0aGluIGEgc2luZ2xlIGFwcGxpY2F0aW9uIG9yCiAgIG9yZ2FuaXphdGlvbiwgb3IgZm9yIGV4cGVyaW1lbnRhbCBvcHRpb25zLCB1c2UgZmllbGQgbnVtYmVycyA1MDAwMAogICB0aHJvdWdoIDk5OTk5LiAgSXQgaXMgdXAgdG8geW91IHRvIGVuc3VyZSB0aGF0IHlvdSBkbyBub3QgdXNlIHRoZQogICBzYW1lIG51bWJlciBmb3IgbXVsdGlwbGUgb3B0aW9ucy4KICogRm9yIG9wdGlvbnMgd2hpY2ggd2lsbCBiZSBwdWJsaXNoZWQgYW5kIHVzZWQgcHVibGljbHkgYnkgbXVsdGlwbGUKICAgaW5kZXBlbmRlbnQgZW50aXRpZXMsIGUtbWFpbCBwcm90b2J1Zi1nbG9iYWwtZXh0ZW5zaW9uLXJlZ2lzdHJ5QGdvb2dsZS5jb20KICAgdG8gcmVzZXJ2ZSBleHRlbnNpb24gbnVtYmVycy4gU2ltcGx5IHByb3ZpZGUgeW91ciBwcm9qZWN0IG5hbWUgKGUuZy4KICAgT2JqZWN0aXZlLUMgcGx1Z2luKSBhbmQgeW91ciBwcm9qZWN0IHdlYnNpdGUgKGlmIGF2YWlsYWJsZSkgLS0gdGhlcmUncyBubwogICBuZWVkIHRvIGV4cGxhaW4gaG93IHlvdSBpbnRlbmQgdG8gdXNlIHRoZW0uIFVzdWFsbHkgeW91IG9ubHkgbmVlZCBvbmUKICAgZXh0ZW5zaW9uIG51bWJlci4gWW91IGNhbiBkZWNsYXJlIG11bHRpcGxlIG9wdGlvbnMgd2l0aCBvbmx5IG9uZSBleHRlbnNpb24KICAgbnVtYmVyIGJ5IHB1dHRpbmcgdGhlbSBpbiBhIHN1Yi1tZXNzYWdlLiBTZWUgdGhlIEN1c3RvbSBPcHRpb25zIHNlY3Rpb24gb2YKICAgdGhlIGRvY3MgZm9yIGV4YW1wbGVzOgogICBodHRwczovL2RldmVsb3BlcnMuZ29vZ2xlLmNvbS9wcm90b2NvbC1idWZmZXJzL2RvY3MvcHJvdG8jb3B0aW9ucwogICBJZiB0aGlzIHR1cm5zIG91dCB0byBiZSBwb3B1bGFyLCBhIHdlYiBzZXJ2aWNlIHdpbGwgYmUgc2V0IHVwCiAgIHRvIGF1dG9tYXRpY2FsbHkgYXNzaWduIG9wdGlvbiBudW1iZXJzLgoKCwoDBAoBEgS9AggTCvQBCgQECgIAEgTDAgIjGuUBIFNldHMgdGhlIEphdmEgcGFja2FnZSB3aGVyZSBjbGFzc2VzIGdlbmVyYXRlZCBmcm9tIHRoaXMgLnByb3RvIHdpbGwgYmUKIHBsYWNlZC4gIEJ5IGRlZmF1bHQsIHRoZSBwcm90byBwYWNrYWdlIGlzIHVzZWQsIGJ1dCB0aGlzIGlzIG9mdGVuCiBpbmFwcHJvcHJpYXRlIGJlY2F1c2UgcHJvdG8gcGFja2FnZXMgZG8gbm90IG5vcm1hbGx5IHN0YXJ0IHdpdGggYmFja3dhcmRzCiBkb21haW4gbmFtZXMuCgoNCgUECgIABBIEwwICCgoNCgUECgIABRIEwwILEQoNCgUECgIAARIEwwISHgoNCgUECgIAAxIEwwIhIgq/AgoEBAoCARIEywICKxqwAiBJZiBzZXQsIGFsbCB0aGUgY2xhc3NlcyBmcm9tIHRoZSAucHJvdG8gZmlsZSBhcmUgd3JhcHBlZCBpbiBhIHNpbmdsZQogb3V0ZXIgY2xhc3Mgd2l0aCB0aGUgZ2l2ZW4gbmFtZS4gIFRoaXMgYXBwbGllcyB0byBib3RoIFByb3RvMQogKGVxdWl2YWxlbnQgdG8gdGhlIG9sZCAiLS1vbmVfamF2YV9maWxlIiBvcHRpb24pIGFuZCBQcm90bzIgKHdoZXJlCiBhIC5wcm90byBhbHdheXMgdHJhbnNsYXRlcyB0byBhIHNpbmdsZSBjbGFzcywgYnV0IHlvdSBtYXkgd2FudCB0bwogZXhwbGljaXRseSBjaG9vc2UgdGhlIGNsYXNzIG5hbWUpLgoKDQoFBAoCAQQSBMsCAgoKDQoFBAoCAQUSBMsCCxEKDQoFBAoCAQESBMsCEiYKDQoFBAoCAQMSBMsCKSoKowMKBAQKAgISBNMCAjkalAMgSWYgc2V0IHRydWUsIHRoZW4gdGhlIEphdmEgY29kZSBnZW5lcmF0b3Igd2lsbCBnZW5lcmF0ZSBhIHNlcGFyYXRlIC5qYXZhCiBmaWxlIGZvciBlYWNoIHRvcC1sZXZlbCBtZXNzYWdlLCBlbnVtLCBhbmQgc2VydmljZSBkZWZpbmVkIGluIHRoZSAucHJvdG8KIGZpbGUuICBUaHVzLCB0aGVzZSB0eXBlcyB3aWxsICpub3QqIGJlIG5lc3RlZCBpbnNpZGUgdGhlIG91dGVyIGNsYXNzCiBuYW1lZCBieSBqYXZhX291dGVyX2NsYXNzbmFtZS4gIEhvd2V2ZXIsIHRoZSBvdXRlciBjbGFzcyB3aWxsIHN0aWxsIGJlCiBnZW5lcmF0ZWQgdG8gY29udGFpbiB0aGUgZmlsZSdzIGdldERlc2NyaXB0b3IoKSBtZXRob2QgYXMgd2VsbCBhcyBhbnkKIHRvcC1sZXZlbCBleHRlbnNpb25zIGRlZmluZWQgaW4gdGhlIGZpbGUuCgoNCgUECgICBBIE0wICCgoNCgUECgICBRIE0wILDwoNCgUECgICARIE0wIQIwoNCgUECgICAxIE0wImKAoNCgUECgICCBIE0wIpOAoNCgUECgICBxIE0wIyNwopCgQECgIDEgTWAgJFGhsgVGhpcyBvcHRpb24gZG9lcyBub3RoaW5nLgoKDQoFBAoCAwQSBNYCAgoKDQoFBAoCAwUSBNYCCw8KDQoFBAoCAwESBNYCEC0KDQoFBAoCAwMSBNYCMDIKDQoFBAoCAwgSBNYCM0QKEAoIBAoCAwjnBwASBNYCNEMKEQoJBAoCAwjnBwACEgTWAjQ+ChIKCgQKAgMI5wcAAgASBNYCND4KEwoLBAoCAwjnBwACAAESBNYCND4KEQoJBAoCAwjnBwADEgTWAj9DCuYCCgQECgIEEgTeAgI8GtcCIElmIHNldCB0cnVlLCB0aGVuIHRoZSBKYXZhMiBjb2RlIGdlbmVyYXRvciB3aWxsIGdlbmVyYXRlIGNvZGUgdGhhdAogdGhyb3dzIGFuIGV4Y2VwdGlvbiB3aGVuZXZlciBhbiBhdHRlbXB0IGlzIG1hZGUgdG8gYXNzaWduIGEgbm9uLVVURi04CiBieXRlIHNlcXVlbmNlIHRvIGEgc3RyaW5nIGZpZWxkLgogTWVzc2FnZSByZWZsZWN0aW9uIHdpbGwgZG8gdGhlIHNhbWUuCiBIb3dldmVyLCBhbiBleHRlbnNpb24gZmllbGQgc3RpbGwgYWNjZXB0cyBub24tVVRGLTggYnl0ZSBzZXF1ZW5jZXMuCiBUaGlzIG9wdGlvbiBoYXMgbm8gZWZmZWN0IG9uIHdoZW4gdXNlZCB3aXRoIHRoZSBsaXRlIHJ1bnRpbWUuCgoNCgUECgIEBBIE3gICCgoNCgUECgIEBRIE3gILDwoNCgUECgIEARIE3gIQJgoNCgUECgIEAxIE3gIpKwoNCgUECgIECBIE3gIsOwoNCgUECgIEBxIE3gI1OgpMCgQECgQAEgbiAgLnAgMaPCBHZW5lcmF0ZWQgY2xhc3NlcyBjYW4gYmUgb3B0aW1pemVkIGZvciBzcGVlZCBvciBjb2RlIHNpemUuCgoNCgUECgQAARIE4gIHEwpECgYECgQAAgASBOMCBA4iNCBHZW5lcmF0ZSBjb21wbGV0ZSBjb2RlIGZvciBwYXJzaW5nLCBzZXJpYWxpemF0aW9uLAoKDwoHBAoEAAIAARIE4wIECQoPCgcECgQAAgACEgTjAgwNCkcKBgQKBAACARIE5QIEEhoGIGV0Yy4KIi8gVXNlIFJlZmxlY3Rpb25PcHMgdG8gaW1wbGVtZW50IHRoZXNlIG1ldGhvZHMuCgoPCgcECgQAAgEBEgTlAgQNCg8KBwQKBAACAQISBOUCEBEKRwoGBAoEAAICEgTmAgQVIjcgR2VuZXJhdGUgY29kZSB1c2luZyBNZXNzYWdlTGl0ZSBhbmQgdGhlIGxpdGUgcnVudGltZS4KCg8KBwQKBAACAgESBOYCBBAKDwoHBAoEAAICAhIE5gITFAoMCgQECgIFEgToAgI5Cg0KBQQKAgUEEgToAgIKCg0KBQQKAgUGEgToAgsXCg0KBQQKAgUBEgToAhgkCg0KBQQKAgUDEgToAicoCg0KBQQKAgUIEgToAik4Cg0KBQQKAgUHEgToAjI3CuICCgQECgIGEgTvAgIiGtMCIFNldHMgdGhlIEdvIHBhY2thZ2Ugd2hlcmUgc3RydWN0cyBnZW5lcmF0ZWQgZnJvbSB0aGlzIC5wcm90byB3aWxsIGJlCiBwbGFjZWQuIElmIG9taXR0ZWQsIHRoZSBHbyBwYWNrYWdlIHdpbGwgYmUgZGVyaXZlZCBmcm9tIHRoZSBmb2xsb3dpbmc6CiAgIC0gVGhlIGJhc2VuYW1lIG9mIHRoZSBwYWNrYWdlIGltcG9ydCBwYXRoLCBpZiBwcm92aWRlZC4KICAgLSBPdGhlcndpc2UsIHRoZSBwYWNrYWdlIHN0YXRlbWVudCBpbiB0aGUgLnByb3RvIGZpbGUsIGlmIHByZXNlbnQuCiAgIC0gT3RoZXJ3aXNlLCB0aGUgYmFzZW5hbWUgb2YgdGhlIC5wcm90byBmaWxlLCB3aXRob3V0IGV4dGVuc2lvbi4KCg0KBQQKAgYEEgTvAgIKCg0KBQQKAgYFEgTvAgsRCg0KBQQKAgYBEgTvAhIcCg0KBQQKAgYDEgTvAh8hCtQECgQECgIHEgT9AgI5GsUEIFNob3VsZCBnZW5lcmljIHNlcnZpY2VzIGJlIGdlbmVyYXRlZCBpbiBlYWNoIGxhbmd1YWdlPyAgIkdlbmVyaWMiIHNlcnZpY2VzCiBhcmUgbm90IHNwZWNpZmljIHRvIGFueSBwYXJ0aWN1bGFyIFJQQyBzeXN0ZW0uICBUaGV5IGFyZSBnZW5lcmF0ZWQgYnkgdGhlCiBtYWluIGNvZGUgZ2VuZXJhdG9ycyBpbiBlYWNoIGxhbmd1YWdlICh3aXRob3V0IGFkZGl0aW9uYWwgcGx1Z2lucykuCiBHZW5lcmljIHNlcnZpY2VzIHdlcmUgdGhlIG9ubHkga2luZCBvZiBzZXJ2aWNlIGdlbmVyYXRpb24gc3VwcG9ydGVkIGJ5CiBlYXJseSB2ZXJzaW9ucyBvZiBnb29nbGUucHJvdG9idWYuCgogR2VuZXJpYyBzZXJ2aWNlcyBhcmUgbm93IGNvbnNpZGVyZWQgZGVwcmVjYXRlZCBpbiBmYXZvciBvZiB1c2luZyBwbHVnaW5zCiB0aGF0IGdlbmVyYXRlIGNvZGUgc3BlY2lmaWMgdG8geW91ciBwYXJ0aWN1bGFyIFJQQyBzeXN0ZW0uICBUaGVyZWZvcmUsCiB0aGVzZSBkZWZhdWx0IHRvIGZhbHNlLiAgT2xkIGNvZGUgd2hpY2ggZGVwZW5kcyBvbiBnZW5lcmljIHNlcnZpY2VzIHNob3VsZAogZXhwbGljaXRseSBzZXQgdGhlbSB0byB0cnVlLgoKDQoFBAoCBwQSBP0CAgoKDQoFBAoCBwUSBP0CCw8KDQoFBAoCBwESBP0CECMKDQoFBAoCBwMSBP0CJigKDQoFBAoCBwgSBP0CKTgKDQoFBAoCBwcSBP0CMjcKDAoEBAoCCBIE/gICOwoNCgUECgIIBBIE/gICCgoNCgUECgIIBRIE/gILDwoNCgUECgIIARIE/gIQJQoNCgUECgIIAxIE/gIoKgoNCgUECgIICBIE/gIrOgoNCgUECgIIBxIE/gI0OQoMCgQECgIJEgT/AgI5Cg0KBQQKAgkEEgT/AgIKCg0KBQQKAgkFEgT/AgsPCg0KBQQKAgkBEgT/AhAjCg0KBQQKAgkDEgT/AiYoCg0KBQQKAgkIEgT/Aik4Cg0KBQQKAgkHEgT/AjI3CgwKBAQKAgoSBIADAjoKDQoFBAoCCgQSBIADAgoKDQoFBAoCCgUSBIADCw8KDQoFBAoCCgESBIADECQKDQoFBAoCCgMSBIADJykKDQoFBAoCCggSBIADKjkKDQoFBAoCCgcSBIADMzgK8wEKBAQKAgsSBIYDAjAa5AEgSXMgdGhpcyBmaWxlIGRlcHJlY2F0ZWQ/CiBEZXBlbmRpbmcgb24gdGhlIHRhcmdldCBwbGF0Zm9ybSwgdGhpcyBjYW4gZW1pdCBEZXByZWNhdGVkIGFubm90YXRpb25zCiBmb3IgZXZlcnl0aGluZyBpbiB0aGUgZmlsZSwgb3IgaXQgd2lsbCBiZSBjb21wbGV0ZWx5IGlnbm9yZWQ7IGluIHRoZSB2ZXJ5CiBsZWFzdCwgdGhpcyBpcyBhIGZvcm1hbGl6YXRpb24gZm9yIGRlcHJlY2F0aW5nIGZpbGVzLgoKDQoFBAoCCwQSBIYDAgoKDQoFBAoCCwUSBIYDCw8KDQoFBAoCCwESBIYDEBoKDQoFBAoCCwMSBIYDHR8KDQoFBAoCCwgSBIYDIC8KDQoFBAoCCwcSBIYDKS4KfwoEBAoCDBIEigMCNhpxIEVuYWJsZXMgdGhlIHVzZSBvZiBhcmVuYXMgZm9yIHRoZSBwcm90byBtZXNzYWdlcyBpbiB0aGlzIGZpbGUuIFRoaXMgYXBwbGllcwogb25seSB0byBnZW5lcmF0ZWQgY2xhc3NlcyBmb3IgQysrLgoKDQoFBAoCDAQSBIoDAgoKDQoFBAoCDAUSBIoDCw8KDQoFBAoCDAESBIoDECAKDQoFBAoCDAMSBIoDIyUKDQoFBAoCDAgSBIoDJjUKDQoFBAoCDAcSBIoDLzQKkgEKBAQKAg0SBI8DAikagwEgU2V0cyB0aGUgb2JqZWN0aXZlIGMgY2xhc3MgcHJlZml4IHdoaWNoIGlzIHByZXBlbmRlZCB0byBhbGwgb2JqZWN0aXZlIGMKIGdlbmVyYXRlZCBjbGFzc2VzIGZyb20gdGhpcyAucHJvdG8uIFRoZXJlIGlzIG5vIGRlZmF1bHQuCgoNCgUECgINBBIEjwMCCgoNCgUECgINBRIEjwMLEQoNCgUECgINARIEjwMSIwoNCgUECgINAxIEjwMmKApJCgQECgIOEgSSAwIoGjsgTmFtZXNwYWNlIGZvciBnZW5lcmF0ZWQgY2xhc3NlczsgZGVmYXVsdHMgdG8gdGhlIHBhY2thZ2UuCgoNCgUECgIOBBIEkgMCCgoNCgUECgIOBRIEkgMLEQoNCgUECgIOARIEkgMSIgoNCgUECgIOAxIEkgMlJwqRAgoEBAoCDxIEmAMCJBqCAiBCeSBkZWZhdWx0IFN3aWZ0IGdlbmVyYXRvcnMgd2lsbCB0YWtlIHRoZSBwcm90byBwYWNrYWdlIGFuZCBDYW1lbENhc2UgaXQKIHJlcGxhY2luZyAnLicgd2l0aCB1bmRlcnNjb3JlIGFuZCB1c2UgdGhhdCB0byBwcmVmaXggdGhlIHR5cGVzL3N5bWJvbHMKIGRlZmluZWQuIFdoZW4gdGhpcyBvcHRpb25zIGlzIHByb3ZpZGVkLCB0aGV5IHdpbGwgdXNlIHRoaXMgdmFsdWUgaW5zdGVhZAogdG8gcHJlZml4IHRoZSB0eXBlcy9zeW1ib2xzIGRlZmluZWQuCgoNCgUECgIPBBIEmAMCCgoNCgUECgIPBRIEmAMLEQoNCgUECgIPARIEmAMSHgoNCgUECgIPAxIEmAMhIwp+CgQECgIQEgScAwIoGnAgU2V0cyB0aGUgcGhwIGNsYXNzIHByZWZpeCB3aGljaCBpcyBwcmVwZW5kZWQgdG8gYWxsIHBocCBnZW5lcmF0ZWQgY2xhc3NlcwogZnJvbSB0aGlzIC5wcm90by4gRGVmYXVsdCBpcyBlbXB0eS4KCg0KBQQKAhAEEgScAwIKCg0KBQQKAhAFEgScAwsRCg0KBQQKAhABEgScAxIiCg0KBQQKAhADEgScAyUnCr4BCgQECgIREgShAwIlGq8BIFVzZSB0aGlzIG9wdGlvbiB0byBjaGFuZ2UgdGhlIG5hbWVzcGFjZSBvZiBwaHAgZ2VuZXJhdGVkIGNsYXNzZXMuIERlZmF1bHQKIGlzIGVtcHR5LiBXaGVuIHRoaXMgb3B0aW9uIGlzIGVtcHR5LCB0aGUgcGFja2FnZSBuYW1lIHdpbGwgYmUgdXNlZCBmb3IKIGRldGVybWluaW5nIHRoZSBuYW1lc3BhY2UuCgoNCgUECgIRBBIEoQMCCgoNCgUECgIRBRIEoQMLEQoNCgUECgIRARIEoQMSHwoNCgUECgIRAxIEoQMiJAp8CgQECgISEgSlAwI6Gm4gVGhlIHBhcnNlciBzdG9yZXMgb3B0aW9ucyBpdCBkb2Vzbid0IHJlY29nbml6ZSBoZXJlLgogU2VlIHRoZSBkb2N1bWVudGF0aW9uIGZvciB0aGUgIk9wdGlvbnMiIHNlY3Rpb24gYWJvdmUuCgoNCgUECgISBBIEpQMCCgoNCgUECgISBhIEpQMLHgoNCgUECgISARIEpQMfMwoNCgUECgISAxIEpQM2OQqHAQoDBAoFEgSpAwIZGnogQ2xpZW50cyBjYW4gZGVmaW5lIGN1c3RvbSBvcHRpb25zIGluIGV4dGVuc2lvbnMgb2YgdGhpcyBtZXNzYWdlLgogU2VlIHRoZSBkb2N1bWVudGF0aW9uIGZvciB0aGUgIk9wdGlvbnMiIHNlY3Rpb24gYWJvdmUuCgoMCgQECgUAEgSpAw0YCg0KBQQKBQABEgSpAw0RCg0KBQQKBQACEgSpAxUYCgsKAwQKCRIEqwMLDgoMCgQECgkAEgSrAwsNCg0KBQQKCQABEgSrAwsNCg0KBQQKCQACEgSrAwsNCgwKAgQLEgauAwDtAwEKCwoDBAsBEgSuAwgWCtgFCgQECwIAEgTBAwI8GskFIFNldCB0cnVlIHRvIHVzZSB0aGUgb2xkIHByb3RvMSBNZXNzYWdlU2V0IHdpcmUgZm9ybWF0IGZvciBleHRlbnNpb25zLgogVGhpcyBpcyBwcm92aWRlZCBmb3IgYmFja3dhcmRzLWNvbXBhdGliaWxpdHkgd2l0aCB0aGUgTWVzc2FnZVNldCB3aXJlCiBmb3JtYXQuICBZb3Ugc2hvdWxkIG5vdCB1c2UgdGhpcyBmb3IgYW55IG90aGVyIHJlYXNvbjogIEl0J3MgbGVzcwogZWZmaWNpZW50LCBoYXMgZmV3ZXIgZmVhdHVyZXMsIGFuZCBpcyBtb3JlIGNvbXBsaWNhdGVkLgoKIFRoZSBtZXNzYWdlIG11c3QgYmUgZGVmaW5lZCBleGFjdGx5IGFzIGZvbGxvd3M6CiAgIG1lc3NhZ2UgRm9vIHsKICAgICBvcHRpb24gbWVzc2FnZV9zZXRfd2lyZV9mb3JtYXQgPSB0cnVlOwogICAgIGV4dGVuc2lvbnMgNCB0byBtYXg7CiAgIH0KIE5vdGUgdGhhdCB0aGUgbWVzc2FnZSBjYW5ub3QgaGF2ZSBhbnkgZGVmaW5lZCBmaWVsZHM7IE1lc3NhZ2VTZXRzIG9ubHkKIGhhdmUgZXh0ZW5zaW9ucy4KCiBBbGwgZXh0ZW5zaW9ucyBvZiB5b3VyIHR5cGUgbXVzdCBiZSBzaW5ndWxhciBtZXNzYWdlczsgZS5nLiB0aGV5IGNhbm5vdAogYmUgaW50MzJzLCBlbnVtcywgb3IgcmVwZWF0ZWQgbWVzc2FnZXMuCgogQmVjYXVzZSB0aGlzIGlzIGFuIG9wdGlvbiwgdGhlIGFib3ZlIHR3byByZXN0cmljdGlvbnMgYXJlIG5vdCBlbmZvcmNlZCBieQogdGhlIHByb3RvY29sIGNvbXBpbGVyLgoKDQoFBAsCAAQSBMEDAgoKDQoFBAsCAAUSBMEDCw8KDQoFBAsCAAESBMEDECcKDQoFBAsCAAMSBMEDKisKDQoFBAsCAAgSBMEDLDsKDQoFBAsCAAcSBMEDNToK6wEKBAQLAgESBMYDAkQa3AEgRGlzYWJsZXMgdGhlIGdlbmVyYXRpb24gb2YgdGhlIHN0YW5kYXJkICJkZXNjcmlwdG9yKCkiIGFjY2Vzc29yLCB3aGljaCBjYW4KIGNvbmZsaWN0IHdpdGggYSBmaWVsZCBvZiB0aGUgc2FtZSBuYW1lLiAgVGhpcyBpcyBtZWFudCB0byBtYWtlIG1pZ3JhdGlvbgogZnJvbSBwcm90bzEgZWFzaWVyOyBuZXcgY29kZSBzaG91bGQgYXZvaWQgZmllbGRzIG5hbWVkICJkZXNjcmlwdG9yIi4KCg0KBQQLAgEEEgTGAwIKCg0KBQQLAgEFEgTGAwsPCg0KBQQLAgEBEgTGAxAvCg0KBQQLAgEDEgTGAzIzCg0KBQQLAgEIEgTGAzRDCg0KBQQLAgEHEgTGAz1CCu4BCgQECwICEgTMAwIvGt8BIElzIHRoaXMgbWVzc2FnZSBkZXByZWNhdGVkPwogRGVwZW5kaW5nIG9uIHRoZSB0YXJnZXQgcGxhdGZvcm0sIHRoaXMgY2FuIGVtaXQgRGVwcmVjYXRlZCBhbm5vdGF0aW9ucwogZm9yIHRoZSBtZXNzYWdlLCBvciBpdCB3aWxsIGJlIGNvbXBsZXRlbHkgaWdub3JlZDsgaW4gdGhlIHZlcnkgbGVhc3QsCiB0aGlzIGlzIGEgZm9ybWFsaXphdGlvbiBmb3IgZGVwcmVjYXRpbmcgbWVzc2FnZXMuCgoNCgUECwICBBIEzAMCCgoNCgUECwICBRIEzAMLDwoNCgUECwICARIEzAMQGgoNCgUECwICAxIEzAMdHgoNCgUECwICCBIEzAMfLgoNCgUECwICBxIEzAMoLQqeBgoEBAsCAxIE4wMCHhqPBiBXaGV0aGVyIHRoZSBtZXNzYWdlIGlzIGFuIGF1dG9tYXRpY2FsbHkgZ2VuZXJhdGVkIG1hcCBlbnRyeSB0eXBlIGZvciB0aGUKIG1hcHMgZmllbGQuCgogRm9yIG1hcHMgZmllbGRzOgogICAgIG1hcDxLZXlUeXBlLCBWYWx1ZVR5cGU+IG1hcF9maWVsZCA9IDE7CiBUaGUgcGFyc2VkIGRlc2NyaXB0b3IgbG9va3MgbGlrZToKICAgICBtZXNzYWdlIE1hcEZpZWxkRW50cnkgewogICAgICAgICBvcHRpb24gbWFwX2VudHJ5ID0gdHJ1ZTsKICAgICAgICAgb3B0aW9uYWwgS2V5VHlwZSBrZXkgPSAxOwogICAgICAgICBvcHRpb25hbCBWYWx1ZVR5cGUgdmFsdWUgPSAyOwogICAgIH0KICAgICByZXBlYXRlZCBNYXBGaWVsZEVudHJ5IG1hcF9maWVsZCA9IDE7CgogSW1wbGVtZW50YXRpb25zIG1heSBjaG9vc2Ugbm90IHRvIGdlbmVyYXRlIHRoZSBtYXBfZW50cnk9dHJ1ZSBtZXNzYWdlLCBidXQKIHVzZSBhIG5hdGl2ZSBtYXAgaW4gdGhlIHRhcmdldCBsYW5ndWFnZSB0byBob2xkIHRoZSBrZXlzIGFuZCB2YWx1ZXMuCiBUaGUgcmVmbGVjdGlvbiBBUElzIGluIHN1Y2ggaW1wbGVtZW50aW9ucyBzdGlsbCBuZWVkIHRvIHdvcmsgYXMKIGlmIHRoZSBmaWVsZCBpcyBhIHJlcGVhdGVkIG1lc3NhZ2UgZmllbGQuCgogTk9URTogRG8gbm90IHNldCB0aGUgb3B0aW9uIGluIC5wcm90byBmaWxlcy4gQWx3YXlzIHVzZSB0aGUgbWFwcyBzeW50YXgKIGluc3RlYWQuIFRoZSBvcHRpb24gc2hvdWxkIG9ubHkgYmUgaW1wbGljaXRseSBzZXQgYnkgdGhlIHByb3RvIGNvbXBpbGVyCiBwYXJzZXIuCgoNCgUECwIDBBIE4wMCCgoNCgUECwIDBRIE4wMLDwoNCgUECwIDARIE4wMQGQoNCgUECwIDAxIE4wMcHQokCgMECwkSBOUDCw0iFyBqYXZhbGl0ZV9zZXJpYWxpemFibGUKCgwKBAQLCQASBOUDCwwKDQoFBAsJAAESBOUDCwwKDQoFBAsJAAISBOUDCwwKHwoDBAsJEgTmAwsNIhIgamF2YW5hbm9fYXNfbGl0ZQoKDAoEBAsJARIE5gMLDAoNCgUECwkBARIE5gMLDAoNCgUECwkBAhIE5gMLDApPCgQECwIEEgTpAwI6GkEgVGhlIHBhcnNlciBzdG9yZXMgb3B0aW9ucyBpdCBkb2Vzbid0IHJlY29nbml6ZSBoZXJlLiBTZWUgYWJvdmUuCgoNCgUECwIEBBIE6QMCCgoNCgUECwIEBhIE6QMLHgoNCgUECwIEARIE6QMfMwoNCgUECwIEAxIE6QM2OQpaCgMECwUSBOwDAhkaTSBDbGllbnRzIGNhbiBkZWZpbmUgY3VzdG9tIG9wdGlvbnMgaW4gZXh0ZW5zaW9ucyBvZiB0aGlzIG1lc3NhZ2UuIFNlZSBhYm92ZS4KCgwKBAQLBQASBOwDDRgKDQoFBAsFAAESBOwDDREKDQoFBAsFAAISBOwDFRgKDAoCBAwSBu8DAMoEAQoLCgMEDAESBO8DCBQKowIKBAQMAgASBPQDAi4alAIgVGhlIGN0eXBlIG9wdGlvbiBpbnN0cnVjdHMgdGhlIEMrKyBjb2RlIGdlbmVyYXRvciB0byB1c2UgYSBkaWZmZXJlbnQKIHJlcHJlc2VudGF0aW9uIG9mIHRoZSBmaWVsZCB0aGFuIGl0IG5vcm1hbGx5IHdvdWxkLiAgU2VlIHRoZSBzcGVjaWZpYwogb3B0aW9ucyBiZWxvdy4gIFRoaXMgb3B0aW9uIGlzIG5vdCB5ZXQgaW1wbGVtZW50ZWQgaW4gdGhlIG9wZW4gc291cmNlCiByZWxlYXNlIC0tIHNvcnJ5LCB3ZSdsbCB0cnkgdG8gaW5jbHVkZSBpdCBpbiBhIGZ1dHVyZSB2ZXJzaW9uIQoKDQoFBAwCAAQSBPQDAgoKDQoFBAwCAAYSBPQDCxAKDQoFBAwCAAESBPQDERYKDQoFBAwCAAMSBPQDGRoKDQoFBAwCAAgSBPQDGy0KDQoFBAwCAAcSBPQDJiwKDgoEBAwEABIG9QMC/AMDCg0KBQQMBAABEgT1AwcMCh8KBgQMBAACABIE9wMEDxoPIERlZmF1bHQgbW9kZS4KCg8KBwQMBAACAAESBPcDBAoKDwoHBAwEAAIAAhIE9wMNDgoOCgYEDAQAAgESBPkDBA0KDwoHBAwEAAIBARIE+QMECAoPCgcEDAQAAgECEgT5AwsMCg4KBgQMBAACAhIE+wMEFQoPCgcEDAQAAgIBEgT7AwQQCg8KBwQMBAACAgISBPsDExQK2gIKBAQMAgESBIIEAhsaywIgVGhlIHBhY2tlZCBvcHRpb24gY2FuIGJlIGVuYWJsZWQgZm9yIHJlcGVhdGVkIHByaW1pdGl2ZSBmaWVsZHMgdG8gZW5hYmxlCiBhIG1vcmUgZWZmaWNpZW50IHJlcHJlc2VudGF0aW9uIG9uIHRoZSB3aXJlLiBSYXRoZXIgdGhhbiByZXBlYXRlZGx5CiB3cml0aW5nIHRoZSB0YWcgYW5kIHR5cGUgZm9yIGVhY2ggZWxlbWVudCwgdGhlIGVudGlyZSBhcnJheSBpcyBlbmNvZGVkIGFzCiBhIHNpbmdsZSBsZW5ndGgtZGVsaW1pdGVkIGJsb2IuIEluIHByb3RvMywgb25seSBleHBsaWNpdCBzZXR0aW5nIGl0IHRvCiBmYWxzZSB3aWxsIGF2b2lkIHVzaW5nIHBhY2tlZCBlbmNvZGluZy4KCg0KBQQMAgEEEgSCBAIKCg0KBQQMAgEFEgSCBAsPCg0KBQQMAgEBEgSCBBAWCg0KBQQMAgEDEgSCBBkaCpoFCgQEDAICEgSPBAIzGosFIFRoZSBqc3R5cGUgb3B0aW9uIGRldGVybWluZXMgdGhlIEphdmFTY3JpcHQgdHlwZSB1c2VkIGZvciB2YWx1ZXMgb2YgdGhlCiBmaWVsZC4gIFRoZSBvcHRpb24gaXMgcGVybWl0dGVkIG9ubHkgZm9yIDY0IGJpdCBpbnRlZ3JhbCBhbmQgZml4ZWQgdHlwZXMKIChpbnQ2NCwgdWludDY0LCBzaW50NjQsIGZpeGVkNjQsIHNmaXhlZDY0KS4gIEEgZmllbGQgd2l0aCBqc3R5cGUgSlNfU1RSSU5HCiBpcyByZXByZXNlbnRlZCBhcyBKYXZhU2NyaXB0IHN0cmluZywgd2hpY2ggYXZvaWRzIGxvc3Mgb2YgcHJlY2lzaW9uIHRoYXQKIGNhbiBoYXBwZW4gd2hlbiBhIGxhcmdlIHZhbHVlIGlzIGNvbnZlcnRlZCB0byBhIGZsb2F0aW5nIHBvaW50IEphdmFTY3JpcHQuCiBTcGVjaWZ5aW5nIEpTX05VTUJFUiBmb3IgdGhlIGpzdHlwZSBjYXVzZXMgdGhlIGdlbmVyYXRlZCBKYXZhU2NyaXB0IGNvZGUgdG8KIHVzZSB0aGUgSmF2YVNjcmlwdCAibnVtYmVyIiB0eXBlLiAgVGhlIGJlaGF2aW9yIG9mIHRoZSBkZWZhdWx0IG9wdGlvbgogSlNfTk9STUFMIGlzIGltcGxlbWVudGF0aW9uIGRlcGVuZGVudC4KCiBUaGlzIG9wdGlvbiBpcyBhbiBlbnVtIHRvIHBlcm1pdCBhZGRpdGlvbmFsIHR5cGVzIHRvIGJlIGFkZGVkLCBlLmcuCiBnb29nLm1hdGguSW50ZWdlci4KCg0KBQQMAgIEEgSPBAIKCg0KBQQMAgIGEgSPBAsRCg0KBQQMAgIBEgSPBBIYCg0KBQQMAgIDEgSPBBscCg0KBQQMAgIIEgSPBB0yCg0KBQQMAgIHEgSPBCgxCg4KBAQMBAESBpAEApkEAwoNCgUEDAQBARIEkAQHDQonCgYEDAQBAgASBJIEBBIaFyBVc2UgdGhlIGRlZmF1bHQgdHlwZS4KCg8KBwQMBAECAAESBJIEBA0KDwoHBAwEAQIAAhIEkgQQEQopCgYEDAQBAgESBJUEBBIaGSBVc2UgSmF2YVNjcmlwdCBzdHJpbmdzLgoKDwoHBAwEAQIBARIElQQEDQoPCgcEDAQBAgECEgSVBBARCikKBgQMBAECAhIEmAQEEhoZIFVzZSBKYXZhU2NyaXB0IG51bWJlcnMuCgoPCgcEDAQBAgIBEgSYBAQNCg8KBwQMBAECAgISBJgEEBEK7wwKBAQMAgMSBLcEAika4AwgU2hvdWxkIHRoaXMgZmllbGQgYmUgcGFyc2VkIGxhemlseT8gIExhenkgYXBwbGllcyBvbmx5IHRvIG1lc3NhZ2UtdHlwZQogZmllbGRzLiAgSXQgbWVhbnMgdGhhdCB3aGVuIHRoZSBvdXRlciBtZXNzYWdlIGlzIGluaXRpYWxseSBwYXJzZWQsIHRoZQogaW5uZXIgbWVzc2FnZSdzIGNvbnRlbnRzIHdpbGwgbm90IGJlIHBhcnNlZCBidXQgaW5zdGVhZCBzdG9yZWQgaW4gZW5jb2RlZAogZm9ybS4gIFRoZSBpbm5lciBtZXNzYWdlIHdpbGwgYWN0dWFsbHkgYmUgcGFyc2VkIHdoZW4gaXQgaXMgZmlyc3QgYWNjZXNzZWQuCgogVGhpcyBpcyBvbmx5IGEgaGludC4gIEltcGxlbWVudGF0aW9ucyBhcmUgZnJlZSB0byBjaG9vc2Ugd2hldGhlciB0byB1c2UKIGVhZ2VyIG9yIGxhenkgcGFyc2luZyByZWdhcmRsZXNzIG9mIHRoZSB2YWx1ZSBvZiB0aGlzIG9wdGlvbi4gIEhvd2V2ZXIsCiBzZXR0aW5nIHRoaXMgb3B0aW9uIHRydWUgc3VnZ2VzdHMgdGhhdCB0aGUgcHJvdG9jb2wgYXV0aG9yIGJlbGlldmVzIHRoYXQKIHVzaW5nIGxhenkgcGFyc2luZyBvbiB0aGlzIGZpZWxkIGlzIHdvcnRoIHRoZSBhZGRpdGlvbmFsIGJvb2trZWVwaW5nCiBvdmVyaGVhZCB0eXBpY2FsbHkgbmVlZGVkIHRvIGltcGxlbWVudCBpdC4KCiBUaGlzIG9wdGlvbiBkb2VzIG5vdCBhZmZlY3QgdGhlIHB1YmxpYyBpbnRlcmZhY2Ugb2YgYW55IGdlbmVyYXRlZCBjb2RlOwogYWxsIG1ldGhvZCBzaWduYXR1cmVzIHJlbWFpbiB0aGUgc2FtZS4gIEZ1cnRoZXJtb3JlLCB0aHJlYWQtc2FmZXR5IG9mIHRoZQogaW50ZXJmYWNlIGlzIG5vdCBhZmZlY3RlZCBieSB0aGlzIG9wdGlvbjsgY29uc3QgbWV0aG9kcyByZW1haW4gc2FmZSB0bwogY2FsbCBmcm9tIG11bHRpcGxlIHRocmVhZHMgY29uY3VycmVudGx5LCB3aGlsZSBub24tY29uc3QgbWV0aG9kcyBjb250aW51ZQogdG8gcmVxdWlyZSBleGNsdXNpdmUgYWNjZXNzLgoKCiBOb3RlIHRoYXQgaW1wbGVtZW50YXRpb25zIG1heSBjaG9vc2Ugbm90IHRvIGNoZWNrIHJlcXVpcmVkIGZpZWxkcyB3aXRoaW4KIGEgbGF6eSBzdWItbWVzc2FnZS4gIFRoYXQgaXMsIGNhbGxpbmcgSXNJbml0aWFsaXplZCgpIG9uIHRoZSBvdXRlciBtZXNzYWdlCiBtYXkgcmV0dXJuIHRydWUgZXZlbiBpZiB0aGUgaW5uZXIgbWVzc2FnZSBoYXMgbWlzc2luZyByZXF1aXJlZCBmaWVsZHMuCiBUaGlzIGlzIG5lY2Vzc2FyeSBiZWNhdXNlIG90aGVyd2lzZSB0aGUgaW5uZXIgbWVzc2FnZSB3b3VsZCBoYXZlIHRvIGJlCiBwYXJzZWQgaW4gb3JkZXIgdG8gcGVyZm9ybSB0aGUgY2hlY2ssIGRlZmVhdGluZyB0aGUgcHVycG9zZSBvZiBsYXp5CiBwYXJzaW5nLiAgQW4gaW1wbGVtZW50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dCByZWNvZ25pemUuIFRoaXMgb25seQogYXBwZWFycyBpbiBvcHRpb25zIHByb3RvcyBjcmVhdGVkIGJ5IHRoZSBjb21waWxlcjo6UGFyc2VyIGNsYXNzLgogRGVzY3JpcHRvclBvb2wgcmVzb2x2ZXMgdGhlc2Ugd2hlbiBidWlsZGluZyBEZXNjcmlwdG9yIG9iamVjdHMuIFRoZXJlZm9yZSwKIG9wdGlvbnMgcHJvdG9zIGluIGRlc2NyaXB0b3Igb2JqZWN0cyAoZS5nLiByZXR1cm5lZCBieSBEZXNjcmlwdG9yOjpvcHRpb25zKCksCiBvciBwcm9kdWNlZCBieSBEZXNjcmlwdG9yOjpDb3B5VG8oKSkgd2lsbCBuZXZlciBoYXZlIFVuaW50ZXJwcmV0ZWRPcHRpb25zCiBpbiB0aGVtLgoKCwoDBBIBEgSxBQgbCssCCgQEEgMAEga3BQK6BQMaugIgVGhlIG5hbWUgb2YgdGhlIHVuaW50ZXJwcmV0ZWQgb3B0aW9uLiAgRWFjaCBzdHJpbmcgcmVwcmVzZW50cyBhIHNlZ21lbnQgaW4KIGEgZG90LXNlcGFyYXRlZCBuYW1lLiAgaXNfZXh0ZW5zaW9uIGlzIHRydWUgaWZmIGEgc2VnbWVudCByZXByZXNlbnRzIGFuCiBleHRlbnNpb24gKGRlbm90ZWQgd2l0aCBwYXJlbnRoZXNlcyBpbiBvcHRpb25zIHNwZWNzIGluIC5wcm90byBmaWxlcykuCiBFLmcuLHsgWyJmb28iLCBmYWxzZV0sIFsiYmFyLmJheiIsIHRydWVdLCBbInF1eCIsIGZhbHNlXSB9IHJlcHJlc2VudHMKICJmb28uKGJhci5iYXopLnF1eCIuCgoNCgUEEgMAARIEtwUKEgoOCgYEEgMAAgASBLgFBCIKDwoHBBIDAAIABBIEuAUEDAoPCgcEEgMAAgAFEgS4BQ0TCg8KBwQSAwACAAESBLgFFB0KDwoHBBIDAAIAAxIEuAUgIQoOCgYEEgMAAgESBLkFBCMKDwoHBBIDAAIBBBIEuQUEDAoPCgcEEgMAAgEFEgS5BQ0RCg8KBwQSAwACAQESBLkFEh4KDwoHBBIDAAIBAxIEuQUhIgoMCgQEEgIAEgS7BQIdCg0KBQQSAgAEEgS7BQIKCg0KBQQSAgAGEgS7BQsTCg0KBQQSAgABEgS7BRQYCg0KBQQSAgADEgS7BRscCpwBCgQEEgIBEgS/BQInGo0BIFRoZSB2YWx1ZSBvZiB0aGUgdW5pbnRlcnByZXRlZCBvcHRpb24sIGluIHdoYXRldmVyIHR5cGUgdGhlIHRva2VuaXplcgogaWRlbnRpZmllZCBpdCBhcyBkdXJpbmcgcGFyc2luZy4gRXhhY3RseSBvbmUgb2YgdGhlc2Ugc2hvdWxkIGJlIHNldC4KCg0KBQQSAgEEEgS/BQIKCg0KBQQSAgEFEgS/BQsRCg0KBQQSAgEBEgS/BRIiCg0KBQQSAgEDEgS/BSUmCgwKBAQSAgISBMAFAikKDQoFBBICAgQSBMAFAgoKDQoFBBICAgUSBMAFCxEKDQoFBBICAgESBMAFEiQKDQoFBBICAgMSBMAFJygKDAoEBBICAxIEwQUCKAoNCgUEEgIDBBIEwQUCCgoNCgUEEgIDBRIEwQULEAoNCgUEEgIDARIEwQURIwoNCgUEEgIDAxIEwQUmJwoMCgQEEgIEEgTCBQIjCg0KBQQSAgQEEgTCBQIKCg0KBQQSAgQFEgTCBQsRCg0KBQQSAgQBEgTCBRIeCg0KBQQSAgQDEgTCBSEiCgwKBAQSAgUSBMMFAiIKDQoFBBICBQQSBMMFAgoKDQoFBBICBQUSBMMFCxAKDQoFBBICBQESBMMFER0KDQoFBBICBQMSBMMFICEKDAoEBBICBhIExAUCJgoNCgUEEgIGBBIExAUCCgoNCgUEEgIGBRIExAULEQoNCgUEEgIGARIExAUSIQoNCgUEEgIGAxIExAUkJQraAQoCBBMSBswFAM0GARpqIEVuY2Fwc3VsYXRlcyBpbmZvcm1hdGlvbiBhYm91dCB0aGUgb3JpZ2luYWwgc291cmNlIGZpbGUgZnJvbSB3aGljaCBhCiBGaWxlRGVzY3JpcHRvclByb3RvIHdhcyBnZW5lcmF0ZWQuCjJgID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT0KIE9wdGlvbmFsIHNvdXJjZSBjb2RlIGluZm8KCgsKAwQTARIEzAUIFgqCEQoEBBMCABIE+AUCIRrzECBBIExvY2F0aW9uIGlkZW50aWZpZXMgYSBwaWVjZSBvZiBzb3VyY2UgY29kZSBpbiBhIC5wcm90byBmaWxlIHdoaWNoCiBjb3JyZXNwb25kcyB0byBhIHBhcnRpY3VsYXIgZGVmaW5pdGlvbi4gIFRoaXMgaW5mb3JtYXRpb24gaXMgaW50ZW5kZWQKIHRvIGJlIHVzZWZ1bCB0byBJREVzLCBjb2RlIGluZGV4ZXJzLCBkb2N1bWVudGF0aW9uIGdlbmVyYXRvcnMsIGFuZCBzaW1pbGFyCiB0b29scy4KCiBGb3IgZXhhbXBsZSwgc2F5IHdlIGhhdmUgYSBmaWxlIGxpa2U6CiAgIG1lc3NhZ2UgRm9vIHsKICAgICBvcHRpb25hbCBzdHJpbmcgZm9vID0gMTsKICAgfQogTGV0J3MgbG9vayBhdCBqdXN0IHRoZSBmaWVsZCBkZWZpbml0aW9uOgogICBvcHRpb25hbCBzdHJpbmcgZm9vID0gMTsKICAgXiAgICAgICBeXiAgICAgXl4gIF4gIF5eXgogICBhICAgICAgIGJjICAgICBkZSAgZiAgZ2hpCiBXZSBoYXZlIHRoZSBmb2xsb3dpbmcgbG9jYXRpb25zOgogICBzcGFuICAgcGF0aCAgICAgICAgICAgICAgIHJlcHJlc2VudHMKICAgW2EsaSkgIFsgNCwgMCwgMiwgMCBdICAgICBUaGUgd2hvbGUgZmllbGQgZGVmaW5pdGlvbi4KICAgW2EsYikgIFsgNCwgMCwgMiwgMCwgNCBdICBUaGUgbGFiZWwgKG9wdGlvbmFsKS4KICAgW2MsZCkgIFsgNCwgMCwgMiwgMCwgNSBdICBUaGUgdHlwZSAoc3RyaW5nKS4KICAgW2UsZikgIFsgNCwgMCwgMiwgMCwgMSBdICBUaGUgbmFtZSAoZm9vKS4KICAgW2csaCkgIFsgNCwgMCwgMiwgMCwgMyBdICBUaGUgbnVtYmVyICgxKS4KCiBOb3RlczoKIC0gQSBsb2NhdGlvbiBtYXkgcmVmZXIgdG8gYSByZXBlYXRlZCBmaWVsZCBpdHNlbGYgKGkuZS4gbm90IHRvIGFueQogICBwYXJ0aWN1bGFyIGluZGV4IHdpdGhpbiBpdCkuICBUaGlzIGlzIHVzZWQgd2hlbmV2ZXIgYSBzZXQgb2YgZWxlbWVudHMgYXJlCiAgIGxvZ2ljYWxseSBlbmNsb3NlZCBpbiBhIHNpbmdsZSBjb2RlIHNlZ21lbnQuICBGb3IgZXhhbXBsZSwgYW4gZW50aXJlCiAgIGV4dGVuZCBibG9jayAocG9zc2libHkgY29udGFpbmluZyBtdWx0aXBsZSBleHRlbnNpb24gZGVmaW5pdGlvbnMpIHdpbGwKICAgaGF2ZSBhbiBvdXRlciBsb2NhdGlvbiB3aG9zZSBwYXRoIHJlZmVycyB0byB0aGUgImV4dGVuc2lvbnMiIHJlcGVhdGVkCiAgIGZpZWxkIHdpdGhvdXQgYW4gaW5kZXguCiAtIE11bHRpcGxlIGxvY2F0aW9ucyBtYXkgaGF2ZSB0aGUgc2FtZSBwYXRoLiAgVGhpcyBoYXBwZW5zIHdoZW4gYSBzaW5nbGUKICAgbG9naWNhbCBkZWNsYXJhdGlvbiBpcyBzcHJlYWQgb3V0IGFjcm9zcyBtdWx0aXBsZSBwbGFjZXMuICBUaGUgbW9zdAogICBvYnZpb3VzIGV4YW1wbGUgaXMgdGhlICJleHRlbmQiIGJsb2NrIGFnYWluIC0tIHRoZXJlIG1heSBiZSBtdWx0aXBsZQogICBleHRlbmQgYmxvY2tzIGluIHRoZSBzYW1lIHNjb3BlLCBlYWNoIG9mIHdoaWNoIHdpbGwgaGF2ZSB0aGUgc2FtZSBwYXRoLgogLSBBIGxvY2F0aW9uJ3Mgc3BhbiBpcyBub3QgYWx3YXlzIGEgc3Vic2V0IG9mIGl0cyBwYXJlbnQncyBzcGFuLiAgRm9yCiAgIGV4YW1wbGUsIHRoZSAiZXh0ZW5kZWUiIG9mIGFuIGV4dGVuc2lvbiBkZWNsYXJhdGlvbiBhcHBlYXJzIGF0IHRoZQogICBiZWdpbm5pbmcgb2YgdGhlICJleHRlbmQiIGJsb2NrIGFuZCBpcyBzaGFyZWQgYnkgYWxsIGV4dGVuc2lvbnMgd2l0aGluCiAgIHRoZSBibG9jay4KIC0gSnVzdCBiZWNhdXNlIGEgbG9jYXRpb24ncyBzcGFuIGlzIGEgc3Vic2V0IG9mIHNvbWUgb3RoZXIgbG9jYXRpb24ncyBzcGFuCiAgIGRvZXMgbm90IG1lYW4gdGhhdCBpdCBpcyBhIGRlc2NlbmRlbnQuICBGb3IgZXhhbXBsZSwgYSAiZ3JvdXAiIGRlZmluZXMKICAgYm90aCBhIHR5cGUgYW5kIGEgZmllbGQgaW4gYSBzaW5nbGUgZGVjbGFyYXRpb24uICBUaHVzLCB0aGUgbG9jYXRpb25zCiAgIGNvcnJlc3BvbmRpbmcgdG8gdGhlIHR5cGUgYW5kIGZpZWxkIGFuZCB0aGVpciBjb21wb25lbnRzIHdpbGwgb3ZlcmxhcC4KIC0gQ29kZSB3aGljaCB0cmllcyB0byBpbnRlcnByZXQgbG9jYXRpb25zIHNob3VsZCBwcm9iYWJseSBiZSBkZXNpZ25lZCB0bwogICBpZ25vcmUgdGhvc2UgdGhhdCBpdCBkb2Vzbid0IHVuZGVyc3RhbmQsIGFzIG1vcmUgdHlwZXMgb2YgbG9jYXRpb25zIGNvdWxkCiAgIGJlIHJlY29yZGVkIGluIHRoZSBmdXR1cmUuCgoNCgUEEwIABBIE+AUCCgoNCgUEEwIABhIE+AULEwoNCgUEEwIAARIE+AUUHAoNCgUEEwIAAxIE+AUfIAoOCgQEEwMAEgb5BQLMBgMKDQoFBBMDAAESBPkFChIKgwcKBgQTAwACABIEkQYEKhryBiBJZGVudGlmaWVzIHdoaWNoIHBhcnQgb2YgdGhlIEZpbGVEZXNjcmlwdG9yUHJvdG8gd2FzIGRlZmluZWQgYXQgdGhpcwogbG9jYXRpb24uCgogRWFjaCBlbGVtZW50IGlzIGEgZmllbGQgbnVtYmVyIG9yIGFuIGluZGV4LiAgVGhleSBmb3JtIGEgcGF0aCBmcm9tCiB0aGUgcm9vdCBGaWxlRGVzY3JpcHRvclByb3RvIHRvIHRoZSBwbGFjZSB3aGVyZSB0aGUgZGVmaW5pdGlvbi4gIEZvcgogZXhhbXBsZSwgdGhpcyBwYXRoOgogICBbIDQsIDMsIDIsIDcsIDEgXQogcmVmZXJzIHRvOgogICBmaWxlLm1lc3NhZ2VfdHlwZSgzKSAgLy8gNCwgMwogICAgICAgLmZpZWxkKDcpICAgICAgICAgLy8gMiwgNwogICAgICAgLm5hbWUoKSAgICAgICAgICAgLy8gMQogVGhpcyBpcyBiZWNhdXNlIEZpbGVEZXNjcmlwdG9yUHJvdG8ubWVzc2FnZV90eXBlIGhhcyBmaWVsZCBudW1iZXIgNDoKICAgcmVwZWF0ZWQgRGVzY3JpcHRvclByb3RvIG1lc3NhZ2VfdHlwZSA9IDQ7CiBhbmQgRGVzY3JpcHRvclByb3RvLmZpZWxkIGhhcyBmaWVsZCBudW1iZXIgMjoKICAgcmVwZWF0ZWQgRmllbGREZXNjcmlwdG9yUHJvdG8gZmllbGQgPSAyOwogYW5kIEZpZWxkRGVzY3JpcHRvclByb3RvLm5hbWUgaGFzIGZpZWxkIG51bWJlciAxOgogICBvcHRpb25hbCBzdHJpbmcgbmFtZSA9IDE7CgogVGh1cywgdGhlIGFib3ZlIHBhdGggZ2l2ZXMgdGhlIGxvY2F0aW9uIG9mIGEgZmllbGQgbmFtZS4gIElmIHdlIHJlbW92ZWQKIHRoZSBsYXN0IGVsZW1lbnQ6CiAgIFsgNCwgMywgMiwgNyBdCiB0aGlzIHBhdGggcmVmZXJzIHRvIHRoZSB3aG9sZSBmaWVsZCBkZWNsYXJhdGlvbiAoZnJvbSB0aGUgYmVnaW5uaW5nCiBvZiB0aGUgbGFiZWwgdG8gdGhlIHRlcm1pbmF0aW5nIHNlbWljb2xvbikuCgoPCgcEEwMAAgAEEgSRBgQMCg8KBwQTAwACAAUSBJEGDRIKDwoHBBMDAAIAARIEkQYTFwoPCgcEEwMAAgADEgSRBhobCg8KBwQTAwACAAgSBJEGHCkKEgoKBBMDAAIACOcHABIEkQYdKAoTCgsEEwMAAgAI5wcAAhIEkQYdIwoUCgwEEwMAAgAI5wcAAgASBJEGHSMKFQoNBBMDAAIACOcHAAIAARIEkQYdIwoTCgsEEwMAAgAI5wcAAxIEkQYkKArSAgoGBBMDAAIBEgSYBgQqGsECIEFsd2F5cyBoYXMgZXhhY3RseSB0aHJlZSBvciBmb3VyIGVsZW1lbnRzOiBzdGFydCBsaW5lLCBzdGFydCBjb2x1bW4sCiBlbmQgbGluZSAob3B0aW9uYWwsIG90aGVyd2lzZSBhc3N1bWVkIHNhbWUgYXMgc3RhcnQgbGluZSksIGVuZCBjb2x1bW4uCiBUaGVzZSBhcmUgcGFja2VkIGludG8gYSBzaW5nbGUgZmllbGQgZm9yIGVmZmljaWVuY3kuICBOb3RlIHRoYXQgbGluZQogYW5kIGNvbHVtbiBudW1iZXJzIGFyZSB6ZXJvLWJhc2VkIC0tIHR5cGljYWxseSB5b3Ugd2lsbCB3YW50IHRvIGFkZAogMSB0byBlYWNoIGJlZm9yZSBkaXNwbGF5aW5nIHRvIGEgdXNlci4KCg8KBwQTAwACAQQSBJgGBAwKDwoHBBMDAAIBBRIEmAYNEgoPCgcEEwMAAgEBEgSYBhMXCg8KBwQTAwACAQMSBJgGGhsKDwoHBBMDAAIBCBIEmAYcKQoSCgoEEwMAAgEI5wcAEgSYBh0oChMKCwQTAwACAQjnBwACEgSYBh0jChQKDAQTAwACAQjnBwACABIEmAYdIwoVCg0EEwMAAgEI5wcAAgABEgSYBh0jChMKCwQTAwACAQjnBwADEgSYBiQoCqUMCgYEEwMAAgISBMkGBCkalAwgSWYgdGhpcyBTb3VyY2VDb2RlSW5mbyByZXByZXNlbnRzIGEgY29tcGxldGUgZGVjbGFyYXRpb24sIHRoZXNlIGFyZSBhbnkKIGNvbW1lbnRzIGFwcGVhcmluZyBiZWZvcmUgYW5kIGFmdGVyIHRoZSBkZWNsYXJhdGlvbiB3aGljaCBhcHBlYXIgdG8gYmUKIGF0dGFjaGVkIHRvIHRoZSBkZWNsYXJhdGlvbi4KCiBBIHNlcmllcyBvZiBsaW5lIGNvbW1lbnRzIGFwcGVhcmluZyBvbiBjb25zZWN1dGl2ZSBsaW5lcywgd2l0aCBubyBvdGhlcgogdG9rZW5zIGFwcGVhcmluZyBvbiB0aG9zZSBsaW5lcywgd2lsbCBiZSB0cmVhdGVkIGFzIGEgc2luZ2xlIGNvbW1lbnQuCgogbGVhZGluZ19kZXRhY2hlZF9jb21tZW50cyB3aWxsIGtlZXAgcGFyYWdyYXBocyBvZiBjb21tZW50cyB0aGF0IGFwcGVhcgogYmVmb3JlIChidXQgbm90IGNvbm5lY3RlZCB0bykgdGhlIGN1cnJlbnQgZWxlbWVudC4gRWFjaCBwYXJhZ3JhcGgsCiBzZXBhcmF0ZWQgYnkgZW1wdHkgbGluZXMsIHdpbGwgYmUgb25lIGNvbW1lbnQgZWxlbWVudCBpbiB0aGUgcmVwZWF0ZWQKIGZpZWxkLgoKIE9ubHkgdGhlIGNvbW1lbnQgY29udGVudCBpcyBwcm92aWRlZDsgY29tbWVudCBtYXJrZXJzIChlLmcuIC8vKSBhcmUKIHN0cmlwcGVkIG91dC4gIEZvciBibG9jayBjb21tZW50cywgbGVhZGluZyB3aGl0ZXNwYWNlIGFuZCBhbiBhc3Rlcmlzawogd2lsbCBiZSBzdHJpcHBlZCBmcm9tIHRoZSBiZWdpbm5pbmcgb2YgZWFjaCBsaW5lIG90aGVyIHRoYW4gdGhlIGZpcnN0LgogTmV3bGluZXMgYXJlIGluY2x1ZGVkIGluIHRoZSBvdXRwdXQuCgogRXhhbXBsZXM6CgogICBvcHRpb25hbCBpbnQzMiBmb28gPSAxOyAgLy8gQ29tbWVudCBhdHRhY2hlZCB0byBmb28uCiAgIC8vIENvbW1lbnQgYXR0YWNoZWQgdG8gYmFyLgogICBvcHRpb25hbCBpbnQzMiBiYXIgPSAyOwoKICAgb3B0aW9uYWwgc3RyaW5nIGJheiA9IDM7CiAgIC8vIENvbW1lbnQgYXR0YWNoZWQgdG8gYmF6LgogICAvLyBBbm90aGVyIGxpbmUgYXR0YWNoZWQgdG8gYmF6LgoKICAgLy8gQ29tbWVudCBhdHRhY2hlZCB0byBxdXguCiAgIC8vCiAgIC8vIEFub3RoZXIgbGluZSBhdHRhY2hlZCB0byBxdXguCiAgIG9wdGlvbmFsIGRvdWJsZSBxdXggPSA0OwoKICAgLy8gRGV0YWNoZWQgY29tbWVudCBmb3IgY29yZ2UuIFRoaXMgaXMgbm90IGxlYWRpbmcgb3IgdHJhaWxpbmcgY29tbWVudHMKICAgLy8gdG8gcXV4IG9yIGNvcmdlIGJlY2F1c2UgdGhlcmUgYXJlIGJsYW5rIGxpbmVzIHNlcGFyYXRpbmcgaXQgZnJvbQogICAvLyBib3RoLgoKICAgLy8gRGV0YWNoZWQgY29tbWVudCBmb3IgY29yZ2UgcGFyYWdyYXBoIDIuCgogICBvcHRpb25hbCBzdHJpbmcgY29yZ2UgPSA1OwogICAvKiBCbG9jayBjb21tZW50IGF0dGFjaGVkCiAgICAqIHRvIGNvcmdlLiAgTGVhZGluZyBhc3Rlcmlza3MKICAgICogd2lsbCBiZSByZW1vdmVkLiAqLwogICAvKiBCbG9jayBjb21tZW50IGF0dGFjaGVkIHRvCiAgICAqIGdyYXVsdC4gKi8KICAgb3B0aW9uYWwgaW50MzIgZ3JhdWx0ID0gNjsKCiAg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bGUucHJvdG9idWYuRW51bU9wdGlvbnMYseQDIAEoCFIRZ29wcm90b0VudW1QcmVmaXg6UgoVZ29wcm90b19lbnVtX3N0cmluZ2VyEhwuZ29vZ2xlLnByb3RvYnVmLkVudW1PcHRpb25zGMXkAyABKAhSE2dvcHJvdG9FbnVtU3RyaW5nZXI6QwoNZW51bV9zdHJpbmdlchIcLmdvb2dsZS5wcm90b2J1Zi5FbnVtT3B0aW9ucxjG5AMgASgIUgxlbnVtU3RyaW5nZXI6RwoPZW51bV9jdXN0b21uYW1lEhwuZ29vZ2xlLnByb3RvYnVmLkVudW1PcHRpb25zGMfkAyABKAlSDmVudW1DdXN0b21uYW1lOjoKCGVudW1kZWNsEhwuZ29vZ2xlLnByb3RvYnVmLkVudW1PcHRpb25zGMjkAyABKAhSCGVudW1kZWNsOlYKFGVudW12YWx1ZV9jdXN0b21uYW1lEiEuZ29vZ2xlLnByb3RvYnVmLkVudW1WYWx1ZU9wdGlvbnMY0YMEIAEoCVITZW51bXZhbHVlQ3VzdG9tbmFtZTpOChNnb3Byb3RvX2dldHRlcnNfYWxsEhwuZ29vZ2xlLnByb3RvYnVmLkZpbGVPcHRpb25zGJnsAyABKAhSEWdvcHJvdG9HZXR0ZXJzQWxsOlUKF2dvcHJvdG9fZW51bV9wcmVmaXhfYWxsEhwuZ29vZ2xlLnByb3RvYnVmLkZpbGVPcHRpb25zGJrsAyABKAhSFGdvcHJvdG9FbnVtUHJlZml4QWxsOlAKFGdvcHJvdG9fc3RyaW5nZXJfYWxsEhwuZ29vZ2xlLnByb3RvYnVmLkZpbGVPcHRpb25zGJvsAyABKAhSEmdvcHJvdG9TdHJpbmdlckFsbDpKChF2ZXJib3NlX2VxdWFsX2FsbBIcLmdvb2dsZS5wcm90b2J1Zi5GaWxlT3B0aW9ucxic7AMgASgIUg92ZXJib3NlRXF1YWxBbGw6OQoIZmFjZV9hbGwSHC5nb29nbGUucHJvdG9idWYuRmlsZU9wdGlvbnMYnewDIAEoCFIHZmFjZUFsbDpBCgxnb3N0cmluZ19hbGwSHC5nb29nbGUucHJvdG9idWYuRmlsZU9wdGlvbnMYnuwDIAEoCFILZ29zdHJpbmdBbGw6QQoMcG9wdWxhdGVfYWxsEhwuZ29vZ2xlLnByb3RvYnVmLkZpbGVPcHRpb25zGJ/sAyABKAhSC3BvcHVsYXRlQWxsOkEKDHN0cmluZ2VyX2FsbBIcLmdvb2dsZS5wcm90b2J1Zi5GaWxlT3B0aW9ucxig7AMgASgIUgtzdHJpbmdlckFsbDo/Cgtvbmx5b25lX2FsbBIcLmdvb2dsZS5wcm90b2J1Zi5GaWxlT3B0aW9ucxih7AMgASgIUgpvbmx5b25lQWxsOjsKCWVxdWFsX2FsbBIcLmdvb2dsZS5wcm90b2J1Zi5GaWxlT3B0aW9ucxil7AMgASgIUghlcXVhbEFsbDpHCg9kZXNjcmlwdGlvbl9hbGwSHC5nb29nbGUucHJvdG9idWYuRmlsZU9wdGlvbnMYpuwDIAEoCFIOZGVzY3JpcHRpb25BbGw6PwoLdGVzdGdlbl9hbGwSHC5nb29nbGUucHJvdG9idWYuRmlsZU9wdGlvbnMYp+wDIAEoCFIKdGVzdGdlbkFsbDpBCgxiZW5jaGdlbl9hbGwSHC5nb29nbGUucHJvdG9idWYuRmlsZU9wdGlvbnMYqOwDIAEoCFILYmVuY2hnZW5BbGw6QwoNbWFyc2hhbGVyX2FsbBIcLmdvb2dsZS5wcm90b2J1Zi5GaWxlT3B0aW9ucxip7AMgASgIUgxtYXJzaGFsZXJBbGw6RwoPdW5tYXJzaGFsZXJfYWxsEhwuZ29vZ2xlLnByb3RvYnVmLkZpbGVPcHRpb25zGKrsAyABKAhSDnVubWFyc2hhbGVyQWxsOlAKFHN0YWJsZV9tYXJzaGFsZXJfYWxsEhwuZ29vZ2xlLnByb3RvYnVmLkZpbGVPcHRpb25zGKvsAyABKAhSEnN0YWJsZU1hcnNoYWxlckFsbDo7CglzaXplcl9hbGwSHC5nb29nbGUucHJvdG9idWYuRmlsZU9wdGlvbnMYrOwDIAEoCFIIc2l6ZXJBbGw6WQoZZ29wcm90b19lbnVtX3N0cmluZ2VyX2FsbBIcLmdvb2dsZS5wcm90b2J1Zi5GaWxlT3B0aW9ucxit7AMgASgIUhZnb3Byb3RvRW51bVN0cmluZ2VyQWxsOkoKEWVudW1fc3RyaW5nZXJfYWxsEhwuZ29vZ2xlLnByb3RvYnVmLkZpbGVPcHRpb25zGK7sAyABKAhSD2VudW1TdHJpbmdlckFsbDpQChR1bnNhZmVfbWFyc2hhbGVyX2FsbBIcLmdvb2dsZS5wcm90b2J1Zi5GaWxlT3B0aW9ucxiv7AMgASgIUhJ1bnNhZmVNYXJzaGFsZXJBbGw6VAoWdW5zYWZlX3VubWFyc2hhbGVyX2FsbBIcLmdvb2dsZS5wcm90b2J1Zi5GaWxlT3B0aW9ucxiw7AMgASgIUhR1bnNhZmVVbm1hcnNoYWxlckFsbDpbChpnb3Byb3RvX2V4dGVuc2lvbnNfbWFwX2FsbBIcLmdvb2dsZS5wcm90b2J1Zi5GaWxlT3B0aW9ucxix7AMgASgIUhdnb3Byb3RvRXh0ZW5zaW9uc01hcEFsbDpYChhnb3Byb3RvX3VucmVjb2duaXplZF9hbGwSHC5nb29nbGUucHJvdG9idWYuRmlsZU9wdGlvbnMYsuwDIAEoCFIWZ29wcm90b1VucmVjb2duaXplZEFsbDpJChBnb2dvcHJvdG9faW1wb3J0EhwuZ29vZ2xlLnByb3RvYnVmLkZpbGVPcHRpb25zGLPsAyABKAhSD2dvZ29wcm90b0ltcG9ydDpFCg5wcm90b3NpemVyX2FsbBIcLmdvb2dsZS5wcm90b2J1Zi5GaWxlT3B0aW9ucxi07AMgASgIUg1wcm90b3NpemVyQWxsOj8KC2NvbXBhcmVfYWxsEhwuZ29vZ2xlLnByb3RvYnVmLkZpbGVPcHRpb25zGLXsAyABKAhSCmNvbXBhcmVBbGw6QQoMdHlwZWRlY2xfYWxsEhwuZ29vZ2xlLnByb3RvYnVmLkZpbGVPcHRpb25zGLbsAyABKAhSC3R5cGVkZWNsQWxsOkEKDGVudW1kZWNsX2FsbBIcLmdvb2dsZS5wcm90b2J1Zi5GaWxlT3B0aW9ucxi37AMgASgIUgtlbnVtZGVjbEFsbDpRChRnb3Byb3RvX3JlZ2lzdHJhdGlvbhIcLmdvb2dsZS5wcm90b2J1Zi5GaWxlT3B0aW9ucxi47AMgASgIUhNnb3Byb3RvUmVnaXN0cmF0aW9uOkcKD21lc3NhZ2VuYW1lX2FsbBIcLmdvb2dsZS5wcm90b2J1Zi5GaWxlT3B0aW9ucxi57AMgASgIUg5tZXNzYWdlbmFtZUFsbDpKCg9nb3Byb3RvX2dldHRlcnMSHy5nb29nbGUucHJvdG9idWYuTWVzc2FnZU9wdGlvbnMYgfQDIAEoCFIOZ29wcm90b0dldHRlcnM6TAoQZ29wcm90b19zdHJpbmdlchIfLmdvb2dsZS5wcm90b2J1Zi5NZXNzYWdlT3B0aW9ucxiD9AMgASgIUg9nb3Byb3RvU3RyaW5nZXI6RgoNdmVyYm9zZV9lcXVhbBIfLmdvb2dsZS5wcm90b2J1Zi5NZXNzYWdlT3B0aW9ucxiE9AMgASgIUgx2ZXJib3NlRXF1YWw6NQoEZmFjZRIfLmdvb2dsZS5wcm90b2J1Zi5NZXNzYWdlT3B0aW9ucxiF9AMgASgIUgRmYWNlOj0KCGdvc3RyaW5nEh8uZ29vZ2xlLnByb3RvYnVmLk1lc3NhZ2VPcHRpb25zGIb0AyABKAhSCGdvc3RyaW5nOj0KCHBvcHVsYXRlEh8uZ29vZ2xlLnByb3RvYnVmLk1lc3NhZ2VPcHRpb25zGIf0AyABKAhSCHBvcHVsYXRlOj0KCHN0cmluZ2VyEh8uZ29vZ2xlLnByb3RvYnVmLk1lc3NhZ2VPcHRpb25zGMCLBCABKAhSCHN0cmluZ2VyOjsKB29ubHlvbmUSHy5nb29nbGUucHJvdG9idWYuTWVzc2FnZU9wdGlvbnMYifQDIAEoCFIHb25seW9uZTo3CgVlcXVhbBIfLmdvb2dsZS5wcm90b2J1Zi5NZXNzYWdlT3B0aW9ucxiN9AMgASgIUgVlcXVhbDpDCgtkZXNjcmlwdGlvbhIfLmdvb2dsZS5wcm90b2J1Zi5NZXNzYWdlT3B0aW9ucxiO9AMgASgIUgtkZXNjcmlwdGlvbjo7Cgd0ZXN0Z2VuEh8uZ29vZ2xlLnByb3RvYnVmLk1lc3NhZ2VPcHRpb25zGI/0AyABKAhSB3Rlc3RnZW46PQoIYmVuY2hnZW4SHy5nb29nbGUucHJvdG9idWYuTWVzc2FnZU9wdGlvbnMYkPQDIAEoCFIIYmVuY2hnZW46PwoJbWFyc2hhbGVyEh8uZ29vZ2xlLnByb3RvYnVmLk1lc3NhZ2VPcHRpb25zGJH0AyABKAhSCW1hcnNoYWxlcjpDCgt1bm1hcnNoYWxlchIfLmdvb2dsZS5wcm90b2J1Zi5NZXNzYWdlT3B0aW9ucxiS9AMgASgIUgt1bm1hcnNoYWxlcjpMChBzdGFibGVfbWFyc2hhbGVyEh8uZ29vZ2xlLnByb3RvYnVmLk1lc3NhZ2VPcHRpb25zGJP0AyABKAhSD3N0YWJsZU1hcnNoYWxlcjo3CgVzaXplchIfLmdvb2dsZS5wcm90b2J1Zi5NZXNzYWdlT3B0aW9ucxiU9AMgASgIUgVzaXplcjpMChB1bnNhZmVfbWFyc2hhbGVyEh8uZ29vZ2xlLnByb3RvYnVmLk1lc3NhZ2VPcHRpb25zGJf0AyABKAhSD3Vuc2FmZU1hcnNoYWxlcjpQChJ1bnNhZmVfdW5tYXJzaGFsZXISHy5nb29nbGUucHJvdG9idWYuTWVzc2FnZU9wdGlvbnMYmPQDIAEoCFIRdW5zYWZlVW5tYXJzaGFsZXI6VwoWZ29wcm90b19leHRlbnNpb25zX21hcBIfLmdvb2dsZS5wcm90b2J1Zi5NZXNzYWdlT3B0aW9ucxiZ9AMgASgIUhRnb3Byb3RvRXh0ZW5zaW9uc01hcDpUChRnb3Byb3RvX3VucmVjb2duaXplZBIfLmdvb2dsZS5wcm90b2J1Zi5NZXNzYWdlT3B0aW9ucxia9AMgASgIUhNnb3Byb3RvVW5yZWNvZ25pemVkOkEKCnByb3Rvc2l6ZXISHy5nb29nbGUucHJvdG9idWYuTWVzc2FnZU9wdGlvbnMYnPQDIAEoCFIKcHJvdG9zaXplcjo7Cgdjb21wYXJlEh8uZ29vZ2xlLnByb3RvYnVmLk1lc3NhZ2VPcHRpb25zGJ30AyABKAhSB2NvbXBhcmU6PQoIdHlwZWRlY2wSHy5nb29nbGUucHJvdG9idWYuTWVzc2FnZU9wdGlvbnMYnvQDIAEoCFIIdHlwZWRlY2w6QwoLbWVzc2FnZW5hbWUSHy5nb29nbGUucHJvdG9idWYuTWVzc2FnZU9wdGlvbnMYofQDIAEoCFILbWVzc2FnZW5hbWU6OwoIbnVsbGFibGUSHS5nb29nbGUucHJvdG9idWYuRmllbGRPcHRpb25zGOn7AyABKAhSCG51bGxhYmxlOjUKBWVtYmVkEh0uZ29vZ2xlLnByb3RvYnVmLkZpZWxkT3B0aW9ucxjq+wMgASgIUgVlbWJlZDo/CgpjdXN0b210eXBlEh0uZ29vZ2xlLnByb3RvYnVmLkZpZWxkT3B0aW9ucxjr+wMgASgJUgpjdXN0b210eXBlOj8KCmN1c3RvbW5hbWUSHS5nb29nbGUucHJvdG9idWYuRmllbGRPcHRpb25zGOz7AyABKAlSCmN1c3RvbW5hbWU6OQoHanNvbnRhZxIdLmdvb2dsZS5wcm90b2J1Zi5GaWVsZE9wdGlvbnMY7fsDIAEoCVIHanNvbnRhZzo7Cghtb3JldGFncxIdLmdvb2dsZS5wcm90b2J1Zi5GaWVsZE9wdGlvbnMY7vsDIAEoCVIIbW9yZXRhZ3M6OwoIY2FzdHR5cGUSHS5nb29nbGUucHJvdG9idWYuRmllbGRPcHRpb25zGO/7AyABKAlSCGNhc3R0eXBlOjkKB2Nhc3RrZXkSHS5nb29nbGUucHJvdG9idWYuRmllbGRPcHRpb25zGPD7AyABKAlSB2Nhc3RrZXk6PQoJY2FzdHZhbHVlEh0uZ29vZ2xlLnByb3RvYnVmLkZpZWxkT3B0aW9ucxjx+wMgASgJUgljYXN0dmFsdWU6OQoHc3RkdGltZRIdLmdvb2dsZS5wcm90b2J1Zi5GaWVsZE9wdGlvbnMY8vsDIAEoCFIHc3RkdGltZTpBCgtzdGRkdXJhdGlvbhIdLmdvb2dsZS5wcm90b2J1Zi5GaWVsZE9wdGlvbnMY8/sDIAEoCFILc3RkZHVyYXRpb25CRQoTY29tLmdvb2dsZS5wcm90b2J1ZkIKR29Hb1Byb3Rvc1oiZ2l0aHViLmNvbS9nb2dvL3Byb3RvYnVmL2dvZ29wcm90b0qaNQoHEgUcAIcBAQr8CgoBDBIDHAASMvEKIFByb3RvY29sIEJ1ZmZlcnMgZm9yIEdvIHdpdGggR2FkZ2V0cwoKIENvcHlyaWdodCAoYykgMjAxMywgVGhlIEdvR28gQXV0aG9ycy4gQWxsIHJpZ2h0cyByZXNlcnZlZC4KIGh0dHA6Ly9naXRodWIuY29tL2dvZ28vcHJvdG9idWYKCiBSZWRpc3RyaWJ1dGlvbiBhbmQgdXNlIGluIHNvdXJjZSBhbmQgYmluYXJ5IGZvcm1zLCB3aXRoIG9yIHdpdGhvdXQKIG1vZGlmaWNhdGlvbiwgYXJlIHBlcm1pdHRlZCBwcm92aWRlZCB0aGF0IHRoZSBmb2xsb3dpbmcgY29uZGl0aW9ucyBhcmUKIG1ldDoKCiAgICAgKiBSZWRpc3RyaWJ1dGlvbnMgb2Ygc291cmNlIGNvZGUgbXVzdCByZXRhaW4gdGhlIGFib3ZlIGNvcHlyaWdodAogbm90aWNlLCB0aGlzIGxpc3Qgb2YgY29uZGl0aW9ucyBhbmQgdGhlIGZvbGxvd2luZyBkaXNjbGFpbWVyLgogICAgICogUmVkaXN0cmlidXRpb25zIGluIGJpbmFyeSBmb3JtIG11c3QgcmVwcm9kdWNlIHRoZSBhYm92ZQogY29weXJpZ2h0IG5vdGljZSwgdGhpcyBsaXN0IG9mIGNvbmRpdGlvbnMgYW5kIHRoZSBmb2xsb3dpbmcgZGlzY2xhaW1lcgogaW4gdGhlIGRvY3VtZW50YXRpb24gYW5kL29yIG90aGVyIG1hdGVyaWFscyBwcm92aWRlZCB3aXRoIHRoZQogZGlzdHJpYnV0aW9uLgoKIFRISVMgU09GVFdBUkUgSVMgUFJPVklERUQgQlkgVEhFIENPUFlSSUdIVCBIT0xERVJTIEFORCBDT05UUklCVVRPUlMKICJBUyBJUyIgQU5EIEFOWSBFWFBSRVNTIE9SIElNUExJRUQgV0FSUkFOVElFUywgSU5DTFVESU5HLCBCVVQgTk9UCiBMSU1JVEVEIFRPLCBUSEUgSU1QTElFRCBXQVJSQU5USUVTIE9GIE1FUkNIQU5UQUJJTElUWSBBTkQgRklUTkVTUyBGT1IKIEEgUEFSVElDVUxBUiBQVVJQT1NFIEFSRSBESVNDTEFJTUVELiBJTiBOTyBFVkVOVCBTSEFMTCBUSEUgQ09QWVJJR0hUCiBPV05FUiBPUiBDT05UUklCVVRPUlMgQkUgTElBQkxFIEZPUiBBTlkgRElSRUNULCBJTkRJUkVDVCwgSU5DSURFTlRBTCwKIFNQRUNJQUwsIEVYRU1QTEFSWSwgT1IgQ09OU0VRVUVOVElBTCBEQU1BR0VTIChJTkNMVURJTkcsIEJVVCBOT1QKIExJTUlURUQgVE8sIFBST0NVUkVNRU5UIE9GIFNVQlNUSVRVVEUgR09PRFMgT1IgU0VSVklDRVM7IExPU1MgT0YgVVNFLAogREFUQSwgT1IgUFJPRklUUzsgT1IgQlVTSU5FU1MgSU5URVJSVVBUSU9OKSBIT1dFVkVSIENBVVNFRCBBTkQgT04gQU5ZCiBUSEVPUlkgT0YgTElBQklMSVRZLCBXSEVUSEVSIElOIENPTlRSQUNULCBTVFJJQ1QgTElBQklM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B0USBIUBCCYKCgoDB0UCEgN6ByMKCwoDB0UEEgSFAQgQCgsKAwdFBRIEhQERFQoLCgMHRQESBIUBFh0KCwoDB0UDEgSFASAlCgoKAgdGEgSGAQgqCgoKAwdGAhIDegcjCgsKAwdGBBIEhgEIEAoLCgMHRgUSBIYBERUKCwoDB0YBEgSGARYhCgsKAwdGAxIEhgEkKQqMFwosbWl4ZXIvYWRhcHRlci9tb2RlbC92MWJldGExL2V4dGVuc2lvbnMucHJvdG8SIWlzdGlvLm1peGVyLmFkYXB0ZXIubW9kZWwudjFiZXRhMRogZ29vZ2xlL3Byb3RvYnVmL2Rlc2NyaXB0b3IucHJvdG8quAEKD1RlbXBsYXRlVmFyaWV0eRIaChZURU1QTEFURV9WQVJJRVRZX0NIRUNLEAASGwoXVEVNUExBVEVfVkFSSUVUWV9SRVBPUlQQARIaChZURU1QTEFURV9WQVJJRVRZX1FVT1RBEAISKAokVEVNUExBVEVfVkFSSUVUWV9BVFRSSUJVVEVfR0VORVJBVE9SEAMSJgoiVEVNUExBVEVfVkFSSUVUWV9DSEVDS19XSVRIX09VVFBVVBAEOn4KEHRlbXBsYXRlX3ZhcmlldHkSHC5nb29nbGUucHJvdG9idWYuRmlsZU9wdGlvbnMYr8q8IiABKA4yMi5pc3Rpby5taXhlci5hZGFwdGVyLm1vZGVsLnYxYmV0YTEuVGVtcGxhdGVWYXJpZXR5Ug90ZW1wbGF0ZVZhcmlldHk6RAoNdGVtcGxhdGVfbmFtZRIcLmdvb2dsZS5wcm90b2J1Zi5GaWxlT3B0aW9ucxjQy7wiIAEoCVIMdGVtcGxhdGVOYW1lQipaKGlzdGlvLmlvL2FwaS9taXhlci9hZGFwdGVyL21vZGVsL3YxYmV0YTFK4RIKBhIEDgAyAQq/BAoBDBIDDgASMrQEIENvcHlyaWdodCAyMDE4IElzdGlvIEF1dGhvcnMKCiBMaWNlbnNlZCB1bmRlciB0aGUgQXBhY2hlIExpY2Vuc2UsIFZlcnNpb24gMi4wICh0aGUgIkxpY2Vuc2UiKTsKIHlvdSBtYXkgbm90IHVzZSB0aGlzIGZpbGUgZXhjZXB0IGluIGNvbXBsaWFuY2Ugd2l0aCB0aGUgTGljZW5zZS4KIFlvdSBtYXkgb2J0YWluIGEgY29weSBvZiB0aGUgTGljZW5zZSBhdAoKICAgICBodHRwOi8vd3d3LmFwYWNoZS5vcmcvbGljZW5zZXMvTElDRU5TRS0yLjAKCiBVbmxlc3MgcmVxdWlyZWQgYnkgYXBwbGljYWJsZSBsYXcgb3IgYWdyZWVkIHRvIGluIHdyaXRpbmcsIHNvZnR3YXJlCiBkaXN0cmlidXRlZCB1bmRlciB0aGUgTGljZW5zZSBpcyBkaXN0cmlidXRlZCBvbiBhbiAiQVMgSVMiIEJBU0lTLAogV0lUSE9VVCBXQVJSQU5USUVTIE9SIENPTkRJVElPTlMgT0YgQU5ZIEtJTkQsIGVpdGhlciBleHByZXNzIG9yIGltcGxpZWQuCiBTZWUgdGhlIExpY2Vuc2UgZm9yIHRoZSBzcGVjaWZpYyBsYW5ndWFnZSBnb3Zlcm5pbmcgcGVybWlzc2lvbnMgYW5kCiBsaW1pdGF0aW9ucyB1bmRlciB0aGUgTGljZW5zZS4KCggKAQISAxAIKQoICgEIEgMSAD0KCwoECOcHABIDEgA9CgwKBQjnBwACEgMSBxEKDQoGCOcHAAIAEgMSBxEKDgoHCOcHAAIAARIDEgcRCgwKBQjnBwAHEgMSEjwKCQoCAwASAxQHKQp5CgIFABIEGAAoARptIFRoZSBhdmFpbGFibGUgdmFyaWV0aWVzIG9mIHRlbXBsYXRlcywgY29udHJvbGxpbmcgdGhlIHNlbWFudGljcyBvZiB3aGF0IGFuIGFkYXB0ZXIgZG9lcyB3aXRoIGVhY2ggaW5zdGFuY2UuCgoKCgMFAAESAxgFFArHAQoEBQACABIDGwQfGrkBIE1ha2VzIHRoZSB0ZW1wbGF0ZSBhcHBsaWNhYmxlIGZvciBNaXhlcidzIGNoZWNrIGNhbGxzLiBJbnN0YW5jZXMgb2Ygc3VjaCB0ZW1wbGF0ZSBhcmUgY3JlYXRlZCBkdXJpbmcKIGNoZWNrIGNhbGxzIGluIE1peGVyIGFuZCBwYXNzZWQgdG8gdGhlIGhhbmRsZXJzIGJhc2VkIG9uIHRoZSBydWxlIGNvbmZpZ3VyYXRpb25zLgoKDAoFBQACAAESAxsEGgoMCgUFAAIAAhIDGx0eCskBCgQFAAIBEgMeBCAauwEgTWFrZXMgdGhlIHRlbXBsYXRlIGFwcGxpY2FibGUgZm9yIE1peGVyJ3MgcmVwb3J0IGNhbGxzLiBJbnN0YW5jZXMgb2Ygc3VjaCB0ZW1wbGF0ZSBhcmUgY3JlYXRlZCBkdXJpbmcKIHJlcG9ydCBjYWxscyBpbiBNaXhlciBhbmQgcGFzc2VkIHRvIHRoZSBoYW5kbGVycyBiYXNlZCBvbiB0aGUgcnVsZSBjb25maWd1cmF0aW9ucy4KCgwKBQUAAgEBEgMeBBsKDAoFBQACAQISAx4eHwrNAQoEBQACAhIDIQQfGr8BIE1ha2VzIHRoZSB0ZW1wbGF0ZSBhcHBsaWNhYmxlIGZvciBNaXhlcidzIHF1b3RhIGNhbGxzLiBJbnN0YW5jZXMgb2Ygc3VjaCB0ZW1wbGF0ZSBhcmUgY3JlYXRlZCBkdXJpbmcKIHF1b3RhIGNoZWNrIGNhbGxzIGluIE1peGVyIGFuZCBwYXNzZWQgdG8gdGhlIGhhbmRsZXJzIGJhc2VkIG9uIHRoZSBydWxlIGNvbmZpZ3VyYXRpb25zLgoKDAoFBQACAgESAyEEGgoMCgUFAAICAhIDIR0eCusBCgQFAAIDEgMkBC0a3QEgTWFrZXMgdGhlIHRlbXBsYXRlIGFwcGxpY2FibGUgZm9yIE1peGVyJ3MgYXR0cmlidXRlIGdlbmVyYXRpb24gcGhhc2UuIEluc3RhbmNlcyBvZiBzdWNoIHRlbXBsYXRlIGFyZSBjcmVhdGVkIGR1cmluZwogcHJlLXByb2Nlc3NpbmcgYXR0cmlidXRlIGdlbmVyYXRpb24gcGhhc2UgYW5kIHBhc3NlZCB0byB0aGUgaGFuZGxlcnMgYmFzZWQgb24gdGhlIHJ1bGUgY29uZmlndXJhdGlvbnMuCgoMCgUFAAIDARIDJAQoCgwKBQUAAgMCEgMkKywKugEKBAUAAgQSAycEKxqsASBNYWtlcyB0aGUgdGVtcGxhdGUgYXBwbGljYWJsZSBmb3IgTWl4ZXIncyBjaGVjayBjYWxscy4gSW5zdGFuY2VzIG9mIHN1Y2ggdGVtcGxhdGUgYXJlIGNyZWF0ZWQgZHVyaW5nCiBjaGVjayBjYWxscyBpbiBNaXhlciBhbmQgcGFzc2VkIHRvIHRoZSBoYW5kbGVycyB0aGF0IHByb2R1Y2UgdmFsdWVzLgoKDAoFBQACBAESAycEJgoMCgUFAAIEAhIDJykqCjEKAQcSBCsAMgEaJiBGaWxlIGxldmVsIG9wdGlvbnMgZm9yIHRoZSB0ZW1wbGF0ZS4KCjYKAgcAEgMtBDAaKyBSZXF1aXJlZDogb3B0aW9uIGZvciB0aGUgVGVtcGxhdGVWYXJpZXR5LgoKCgoDBwACEgMrByIKCwoDBwAEEgQtBCskCgoKAwcABhIDLQQTCgoKAwcAARIDLRQkCgoKAwcAAxIDLScvCqQBCgIHARIDMQQkGpgBIE9wdGlvbmFsOiBvcHRpb24gZm9yIHRoZSB0ZW1wbGF0ZSBuYW1lLgogSWYgbm90IHNwZWNpZmllZCwgdGhlIGxhc3Qgc2VnbWVudCBvZiB0aGUgdGVtcGxhdGUgcHJvdG8ncyBwYWNrYWdlIG5hbWUgaXMgdXNlZCB0bwogZGVyaXZlIHRoZSB0ZW1wbGF0ZSBuYW1lLgoKCgoDBwECEgMrByIKCwoDBwEEEgQxBC0wCgoKAwcBBRIDMQQKCgoKAwcBARIDMQsYCgoKAwcBAxIDMRsjYgZwcm90bzMK3CwKGWdvb2dsZS9wcm90b2J1Zi9hbnkucHJvdG8SD2dvb2dsZS5wcm90b2J1ZiI2CgNBbnkSGQoIdHlwZV91cmwYASABKAlSB3R5cGVVcmwSFAoFdmFsdWUYAiABKAxSBXZhbHVlQm8KE2NvbS5nb29nbGUucHJvdG9idWZCCEFueVByb3RvUAFaJWdpdGh1Yi5jb20vZ29sYW5nL3Byb3RvYnVmL3B0eXBlcy9hbnmiAgNHUEKqAh5Hb29nbGUuUHJvdG9idWYuV2VsbEtub3duVHlwZXNK/CoKBxIFHgCUAQEKzAwKAQwSAx4AEjLBDCBQcm90b2NvbCBCdWZmZXJzIC0gR29vZ2xlJ3MgZGF0YSBpbnRlcmNoYW5nZSBmb3JtYXQKIENvcHlyaWdodCAyMDA4IEdvb2dsZSBJbmMuICBBbGwgcmlnaHRzIHJlc2VydmVkLgogaHR0cHM6Ly9kZXZlbG9wZXJzLmdvb2dsZS5jb20vcHJvdG9jb2wtYnVmZmVycy8KCiBSZWRpc3RyaWJ1dGlvbiBhbmQgdXNlIGluIHNvdXJjZSBhbmQgYmluYXJ5IGZvcm1zLCB3aXRoIG9yIHdpdGhvdXQKIG1vZGlmaWNhdGlvbiwgYXJlIHBlcm1pdHRlZCBwcm92aWRlZCB0aGF0IHRoZSBmb2xsb3dpbmcgY29uZGl0aW9ucyBhcmUKIG1ldDoKCiAgICAgKiBSZWRpc3RyaWJ1dGlvbnMgb2Ygc291cmNlIGNvZGUgbXVzdCByZXRhaW4gdGhlIGFib3ZlIGNvcHlyaWdodAogbm90aWNlLCB0aGlzIGxpc3Qgb2YgY29uZGl0aW9ucyBhbmQgdGhlIGZvbGxvd2luZyBkaXNjbGFpbWVyLgogICAgICogUmVkaXN0cmlidXRpb25zIGluIGJpbmFyeSBmb3JtIG11c3QgcmVwcm9kdWNlIHRoZSBhYm92ZQogY29weXJpZ2h0IG5vdGljZSwgdGhpcyBsaXN0IG9mIGNvbmRpdGlvbnMgYW5kIHRoZSBmb2xsb3dpbmcgZGlzY2xhaW1lcgogaW4gdGhlIGRvY3VtZW50YXRpb24gYW5kL29yIG90aGVyIG1hdGVyaWFscyBwcm92aWRlZCB3aXRoIHRoZQogZGlzdHJpYnV0aW9uLgogICAgICogTmVpdGhlciB0aGUgbmFtZSBvZiBHb29nbGUgSW5jLiBub3IgdGhlIG5hbWVzIG9mIGl0cwogY29udHJpYnV0b3JzIG1heSBiZSB1c2VkIHRvIGVuZG9yc2Ugb3IgcHJvbW90ZSBwcm9kdWN0cyBkZXJpdmVkIGZyb20KIHRoaXMgc29mdHdhcmUgd2l0aG91dCBzcGVjaWZpYyBwcmlvciB3cml0dGVuIHBlcm1pc3Npb24uCgogVEhJUyBTT0ZUV0FSRSBJUyBQUk9WSURFRCBCWSBUSEUgQ09QWVJJR0hUIEhPTERFUlMgQU5EIENPTlRSSUJVVE9SUwogIkFTIElTIiBBTkQgQU5ZIEVYUFJFU1MgT1IgSU1QTElFRCBXQVJSQU5USUVTLCBJTkNMVURJTkcsIEJVVCBOT1QKIExJTUlURUQgVE8sIFRIRSBJTVBMSUVEIFdBUlJBTlRJRVMgT0YgTUVSQ0hBTlRBQklMSVRZIEFORCBGSVRORVNTIEZPUgogQSBQQVJUSUNVTEFSIFBVUlBPU0UgQVJFIERJU0NMQUlNRUQuIElOIE5PIEVWRU5UIFNIQUxMIFRIRSBDT1BZUklHSFQKIE9XTkVSIE9SIENPTlRSSUJVVE9SUyBCRSBMSUFCTEUgRk9SIEFO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cGFjayBhIG1lc3NhZ2UgaW4gR28KCiAgICAgIGZvbyA6PSAmcGIuRm9vey4uLn0KICAgICAgYW55LCBlcnIgOj0gcHR5cGVzLk1hcnNoYWxBbnkoZm9vKQogICAgICAuLi4KICAgICAgZm9vIDo9ICZwYi5Gb297fQogICAgICBpZiBlcnIgOj0gcHR5cGVzLlVubWFyc2hhbEFueShhbnksIGZvbyk7IGVyciAhPSBuaWwgewogICAgICAgIC4uLgogICAgICB9CgogVGhlIHBhY2sgbWV0aG9kcyBwcm92aWRlZCBieSBwcm90b2J1ZiBsaWJyYXJ5IHdpbGwgYnkgZGVmYXVsdCB1c2UKICd0eXBlLmdvb2dsZWFwaXMuY29tL2Z1bGwudHlwZS5uYW1lJyBhcyB0aGUgdHlwZSBVUkwgYW5kIHRoZSB1bnBhY2sKIG1ldGhvZHMgb25seSB1c2UgdGhlIGZ1bGx5IHF1YWxpZmllZCB0eXBlIG5hbWUgYWZ0ZXIgdGhlIGxhc3QgJy8nCiBpbiB0aGUgdHlwZSBVUkwsIGZvciBleGFtcGxlICJmb28uYmFyLmNvbS94L3kueiIgd2lsbCB5aWVsZCB0eXBlCiBuYW1lICJ5LnoiLgoKCiBKU09OCiA9PT09CiBUaGUgSlNPTiByZXByZXNlbnRhdGlvbiBvZiBhbiBgQW55YCB2YWx1ZSB1c2VzIHRoZSByZWd1bGFyCiByZXByZXNlbnRhdGlvbiBvZiB0aGUgZGVzZXJpYWxpemVkLCBlbWJlZGRlZCBtZXNzYWdlLCB3aXRoIGFuCiBhZGRpdGlvbmFsIGZpZWxkIGBAdHlwZWAgd2hpY2ggY29udGFpbnMgdGhlIHR5cGUgVVJMLiBFeGFtcGxlOgoKICAgICBwYWNrYWdlIGdvb2dsZS5wcm9maWxlOwogICAgIG1lc3NhZ2UgUGVyc29uIHsKICAgICAgIHN0cmluZyBmaXJzdF9uYW1lID0gMTsKICAgICAgIHN0cmluZyBsYXN0X25hbWUgPSAyOwogICAgIH0KCiAgICAgewogICAgICAgIkB0eXBlIjogInR5cGUuZ29vZ2xlYXBpcy5jb20vZ29vZ2xlLnByb2ZpbGUuUGVyc29uIiwKICAgICAgICJmaXJzdE5hbWUiOiA8c3RyaW5nPiwKICAgICAgICJsYXN0TmFtZSI6IDxzdHJpbmc+CiAgICAgfQoKIElmIHRoZSBlbWJlZGRlZCBtZXNzYWdlIHR5cGUgaXMgd2VsbC1rbm93biBhbmQgaGFzIGEgY3VzdG9tIEpTT04KIHJlcHJlc2VudGF0aW9uLCB0aGF0IHJlcHJlc2VudGF0aW9uIHdpbGwgYmUgZW1iZWRkZWQgYWRkaW5nIGEgZmllbGQKIGB2YWx1ZWAgd2hpY2ggaG9sZHMgdGhlIGN1c3RvbSBKU09OIGluIGFkZGl0aW9uIHRvIHRoZSBgQHR5cGVgCiBmaWVsZC4gRXhhbXBsZSAoZm9yIG1lc3NhZ2UgW2dvb2dsZS5wcm90b2J1Zi5EdXJhdGlvbl1bXSk6CgogICAgIHsKICAgICAgICJAdHlwZSI6ICJ0eXBlLmdvb2dsZWFwaXMuY29tL2dvb2dsZS5wcm90b2J1Zi5EdXJhdGlvbiIsCiAgICAgICAidmFsdWUiOiAiMS4yMTJzIgogICAgIH0KCgoKCgMEAAESA3kICwrkBwoEBAACABIEkAECFhrVByBBIFVSTC9yZXNvdXJjZSBuYW1lIHdob3NlIGNvbnRlbnQgZGVzY3JpYmVzIHRoZSB0eXBlIG9mIHRoZQogc2VyaWFsaXplZCBwcm90b2NvbCBidWZmZXIgbWVzc2FnZS4KCiBGb3IgVVJMcyB3aGljaCB1c2UgdGhlIHNjaGVtZSBgaHR0cGAsIGBodHRwc2AsIG9yIG5vIHNjaGVtZSwgdGhlCiBmb2xsb3dpbmcgcmVzdHJpY3Rpb25zIGFuZCBpbnRlcnByZXRhdGlvbnMgYXBwbHk6CgogKiBJZiBubyBzY2hlbWUgaXMgcHJvdmlkZWQsIGBodHRwc2AgaXMgYXNzdW1lZC4KICogVGhlIGxhc3Qgc2VnbWVudCBvZiB0aGUgVVJMJ3MgcGF0aCBtdXN0IHJlcHJlc2VudCB0aGUgZnVsbHkKICAgcXVhbGlmaWVkIG5hbWUgb2YgdGhlIHR5cGUgKGFzIGluIGBwYXRoL2dvb2dsZS5wcm90b2J1Zi5EdXJhdGlvbmApLgogICBUaGUgbmFtZSBzaG91bGQgYmUgaW4gYSBjYW5vbmljYWwgZm9ybSAoZS5nLiwgbGVhZGluZyAiLiIgaXMKICAgbm90IGFjY2VwdGVkKS4KICogQW4gSFRUUCBHRVQgb24gdGhlIFVSTCBtdXN0IHlpZWxkIGEgW2dvb2dsZS5wcm90b2J1Zi5UeXBlXVtdCiAgIHZhbHVlIGluIGJpbmFyeSBmb3JtYXQsIG9yIHByb2R1Y2UgYW4gZXJyb3IuCiAqIEFwcGxpY2F0aW9ucyBhcmUgYWxsb3dlZCB0byBjYWNoZSBsb29rdXAgcmVzdWx0cyBiYXNlZCBvbiB0aGUKICAgVVJMLCBvciBoYXZlIHRoZW0gcHJlY29tcGlsZWQgaW50byBhIGJpbmFyeSB0byBhdm9pZCBhbnkKICAgbG9va3VwLiBUaGVyZWZvcmUsIGJpbmFyeSBjb21wYXRpYmlsaXR5IG5lZWRzIHRvIGJlIHByZXNlcnZlZAogICBvbiBjaGFuZ2VzIHRvIHR5cGVzLiAoVXNlIHZlcnNpb25lZCB0eXBlIG5hbWVzIHRvIG1hbmFnZQogICBicmVha2luZyBjaGFuZ2VzLikKCiBTY2hlbWVzIG90aGVyIHRoYW4gYGh0dHBgLCBgaHR0cHNgIChvciB0aGUgZW1wdHkgc2NoZW1lKSBtaWdodCBiZQogdXNlZCB3aXRoIGltcGxlbWVudGF0aW9uIHNwZWNpZmljIHNlbWFudGljcy4KCgoOCgUEAAIABBIFkAECeQ0KDQoFBAACAAUSBJABAggKDQoFBAACAAESBJABCREKDQoFBAACAAMSBJABFBUKVwoEBAACARIEkwECEhpJIE11c3QgYmUgYSB2YWxpZCBzZXJpYWxpemVkIHByb3RvY29sIGJ1ZmZlciBvZiB0aGUgYWJvdmUgc3BlY2lmaWVkIHR5cGUuCgoPCgUEAAIBBBIGkwECkAEWCg0KBQQAAgEFEgSTAQIHCg0KBQQAAgEBEgSTAQgNCg0KBQQAAgEDEgSTARARYgZwcm90bzMKmikKHmdvb2dsZS9wcm90b2J1Zi9kdXJhdGlvbi5wcm90bxIPZ29vZ2xlLnByb3RvYnVmIjoKCER1cmF0aW9uEhgKB3NlY29uZHMYASABKANSB3NlY29uZHMSFAoFbmFub3MYAiABKAVSBW5hbm9zQnwKE2NvbS5nb29nbGUucHJvdG9idWZCDUR1cmF0aW9uUHJvdG9QAVoqZ2l0aHViLmNvbS9nb2xhbmcvcHJvdG9idWYvcHR5cGVzL2R1cmF0aW9u+AEBogIDR1BCqgIeR29vZ2xlLlByb3RvYnVmLldlbGxLbm93blR5cGVzSqQnCgYSBB4AdAEKzAwKAQwSAx4AEjLBDCBQcm90b2NvbCBCdWZmZXJzIC0gR29vZ2xlJ3MgZGF0YSBpbnRlcmNoYW5nZSBmb3JtYXQKIENvcHlyaWdodCAyMDA4IEdvb2dsZSBJbmMuICBBbGwgcmlnaHRzIHJlc2VydmVkLgogaHR0cHM6Ly9kZXZlbG9wZXJzLmdvb2dsZS5jb20vcHJvdG9jb2wtYnVmZmVycy8KCiBSZWRpc3RyaWJ1dGlvbiBhbmQgdXNlIGluIHNvdXJjZSBhbmQgYmluYXJ5IGZvcm1zLCB3aXRoIG9yIHdpdGhvdXQKIG1vZGlmaWNhdGlvbiwgYXJlIHBlcm1pdHRlZCBwcm92aWRlZCB0aGF0IHRoZSBmb2xsb3dpbmcgY29uZGl0aW9ucyBhcmUKIG1ldDoKCiAgICAgKiBSZWRpc3RyaWJ1dGlvbnMgb2Ygc291cmNlIGNvZGUgbXVzdCByZXRhaW4gdGhlIGFib3ZlIGNvcHlyaWdodAogbm90aWNlLCB0aGlzIGxpc3Qgb2YgY29uZGl0aW9ucyBhbmQgdGhlIGZvbGxvd2luZyBkaXNjbGFpbWVyLgogICAgICogUmVkaXN0cmlidXRpb25zIGluIGJpbmFyeSBmb3JtIG11c3QgcmVwcm9kdWNlIHRoZSBhYm92ZQogY29weXJpZ2h0IG5vdGljZSwgdGhpcyBsaXN0IG9mIGNvbmRpdGlvbnMgYW5kIHRoZSBmb2xsb3dpbmcgZGlzY2xhaW1lcgogaW4gdGhlIGRvY3VtZW50YXRpb24gYW5kL29yIG90aGVyIG1hdGVyaWFscyBwcm92aWRlZCB3aXRoIHRoZQogZGlzdHJpYnV0aW9uLgogICAgICogTmVpdGhlciB0aGUgbmFtZSBvZiBHb29nbGUgSW5jLiBub3IgdGhlIG5hbWVzIG9mIGl0cwogY29udHJpYnV0b3JzIG1heSBiZSB1c2VkIHRvIGVuZG9yc2Ugb3IgcHJvbW90ZSBwcm9kdWN0cyBkZXJpdmVkIGZyb20KIHRoaXMgc29mdHdhcmUgd2l0aG91dCBzcGVjaWZpYyBwcmlvciB3cml0dGVuIHBlcm1pc3Npb24uCgogVEhJUyBTT0ZUV0FSRSBJUyBQUk9WSURFRCBCWSBUSEUgQ09QWVJJR0hUIEhPTERFUlMgQU5EIENPTlRSSUJVVE9SUwogIkFTIElTIiBBTkQgQU5ZIEVYUFJFU1MgT1IgSU1QTElFRCBXQVJSQU5USUVTLCBJTkNMVURJTkcsIEJVVCBOT1QKIExJTUlURUQgVE8sIFRIRSBJTVBMSUVEIFdBUlJBTlRJRVMgT0YgTUVSQ0hBTlRBQklMSVRZIEFORCBGSVRORVNTIEZPUgogQSBQQVJUSUNVTEFSIFBVUlBPU0UgQVJFIERJU0NMQUlNRUQuIElOIE5PIEVWRU5UIFNIQUxMIFRIRSBDT1BZUklHSFQKIE9XTkVSIE9SIENPTlRSSUJVVE9SUyBCRSBMSUFCTEUgRk9SIEFOWSBESVJFQ1QsIElORElSRUNULCBJTkNJREVOVEFMLAogU1BFQ0lBTCwgRVhFTVBMQVJZLCBPUiBDT05TRVFVRU5USUFMIERBTUFHRVMgKElOQ0xVRElORywgQlVUIE5PVAogTElNSVRFRCBUTywgUFJPQ1VSRU1FTlQgT0YgU1VCU1RJVFVURSBHT09EUyBPUiBTRVJWSUNFUzsgTE9TUyBPRiBVU0UsCiBEQVRBLCBPUiBQUk9GSVRTOyBPUiBCVVNJTkVTUyBJTlRFUlJVUFRJT04pIEhPV0VWRVIgQ0FVU0VEIEFORCBPTiBBTlkKIFRIRU9SWSBPRiBMSUFCSUxJVFksIFdIRVRIRVIgSU4gQ09OVFJBQ1QsIFNUUklDVCBMSUFCSUxJVFksIE9SIFRPUlQKIChJTkNMVURJTkcgTkVHTElHRU5DRSBPUiBPVEhFUldJU0UpIEFSSVNJTkcgSU4gQU5ZIFdBWSBPVVQgT0YgVEhFIFVTRQogT0YgVEhJUyBTT0ZUV0FSRSwgRVZFTiBJRiBBRFZJU0VEIE9GIFRIRSBQT1NTSUJJTElUWSBPRiBTVUNIIERBTUFHRS4KCggKAQISAyAIFwoICgEIEgMiADsKCwoECOcHABIDIgA7CgwKBQjnBwACEgMiBxcKDQoGCOcHAAIAEgMiBxcKDgoHCOcHAAIAARIDIgcXCgwKBQjnBwAHEgMiGjoKCAoBCBIDIwAfCgsKBAjnBwESAyMAHwoMCgUI5wcBAhIDIwcXCg0KBgjnBwECABIDIwcXCg4KBwjnBwECAAESAyMHFwoMCgUI5wcBAxIDIxoeCggKAQgSAyQAQQoLCgQI5wcCEgMkAEEKDAoFCOcHAgISAyQHEQoNCgYI5wcCAgASAyQHEQoOCgcI5wcCAgABEgMkBxEKDAoFCOcHAgcSAyQUQAoICgEIEgMlACwKCwoECOcHAxIDJQAsCgwKBQjnBwMCEgMlBxMKDQoGCOcHAwIAEgMlBxMKDgoHCOcHAwIAARIDJQcTCgwKBQjnBwMHEgMlFisKCAoBCBIDJgAuCgsKBAjnBwQSAyYALgoMCgUI5wcEAhIDJgcbCg0KBgjnBwQCABIDJgcbCg4KBwjnBwQCAAESAyYHGwoMCgUI5wcEBxIDJh4tCggKAQgSAycAIgoLCgQI5wcFEgMnACIKDAoFCOcHBQISAycHGgoNCgYI5wcFAgASAycHGgoOCgcI5wcFAgABEgMnBxoKDAoFCOcHBQMSAycdIQoICgEIEgMoACEKCwoECOcHBhIDKAAhCgwKBQjnBwYCEgMoBxgKDQoGCOcHBgIAEgMoBxgKDgoHCOcHBgIAARIDKAcYCgwKBQjnBwYHEgMoGyAKnxAKAgQAEgRmAHQBGpIQIEEgRHVyYXRpb24gcmVwcmVzZW50cyBhIHNpZ25lZCwgZml4ZWQtbGVuZ3RoIHNwYW4gb2YgdGltZSByZXByZXNlbnRlZAogYXMgYSBjb3VudCBvZiBzZWNvbmRzIGFuZCBmcmFjdGlvbnMgb2Ygc2Vjb25kcyBhdCBuYW5vc2Vjb25kCiByZXNvbHV0aW9uLiBJdCBpcyBpbmRlcGVuZGVudCBvZiBhbnkgY2FsZW5kYXIgYW5kIGNvbmNlcHRzIGxpa2UgImRheSIKIG9yICJtb250aCIuIEl0IGlzIHJlbGF0ZWQgdG8gVGltZXN0YW1wIGluIHRoYXQgdGhlIGRpZmZlcmVuY2UgYmV0d2VlbgogdHdvIFRpbWVzdGFtcCB2YWx1ZXMgaXMgYSBEdXJhdGlvbiBhbmQgaXQgY2FuIGJlIGFkZGVkIG9yIHN1YnRyYWN0ZWQKIGZyb20gYSBUaW1lc3RhbXAuIFJhbmdlIGlzIGFwcHJveGltYXRlbHkgKy0xMCwwMDAgeWVhcnMuCgogIyBFeGFtcGxlcwoKIEV4YW1wbGUgMTogQ29tcHV0ZSBEdXJhdGlvbiBmcm9tIHR3byBUaW1lc3RhbXBzIGluIHBzZXVkbyBjb2RlLgoKICAgICBUaW1lc3RhbXAgc3RhcnQgPSAuLi47CiAgICAgVGltZXN0YW1wIGVuZCA9IC4uLjsKICAgICBEdXJhdGlvbiBkdXJhdGlvbiA9IC4uLjsKCiAgICAgZHVyYXRpb24uc2Vjb25kcyA9IGVuZC5zZWNvbmRzIC0gc3RhcnQuc2Vjb25kczsKICAgICBkdXJhdGlvbi5uYW5vcyA9IGVuZC5uYW5vcyAtIHN0YXJ0Lm5hbm9zOwoKICAgICBpZiAoZHVyYXRpb24uc2Vjb25kcyA8IDAgJiYgZHVyYXRpb24ubmFub3MgPiAwKSB7CiAgICAgICBkdXJhdGlvbi5zZWNvbmRzICs9IDE7CiAgICAgICBkdXJhdGlvbi5uYW5vcyAtPSAxMDAwMDAwMDAwOwogICAgIH0gZWxzZSBpZiAoZHVyYXRpb25zLnNlY29uZHMgPiAwICYmIGR1cmF0aW9uLm5hbm9zIDwgMCkgewogICAgICAgZHVyYXRpb24uc2Vjb25kcyAtPSAxOwogICAgICAgZHVyYXRpb24ubmFub3MgKz0gMTAwMDAwMDAwMDsKICAgICB9CgogRXhhbXBsZSAyOiBDb21wdXRlIFRpbWVzdGFtcCBmcm9tIFRpbWVzdGFtcCArIER1cmF0aW9uIGluIHBzZXVkbyBjb2RlLgoKICAgICBUaW1lc3RhbXAgc3RhcnQgPSAuLi47CiAgICAgRHVyYXRpb24gZHVyYXRpb24gPSAuLi47CiAgICAgVGltZXN0YW1wIGVuZCA9IC4uLjsKCiAgICAgZW5kLnNlY29uZHMgPSBzdGFydC5zZWNvbmRzICsgZHVyYXRpb24uc2Vjb25kczsKICAgICBlbmQubmFub3MgPSBzdGFydC5uYW5vcyArIGR1cmF0aW9uLm5hbm9zOwoKICAgICBpZiAoZW5kLm5hbm9zIDwgMCkgewogICAgICAgZW5kLnNlY29uZHMgLT0gMTsKICAgICAgIGVuZC5uYW5vcyArPSAxMDAwMDAwMDAwOwogICAgIH0gZWxzZSBpZiAoZW5kLm5hbm9zID49IDEwMDAwMDAwMDApIHsKICAgICAgIGVuZC5zZWNvbmRzICs9IDE7CiAgICAgICBlbmQubmFub3MgLT0gMTAwMDAwMDAwMDsKICAgICB9CgogRXhhbXBsZSAzOiBDb21wdXRlIER1cmF0aW9uIGZyb20gZGF0ZXRpbWUudGltZWRlbHRhIGluIFB5dGhvbi4KCiAgICAgdGQgPSBkYXRldGltZS50aW1lZGVsdGEoZGF5cz0zLCBtaW51dGVzPTEwKQogICAgIGR1cmF0aW9uID0gRHVyYXRpb24oKQogICAgIGR1cmF0aW9uLkZyb21UaW1lZGVsdGEodGQpCgogIyBKU09OIE1hcHBpbmcKCiBJbiBKU09OIGZvcm1hdCwgdGhlIER1cmF0aW9uIHR5cGUgaXMgZW5jb2RlZCBhcyBhIHN0cmluZyByYXRoZXIgdGhhbiBhbgogb2JqZWN0LCB3aGVyZSB0aGUgc3RyaW5nIGVuZHMgaW4gdGhlIHN1ZmZpeCAicyIgKGluZGljYXRpbmcgc2Vjb25kcykgYW5kCiBpcyBwcmVjZWRlZCBieSB0aGUgbnVtYmVyIG9mIHNlY29uZHMsIHdpdGggbmFub3NlY29uZHMgZXhwcmVzc2VkIGFzCiBmcmFjdGlvbmFsIHNlY29uZHMuIEZvciBleGFtcGxlLCAzIHNlY29uZHMgd2l0aCAwIG5hbm9zZWNvbmRzIHNob3VsZCBiZQogZW5jb2RlZCBpbiBKU09OIGZvcm1hdCBhcyAiM3MiLCB3aGlsZSAzIHNlY29uZHMgYW5kIDEgbmFub3NlY29uZCBzaG91bGQKIGJlIGV4cHJlc3NlZCBpbiBKU09OIGZvcm1hdCBhcyAiMy4wMDAwMDAwMDFzIiwgYW5kIDMgc2Vjb25kcyBhbmQgMQogbWljcm9zZWNvbmQgc2hvdWxkIGJlIGV4cHJlc3NlZCBpbiBKU09OIGZvcm1hdCBhcyAiMy4wMDAwMDFzIi4KCgoKCgoDBAABEgNmCBAK3AEKBAQAAgASA2sCFBrOASBTaWduZWQgc2Vjb25kcyBvZiB0aGUgc3BhbiBvZiB0aW1lLiBNdXN0IGJlIGZyb20gLTMxNSw1NzYsMDAwLDAwMAogdG8gKzMxNSw1NzYsMDAwLDAwMCBpbmNsdXNpdmUuIE5vdGU6IHRoZXNlIGJvdW5kcyBhcmUgY29tcHV0ZWQgZnJvbToKIDYwIHNlYy9taW4gKiA2MCBtaW4vaHIgKiAyNCBoci9kYXkgKiAzNjUuMjUgZGF5cy95ZWFyICogMTAwMDAgeWVhcnMKCg0KBQQAAgAEEgRrAmYSCgwKBQQAAgAFEgNrAgcKDAoFBAACAAESA2sIDwoMCgUEAAIAAxIDaxITCoMDCgQEAAIBEgNzAhIa9QIgU2lnbmVkIGZyYWN0aW9ucyBvZiBhIHNlY29uZCBhdCBuYW5vc2Vjb25kIHJlc29sdXRpb24gb2YgdGhlIHNwYW4KIG9mIHRpbWUuIER1cmF0aW9ucyBsZXNzIHRoYW4gb25lIHNlY29uZCBhcmUgcmVwcmVzZW50ZWQgd2l0aCBhIDAKIGBzZWNvbmRzYCBmaWVsZCBhbmQgYSBwb3NpdGl2ZSBvciBuZWdhdGl2ZSBgbmFub3NgIGZpZWxkLiBGb3IgZHVyYXRpb25zCiBvZiBvbmUgc2Vjb25kIG9yIG1vcmUsIGEgbm9uLXplcm8gdmFsdWUgZm9yIHRoZSBgbmFub3NgIGZpZWxkIG11c3QgYmUKIG9mIHRoZSBzYW1lIHNpZ24gYXMgdGhlIGBzZWNvbmRzYCBmaWVsZC4gTXVzdCBiZSBmcm9tIC05OTksOTk5LDk5OQogdG8gKzk5OSw5OTksOTk5IGluY2x1c2l2ZS4KCg0KBQQAAgEEEgRzAmsUCgwKBQQAAgEFEgNzAgcKDAoFBAACAQESA3MIDQoMCgUEAAIBAxIDcxARYgZwcm90bzMKqyIKF2dvb2dsZS9ycGMvc3RhdHVzLnByb3RvEgpnb29nbGUucnBjGhlnb29nbGUvcHJvdG9idWYvYW55LnByb3RvImYKBlN0YXR1cxISCgRjb2RlGAEgASgFUgRjb2RlEhgKB21lc3NhZ2UYAiABKAlSB21lc3NhZ2USLgoHZGV0YWlscxgDIAMoCzIULmdvb2dsZS5wcm90b2J1Zi5BbnlSB2RldGFpbHNCKgoOY29tLmdvb2dsZS5ycGNCC1N0YXR1c1Byb3RvUAFaA3JwY6ICA1JQQ0rMIAoGEgQOAFsBCr0ECgEMEgMOABIysgQgQ29weXJpZ2h0IDIwMTcgR29vZ2xlIEluYy4KCiBMaWNlbnNlZCB1bmRlciB0aGUgQXBhY2hlIExpY2Vuc2UsIFZlcnNpb24gMi4wICh0aGUgIkxpY2Vuc2UiKTsKIHlvdSBtYXkgbm90IHVzZSB0aGlzIGZpbGUgZXhjZXB0IGluIGNvbXBsaWFuY2Ugd2l0aCB0aGUgTGljZW5zZS4KIFlvdSBtYXkgb2J0YWluIGEgY29weSBvZiB0aGUgTGljZW5zZSBhdAoKICAgICBodHRwOi8vd3d3LmFwYWNoZS5vcmcvbGljZW5zZXMvTElDRU5TRS0yLjAKCiBVbmxlc3MgcmVxdWlyZWQgYnkgYXBwbGljYWJsZSBsYXcgb3IgYWdyZWVkIHRvIGluIHdyaXRpbmcsIHNvZnR3YXJlCiBkaXN0cmlidXRlZCB1bmRlciB0aGUgTGljZW5zZSBpcyBkaXN0cmlidXRlZCBvbiBhbiAiQVMgSVMiIEJBU0lTLAogV0lUSE9VVCBXQVJSQU5USUVTIE9SIENPTkRJVElPTlMgT0YgQU5ZIEtJTkQsIGVpdGhlciBleHByZXNzIG9yIGltcGxpZWQuCiBTZWUgdGhlIExpY2Vuc2UgZm9yIHRoZSBzcGVjaWZpYyBsYW5ndWFnZSBnb3Zlcm5pbmcgcGVybWlzc2lvbnMgYW5kCiBsaW1pdGF0aW9ucyB1bmRlciB0aGUgTGljZW5zZS4KCggKAQISAxAIEgoJCgIDABIDEgciCggKAQgSAxQAGgoLCgQI5wcAEgMUABoKDAoFCOcHAAISAxQHEQoNCgYI5wcAAgASAxQHEQoOCgcI5wcAAgABEgMUBxEKDAoFCOcHAAcSAxQUGQoICgEIEgMVACIKCwoECOcHARIDFQAiCgwKBQjnBwECEgMVBxoKDQoGCOcHAQIAEgMVBxoKDgoHCOcHAQIAARIDFQcaCgwKBQjnBwEDEgMVHSEKCAoBCBIDFgAsCgsKBAjnBwISAxYALAoMCgUI5wcCAhIDFgcbCg0KBgjnBwICABIDFgcbCg4KBwjnBwICAAESAxYHGwoMCgUI5wcCBxIDFh4rCggKAQgSAxcAJwoLCgQI5wcDEgMXACcKDAoFCOcHAwISAxcHEwoNCgYI5wcDAgASAxcHEwoOCgcI5wcDAgABEgMXBxMKDAoFCOcHAwcSAxcWJgoICgEIEgMYACEKCwoECOcHBBIDGAAhCgwKBQjnBwQCEgMYBxgKDQoGCOcHBAIAEgMYBxgKDgoHCOcHBAIAARIDGAcYCgwKBQjnBwQHEgMYGyAKzRMKAgQAEgRPAFsBGsATIFRoZSBgU3RhdHVzYCB0eXBlIGRlZmluZXMgYSBsb2dpY2FsIGVycm9yIG1vZGVsIHRoYXQgaXMgc3VpdGFibGUgZm9yIGRpZmZlcmVudAogcHJvZ3JhbW1pbmcgZW52aXJvbm1lbnRzLCBpbmNsdWRpbmcgUkVTVCBBUElzIGFuZCBSUEMgQVBJcy4gSXQgaXMgdXNlZCBieQogW2dSUENdKGh0dHBzOi8vZ2l0aHViLmNvbS9ncnBjKS4gVGhlIGVycm9yIG1vZGVsIGlzIGRlc2lnbmVkIHRvIGJlOgoKIC0gU2ltcGxlIHRvIHVzZSBhbmQgdW5kZXJzdGFuZCBmb3IgbW9zdCB1c2VycwogLSBGbGV4aWJsZSBlbm91Z2ggdG8gbWVldCB1bmV4cGVjdGVkIG5lZWRzCgogIyBPdmVydmlldwoKIFRoZSBgU3RhdHVzYCBtZXNzYWdlIGNvbnRhaW5zIHRocmVlIHBpZWNlcyBvZiBkYXRhOiBlcnJvciBjb2RlLCBlcnJvciBtZXNzYWdlLAogYW5kIGVycm9yIGRldGFpbHMuIFRoZSBlcnJvciBjb2RlIHNob3VsZCBiZSBhbiBlbnVtIHZhbHVlIG9mCiBbZ29vZ2xlLnJwYy5Db2RlXVtnb29nbGUucnBjLkNvZGVdLCBidXQgaXQgbWF5IGFjY2VwdCBhZGRpdGlvbmFsIGVycm9yIGNvZGVzIGlmIG5lZWRlZC4gIFRoZQogZXJyb3IgbWVzc2FnZSBzaG91bGQgYmUgYSBkZXZlbG9wZXItZmFjaW5nIEVuZ2xpc2ggbWVzc2FnZSB0aGF0IGhlbHBzCiBkZXZlbG9wZXJzICp1bmRlcnN0YW5kKiBhbmQgKnJlc29sdmUqIHRoZSBlcnJvci4gSWYgYSBsb2NhbGl6ZWQgdXNlci1mYWNpbmcKIGVycm9yIG1lc3NhZ2UgaXMgbmVlZGVkLCBwdXQgdGhlIGxvY2FsaXplZCBtZXNzYWdlIGluIHRoZSBlcnJvciBkZXRhaWxzIG9yCiBsb2NhbGl6ZSBpdCBpbiB0aGUgY2xpZW50LiBUaGUgb3B0aW9uYWwgZXJyb3IgZGV0YWlscyBtYXkgY29udGFpbiBhcmJpdHJhcnkKIGluZm9ybWF0aW9uIGFib3V0IHRoZSBlcnJvci4gVGhlcmUgaXMgYSBwcmVkZWZpbmVkIHNldCBvZiBlcnJvciBkZXRhaWwgdHlwZXMKIGluIHRoZSBwYWNrYWdlIGBnb29nbGUucnBjYCB0aGF0IGNhbiBiZSB1c2VkIGZvciBjb21tb24gZXJyb3IgY29uZGl0aW9ucy4KCiAjIExhbmd1YWdlIG1hcHBpbmcKCiBUaGUgYFN0YXR1c2AgbWVzc2FnZSBpcyB0aGUgbG9naWNhbCByZXByZXNlbnRhdGlvbiBvZiB0aGUgZXJyb3IgbW9kZWwsIGJ1dCBpdAogaXMgbm90IG5lY2Vzc2FyaWx5IHRoZSBhY3R1YWwgd2lyZSBmb3JtYXQuIFdoZW4gdGhlIGBTdGF0dXNgIG1lc3NhZ2UgaXMKIGV4cG9zZWQgaW4gZGlmZmVyZW50IGNsaWVudCBsaWJyYXJpZXMgYW5kIGRpZmZlcmVudCB3aXJlIHByb3RvY29scywgaXQgY2FuIGJlCiBtYXBwZWQgZGlmZmVyZW50bHkuIEZvciBleGFtcGxlLCBpdCB3aWxsIGxpa2VseSBiZSBtYXBwZWQgdG8gc29tZSBleGNlcHRpb25zCiBpbiBKYXZhLCBidXQgbW9yZSBsaWtlbHkgbWFwcGVkIHRvIHNvbWUgZXJyb3IgY29kZXMgaW4gQy4KCiAjIE90aGVyIHVzZXMKCiBUaGUgZXJyb3IgbW9kZWwgYW5kIHRoZSBgU3RhdHVzYCBtZXNzYWdlIGNhbiBiZSB1c2VkIGluIGEgdmFyaWV0eSBvZgogZW52aXJvbm1lbnRzLCBlaXRoZXIgd2l0aCBvciB3aXRob3V0IEFQSXMsIHRvIHByb3ZpZGUgYQogY29uc2lzdGVudCBkZXZlbG9wZXIgZXhwZXJpZW5jZSBhY3Jvc3MgZGlmZmVyZW50IGVudmlyb25tZW50cy4KCiBFeGFtcGxlIHVzZXMgb2YgdGhpcyBlcnJvciBtb2RlbCBpbmNsdWRlOgoKIC0gUGFydGlhbCBlcnJvcnMuIElmIGEgc2VydmljZSBuZWVkcyB0byByZXR1cm4gcGFydGlhbCBlcnJvcnMgdG8gdGhlIGNsaWVudCwKICAgICBpdCBtYXkgZW1iZWQgdGhlIGBTdGF0dXNgIGluIHRoZSBub3JtYWwgcmVzcG9uc2UgdG8gaW5kaWNhdGUgdGhlIHBhcnRpYWwKICAgICBlcnJvcnMuCgogLSBXb3JrZmxvdyBlcnJvcnMuIEEgdHlwaWNhbCB3b3JrZmxvdyBoYXMgbXVsdGlwbGUgc3RlcHMuIEVhY2ggc3RlcCBtYXkKICAgICBoYXZlIGEgYFN0YXR1c2AgbWVzc2FnZSBmb3IgZXJyb3IgcmVwb3J0aW5nLgoKIC0gQmF0Y2ggb3BlcmF0aW9ucy4gSWYgYSBjbGllbnQgdXNlcyBiYXRjaCByZXF1ZXN0IGFuZCBiYXRjaCByZXNwb25zZSwgdGhlCiAgICAgYFN0YXR1c2AgbWVzc2FnZSBzaG91bGQgYmUgdXNlZCBkaXJlY3RseSBpbnNpZGUgYmF0Y2ggcmVzcG9uc2UsIG9uZSBmb3IKICAgICBlYWNoIGVycm9yIHN1Yi1yZXNwb25zZS4KCiAtIEFzeW5jaHJvbm91cyBvcGVyYXRpb25zLiBJZiBhbiBBUEkgY2FsbCBlbWJlZHMgYXN5bmNocm9ub3VzIG9wZXJhdGlvbgogICAgIHJlc3VsdHMgaW4gaXRzIHJlc3BvbnNlLCB0aGUgc3RhdHVzIG9mIHRob3NlIG9wZXJhdGlvbnMgc2hvdWxkIGJlCiAgICAgcmVwcmVzZW50ZWQgZGlyZWN0bHkgdXNpbmcgdGhlIGBTdGF0dXNgIG1lc3NhZ2UuCgogLSBMb2dnaW5nLiBJZiBzb21lIEFQSSBlcnJvcnMgYXJlIHN0b3JlZCBpbiBsb2dzLCB0aGUgbWVzc2FnZSBgU3RhdHVzYCBjb3VsZAogICAgIGJlIHVzZWQgZGlyZWN0bHkgYWZ0ZXIgYW55IHN0cmlwcGluZyBuZWVkZWQgZm9yIHNlY3VyaXR5L3ByaXZhY3kgcmVhc29ucy4KCgoKAwQAARIDTwgOCmQKBAQAAgASA1ECERpXIFRoZSBzdGF0dXMgY29kZSwgd2hpY2ggc2hvdWxkIGJlIGFuIGVudW0gdmFsdWUgb2YgW2dvb2dsZS5ycGMuQ29kZV1bZ29vZ2xlLnJwYy5Db2RlXS4KCg0KBQQAAgAEEgRRAk8QCgwKBQQAAgAFEgNRAgcKDAoFBAACAAESA1EIDAoMCgUEAAIAAxIDUQ8QCusBCgQEAAIBEgNWAhUa3QEgQSBkZXZlbG9wZXItZmFjaW5nIGVycm9yIG1lc3NhZ2UsIHdoaWNoIHNob3VsZCBiZSBpbiBFbmdsaXNoLiBBbnkKIHVzZXItZmFjaW5nIGVycm9yIG1lc3NhZ2Ugc2hvdWxkIGJlIGxvY2FsaXplZCBhbmQgc2VudCBpbiB0aGUKIFtnb29nbGUucnBjLlN0YXR1cy5kZXRhaWxzXVtnb29nbGUucnBjLlN0YXR1cy5kZXRhaWxzXSBmaWVsZCwgb3IgbG9jYWxpemVkIGJ5IHRoZSBjbGllbnQuCgoNCgUEAAIBBBIEVgJREQoMCgUEAAIBBRIDVgIICgwKBQQAAgEBEgNWCRAKDAoFBAACAQMSA1YTFAp5CgQEAAICEgNaAisabCBBIGxpc3Qgb2YgbWVzc2FnZXMgdGhhdCBjYXJyeSB0aGUgZXJyb3IgZGV0YWlscy4gIFRoZXJlIGlzIGEgY29tbW9uIHNldCBvZgogbWVzc2FnZSB0eXBlcyBmb3IgQVBJcyB0byB1c2UuCgoMCgUEAAICBBIDWgIKCgwKBQQAAgIGEgNaCx4KDAoFBAACAgESA1ofJgoMCgUEAAICAxIDWikqYgZwcm90bzMKvBEKJ21peGVyL2FkYXB0ZXIvbW9kZWwvdjFiZXRhMS9jaGVjay5wcm90bxIhaXN0aW8ubWl4ZXIuYWRhcHRlci5tb2RlbC52MWJldGExGhRnb2dvcHJvdG8vZ29nby5wcm90bxoeZ29vZ2xlL3Byb3RvYnVmL2R1cmF0aW9uLnByb3RvGhdnb29nbGUvcnBjL3N0YXR1cy5wcm90byKzAQoLQ2hlY2tSZXN1bHQSMAoGc3RhdHVzGAEgASgLMhIuZ29vZ2xlLnJwYy5TdGF0dXNCBMjeHwBSBnN0YXR1cxJKCg52YWxpZF9kdXJhdGlvbhgCIAEoCzIZLmdvb2dsZS5wcm90b2J1Zi5EdXJhdGlvbkIIyN4fAJjfHwFSDXZhbGlkRHVyYXRpb24SJgoPdmFsaWRfdXNlX2NvdW50GAMgASgFUg12YWxpZFVzZUNvdW50QjZaKGlzdGlvLmlvL2FwaS9taXhlci9hZGFwdGVyL21vZGVsL3YxYmV0YTHI4R4AqOIe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CgUEAAICBRIDJAIHCgwKBQQAAgIBEgMkCBcKDAoFBAACAgMSAyQaG2IGcHJvdG8zCoEhCjBtaXhlci90ZXN0L2tleXZhbC90ZW1wbGF0ZV9oYW5kbGVyX3NlcnZpY2UucHJvdG8SBmtleXZhbBoUZ29nb3Byb3RvL2dvZ28ucHJvdG8aLG1peGVyL2FkYXB0ZXIvbW9kZWwvdjFiZXRhMS9leHRlbnNpb25zLnByb3RvGhlnb29nbGUvcHJvdG9idWYvYW55LnByb3RvGidtaXhlci9hZGFwdGVyL21vZGVsL3YxYmV0YTEvY2hlY2sucHJvdG8ingEKE0hhbmRsZUtleXZhbFJlcXVlc3QSLwoIaW5zdGFuY2UYASABKAsyEy5rZXl2YWwuSW5zdGFuY2VNc2dSCGluc3RhbmNlEjsKDmFkYXB0ZXJfY29uZmlnGAIgASgLMhQuZ29vZ2xlLnByb3RvYnVmLkFueVINYWRhcHRlckNvbmZpZxIZCghkZWR1cF9pZBgDIAEoCVIHZGVkdXBJZCKJAQoUSGFuZGxlS2V5dmFsUmVzcG9uc2USRgoGcmVzdWx0GAEgASgLMi4uaXN0aW8ubWl4ZXIuYWRhcHRlci5tb2RlbC52MWJldGExLkNoZWNrUmVzdWx0UgZyZXN1bHQSKQoGb3V0cHV0GAIgASgLMhEua2V5dmFsLk91dHB1dE1zZ1IGb3V0cHV0IiEKCU91dHB1dE1zZxIUCgV2YWx1ZRgCIAEoCVIFdmFsdWUiNgoLSW5zdGFuY2VNc2cSFQoEbmFtZRivyrwiIAEoCVIEbmFtZRIQCgNrZXkYASABKAlSA2tleSIGCgRUeXBlIiEKDUluc3RhbmNlUGFyYW0SEAoDa2V5GAEgASgJUgNrZXkyYAoTSGFuZGxlS2V5dmFsU2VydmljZRJJCgxIYW5kbGVLZXl2YWwSGy5rZXl2YWwuSGFuZGxlS2V5dmFsUmVxdWVzdBocLmtleXZhbC5IYW5kbGVLZXl2YWxSZXNwb25zZUIe+NLkkwIEgt3kkwIGa2V5dmFsyOEeAKjiHgDw4R4ASv8aCgYSBBAAZQEK8gQKAQwSAxAAEjK0BCBDb3B5cmlnaHQgMjAxNyBJc3RpbyBBdXRob3JzCgogTGljZW5zZWQgdW5kZXIgdGhlIEFwYWNoZSBMaWNlbnNlLCBWZXJzaW9uIDIuMCAodGhlICJMaWNlbnNlIik7CiB5b3UgbWF5IG5vdCB1c2UgdGhpcyBmaWxlIGV4Y2VwdCBpbiBjb21wbGlhbmNlIHdpdGggdGhlIExpY2Vuc2UuCiBZb3UgbWF5IG9idGFpbiBhIGNvcHkgb2YgdGhlIExpY2Vuc2UgYXQKCiAgICAgaHR0cDovL3d3dy5hcGFjaGUub3JnL2xpY2Vuc2VzL0xJQ0VOU0UtMi4wCgogVW5sZXNzIHJlcXVpcmVkIGJ5IGFwcGxpY2FibGUgbGF3IG9yIGFncmVlZCB0byBpbiB3cml0aW5nLCBzb2Z0d2FyZQogZGlzdHJpYnV0ZWQgdW5kZXIgdGhlIExpY2Vuc2UgaXMgZGlzdHJpYnV0ZWQgb24gYW4gIkFTIElTIiBCQVNJUywKIFdJVEhPVVQgV0FSUkFOVElFUyBPUiBDT05ESVRJT05TIE9GIEFOWSBLSU5ELCBlaXRoZXIgZXhwcmVzcyBvciBpbXBsaWVkLgogU2VlIHRoZSBMaWNlbnNlIGZvciB0aGUgc3BlY2lmaWMgbGFuZ3VhZ2UgZ292ZXJuaW5nIHBlcm1pc3Npb25zIGFuZAogbGltaXRhdGlvbnMgdW5kZXIgdGhlIExpY2Vuc2UuCjIxIFRISVMgRklMRSBJUyBBVVRPTUFUSUNBTExZIEdFTkVSQVRFRCBCWSBNSVhHRU4uCgobCgECEgMWCA4aEQogSW5wdXQgdGVtcGxhdGUKCgkKAgMAEgMZBx0KCQoCAwESAxoHNQoJCgIDAhIDGwciCgkKAgMDEgMcBzAKCAoBCBIDHwBhCgsKBAjnBwASAx8AYQoMCgUI5wcAAhIDHwc7Cg0KBgjnBwACABIDHwc7Cg4KBwjnBwACAAESAx8IOgoMCgUI5wcAAxIDHz5gCggKAQgSAyAARAoLCgQI5wcBEgMgAEQKDAoFCOcHAQISAyAHOAoNCgYI5wcBAgASAyAHOAoOCgcI5wcBAgABEgMgCDcKDAoFCOcHAQcSAyA7QwoICgEIEgMiAC8KCwoECOcHAhIDIgAvCgwKBQjnBwICEgMiByYKDQoGCOcHAgIAEgMiByYKDgoHCOcHAgIAARIDIgglCgwKBQjnBwIDEgMiKS4KCAoBCBIDIwAlCgsKBAjnBwMSAyMAJQoMCgUI5wcDAhIDIwccCg0KBgjnBwMCABIDIwccCg4KBwjnBwMCAAESAyMIGwoMCgUI5wcDAxIDIx8kCggKAQgSAyQAKAoLCgQI5wcEEgMkACgKDAoFCOcHBAISAyQHHwoNCgYI5wcEAgASAyQHHwoOCgcI5wcEAgABEgMkCB4KDAoFCOcHBAMSAyQiJwpyCgIGABIEJwArARpmIEhhbmRsZUtleXZhbFNlcnZpY2UgaXMgaW1wbGVtZW50ZWQgYnkgYmFja2VuZHMgdGhhdCB3YW50cyB0byBoYW5kbGUgcmVxdWVzdC10aW1lICdrZXl2YWwnIGluc3RhbmNlcy4KCgoKAwYAARIDJwgbCmwKBAYAAgASAykESRpfIEhhbmRsZUtleXZhbCBpcyBjYWxsZWQgYnkgTWl4ZXIgYXQgcmVxdWVzdC10aW1lIHRvIGRlbGl2ZXIgJ2tleXZhbCcgaW5zdGFuY2VzIHRvIHRoZSBiYWNrZW5kLgoKDAoFBgACAAESAykIFAoMCgUGAAIAAhIDKRUoCgwKBQYAAgADEgMpM0cKNgoCBAASBC4APQEaKiBSZXF1ZXN0IG1lc3NhZ2UgZm9yIEhhbmRsZUtleXZhbCBtZXRob2QuCgoKCgMEAAESAy4IGwohCgQEAAIAEgMxBB0aFCAna2V5dmFsJyBpbnN0YW5jZS4KCg0KBQQAAgAEEgQxBC4dCgwKBQQAAgAGEgMxBA8KDAoFBAACAAESAzEQGAoMCgUEAAIAAxIDMRscCrkECgQEAAIBEgM5BCsaqwQgQWRhcHRlciBzcGVjaWZpYyBoYW5kbGVyIGNvbmZpZ3VyYXRpb24uCgogTm90ZTogQmFja2VuZHMgY2FuIGFsc28gaW1wbGVtZW50IFtJbmZyYXN0cnVjdHVyZUJhY2tlbmRdW2h0dHBzOi8vaXN0aW8uaW8vZG9jcy9yZWZlcmVuY2UvY29uZmlnL21peGVyL2lzdGlvLm1peGVyLmFkYXB0ZXIubW9kZWwudjFiZXRhMS5odG1sI0luZnJhc3RydWN0dXJlQmFja2VuZF0KIHNlcnZpY2UgYW5kIHRoZXJlZm9yZSBvcHQgdG8gcmVjZWl2ZSBoYW5kbGVyIGNvbmZpZ3VyYXRpb24gZHVyaW5nIHNlc3Npb24gY3JlYXRpb24gdGhyb3VnaCBbSW5mcmFzdHJ1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" +--- diff --git a/istio-1.3.5/samples/httpbin/policy/keyval.yaml b/istio-1.3.5/samples/httpbin/policy/keyval.yaml new file mode 100644 index 0000000..d3a56ba --- /dev/null +++ b/istio-1.3.5/samples/httpbin/policy/keyval.yaml @@ -0,0 +1,14 @@ +# this config is created through command +# mixgen adapter -c $GOPATH/src/istio.io/istio/mixer/test/keyval/config.proto_descriptor -o $GOPATH/src/istio.io/istio/mixer/test/keyval -s=false -n keyval -t keyval +apiVersion: "config.istio.io/v1alpha2" +kind: adapter +metadata: + name: keyval + namespace: istio-system +spec: + description: + session_based: false + templates: + - keyval + config: CsgCCh5taXhlci90ZXN0L2tleXZhbC9jb25maWcucHJvdG8SBmtleXZhbCJzCgZQYXJhbXMSLwoFdGFibGUYASADKAsyGS5rZXl2YWwuUGFyYW1zLlRhYmxlRW50cnlSBXRhYmxlGjgKClRhYmxlRW50cnkSEAoDa2V5GAEgASgJUgNrZXkSFAoFdmFsdWUYAiABKAlSBXZhbHVlOgI4AUqgAQoGEgQAAAgBCggKAQwSAwAAEgoICgECEgMCCA4KIAoCBAASBAUACAEaFCBBZGFwdGVyIHBhcmFtZXRlcnMKCgoKAwQAARIDBQgOChsKBAQAAgASAwcCIBoOIExvb2t1cCB0YWJsZQoKDQoFBAACAAQSBAcCBRAKDAoFBAACAAYSAwcCFQoMCgUEAAIAARIDBxYbCgwKBQQAAgADEgMHHh9iBnByb3RvMw== +--- diff --git a/istio-1.3.5/samples/httpbin/sample-client/fortio-deploy.yaml b/istio-1.3.5/samples/httpbin/sample-client/fortio-deploy.yaml new file mode 100644 index 0000000..06aef93 --- /dev/null +++ b/istio-1.3.5/samples/httpbin/sample-client/fortio-deploy.yaml @@ -0,0 +1,41 @@ +apiVersion: v1 +kind: Service +metadata: + name: fortio + labels: + app: fortio +spec: + ports: + - port: 8080 + name: http + selector: + app: fortio +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: fortio-deploy +spec: + replicas: 1 + selector: + matchLabels: + app: fortio + template: + metadata: + annotations: + # This annotation causes Envoy to serve cluster.outbound statistics via 15000/stats + # in addition to the stats normally served by Istio. The Circuit Breaking example task + # gives an example of inspecting Envoy stats. + sidecar.istio.io/statsInclusionPrefixes: cluster.outbound,cluster_manager,listener_manager,http_mixer_filter,tcp_mixer_filter,server,cluster.xds-grpc + labels: + app: fortio + spec: + containers: + - name: fortio + image: fortio/fortio:latest_release + imagePullPolicy: Always + ports: + - containerPort: 8080 + name: http-fortio + - containerPort: 8079 + name: grpc-ping diff --git a/istio-1.3.5/samples/https/default.conf b/istio-1.3.5/samples/https/default.conf new file mode 100644 index 0000000..4a5b420 --- /dev/null +++ b/istio-1.3.5/samples/https/default.conf @@ -0,0 +1,10 @@ +server { + listen 443 ssl; + + root /usr/share/nginx/html; + index index.html; + + server_name localhost; + ssl_certificate /etc/nginx/ssl/tls.crt; + ssl_certificate_key /etc/nginx/ssl/tls.key; +} diff --git a/istio-1.3.5/samples/https/nginx-app.yaml b/istio-1.3.5/samples/https/nginx-app.yaml new file mode 100644 index 0000000..aece09e --- /dev/null +++ b/istio-1.3.5/samples/https/nginx-app.yaml @@ -0,0 +1,43 @@ +apiVersion: v1 +kind: Service +metadata: + name: my-nginx + labels: + app: nginx +spec: + type: NodePort + ports: + - port: 443 + name: https + selector: + app: nginx +--- +apiVersion: v1 +kind: ReplicationController +metadata: + name: my-nginx +spec: + replicas: 1 + template: + metadata: + labels: + app: nginx + spec: + volumes: + - name: secret-volume + secret: + secretName: nginxsecret + - name: configmap-volume + configMap: + name: nginxconfigmap + containers: + - name: nginxhttps + image: ymqytw/nginxhttps:1.5 + command: ["/home/auto-reload-nginx.sh"] + ports: + - containerPort: 443 + volumeMounts: + - mountPath: /etc/nginx/ssl + name: secret-volume + - mountPath: /etc/nginx/conf.d + name: configmap-volume diff --git a/istio-1.3.5/samples/kubernetes-blog/bookinfo-ratings.yaml b/istio-1.3.5/samples/kubernetes-blog/bookinfo-ratings.yaml new file mode 100644 index 0000000..eae30a6 --- /dev/null +++ b/istio-1.3.5/samples/kubernetes-blog/bookinfo-ratings.yaml @@ -0,0 +1,49 @@ +# Copyright 2017 Istio Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +################################################################################################## +# Ratings service +################################################################################################## +apiVersion: v1 +kind: Service +metadata: + name: ratings + labels: + app: ratings +spec: + ports: + - port: 9080 + name: http + selector: + app: ratings +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: ratings-v1 +spec: + replicas: 1 + template: + metadata: + labels: + app: ratings + version: v1 + spec: + containers: + - name: ratings + image: docker.io/istio/examples-bookinfo-ratings-v1:0.2.3 + imagePullPolicy: IfNotPresent + ports: + - containerPort: 9080 +--- diff --git a/istio-1.3.5/samples/kubernetes-blog/bookinfo-reviews-v2.yaml b/istio-1.3.5/samples/kubernetes-blog/bookinfo-reviews-v2.yaml new file mode 100644 index 0000000..8ae3489 --- /dev/null +++ b/istio-1.3.5/samples/kubernetes-blog/bookinfo-reviews-v2.yaml @@ -0,0 +1,40 @@ +# Copyright 2017 Istio Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +################################################################################################## +# Reviews service v2 +################################################################################################## +apiVersion: apps/v1 +kind: Deployment +metadata: + name: reviews-v2 +spec: + replicas: 1 + selector: + matchLabels: + app: reviews + version: v2 + template: + metadata: + labels: + app: reviews + version: v2 + spec: + containers: + - name: reviews + image: docker.io/istio/examples-bookinfo-reviews-v2:0.2.3 + imagePullPolicy: IfNotPresent + ports: + - containerPort: 9080 +--- diff --git a/istio-1.3.5/samples/kubernetes-blog/bookinfo-v1.yaml b/istio-1.3.5/samples/kubernetes-blog/bookinfo-v1.yaml new file mode 100644 index 0000000..d675374 --- /dev/null +++ b/istio-1.3.5/samples/kubernetes-blog/bookinfo-v1.yaml @@ -0,0 +1,131 @@ +# Copyright 2017 Istio Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +################################################################################################## +# Details service +################################################################################################## +apiVersion: v1 +kind: Service +metadata: + name: details + labels: + app: details +spec: + ports: + - port: 9080 + name: http + selector: + app: details +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: details-v1 +spec: + replicas: 1 + selector: + matchLabels: + app: details + version: v1 + template: + metadata: + labels: + app: details + version: v1 + spec: + containers: + - name: details + image: istio/examples-bookinfo-details-v1:0.2.3 + imagePullPolicy: IfNotPresent + ports: + - containerPort: 9080 +--- +################################################################################################## +# Reviews service +################################################################################################## +apiVersion: v1 +kind: Service +metadata: + name: reviews + labels: + app: reviews +spec: + ports: + - port: 9080 + name: http + selector: + app: reviews +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: reviews-v1 +spec: + replicas: 1 + selector: + matchLabels: + app: reviews + version: v1 + template: + metadata: + labels: + app: reviews + version: v1 + spec: + containers: + - name: reviews + image: docker.io/istio/examples-bookinfo-reviews-v1:0.2.3 + imagePullPolicy: IfNotPresent + ports: + - containerPort: 9080 +--- +################################################################################################## +# Productpage services +################################################################################################## +apiVersion: v1 +kind: Service +metadata: + name: productpage + labels: + app: productpage +spec: + ports: + - port: 9080 + name: http + selector: + app: productpage +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: productpage-v1 +spec: + replicas: 1 + selector: + matchLabels: + app: productpage + version: v1 + template: + metadata: + labels: + app: productpage + version: v1 + spec: + containers: + - name: productpage + image: docker.io/istio/examples-bookinfo-productpage-v1:0.2.3 + imagePullPolicy: IfNotPresent + ports: + - containerPort: 9080 +--- diff --git a/istio-1.3.5/samples/rawvm/README.md b/istio-1.3.5/samples/rawvm/README.md new file mode 100644 index 0000000..a059fb9 --- /dev/null +++ b/istio-1.3.5/samples/rawvm/README.md @@ -0,0 +1,158 @@ + +# RawVM in Istio 0.2 demo notes + +## MySQL Installation: + +### Official oracle version +```shell +wget https://dev.mysql.com/get/mysql-apt-config_0.8.7-1_all.deb +sudo dpkg -i mysql-apt-config_0.8.7-1_all.deb +# Select server 5.7 (default), tools and previews not needed/disabled +sudo apt-get update +sudo apt-get install mysql-server +# Clearly this is insecure, don't do that for prod ! +sudo mysql + ALTER USER 'root'@'localhost' IDENTIFIED WITH mysql_native_password BY 'password'; + # Remote 'root' can read test.*, to avoid + # ERROR 1130 (HY000): Host '...' is not allowed to connect to this MySQL server + create user 'root'@'%' IDENTIFIED WITH mysql_native_password BY 'password'; + GRANT SELECT ON test.* TO 'root'@'%'; +# Create tables : +mysql -u root -h 127.0.0.1 --password=password < ~/github/istio/samples/bookinfo/src/mysql/mysqldb-init.sql +# And to be able to connect remotely (only needed to test before injection) +sudo vi /etc/mysql/mysql.conf.d/mysqld.cnf +# comment out: +#bind-address = 127.0.0.1 +sudo service mysql restart +# check it's now binding on * +$ sudo lsof -i :3306 +COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME +mysqld 29145 mysql 31u IPv6 168376 0t0 TCP *:mysql (LISTEN) +# from another host, verify it works: +ldemailly@benchmark-2:~$ mysql -u root -h instance-1 --password=password test -e "select * from ratings" +mysql: [Warning] Using a password on the command line interface can be insecure. ++----------+--------+ +| ReviewID | Rating | ++----------+--------+ +| 1 | 5 | +| 2 | 6 | ++----------+--------+ +# for low volume troubleshooting: +mysql -u root -h instance-1 --password=password + SET global general_log_file='/tmp/mysqlquery.log'; + SET global general_log = 1; +# then +tail -f /tmp/mysqlquery.log +``` + +### Or +sudo apt-get mariadb-server + +TODO: figure out equivalent of above for mariadb + +https://stackoverflow.com/questions/28068155/access-denied-for-user-rootlocalhost-using-password-yes-after-new-instal + + +## Sidecar +See +https://github.com/istio/proxy/tree/master/tools/deb + +## Bookinfo with MySql in k8s: + +You need 5 nodes in your cluster to add mysql (until we tune the requests) +``` +# source istio.VERSION +wget https://storage.googleapis.com/istio-artifacts/pilot/$PILOT_TAG/artifacts/istioctl/istioctl-osx +chmod 755 istioctl-osx +./istioctl-osx kube-inject --hub $PILOT_HUB --tag $PILOT_TAG -f samples/bookinfo/kube/bookinfo.yaml > bookinfo-istio.yaml +kubectl apply -f bookinfo-istio.yaml +./istioctl-osx kube-inject --hub $PILOT_HUB --tag $PILOT_TAG -f samples/bookinfo/kube/bookinfo-mysql.yaml > bookinfo-mysql-istio.yaml +kubectl apply -f bookinfo-mysql-istio.yaml +./istioctl-osx kube-inject --hub $PILOT_HUB --tag $PILOT_TAG -f samples/bookinfo/kube/bookinfo-ratings-v2.yaml > bookinfo-ratings-v2-istio.yaml +kubectl apply -f bookinfo-ratings-v2-istio.yaml +# use it (ratings v2 and mysql) +kubectl apply -f samples/bookinfo/networking/virtual-service-ratings-mysql.yaml +# wait a bit / reload product page +# see mysql in grafana and 5,6 stars +kubectl port-forward mysqldb-v1-325529163-9x1r0 3306:3306 # use actual mysql pod +mysql -u root -h 127.0.0.1 --password=password test + select * from ratings; + update ratings set rating=3 where reviewid=1; +# see first rating change to 3 stars + +# for metrics: +fortio load -t 1m http://$INGRESS_IP/productpage +``` +## Move MySQL to VM +1. remove the k8s based service + ``` + kubectl delete svc mysqldb + ``` +2. observe `product ratings not available` when re-loading the page +3. register the VM instead: + ``` + $ ./istioctl-osx register mysqldb 10.138.0.13 3306 +I0904 11:12:56.785430 34562 register.go:44] Registering for service 'mysqldb' ip '10.138.0.13', ports list [{3306 mysql}] +I0904 11:12:56.785536 34562 register.go:49] 0 labels ([]) and 1 annotations ([alpha.istio.io/kubernetes-serviceaccounts=default]) +W0904 11:12:56.887017 34562 register.go:123] Got 'services "mysqldb" not found' looking up svc 'mysqldb' in namespace 'default', attempting to create it +W0904 11:12:56.938721 34562 register.go:139] Got 'endpoints "mysqldb" not found' looking up endpoints for 'mysqldb' in namespace 'default', attempting to create them +I0904 11:12:57.055643 34562 register.go:180] No pre existing exact matching ports list found, created new subset {[{10.138.0.13 nil}] [] [{mysql 3306 }]} +I0904 11:12:57.090739 34562 register.go:191] Successfully updated mysqldb, now with 1 endpoints + ``` +4. check the registration: + ``` + $ kubectl get svc mysqldb -o yaml +apiVersion: v1 +kind: Service +metadata: + annotations: + alpha.istio.io/kubernetes-serviceaccounts: default + creationTimestamp: 2017-09-04T18:12:56Z + name: mysqldb + namespace: default + resourceVersion: "464459" + selfLink: /api/v1/namespaces/default/services/mysqldb + uid: ad746e4c-919c-11e7-9a62-42010a8a004e +spec: + clusterIP: 10.31.253.143 + ports: + - name: mysql + port: 3306 + protocol: TCP + targetPort: 3306 + sessionAffinity: None + type: ClusterIP +status: + loadBalancer: {} + ``` + +## Build debian packages + +Prereq: + +Linux ubuntu xenial, docker, go 1.8, bazel, ... (the packages listed at https://github.com/istio/istio/blob/master/devel/README.md#collection-of-scripts-and-notes-for-developing-for-istio ) + +ps: for docker - remember to "docker ps" and it should work/not error out and not require sudo, if it doesn't work add your username to /etc/group docker + +For gcloud ( https://cloud.google.com/sdk/docs/quickstart-debian-ubuntu ): +```shell +export CLOUD_SDK_REPO="cloud-sdk-$(lsb_release -c -s)" +echo "deb http://packages.cloud.google.com/apt $CLOUD_SDK_REPO main" | sudo tee -a /etc/apt/sources.list.d/google-cloud-sdk.list +curl https://packages.cloud.google.com/apt/doc/apt-key.gpg | sudo apt-key add - +sudo apt-get update && sudo apt-get install google-cloud-sdk +gcloud init +sudo apt-get install kubectl +gcloud container clusters get-credentials demo-1 --zone us-west1-b --project istio-demo-0-2 +``` + +Note to install rbac yaml you need: +``` +kubectl create clusterrolebinding my-admin-access --clusterrole cluster-admin --user USERNAME +``` + +Then: + +``` +git clone https://github.com/istio/proxy.git -b rawvm-demo-0-2-2 +tools/deb/test/build_all.sh +``` diff --git a/istio-1.3.5/samples/security/psp/all-pods-psp.yaml b/istio-1.3.5/samples/security/psp/all-pods-psp.yaml new file mode 100644 index 0000000..a52d56a --- /dev/null +++ b/istio-1.3.5/samples/security/psp/all-pods-psp.yaml @@ -0,0 +1,51 @@ +# For details about using this yaml file, please refer to: +# https://istio.io/docs/tasks/security/auth-sds/#increasing-security-with-pod-security-policies +apiVersion: extensions/v1beta1 +kind: PodSecurityPolicy +metadata: + name: istio-sds-uds +spec: + # Protect the unix domain socket from unauthorized modification + allowedHostPaths: + - pathPrefix: "/var/run/sds" + readOnly: true + # Allow the istio sidecar injector to work + allowedCapabilities: + - NET_ADMIN + seLinux: + rule: RunAsAny + supplementalGroups: + rule: RunAsAny + runAsUser: + rule: RunAsAny + fsGroup: + rule: RunAsAny + volumes: + - '*' +--- +kind: ClusterRole +apiVersion: rbac.authorization.k8s.io/v1 +metadata: + name: istio-sds-uds-psp +rules: + - apiGroups: + - extensions + resources: + - podsecuritypolicies + resourceNames: + - istio-sds-uds + verbs: + - use +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: istio-sds-uds-psp +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: istio-sds-uds-psp +subjects: + - apiGroup: rbac.authorization.k8s.io + kind: Group + name: system:serviceaccounts diff --git a/istio-1.3.5/samples/security/psp/citadel-agent-psp.yaml b/istio-1.3.5/samples/security/psp/citadel-agent-psp.yaml new file mode 100644 index 0000000..c141ee5 --- /dev/null +++ b/istio-1.3.5/samples/security/psp/citadel-agent-psp.yaml @@ -0,0 +1,48 @@ +# For details about using this yaml file, please refer to: +# https://istio.io/docs/tasks/security/auth-sds/#increasing-security-with-pod-security-policies +apiVersion: extensions/v1beta1 +kind: PodSecurityPolicy +metadata: + name: istio-nodeagent +spec: + allowedHostPaths: + - pathPrefix: "/var/run/sds" + seLinux: + rule: RunAsAny + supplementalGroups: + rule: RunAsAny + runAsUser: + rule: RunAsAny + fsGroup: + rule: RunAsAny + volumes: + - '*' +--- +kind: Role +apiVersion: rbac.authorization.k8s.io/v1 +metadata: + name: istio-nodeagent-istio-system-psp + namespace: istio-system +rules: + - apiGroups: + - extensions + resources: + - podsecuritypolicies + resourceNames: + - istio-nodeagent + verbs: + - use +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: RoleBinding +metadata: + name: istio-nodeagent-istio-system-psp + namespace: istio-system +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: Role + name: istio-nodeagent-istio-system-psp +subjects: + - kind: ServiceAccount + name: istio-nodeagent-service-account + namespace: istio-system diff --git a/istio-1.3.5/samples/sleep/README.md b/istio-1.3.5/samples/sleep/README.md new file mode 100644 index 0000000..5247633 --- /dev/null +++ b/istio-1.3.5/samples/sleep/README.md @@ -0,0 +1,30 @@ +# Simple sleep service + +This sample consists of a simple service that does nothing but sleep. +It's a ubuntu container with curl installed that can be used as a request source for invoking other services +to experiment with Istio networking. +To use it: + +1. Install Istio by following the [istio install instructions](https://istio.io/docs/setup/kubernetes/quick-start.html). + +2. Start the sleep service: + + ```bash + kubectl apply -f <(istioctl kube-inject -f sleep.yaml) + ``` + + Note that if you also want to be able to directly call + external services, you'll need to set the `global.proxy.includeIPRanges` variable of Helm and update the + istio-sidecar-injector configmap by using kubectl apply. + See [configuring egress](https://istio.io/docs/tasks/traffic-management/egress.html) for details. + +3. Start some other services, for example, the [Bookinfo sample](https://istio.io/docs/guides/bookinfo.html). + +Now you can `kubectl exec` into the sleep service to experiment with Istio. +For example, the following commands can be used to call the Bookinfo `ratings` service: + +``` +export SLEEP_POD=$(kubectl get pod -l app=sleep -o jsonpath={.items..metadata.name}) +kubectl exec -it $SLEEP_POD -c sleep curl http://ratings.default.svc.cluster.local:9080/ratings +{"Reviewer1":5,"Reviewer2":4} +``` diff --git a/istio-1.3.5/samples/sleep/policy/sni-serviceaccount.yaml b/istio-1.3.5/samples/sleep/policy/sni-serviceaccount.yaml new file mode 100644 index 0000000..7e77f49 --- /dev/null +++ b/istio-1.3.5/samples/sleep/policy/sni-serviceaccount.yaml @@ -0,0 +1,55 @@ +apiVersion: config.istio.io/v1alpha2 +kind: instance +metadata: + name: requested-server-name + namespace: istio-system +spec: + compiledTemplate: listentry + params: + value: connection.requested_server_name +--- +apiVersion: config.istio.io/v1alpha2 +kind: handler +metadata: + name: us-wikipedia-checker + namespace: istio-system +spec: + compiledAdapter: listchecker + params: + overrides: ["en.wikipedia.org", "es.wikipedia.org"] + blacklist: false +--- +# Rule to check access to *.wikipedia.org +apiVersion: config.istio.io/v1alpha2 +kind: rule +metadata: + name: check-us-wikipedia-access + namespace: istio-system +spec: + match: source.labels["app"] == "istio-egressgateway-with-sni-proxy" && destination.labels["app"] == "" && source.principal == "cluster.local/ns/default/sa/sleep-us" + actions: + - handler: us-wikipedia-checker + instances: [ requested-server-name ] +--- +apiVersion: config.istio.io/v1alpha2 +kind: handler +metadata: + name: canada-wikipedia-checker + namespace: istio-system +spec: + compiledAdapter: listchecker + params: + overrides: ["en.wikipedia.org", "fr.wikipedia.org"] + blacklist: false +--- +# Rule to check access to *.wikipedia.org +apiVersion: "config.istio.io/v1alpha2" +kind: rule +metadata: + name: check-canada-wikipedia-access + namespace: istio-system +spec: + match: source.labels["app"] == "istio-egressgateway-with-sni-proxy" && destination.labels["app"] == "" && source.principal == "cluster.local/ns/default/sa/sleep-canada" + actions: + - handler: canada-wikipedia-checker + instances: [ requested-server-name ] diff --git a/istio-1.3.5/samples/sleep/policy/sni-wikipedia.yaml b/istio-1.3.5/samples/sleep/policy/sni-wikipedia.yaml new file mode 100644 index 0000000..43fe491 --- /dev/null +++ b/istio-1.3.5/samples/sleep/policy/sni-wikipedia.yaml @@ -0,0 +1,32 @@ +apiVersion: config.istio.io/v1alpha2 +kind: handler +metadata: + name: wikipedia-checker + namespace: istio-system +spec: + compiledAdapter: listchecker + params: + overrides: ["en.wikipedia.org"] # overrides provide a static list + blacklist: true +--- +apiVersion: config.istio.io/v1alpha2 +kind: instance +metadata: + name: requested-server-name + namespace: istio-system +spec: + compiledTemplate: listentry + params: + value: connection.requested_server_name +--- +# Rule to check access to *.wikipedia.org +apiVersion: config.istio.io/v1alpha2 +kind: rule +metadata: + name: check-wikipedia-access + namespace: istio-system +spec: + match: source.labels["app"] == "istio-egressgateway-with-sni-proxy" && destination.labels["app"] == "" + actions: + - handler: wikipedia-checker + instances: [ requested-server-name ] diff --git a/istio-1.3.5/samples/sleep/sleep-vault.yaml b/istio-1.3.5/samples/sleep/sleep-vault.yaml new file mode 100644 index 0000000..b82fb14 --- /dev/null +++ b/istio-1.3.5/samples/sleep/sleep-vault.yaml @@ -0,0 +1,56 @@ +# Copyright 2019 Istio Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +################################################################################################## +# Sleep service +################################################################################################## +apiVersion: v1 +kind: ServiceAccount +metadata: + name: sleep +--- +apiVersion: v1 +kind: Service +metadata: + name: sleep + labels: + app: sleep +spec: + ports: + - port: 80 + name: http + selector: + app: sleep +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: sleep +spec: + replicas: 1 + selector: + matchLabels: + app: sleep + template: + metadata: + labels: + app: sleep + spec: + serviceAccountName: vault-citadel-sa + containers: + - name: sleep + image: pstauffer/curl + command: ["/bin/sleep", "3650d"] + imagePullPolicy: IfNotPresent +--- diff --git a/istio-1.3.5/samples/sleep/sleep.yaml b/istio-1.3.5/samples/sleep/sleep.yaml new file mode 100644 index 0000000..84fcfcf --- /dev/null +++ b/istio-1.3.5/samples/sleep/sleep.yaml @@ -0,0 +1,56 @@ +# Copyright 2017 Istio Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +################################################################################################## +# Sleep service +################################################################################################## +apiVersion: v1 +kind: ServiceAccount +metadata: + name: sleep +--- +apiVersion: v1 +kind: Service +metadata: + name: sleep + labels: + app: sleep +spec: + ports: + - port: 80 + name: http + selector: + app: sleep +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: sleep +spec: + replicas: 1 + selector: + matchLabels: + app: sleep + template: + metadata: + labels: + app: sleep + spec: + serviceAccountName: sleep + containers: + - name: sleep + image: governmentpaas/curl-ssl + command: ["/bin/sleep", "3650d"] + imagePullPolicy: IfNotPresent +--- diff --git a/istio-1.3.5/samples/sleep/telemetry/sni-logging.yaml b/istio-1.3.5/samples/sleep/telemetry/sni-logging.yaml new file mode 100644 index 0000000..cf1c89a --- /dev/null +++ b/istio-1.3.5/samples/sleep/telemetry/sni-logging.yaml @@ -0,0 +1,45 @@ +# Log entry for egress access +apiVersion: config.istio.io/v1alpha2 +kind: instance +metadata: + name: egress-access + namespace: istio-system +spec: + compiledTemplate: logentry + params: + severity: '"info"' + timestamp: context.time | timestamp("2017-01-01T00:00:00Z") + variables: + connectionEvent: connection.event | "" + source: source.labels["app"] | "unknown" + sourceNamespace: source.namespace | "unknown" + sourceWorkload: source.workload.name | "" + sourcePrincipal: source.principal | "unknown" + requestedServerName: connection.requested_server_name | "unknown" + destinationApp: destination.labels["app"] | "" + monitored_resource_type: '"UNSPECIFIED"' +--- +# Handler for info egress access entries +apiVersion: config.istio.io/v1alpha2 +kind: handler +metadata: + name: egress-access-logger + namespace: istio-system +spec: + compiledAdapter: stdio + params: + severity_levels: + info: 0 # output log level as info + outputAsJson: true +--- +# Rule to handle access to *.wikipedia.org +apiVersion: config.istio.io/v1alpha2 +kind: rule +metadata: + name: handle-wikipedia-access + namespace: istio-system +spec: + match: source.labels["app"] == "istio-egressgateway-with-sni-proxy" && destination.labels["app"] == "" && connection.event == "open" + actions: + - handler: egress-access-logger + instances: [ egress-access ] diff --git a/istio-1.3.5/samples/tcp-echo/README.md b/istio-1.3.5/samples/tcp-echo/README.md new file mode 100644 index 0000000..59fa157 --- /dev/null +++ b/istio-1.3.5/samples/tcp-echo/README.md @@ -0,0 +1,38 @@ +# TCP Echo Service + +This sample runs [TCP Echo Server](src/) as an Istio service. TCP Echo Server +allows you to connect to it over TCP and echoes back data sent to it along with +a preconfigured prefix. + +## Usage + +To run the TCP Echo Service sample: + +1. Install Istio by following the [istio install instructions](https://istio.io/docs/setup/kubernetes/quick-start.html). + +2. Start the `tcp-echo-server` service inside the Istio service mesh: + + ```console + $ kubectl apply -f <(istioctl kube-inject -f tcp-echo.yaml) + service/tcp-echo created + deployment.extensions/tcp-echo created + ``` + +3. Test by running the `nc` command from a `busybox` container from within the cluster. + + ```console + $ kubectl run -i --rm --restart=Never dummy --image=busybox -- sh -c "echo world | nc tcp-echo 9000" + hello world + pod "dummy" deleted + ``` + + As you observe, sending _world_ on a TCP connection to the server results in + the server prepending _hello_ and echoing back with _hello world_. + +4. To clean up, execute the following command: + + ```console + $ kubectl delete -f tcp-echo.yaml + service "tcp-echo" deleted + deployment.extensions "tcp-echo" deleted + ``` diff --git a/istio-1.3.5/samples/tcp-echo/tcp-echo-20-v2.yaml b/istio-1.3.5/samples/tcp-echo/tcp-echo-20-v2.yaml new file mode 100644 index 0000000..f69ab11 --- /dev/null +++ b/istio-1.3.5/samples/tcp-echo/tcp-echo-20-v2.yaml @@ -0,0 +1,39 @@ +# Copyright 2018 Istio Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +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 diff --git a/istio-1.3.5/samples/tcp-echo/tcp-echo-all-v1.yaml b/istio-1.3.5/samples/tcp-echo/tcp-echo-all-v1.yaml new file mode 100644 index 0000000..3c302c5 --- /dev/null +++ b/istio-1.3.5/samples/tcp-echo/tcp-echo-all-v1.yaml @@ -0,0 +1,61 @@ +# Copyright 2018 Istio Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +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 diff --git a/istio-1.3.5/samples/tcp-echo/tcp-echo-services.yaml b/istio-1.3.5/samples/tcp-echo/tcp-echo-services.yaml new file mode 100644 index 0000000..cb13d92 --- /dev/null +++ b/istio-1.3.5/samples/tcp-echo/tcp-echo-services.yaml @@ -0,0 +1,74 @@ +# Copyright 2018 Istio Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +apiVersion: v1 +kind: Service +metadata: + name: tcp-echo + labels: + app: tcp-echo +spec: + ports: + - name: tcp + port: 9000 + selector: + app: tcp-echo +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: tcp-echo-v1 +spec: + replicas: 1 + selector: + matchLabels: + app: tcp-echo + version: v1 + template: + metadata: + labels: + app: tcp-echo + version: v1 + spec: + containers: + - name: tcp-echo + image: docker.io/istio/tcp-echo-server:1.1 + imagePullPolicy: IfNotPresent + args: [ "9000", "one" ] + ports: + - containerPort: 9000 +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: tcp-echo-v2 +spec: + replicas: 1 + selector: + matchLabels: + app: tcp-echo + version: v2 + template: + metadata: + labels: + app: tcp-echo + version: v2 + spec: + containers: + - name: tcp-echo + image: docker.io/istio/tcp-echo-server:1.1 + imagePullPolicy: IfNotPresent + args: [ "9000", "two" ] + ports: + - containerPort: 9000 diff --git a/istio-1.3.5/samples/tcp-echo/tcp-echo.yaml b/istio-1.3.5/samples/tcp-echo/tcp-echo.yaml new file mode 100644 index 0000000..ed710cd --- /dev/null +++ b/istio-1.3.5/samples/tcp-echo/tcp-echo.yaml @@ -0,0 +1,53 @@ +# Copyright 2018 Istio Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +################################################################################ +# tcp-echo service +################################################################################ +apiVersion: v1 +kind: Service +metadata: + name: tcp-echo + labels: + app: tcp-echo +spec: + ports: + - name: tcp + port: 9000 + selector: + app: tcp-echo +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: tcp-echo +spec: + replicas: 1 + selector: + matchLabels: + app: tcp-echo + version: v1 + template: + metadata: + labels: + app: tcp-echo + version: v1 + spec: + containers: + - name: tcp-echo + image: docker.io/istio/tcp-echo-server:1.1 + imagePullPolicy: IfNotPresent + args: [ "9000", "hello" ] + ports: + - containerPort: 9000 diff --git a/istio-1.3.5/samples/websockets/README.md b/istio-1.3.5/samples/websockets/README.md new file mode 100644 index 0000000..d2bef5e --- /dev/null +++ b/istio-1.3.5/samples/websockets/README.md @@ -0,0 +1,38 @@ +# Tornado - Demo Websockets App + +This is a sample application that demonstrates the use of an upgraded websockets connection on an ingress traffic when using Istio `VirtualService`. +The `app.yaml` creates a Kubernetes `Service` and a `Deployment` that is based on an existing Docker image for [Hiroakis's Tornado Websocket Example](https://github.com/hiroakis/tornado-websocket-example). + +__Notice:__ The addition of websockets upgrade support in v1alpha3 routing rules has only been added after the release of `Istio v0.8.0`. + +## Prerequisites +- Install Istio by following the [Istio Quick Start](https://istio.io/docs/setup/kubernetes/quick-start.html). + +## Installation +1. First install the application service: + - With manual sidecar injection: + ```command + kubectl create -f <(istioctl kube-inject -f samples/websockets/app.yaml) + ``` + - With automatic sidecar injection: + ```command + kubectl create -f samples/websockets/app.yaml + ``` +2. Create the Ingress `Gateway` and `VirtualService` that enables the upgrade to Websocket for incoming traffic: + ```command + kubectl create -f samples/websockets/route.yaml + ``` + +## Test +- [Find your ingress gateway IP](https://istio.io/docs/tasks/traffic-management/ingress/#determining-the-ingress-ip-and-ports) +- Access http://$GATEWAY_IP/ with your browser +- The `WebSocket status` should show a green `open` status which means that a websocket connection to the server has been established. +To see the websocket in action see the instructions in the _REST API examples_ section of the demo app webpage for updating the server-side data and getting the updated data through the open websocket to the table in the webpage (without refreshing). + +## Cleanup +```command +kubectl delete -f samples/websockets/route.yaml +``` +```command +kubectl delete -f samples/websockets/app.yaml +``` diff --git a/istio-1.3.5/samples/websockets/app.yaml b/istio-1.3.5/samples/websockets/app.yaml new file mode 100644 index 0000000..f307f64 --- /dev/null +++ b/istio-1.3.5/samples/websockets/app.yaml @@ -0,0 +1,36 @@ +apiVersion: v1 +kind: Service +metadata: + name: tornado + labels: + app: tornado +spec: + ports: + - port: 8888 + name: http + selector: + app: tornado +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: tornado +spec: + replicas: 1 + selector: + matchLabels: + app: tornado + version: v1 + template: + metadata: + labels: + app: tornado + version: v1 + spec: + containers: + - name: tornado + image: hiroakis/tornado-websocket-example + imagePullPolicy: IfNotPresent + ports: + - containerPort: 8888 +--- diff --git a/istio-1.3.5/samples/websockets/route.yaml b/istio-1.3.5/samples/websockets/route.yaml new file mode 100644 index 0000000..b9450a9 --- /dev/null +++ b/istio-1.3.5/samples/websockets/route.yaml @@ -0,0 +1,33 @@ +apiVersion: networking.istio.io/v1alpha3 +kind: Gateway +metadata: + name: tornado-gateway +spec: + selector: + istio: ingressgateway + servers: + - port: + number: 80 + name: http + protocol: HTTP + hosts: + - "*" +--- +apiVersion: networking.istio.io/v1alpha3 +kind: VirtualService +metadata: + name: tornado +spec: + hosts: + - "*" + gateways: + - tornado-gateway + http: + - match: + - uri: + prefix: / + route: + - destination: + host: tornado + weight: 100 + websocketUpgrade: true diff --git a/istio-1.3.5/tools/README.md b/istio-1.3.5/tools/README.md new file mode 100644 index 0000000..d2a196b --- /dev/null +++ b/istio-1.3.5/tools/README.md @@ -0,0 +1,278 @@ +# Istio Load Testing User Guide +### Introduction +This guide provides step-by-step instructions for using the `setup_perf_cluster.sh` load testing script. +The script deploys a GKE cluster, an Istio service mesh and a GCE VM. The script then runs [Fortio](https://github.com/fortio/fortio/#fortio) +on the VM, 2 pods within the cluster (non-Istio) and 2 pods within the Istio mesh. + +It should not be too difficult to adapt the script to other cloud providers or environments and contributions for additional automated setup are welcome. + +The following diagram provides additional details of the deployment and the main 4 istio-ified scenarios (which are ran twice each, once at max qps and once at fixed 400qps): + +![Deployment Diagram](perf_setup.svg) + +The deployment provides a basis for Istio performance characterization. Fortio is used to perform load testing, +graphing results and as a backend echo server. + +### Download a Release or Clone Istio + +It's recommended you use a release (either [official](https://github.com/istio/istio/releases) or [dailies](https://github.com/istio/istio/wiki/Daily-builds)): +``` +curl -L https://git.io/getLatestIstio | sh - # or download the daily TGZ +``` + +From source: +``` +$ git clone https://github.com/istio/istio.git && cd istio +``` + +### Install fortio locally + +Optional but recommended: + +If not already present from building from source, +Install fortio: `go get fortio.org/fortio` (so you can run `fortio report` to visualize the results) + +### Prepare the Istio Deployment Manifest and Istio Client + +__Option A:__ (From release) Make sure `istioctl` is in your path is the one matching the downloaded release. + +For instance, in `~/tmp/istio-0.6.0/` run: +``` +export PATH=`pwd`/bin:$PATH +# check 'which istioctl' and 'istioctl version' returns the correct version +``` +For versions before 0.5.0 (the tools/ directory is now part of the release) +``` +$ ln -s $GOPATH/src/istio.io/istio/tools +``` +If you want to get newer version of the tools, you can `rm -rf tools/` and do the symlink above to use your updated/newer script. + +__Option B:__ (Advanced users, not recommended, from source) Build the deployment manifest and `istioctl` binary: +``` +$ ./install/updateVersion.sh # This step is only needed when using Istio from source and may or may not work/need additional hub/tags/... +``` +Follow the steps in the [Developer Guide](https://github.com/istio/istio/wiki/Preparing-for-Development) to build the `istioctl` binary. +Make sure the binary is first in to your PATH. +Make sure it does `istioctl kube-inject` producing the HUB/TAG you expect. + +### Set Your Google Cloud Credentials (optional/one time setup) +This is not necessary if you already have working `gcloud` commands and you +did `gcloud auth login` at least once. +``` +$ gcloud auth login +# Or +$ export GOOGLE_APPLICATION_CREDENTIALS=/my/gce/creds.json +``` +If you do not have a Google Cloud account, [set one up](https://cloud.google.com/). + +### Optional: Customize the Deployment +The `setup_perf_cluster.sh` script can be customized. View the script and modify the default variables if needed. +For example, to update the default gcloud zone (us-east4-b): +``` +$ export ZONE=us-west1-a +``` +If you change either the `PROJECT` or the `ZONE`, make sure to run `update_gcp_opts` before calling the other functions. + +The script tries to guess your `PROJECT` but it's safer to set it explicitly. (and use a new empty project if possible) + +### Source the Script +``` +# Set PROJECT and ZONE first then +$ source tools/setup_perf_cluster.sh +``` +__Note:__ `setup_perf_cluster.sh` can be used as a script or sourced and functions called interactively. + +Inside Google, you may need to rerun setup_vm_firewall multiple times. + +### Run the Functions +The output of `source tools/setup_perf_cluster.sh` provides a list of available functions or +you can view the functions from within the `setup_perf_cluster.sh` script. The most common workflow is: +``` +$ setup_all +Obtaining latest ubuntu xenial image name... (takes a few seconds)... + +### Running: kubectl apply -n istio -f tools/cache_buster.yaml +``` +The deployment is now complete. You can verify the deployment using standard `kubectl` commands: +``` +$ kubectl get po --all-namespaces +NAMESPACE NAME READY STATUS RESTARTS AGE +fortio fortio1-1966733334-xj5f6 1/1 Running 0 8m +fortio fortio2-3044850348-v5f74 1/1 Running 0 8m +istio-system istio-ca-1363003450-gvtmn 1/1 Running 0 7m +istio-system istio-ingress-1732553340-gv41r 1/1 Running 0 7m +istio-system istio-mixer-3192291716-psskv 3/3 Running 0 8m +istio-system istio-pilot-3663920167-4ns3g 2/2 Running 0 7m + +``` + +Make sure your ingress is ready: +``` +$ kubectl get ing -n istio +NAME HOSTS ADDRESS PORTS AGE +istio-ingress * 35.188.254.231 80 1m +``` + +You can now run the performance tests, either from the command line or interactively using the UIs (see next section). +For command lines there are a couple of examples in the `run_tests` functions, it will run 4 tests +and start fortio report so you can graph the result on [http://localhost:8080/](http://localhost:8080/) + +``` +$ run_tests ++++ VM Ip is 35.199.55.254 - visit (http on port 443 is not a typo:) http://35.199.55.254:443/fortio/ ++++ In k8s fortio external ip: http://35.199.37.178:8080/fortio/ ++++ In k8s non istio ingress: http://35.227.201.148/fortio/ ++++ In k8s istio ingress: http://35.188.241.231/fortio1/fortio/ and fortio2 +Using istio ingress to fortio1: +### Running: curl -s http://35.199.55.254:443/fortio/?labels=ingress+to+f1\&json=on\&save=on\&qps=-1\&t=30s\&c=48\&load=Start\&url=http://35.188.241.231/fortio1/echo | tee ing-to-f1.json | grep ActualQPS + "ActualQPS": 439.8723210634554, +Using istio ingress to fortio2: +### Running: curl -s http://35.199.55.254:443/fortio/?labels=ingress+to+f2\&json=on\&save=on\&qps=-1\&t=30s\&c=48\&load=Start\&url=http://35.188.241.231/fortio2/echo | tee ing-to-f2.json | grep ActualQPS + "ActualQPS": 540.2583184971915, +Using istio f1 to f2: +### Running: curl -s http://35.188.241.231/fortio1/fortio/?labels=f1+to+f2\&json=on\&save=on\&qps=-1\&t=30s\&c=48\&load=Start\&url=http://echosrv2:8080/echo | tee f1-to-f2.json | grep ActualQPS + "ActualQPS": 439.5027107832303, +Using istio f2 to f1: +### Running: curl -s http://35.188.241.231/fortio2/fortio/?labels=f2+to+f1\&json=on\&save=on\&qps=-1\&t=30s\&c=48\&load=Start\&url=http://echosrv1:8080/echo | tee f2-to-f1.json | grep ActualQPS + "ActualQPS": 330.49386695603846, +``` +And then you will see: +![Single Graph Screen Shot](https://user-images.githubusercontent.com/3664595/37693480-231ac8c0-2c7d-11e8-9b3a-4e77a06f2d37.png) +![Multi Graph Screen Shot](https://user-images.githubusercontent.com/3664595/37693481-232efdf4-2c7d-11e8-92b4-8a6e088d3357.png) + + +For comparison and reference you can also run `run_fortio_test1` uses the default loadbalancer and no Istio mesh or Istio Ingress Controller. + +The following command tells +Fortio on the VM to run a load test against the Fortio echo server running in the Kubernetes cluster: +``` +### Running: curl http://$VM_URL/fortio/?json=on&qps=-1&t=30s&c=48&load=Start&url=http://$K8S_FORTIO_EXT_IP:8080/echo +``` +The following arguments are passed to the Fortio server running on the GCE VM: + +| Argument | Description | +| --------------------------------------- | --------------------------------------- | +| json=on | Sets output in json format | +| qps=-1 | Requested queries per second to "max" | +| t=30s | Requested duration to run load test | +| c=48 | Number of connections/goroutine/threads | +| qps=-1 | Requested queries per second to "max" | +| load=Start | Tells Fortio to be a load generator | +| url=http://$K8S_FORTIO_EXT_IP:8080/echo | The target to load test | + +You can also run `run_fortio_test2` which uses the Fortio Ingress with no Istio mesh and the same arguments as the first test: +``` +### Running: curl http://$VM_URL/?json=on&qps=-1&t=30s&c=48&load=Start&url=http://$NON_ISTIO_INGRESS/echo +``` + +The tests from `run_tests` uses the Istio Ingress with the same arguments. This is the test that performs load testing +of the Istio service mesh: +``` +### Running: curl http://$VM_URL/?json=on&qps=-1&t=30s&c=48&load=Start&url=http://$ISTIO_INGRESS/fortio1/echo +``` +Compare the test results to understand the load differential between the 3 test cases. + +### Interactive Testing / UI Graphing of results + +Fortio provides a [Web UI](https://github.com/fortio/fortio#webgraphical-ui) that +can be used to perform load testing. You can call the `get_ips` function to obtain Fortio endpoint information for further load testing: +``` +$ get_ips ++++ VM Ip is $VM_IP - visit http://$VM_URL/ ++++ In k8s fortio external ip: http://$EXTERNAL_IP:8080/fortio/ ++++ In k8s non istio ingress: http://$NON_ISTIO_INGRESS_IP/fortio/ ++++ In k8s istio ingress: http://$ISTIO_INGRESS_IP/fortio1/fortio/ and fortio2 +``` + +Then visit http://$ISTIO_INGRESS_IP/fortio1/fortio/ or http://$ISTIO_INGRESS_IP/fortio2/fortio/ to generate a load +to one of the Fortio echo servers: + +`echosrv1.istio.svc.cluster.local:8080` or `echosrv2.istio.svc.cluster.local:8080`. + +Fortio provides additional load testing capabilities not covered by this document. For more information, refer to the +[Fortio documentation](https://github.com/fortio/fortio/blob/master/README.md) + +### Canonical Tests + +There is a set of canonical tests in ```run_canonical_perf_tests.sh``` script that runs tests by changing parameters in +various dimensions: +- Number of clients +- QPS +- Cached v.s. non-cached + +If you have a change that you think might affect performance, then you can run these tests to check the affects. + +To establish a baseline, simply deploy a perf cluster using the instructions above. Then run +```run_canonical_perf_tests.sh``` to establish the baseline. You will see output that looks like this: + +``` +> run_canonical_perf_tests.sh ++++ In k8s istio ingress: http:///fortio1/fortio/ and fortio2 +Running 'canonical+fortio2+echo1+Q100+T1s+C16' and storing results in /tmp/istio_perf.cpxCcs/canonical_fortio2_echo1_Q100_T1s_C16.json ++++ In k8s istio ingress: http:///fortio1/fortio/ and fortio2 +Running 'canonical+fortio2+echo1+Q400+T1s+C16' and storing results in /tmp/istio_perf.cpxCcs/canonical_fortio2_echo1_Q400_T1s_C16.json +... +``` + +You can check the Fortio UI of the respective drivers to see the results. Also, you can checkout the raw json files +that gets stored in the temporary folder that is in the output above: + +``` +ls /tmp/istio_perf.cpxCcs/ +canonical_fortio2_echo1_Q1000_T1s_C16.json canonical_fortio2_echo1_Q100_T1s_C20.json canonical_fortio2_echo1_Q1200_T1s_C24.json canonical_fortio2_echo1_Q400_T1s_C16.json +canonical_fortio2_echo1_Q1000_T1s_C20.json canonical_fortio2_echo1_Q100_T1s_C24.json canonical_fortio2_echo1_Q1600_T1s_C16.json canonical_fortio2_echo1_Q400_T1s_C20.json +canonical_fortio2_echo1_Q1000_T1s_C24.json canonical_fortio2_echo1_Q1200_T1s_C16.json canonical_fortio2_echo1_Q1600_T1s_C20.json canonical_fortio2_echo1_Q400_T1s_C24.json +canonical_fortio2_echo1_Q100_T1s_C16.json canonical_fortio2_echo1_Q1200_T1s_C20.json canonical_fortio2_echo1_Q1600_T1s_C24.json out.csv +``` + +You can run `fortio report -data-dir /tmp/istio_perf.cpxCcs/` to see all the results and graph them/compare them by visiting `http://localhost:8080` + +Alternatively, notice the ```out.csv``` file in the folder. This file contains all the data in the individual json files, and can be +imported into a spreadsheet: + + +``` +> cat /tmp/istio_perf.cpxCcs/out.csv +Label,Driver,Target,qps,duration,clients,min,max,avg,p50,p75,p90,p99,p99.9 +canonical,fortio2,echo1,1200,1s,16,0.00243703,0.059164527,0.0134183966225,0.0108966942149,0.01594375,0.02405,0.048646875,0.0575867009348 +canonical,fortio2,echo1,1200,1s,24,0.003420898,0.086621239,0.0248239801951,0.0203296703297,0.0303731343284,0.0494375,0.080344304428,0.085993545542 +... +``` + +To test the affects of your change, simply update your cluster with your binaries by following the +[Developer Guide](https://github.com/istio/istio/wiki/Preparing-for-Development) and rerun the tests again. To ensure +you're tracking the results of your changes correctly, you can explicitly specify a label: + +``` +# Notice the "mylabel" parameter below: +# +> run_canonical_perf_tests.sh mylabel ++++ In k8s istio ingress: http:///fortio1/fortio/ and fortio2 +Running 'mylabel+fortio2+echo1+Q400+T1s+C16' and storing results in /tmp/istio_perf.0XuSIH/mylabel_fortio2_echo1_Q400_T1s_C16.json ++++ In k8s istio ingress: http:///fortio1/fortio/ and fortio2 +... +``` + +After the run, you can find the new results both in Fortio UI, and also in the temporary folder: + +``` +> ls /tmp/istio_perf.0XuSIH/ +mylabel_fortio2_echo1_Q1000_T1s_C16.json mylabel_fortio2_echo1_Q100_T1s_C20.json mylabel_fortio2_echo1_Q1200_T1s_C24.json mylabel_fortio2_echo1_Q400_T1s_C16.json +mylabel_fortio2_echo1_Q1000_T1s_C20.json mylabel_fortio2_echo1_Q100_T1s_C24.json mylabel_fortio2_echo1_Q1600_T1s_C16.json mylabel_fortio2_echo1_Q400_T1s_C20.json +mylabel_fortio2_echo1_Q1000_T1s_C24.json mylabel_fortio2_echo1_Q1200_T1s_C16.json mylabel_fortio2_echo1_Q1600_T1s_C20.json mylabel_fortio2_echo1_Q400_T1s_C24.json +mylabel_fortio2_echo1_Q100_T1s_C16.json mylabel_fortio2_echo1_Q1200_T1s_C20.json mylabel_fortio2_echo1_Q1600_T1s_C24.json out.csv +``` + +### Uninstall +Use the `delete_all` function to remove everything done by the `setup_all` function. The following delete functions are used by +`delete_all` and may be called individually: +``` +$ delete_istio +$ delete_cluster +$ delete_vm +$ delete_vm_firewall +``` + +### See also + +[Perf setup FAQ wiki](https://github.com/istio/istio/wiki/Istio-Performance-oriented-setup-FAQ) diff --git a/istio-1.3.5/tools/_istioctl b/istio-1.3.5/tools/_istioctl new file mode 100644 index 0000000..db9190e --- /dev/null +++ b/istio-1.3.5/tools/_istioctl @@ -0,0 +1,2155 @@ +#compdef istioctl + +__istio_bash_source() { + alias shopt=':' + alias _expand=_bash_expand + alias _complete=_bash_comp + emulate -L sh + setopt kshglob noshglob braceexpand + source "$@" +} +__istio_type() { + # -t is not supported by zsh + if [ "$1" == "-t" ]; then + shift + # fake Bash 4 to disable "complete -o nospace". Instead + # "compopt +-o nospace" is used in the code to toggle trailing + # spaces. We don't support that, but leave trailing spaces on + # all the time + if [ "$1" = "__istio_compopt" ]; then + echo builtin + return 0 + fi + fi + type "$@" +} +__istio_compgen() { + local completions w + completions=( $(compgen "$@") ) || return $? + # filter by given word as prefix + while [[ "$1" = -* && "$1" != -- ]]; do + shift + shift + done + if [[ "$1" == -- ]]; then + shift + fi + for w in "${completions[@]}"; do + if [[ "${w}" = "$1"* ]]; then + echo "${w}" + fi + done +} +__istio_compopt() { + true # don't do anything. Not supported by bashcompinit in zsh +} +__istio_ltrim_colon_completions() +{ + if [[ "$1" == *:* && "$COMP_WORDBREAKS" == *:* ]]; then + # Remove colon-word prefix from COMPREPLY items + local colon_word=${1%${1##*:}} + local i=${#COMPREPLY[*]} + while [[ $((--i)) -ge 0 ]]; do + COMPREPLY[$i]=${COMPREPLY[$i]#"$colon_word"} + done + fi +} +__istio_get_comp_words_by_ref() { + cur="${COMP_WORDS[COMP_CWORD]}" + prev="${COMP_WORDS[${COMP_CWORD}-1]}" + words=("${COMP_WORDS[@]}") + cword=("${COMP_CWORD[@]}") +} +__istio_filedir() { + local RET OLD_IFS w qw + __istio_debug "_filedir $@ cur=$cur" + if [[ "$1" = \~* ]]; then + # somehow does not work. Maybe, zsh does not call this at all + eval echo "$1" + return 0 + fi + OLD_IFS="$IFS" + IFS=$'\n' + if [ "$1" = "-d" ]; then + shift + RET=( $(compgen -d) ) + else + RET=( $(compgen -f) ) + fi + IFS="$OLD_IFS" + IFS="," __istio_debug "RET=${RET[@]} len=${#RET[@]}" + for w in ${RET[@]}; do + if [[ ! "${w}" = "${cur}"* ]]; then + continue + fi + if eval "[[ \"\${w}\" = *.$1 || -d \"\${w}\" ]]"; then + qw="$(__istio_quote "${w}")" + if [ -d "${w}" ]; then + COMPREPLY+=("${qw}/") + else + COMPREPLY+=("${qw}") + fi + fi + done +} +__istio_quote() { + if [[ $1 == \'* || $1 == \"* ]]; then + # Leave out first character + printf %q "${1:1}" + else + printf %q "$1" + fi +} +autoload -U +X bashcompinit && bashcompinit +# use word boundary patterns for BSD or GNU sed +LWORD='[[:<:]]' +RWORD='[[:>:]]' +if sed --help 2>&1 | grep -q GNU; then + LWORD='\<' + RWORD='\>' +fi +__istio_convert_bash_to_zsh() { + sed \ + -e 's/declare -F/whence -w/' \ + -e 's/_get_comp_words_by_ref "\$@"/_get_comp_words_by_ref "\$*"/' \ + -e 's/local \([a-zA-Z0-9_]*\)=/local \1; \1=/' \ + -e 's/flags+=("\(--.*\)=")/flags+=("\1"); two_word_flags+=("\1")/' \ + -e 's/must_have_one_flag+=("\(--.*\)=")/must_have_one_flag+=("\1")/' \ + -e "s/${LWORD}_filedir${RWORD}/__istio_filedir/g" \ + -e "s/${LWORD}_get_comp_words_by_ref${RWORD}/__istio_get_comp_words_by_ref/g" \ + -e "s/${LWORD}__ltrim_colon_completions${RWORD}/__istio_ltrim_colon_completions/g" \ + -e "s/${LWORD}compgen${RWORD}/__istio_compgen/g" \ + -e "s/${LWORD}compopt${RWORD}/__istio_compopt/g" \ + -e "s/${LWORD}declare${RWORD}/builtin declare/g" \ + -e "s/\\\$(type${RWORD}/\$(__istio_type/g" \ + <<'BASH_COMPLETION_EOF' +# bash completion for istioctl -*- shell-script -*- + +__istioctl_debug() +{ + if [[ -n ${BASH_COMP_DEBUG_FILE} ]]; then + echo "$*" >> "${BASH_COMP_DEBUG_FILE}" + fi +} + +# Homebrew on Macs have version 1.3 of bash-completion which doesn't include +# _init_completion. This is a very minimal version of that function. +__istioctl_init_completion() +{ + COMPREPLY=() + _get_comp_words_by_ref "$@" cur prev words cword +} + +__istioctl_index_of_word() +{ + local w word=$1 + shift + index=0 + for w in "$@"; do + [[ $w = "$word" ]] && return + index=$((index+1)) + done + index=-1 +} + +__istioctl_contains_word() +{ + local w word=$1; shift + for w in "$@"; do + [[ $w = "$word" ]] && return + done + return 1 +} + +__istioctl_handle_reply() +{ + __istioctl_debug "${FUNCNAME[0]}" + case $cur in + -*) + if [[ $(type -t compopt) = "builtin" ]]; then + compopt -o nospace + fi + local allflags + if [ ${#must_have_one_flag[@]} -ne 0 ]; then + allflags=("${must_have_one_flag[@]}") + else + allflags=("${flags[*]} ${two_word_flags[*]}") + fi + COMPREPLY=( $(compgen -W "${allflags[*]}" -- "$cur") ) + if [[ $(type -t compopt) = "builtin" ]]; then + [[ "${COMPREPLY[0]}" == *= ]] || compopt +o nospace + fi + + # complete after --flag=abc + if [[ $cur == *=* ]]; then + if [[ $(type -t compopt) = "builtin" ]]; then + compopt +o nospace + fi + + local index flag + flag="${cur%=*}" + __istioctl_index_of_word "${flag}" "${flags_with_completion[@]}" + COMPREPLY=() + if [[ ${index} -ge 0 ]]; then + PREFIX="" + cur="${cur#*=}" + ${flags_completion[${index}]} + if [ -n "${ZSH_VERSION}" ]; then + # zsh completion needs --flag= prefix + eval "COMPREPLY=( \"\${COMPREPLY[@]/#/${flag}=}\" )" + fi + fi + fi + return 0; + ;; + esac + + # check if we are handling a flag with special work handling + local index + __istioctl_index_of_word "${prev}" "${flags_with_completion[@]}" + if [[ ${index} -ge 0 ]]; then + ${flags_completion[${index}]} + return + fi + + # we are parsing a flag and don't have a special handler, no completion + if [[ ${cur} != "${words[cword]}" ]]; then + return + fi + + local completions + completions=("${commands[@]}") + if [[ ${#must_have_one_noun[@]} -ne 0 ]]; then + completions=("${must_have_one_noun[@]}") + fi + if [[ ${#must_have_one_flag[@]} -ne 0 ]]; then + completions+=("${must_have_one_flag[@]}") + fi + COMPREPLY=( $(compgen -W "${completions[*]}" -- "$cur") ) + + if [[ ${#COMPREPLY[@]} -eq 0 && ${#noun_aliases[@]} -gt 0 && ${#must_have_one_noun[@]} -ne 0 ]]; then + COMPREPLY=( $(compgen -W "${noun_aliases[*]}" -- "$cur") ) + fi + + if [[ ${#COMPREPLY[@]} -eq 0 ]]; then + declare -F __custom_func >/dev/null && __custom_func + fi + + # available in bash-completion >= 2, not always present on macOS + if declare -F __ltrim_colon_completions >/dev/null; then + __ltrim_colon_completions "$cur" + fi + + # If there is only 1 completion and it is a flag with an = it will be completed + # but we don't want a space after the = + if [[ "${#COMPREPLY[@]}" -eq "1" ]] && [[ $(type -t compopt) = "builtin" ]] && [[ "${COMPREPLY[0]}" == --*= ]]; then + compopt -o nospace + fi +} + +# The arguments should be in the form "ext1|ext2|extn" +__istioctl_handle_filename_extension_flag() +{ + local ext="$1" + _filedir "@(${ext})" +} + +__istioctl_handle_subdirs_in_dir_flag() +{ + local dir="$1" + pushd "${dir}" >/dev/null 2>&1 && _filedir -d && popd >/dev/null 2>&1 +} + +__istioctl_handle_flag() +{ + __istioctl_debug "${FUNCNAME[0]}: c is $c words[c] is ${words[c]}" + + # if a command required a flag, and we found it, unset must_have_one_flag() + local flagname=${words[c]} + local flagvalue + # if the word contained an = + if [[ ${words[c]} == *"="* ]]; then + flagvalue=${flagname#*=} # take in as flagvalue after the = + flagname=${flagname%=*} # strip everything after the = + flagname="${flagname}=" # but put the = back + fi + __istioctl_debug "${FUNCNAME[0]}: looking for ${flagname}" + if __istioctl_contains_word "${flagname}" "${must_have_one_flag[@]}"; then + must_have_one_flag=() + fi + + # if you set a flag which only applies to this command, don't show subcommands + if __istioctl_contains_word "${flagname}" "${local_nonpersistent_flags[@]}"; then + commands=() + fi + + # keep flag value with flagname as flaghash + # flaghash variable is an associative array which is only supported in bash > 3. + if [[ -z "${BASH_VERSION}" || "${BASH_VERSINFO[0]}" -gt 3 ]]; then + if [ -n "${flagvalue}" ] ; then + flaghash[${flagname}]=${flagvalue} + elif [ -n "${words[ $((c+1)) ]}" ] ; then + flaghash[${flagname}]=${words[ $((c+1)) ]} + else + flaghash[${flagname}]="true" # pad "true" for bool flag + fi + fi + + # skip the argument to a two word flag + if __istioctl_contains_word "${words[c]}" "${two_word_flags[@]}"; then + c=$((c+1)) + # if we are looking for a flags value, don't show commands + if [[ $c -eq $cword ]]; then + commands=() + fi + fi + + c=$((c+1)) + +} + +__istioctl_handle_noun() +{ + __istioctl_debug "${FUNCNAME[0]}: c is $c words[c] is ${words[c]}" + + if __istioctl_contains_word "${words[c]}" "${must_have_one_noun[@]}"; then + must_have_one_noun=() + elif __istioctl_contains_word "${words[c]}" "${noun_aliases[@]}"; then + must_have_one_noun=() + fi + + nouns+=("${words[c]}") + c=$((c+1)) +} + +__istioctl_handle_command() +{ + __istioctl_debug "${FUNCNAME[0]}: c is $c words[c] is ${words[c]}" + + local next_command + if [[ -n ${last_command} ]]; then + next_command="_${last_command}_${words[c]//:/__}" + else + if [[ $c -eq 0 ]]; then + next_command="_istioctl_root_command" + else + next_command="_${words[c]//:/__}" + fi + fi + c=$((c+1)) + __istioctl_debug "${FUNCNAME[0]}: looking for ${next_command}" + declare -F "$next_command" >/dev/null && $next_command +} + +__istioctl_handle_word() +{ + if [[ $c -ge $cword ]]; then + __istioctl_handle_reply + return + fi + __istioctl_debug "${FUNCNAME[0]}: c is $c words[c] is ${words[c]}" + if [[ "${words[c]}" == -* ]]; then + __istioctl_handle_flag + elif __istioctl_contains_word "${words[c]}" "${commands[@]}"; then + __istioctl_handle_command + elif [[ $c -eq 0 ]]; then + __istioctl_handle_command + elif __istioctl_contains_word "${words[c]}" "${command_aliases[@]}"; then + # aliashash variable is an associative array which is only supported in bash > 3. + if [[ -z "${BASH_VERSION}" || "${BASH_VERSINFO[0]}" -gt 3 ]]; then + words[c]=${aliashash[${words[c]}]} + __istioctl_handle_command + else + __istioctl_handle_noun + fi + else + __istioctl_handle_noun + fi + __istioctl_handle_word +} + +_istioctl_auth() +{ + last_command="istioctl_auth" + + command_aliases=() + + commands=() + + flags=() + two_word_flags=() + local_nonpersistent_flags=() + flags_with_completion=() + flags_completion=() + + flags+=("--context=") + flags+=("--istioNamespace=") + two_word_flags+=("-i") + flags+=("--kubeconfig=") + two_word_flags+=("-c") + flags+=("--log_output_level=") + flags+=("--namespace=") + two_word_flags+=("-n") + + must_have_one_flag=() + must_have_one_noun=() + noun_aliases=() +} + +_istioctl_authn_tls-check() +{ + last_command="istioctl_authn_tls-check" + + command_aliases=() + + commands=() + + flags=() + two_word_flags=() + local_nonpersistent_flags=() + flags_with_completion=() + flags_completion=() + + flags+=("--context=") + flags+=("--istioNamespace=") + two_word_flags+=("-i") + flags+=("--kubeconfig=") + two_word_flags+=("-c") + flags+=("--log_output_level=") + flags+=("--namespace=") + two_word_flags+=("-n") + + must_have_one_flag=() + must_have_one_noun=() + noun_aliases=() +} + +_istioctl_authn() +{ + last_command="istioctl_authn" + + command_aliases=() + + commands=() + commands+=("tls-check") + + flags=() + two_word_flags=() + local_nonpersistent_flags=() + flags_with_completion=() + flags_completion=() + + flags+=("--context=") + flags+=("--istioNamespace=") + two_word_flags+=("-i") + flags+=("--kubeconfig=") + two_word_flags+=("-c") + flags+=("--log_output_level=") + flags+=("--namespace=") + two_word_flags+=("-n") + + must_have_one_flag=() + must_have_one_noun=() + noun_aliases=() +} + +_istioctl_convert-ingress() +{ + last_command="istioctl_convert-ingress" + + command_aliases=() + + commands=() + + flags=() + two_word_flags=() + local_nonpersistent_flags=() + flags_with_completion=() + flags_completion=() + + flags+=("--filenames=") + two_word_flags+=("-f") + flags+=("--output=") + two_word_flags+=("-o") + flags+=("--context=") + flags+=("--istioNamespace=") + two_word_flags+=("-i") + flags+=("--kubeconfig=") + two_word_flags+=("-c") + flags+=("--log_output_level=") + flags+=("--namespace=") + two_word_flags+=("-n") + + must_have_one_flag=() + must_have_one_noun=() + noun_aliases=() +} + +_istioctl_dashboard_controlz() +{ + last_command="istioctl_dashboard_controlz" + + command_aliases=() + + commands=() + + flags=() + two_word_flags=() + local_nonpersistent_flags=() + flags_with_completion=() + flags_completion=() + + flags+=("--ctrlz_port=") + flags+=("--context=") + flags+=("--istioNamespace=") + two_word_flags+=("-i") + flags+=("--kubeconfig=") + two_word_flags+=("-c") + flags+=("--log_output_level=") + flags+=("--namespace=") + two_word_flags+=("-n") + + must_have_one_flag=() + must_have_one_noun=() + noun_aliases=() +} + +_istioctl_dashboard_envoy() +{ + last_command="istioctl_dashboard_envoy" + + command_aliases=() + + commands=() + + flags=() + two_word_flags=() + local_nonpersistent_flags=() + flags_with_completion=() + flags_completion=() + + flags+=("--context=") + flags+=("--istioNamespace=") + two_word_flags+=("-i") + flags+=("--kubeconfig=") + two_word_flags+=("-c") + flags+=("--log_output_level=") + flags+=("--namespace=") + two_word_flags+=("-n") + + must_have_one_flag=() + must_have_one_noun=() + noun_aliases=() +} + +_istioctl_dashboard_grafana() +{ + last_command="istioctl_dashboard_grafana" + + command_aliases=() + + commands=() + + flags=() + two_word_flags=() + local_nonpersistent_flags=() + flags_with_completion=() + flags_completion=() + + flags+=("--context=") + flags+=("--istioNamespace=") + two_word_flags+=("-i") + flags+=("--kubeconfig=") + two_word_flags+=("-c") + flags+=("--log_output_level=") + flags+=("--namespace=") + two_word_flags+=("-n") + + must_have_one_flag=() + must_have_one_noun=() + noun_aliases=() +} + +_istioctl_dashboard_jaeger() +{ + last_command="istioctl_dashboard_jaeger" + + command_aliases=() + + commands=() + + flags=() + two_word_flags=() + local_nonpersistent_flags=() + flags_with_completion=() + flags_completion=() + + flags+=("--context=") + flags+=("--istioNamespace=") + two_word_flags+=("-i") + flags+=("--kubeconfig=") + two_word_flags+=("-c") + flags+=("--log_output_level=") + flags+=("--namespace=") + two_word_flags+=("-n") + + must_have_one_flag=() + must_have_one_noun=() + noun_aliases=() +} + +_istioctl_dashboard_kiali() +{ + last_command="istioctl_dashboard_kiali" + + command_aliases=() + + commands=() + + flags=() + two_word_flags=() + local_nonpersistent_flags=() + flags_with_completion=() + flags_completion=() + + flags+=("--context=") + flags+=("--istioNamespace=") + two_word_flags+=("-i") + flags+=("--kubeconfig=") + two_word_flags+=("-c") + flags+=("--log_output_level=") + flags+=("--namespace=") + two_word_flags+=("-n") + + must_have_one_flag=() + must_have_one_noun=() + noun_aliases=() +} + +_istioctl_dashboard_prometheus() +{ + last_command="istioctl_dashboard_prometheus" + + command_aliases=() + + commands=() + + flags=() + two_word_flags=() + local_nonpersistent_flags=() + flags_with_completion=() + flags_completion=() + + flags+=("--context=") + flags+=("--istioNamespace=") + two_word_flags+=("-i") + flags+=("--kubeconfig=") + two_word_flags+=("-c") + flags+=("--log_output_level=") + flags+=("--namespace=") + two_word_flags+=("-n") + + must_have_one_flag=() + must_have_one_noun=() + noun_aliases=() +} + +_istioctl_dashboard_zipkin() +{ + last_command="istioctl_dashboard_zipkin" + + command_aliases=() + + commands=() + + flags=() + two_word_flags=() + local_nonpersistent_flags=() + flags_with_completion=() + flags_completion=() + + flags+=("--context=") + flags+=("--istioNamespace=") + two_word_flags+=("-i") + flags+=("--kubeconfig=") + two_word_flags+=("-c") + flags+=("--log_output_level=") + flags+=("--namespace=") + two_word_flags+=("-n") + + must_have_one_flag=() + must_have_one_noun=() + noun_aliases=() +} + +_istioctl_dashboard() +{ + last_command="istioctl_dashboard" + + command_aliases=() + + commands=() + commands+=("controlz") + commands+=("envoy") + commands+=("grafana") + commands+=("jaeger") + commands+=("kiali") + commands+=("prometheus") + commands+=("zipkin") + + flags=() + two_word_flags=() + local_nonpersistent_flags=() + flags_with_completion=() + flags_completion=() + + flags+=("--context=") + flags+=("--istioNamespace=") + two_word_flags+=("-i") + flags+=("--kubeconfig=") + two_word_flags+=("-c") + flags+=("--log_output_level=") + flags+=("--namespace=") + two_word_flags+=("-n") + + must_have_one_flag=() + must_have_one_noun=() + noun_aliases=() +} + +_istioctl_deregister() +{ + last_command="istioctl_deregister" + + command_aliases=() + + commands=() + + flags=() + two_word_flags=() + local_nonpersistent_flags=() + flags_with_completion=() + flags_completion=() + + flags+=("--context=") + flags+=("--istioNamespace=") + two_word_flags+=("-i") + flags+=("--kubeconfig=") + two_word_flags+=("-c") + flags+=("--log_output_level=") + flags+=("--namespace=") + two_word_flags+=("-n") + + must_have_one_flag=() + must_have_one_noun=() + noun_aliases=() +} + +_istioctl_experimental_add-to-mesh_external-service() +{ + last_command="istioctl_experimental_add-to-mesh_external-service" + + command_aliases=() + + commands=() + + flags=() + two_word_flags=() + local_nonpersistent_flags=() + flags_with_completion=() + flags_completion=() + + flags+=("--annotations=") + two_word_flags+=("-a") + flags+=("--labels=") + two_word_flags+=("-l") + flags+=("--serviceaccount=") + two_word_flags+=("-s") + flags+=("--context=") + flags+=("--istioNamespace=") + two_word_flags+=("-i") + flags+=("--kubeconfig=") + two_word_flags+=("-c") + flags+=("--log_output_level=") + flags+=("--namespace=") + two_word_flags+=("-n") + + must_have_one_flag=() + must_have_one_noun=() + noun_aliases=() +} + +_istioctl_experimental_add-to-mesh_service() +{ + last_command="istioctl_experimental_add-to-mesh_service" + + command_aliases=() + + commands=() + + flags=() + two_word_flags=() + local_nonpersistent_flags=() + flags_with_completion=() + flags_completion=() + + flags+=("--injectConfigFile=") + flags+=("--injectConfigMapName=") + flags+=("--meshConfigFile=") + flags+=("--meshConfigMapName=") + flags+=("--valuesFile=") + flags+=("--context=") + flags+=("--istioNamespace=") + two_word_flags+=("-i") + flags+=("--kubeconfig=") + two_word_flags+=("-c") + flags+=("--log_output_level=") + flags+=("--namespace=") + two_word_flags+=("-n") + + must_have_one_flag=() + must_have_one_noun=() + noun_aliases=() +} + +_istioctl_experimental_add-to-mesh() +{ + last_command="istioctl_experimental_add-to-mesh" + + command_aliases=() + + commands=() + commands+=("external-service") + commands+=("service") + + flags=() + two_word_flags=() + local_nonpersistent_flags=() + flags_with_completion=() + flags_completion=() + + flags+=("--context=") + flags+=("--istioNamespace=") + two_word_flags+=("-i") + flags+=("--kubeconfig=") + two_word_flags+=("-c") + flags+=("--log_output_level=") + flags+=("--namespace=") + two_word_flags+=("-n") + + must_have_one_flag=() + must_have_one_noun=() + noun_aliases=() +} + +_istioctl_experimental_analyze() +{ + last_command="istioctl_experimental_analyze" + + command_aliases=() + + commands=() + + flags=() + two_word_flags=() + local_nonpersistent_flags=() + flags_with_completion=() + flags_completion=() + + flags+=("--use-kube") + flags+=("-k") + flags+=("--context=") + flags+=("--istioNamespace=") + two_word_flags+=("-i") + flags+=("--kubeconfig=") + two_word_flags+=("-c") + flags+=("--log_output_level=") + flags+=("--namespace=") + two_word_flags+=("-n") + + must_have_one_flag=() + must_have_one_noun=() + noun_aliases=() +} + +_istioctl_experimental_auth_check() +{ + last_command="istioctl_experimental_auth_check" + + command_aliases=() + + commands=() + + flags=() + two_word_flags=() + local_nonpersistent_flags=() + flags_with_completion=() + flags_completion=() + + flags+=("--all") + flags+=("-a") + flags+=("--file=") + two_word_flags+=("-f") + flags+=("--context=") + flags+=("--istioNamespace=") + two_word_flags+=("-i") + flags+=("--kubeconfig=") + two_word_flags+=("-c") + flags+=("--log_output_level=") + flags+=("--namespace=") + two_word_flags+=("-n") + + must_have_one_flag=() + must_have_one_noun=() + noun_aliases=() +} + +_istioctl_experimental_auth_validate() +{ + last_command="istioctl_experimental_auth_validate" + + command_aliases=() + + commands=() + + flags=() + two_word_flags=() + local_nonpersistent_flags=() + flags_with_completion=() + flags_completion=() + + flags+=("--file=") + two_word_flags+=("-f") + flags+=("--context=") + flags+=("--istioNamespace=") + two_word_flags+=("-i") + flags+=("--kubeconfig=") + two_word_flags+=("-c") + flags+=("--log_output_level=") + flags+=("--namespace=") + two_word_flags+=("-n") + + must_have_one_flag=() + must_have_one_noun=() + noun_aliases=() +} + +_istioctl_experimental_auth() +{ + last_command="istioctl_experimental_auth" + + command_aliases=() + + commands=() + commands+=("check") + commands+=("validate") + + flags=() + two_word_flags=() + local_nonpersistent_flags=() + flags_with_completion=() + flags_completion=() + + flags+=("--context=") + flags+=("--istioNamespace=") + two_word_flags+=("-i") + flags+=("--kubeconfig=") + two_word_flags+=("-c") + flags+=("--log_output_level=") + flags+=("--namespace=") + two_word_flags+=("-n") + + must_have_one_flag=() + must_have_one_noun=() + noun_aliases=() +} + +_istioctl_experimental_convert-ingress() +{ + last_command="istioctl_experimental_convert-ingress" + + command_aliases=() + + commands=() + + flags=() + two_word_flags=() + local_nonpersistent_flags=() + flags_with_completion=() + flags_completion=() + + flags+=("--context=") + flags+=("--istioNamespace=") + two_word_flags+=("-i") + flags+=("--kubeconfig=") + two_word_flags+=("-c") + flags+=("--log_output_level=") + flags+=("--namespace=") + two_word_flags+=("-n") + + must_have_one_flag=() + must_have_one_noun=() + noun_aliases=() +} + +_istioctl_experimental_dashboard() +{ + last_command="istioctl_experimental_dashboard" + + command_aliases=() + + commands=() + + flags=() + two_word_flags=() + local_nonpersistent_flags=() + flags_with_completion=() + flags_completion=() + + flags+=("--context=") + flags+=("--istioNamespace=") + two_word_flags+=("-i") + flags+=("--kubeconfig=") + two_word_flags+=("-c") + flags+=("--log_output_level=") + flags+=("--namespace=") + two_word_flags+=("-n") + + must_have_one_flag=() + must_have_one_noun=() + noun_aliases=() +} + +_istioctl_experimental_describe_pod() +{ + last_command="istioctl_experimental_describe_pod" + + command_aliases=() + + commands=() + + flags=() + two_word_flags=() + local_nonpersistent_flags=() + flags_with_completion=() + flags_completion=() + + flags+=("--ignoreUnmeshed") + flags+=("--context=") + flags+=("--istioNamespace=") + two_word_flags+=("-i") + flags+=("--kubeconfig=") + two_word_flags+=("-c") + flags+=("--log_output_level=") + flags+=("--namespace=") + two_word_flags+=("-n") + + must_have_one_flag=() + must_have_one_noun=() + noun_aliases=() +} + +_istioctl_experimental_describe() +{ + last_command="istioctl_experimental_describe" + + command_aliases=() + + commands=() + commands+=("pod") + + flags=() + two_word_flags=() + local_nonpersistent_flags=() + flags_with_completion=() + flags_completion=() + + flags+=("--context=") + flags+=("--istioNamespace=") + two_word_flags+=("-i") + flags+=("--kubeconfig=") + two_word_flags+=("-c") + flags+=("--log_output_level=") + flags+=("--namespace=") + two_word_flags+=("-n") + + must_have_one_flag=() + must_have_one_noun=() + noun_aliases=() +} + +_istioctl_experimental_kube-uninject() +{ + last_command="istioctl_experimental_kube-uninject" + + command_aliases=() + + commands=() + + flags=() + two_word_flags=() + local_nonpersistent_flags=() + flags_with_completion=() + flags_completion=() + + flags+=("--filename=") + two_word_flags+=("-f") + flags+=("--output=") + two_word_flags+=("-o") + flags+=("--context=") + flags+=("--istioNamespace=") + two_word_flags+=("-i") + flags+=("--kubeconfig=") + two_word_flags+=("-c") + flags+=("--log_output_level=") + flags+=("--namespace=") + two_word_flags+=("-n") + + must_have_one_flag=() + must_have_one_noun=() + noun_aliases=() +} + +_istioctl_experimental_manifest_apply() +{ + last_command="istioctl_experimental_manifest_apply" + + command_aliases=() + + commands=() + + flags=() + two_word_flags=() + local_nonpersistent_flags=() + flags_with_completion=() + flags_completion=() + + flags+=("--filename=") + two_word_flags+=("-f") + flags+=("--readiness-timeout=") + flags+=("--set=") + two_word_flags+=("-s") + flags+=("--wait") + flags+=("-w") + flags+=("--yes") + flags+=("-y") + flags+=("--context=") + flags+=("--dry-run") + flags+=("--istioNamespace=") + two_word_flags+=("-i") + flags+=("--kubeconfig=") + two_word_flags+=("-c") + flags+=("--log_output_level=") + flags+=("--logtostderr") + flags+=("--namespace=") + two_word_flags+=("-n") + flags+=("--verbose") + + must_have_one_flag=() + must_have_one_noun=() + noun_aliases=() +} + +_istioctl_experimental_manifest_diff() +{ + last_command="istioctl_experimental_manifest_diff" + + command_aliases=() + + commands=() + + flags=() + two_word_flags=() + local_nonpersistent_flags=() + flags_with_completion=() + flags_completion=() + + flags+=("--directory") + flags+=("-r") + flags+=("--ignore=") + flags+=("--select=") + flags+=("--context=") + flags+=("--dry-run") + flags+=("--istioNamespace=") + two_word_flags+=("-i") + flags+=("--kubeconfig=") + two_word_flags+=("-c") + flags+=("--log_output_level=") + flags+=("--logtostderr") + flags+=("--namespace=") + two_word_flags+=("-n") + flags+=("--verbose") + + must_have_one_flag=() + must_have_one_noun=() + noun_aliases=() +} + +_istioctl_experimental_manifest_generate() +{ + last_command="istioctl_experimental_manifest_generate" + + command_aliases=() + + commands=() + + flags=() + two_word_flags=() + local_nonpersistent_flags=() + flags_with_completion=() + flags_completion=() + + flags+=("--filename=") + two_word_flags+=("-f") + flags+=("--output=") + two_word_flags+=("-o") + flags+=("--set=") + two_word_flags+=("-s") + flags+=("--context=") + flags+=("--dry-run") + flags+=("--istioNamespace=") + two_word_flags+=("-i") + flags+=("--kubeconfig=") + two_word_flags+=("-c") + flags+=("--log_output_level=") + flags+=("--logtostderr") + flags+=("--namespace=") + two_word_flags+=("-n") + flags+=("--verbose") + + must_have_one_flag=() + must_have_one_noun=() + noun_aliases=() +} + +_istioctl_experimental_manifest_migrate() +{ + last_command="istioctl_experimental_manifest_migrate" + + command_aliases=() + + commands=() + + flags=() + two_word_flags=() + local_nonpersistent_flags=() + flags_with_completion=() + flags_completion=() + + flags+=("--context=") + flags+=("--dry-run") + flags+=("--istioNamespace=") + two_word_flags+=("-i") + flags+=("--kubeconfig=") + two_word_flags+=("-c") + flags+=("--log_output_level=") + flags+=("--logtostderr") + flags+=("--namespace=") + two_word_flags+=("-n") + flags+=("--verbose") + + must_have_one_flag=() + must_have_one_noun=() + noun_aliases=() +} + +_istioctl_experimental_manifest_versions() +{ + last_command="istioctl_experimental_manifest_versions" + + command_aliases=() + + commands=() + + flags=() + two_word_flags=() + local_nonpersistent_flags=() + flags_with_completion=() + flags_completion=() + + flags+=("--versionsURI=") + two_word_flags+=("-u") + flags+=("--context=") + flags+=("--dry-run") + flags+=("--istioNamespace=") + two_word_flags+=("-i") + flags+=("--kubeconfig=") + two_word_flags+=("-c") + flags+=("--log_output_level=") + flags+=("--logtostderr") + flags+=("--namespace=") + two_word_flags+=("-n") + flags+=("--verbose") + + must_have_one_flag=() + must_have_one_noun=() + noun_aliases=() +} + +_istioctl_experimental_manifest() +{ + last_command="istioctl_experimental_manifest" + + command_aliases=() + + commands=() + commands+=("apply") + commands+=("diff") + commands+=("generate") + commands+=("migrate") + commands+=("versions") + + flags=() + two_word_flags=() + local_nonpersistent_flags=() + flags_with_completion=() + flags_completion=() + + flags+=("--dry-run") + flags+=("--logtostderr") + flags+=("--verbose") + flags+=("--context=") + flags+=("--istioNamespace=") + two_word_flags+=("-i") + flags+=("--kubeconfig=") + two_word_flags+=("-c") + flags+=("--log_output_level=") + flags+=("--namespace=") + two_word_flags+=("-n") + + must_have_one_flag=() + must_have_one_noun=() + noun_aliases=() +} + +_istioctl_experimental_metrics() +{ + last_command="istioctl_experimental_metrics" + + command_aliases=() + + commands=() + + flags=() + two_word_flags=() + local_nonpersistent_flags=() + flags_with_completion=() + flags_completion=() + + flags+=("--context=") + flags+=("--istioNamespace=") + two_word_flags+=("-i") + flags+=("--kubeconfig=") + two_word_flags+=("-c") + flags+=("--log_output_level=") + flags+=("--namespace=") + two_word_flags+=("-n") + + must_have_one_flag=() + must_have_one_noun=() + noun_aliases=() +} + +_istioctl_experimental_profile_diff() +{ + last_command="istioctl_experimental_profile_diff" + + command_aliases=() + + commands=() + + flags=() + two_word_flags=() + local_nonpersistent_flags=() + flags_with_completion=() + flags_completion=() + + flags+=("--context=") + flags+=("--dry-run") + flags+=("--istioNamespace=") + two_word_flags+=("-i") + flags+=("--kubeconfig=") + two_word_flags+=("-c") + flags+=("--log_output_level=") + flags+=("--logtostderr") + flags+=("--namespace=") + two_word_flags+=("-n") + flags+=("--verbose") + + must_have_one_flag=() + must_have_one_noun=() + noun_aliases=() +} + +_istioctl_experimental_profile_dump() +{ + last_command="istioctl_experimental_profile_dump" + + command_aliases=() + + commands=() + + flags=() + two_word_flags=() + local_nonpersistent_flags=() + flags_with_completion=() + flags_completion=() + + flags+=("--config-path=") + two_word_flags+=("-p") + flags+=("--filename=") + two_word_flags+=("-f") + flags+=("--helm-values") + flags+=("--context=") + flags+=("--dry-run") + flags+=("--istioNamespace=") + two_word_flags+=("-i") + flags+=("--kubeconfig=") + two_word_flags+=("-c") + flags+=("--log_output_level=") + flags+=("--logtostderr") + flags+=("--namespace=") + two_word_flags+=("-n") + flags+=("--verbose") + + must_have_one_flag=() + must_have_one_noun=() + noun_aliases=() +} + +_istioctl_experimental_profile_list() +{ + last_command="istioctl_experimental_profile_list" + + command_aliases=() + + commands=() + + flags=() + two_word_flags=() + local_nonpersistent_flags=() + flags_with_completion=() + flags_completion=() + + flags+=("--context=") + flags+=("--dry-run") + flags+=("--istioNamespace=") + two_word_flags+=("-i") + flags+=("--kubeconfig=") + two_word_flags+=("-c") + flags+=("--log_output_level=") + flags+=("--logtostderr") + flags+=("--namespace=") + two_word_flags+=("-n") + flags+=("--verbose") + + must_have_one_flag=() + must_have_one_noun=() + noun_aliases=() +} + +_istioctl_experimental_profile() +{ + last_command="istioctl_experimental_profile" + + command_aliases=() + + commands=() + commands+=("diff") + commands+=("dump") + commands+=("list") + + flags=() + two_word_flags=() + local_nonpersistent_flags=() + flags_with_completion=() + flags_completion=() + + flags+=("--dry-run") + flags+=("--logtostderr") + flags+=("--verbose") + flags+=("--context=") + flags+=("--istioNamespace=") + two_word_flags+=("-i") + flags+=("--kubeconfig=") + two_word_flags+=("-c") + flags+=("--log_output_level=") + flags+=("--namespace=") + two_word_flags+=("-n") + + must_have_one_flag=() + must_have_one_noun=() + noun_aliases=() +} + +_istioctl_experimental_remove-from-mesh_external-service() +{ + last_command="istioctl_experimental_remove-from-mesh_external-service" + + command_aliases=() + + commands=() + + flags=() + two_word_flags=() + local_nonpersistent_flags=() + flags_with_completion=() + flags_completion=() + + flags+=("--context=") + flags+=("--istioNamespace=") + two_word_flags+=("-i") + flags+=("--kubeconfig=") + two_word_flags+=("-c") + flags+=("--log_output_level=") + flags+=("--namespace=") + two_word_flags+=("-n") + + must_have_one_flag=() + must_have_one_noun=() + noun_aliases=() +} + +_istioctl_experimental_remove-from-mesh_service() +{ + last_command="istioctl_experimental_remove-from-mesh_service" + + command_aliases=() + + commands=() + + flags=() + two_word_flags=() + local_nonpersistent_flags=() + flags_with_completion=() + flags_completion=() + + flags+=("--context=") + flags+=("--istioNamespace=") + two_word_flags+=("-i") + flags+=("--kubeconfig=") + two_word_flags+=("-c") + flags+=("--log_output_level=") + flags+=("--namespace=") + two_word_flags+=("-n") + + must_have_one_flag=() + must_have_one_noun=() + noun_aliases=() +} + +_istioctl_experimental_remove-from-mesh() +{ + last_command="istioctl_experimental_remove-from-mesh" + + command_aliases=() + + commands=() + commands+=("external-service") + commands+=("service") + + flags=() + two_word_flags=() + local_nonpersistent_flags=() + flags_with_completion=() + flags_completion=() + + flags+=("--context=") + flags+=("--istioNamespace=") + two_word_flags+=("-i") + flags+=("--kubeconfig=") + two_word_flags+=("-c") + flags+=("--log_output_level=") + flags+=("--namespace=") + two_word_flags+=("-n") + + must_have_one_flag=() + must_have_one_noun=() + noun_aliases=() +} + +_istioctl_experimental() +{ + last_command="istioctl_experimental" + + command_aliases=() + + commands=() + commands+=("add-to-mesh") + if [[ -z "${BASH_VERSION}" || "${BASH_VERSINFO[0]}" -gt 3 ]]; then + command_aliases+=("add") + aliashash["add"]="add-to-mesh" + fi + commands+=("analyze") + commands+=("auth") + commands+=("convert-ingress") + commands+=("dashboard") + commands+=("describe") + if [[ -z "${BASH_VERSION}" || "${BASH_VERSINFO[0]}" -gt 3 ]]; then + command_aliases+=("des") + aliashash["des"]="describe" + fi + commands+=("kube-uninject") + commands+=("manifest") + commands+=("metrics") + if [[ -z "${BASH_VERSION}" || "${BASH_VERSINFO[0]}" -gt 3 ]]; then + command_aliases+=("m") + aliashash["m"]="metrics" + fi + commands+=("profile") + commands+=("remove-from-mesh") + if [[ -z "${BASH_VERSION}" || "${BASH_VERSINFO[0]}" -gt 3 ]]; then + command_aliases+=("remove") + aliashash["remove"]="remove-from-mesh" + fi + + flags=() + two_word_flags=() + local_nonpersistent_flags=() + flags_with_completion=() + flags_completion=() + + flags+=("--context=") + flags+=("--istioNamespace=") + two_word_flags+=("-i") + flags+=("--kubeconfig=") + two_word_flags+=("-c") + flags+=("--log_output_level=") + flags+=("--namespace=") + two_word_flags+=("-n") + + must_have_one_flag=() + must_have_one_noun=() + noun_aliases=() +} + +_istioctl_kube-inject() +{ + last_command="istioctl_kube-inject" + + command_aliases=() + + commands=() + + flags=() + two_word_flags=() + local_nonpersistent_flags=() + flags_with_completion=() + flags_completion=() + + flags+=("--filename=") + two_word_flags+=("-f") + flags+=("--injectConfigFile=") + flags+=("--injectConfigMapName=") + flags+=("--meshConfigFile=") + flags+=("--meshConfigMapName=") + flags+=("--output=") + two_word_flags+=("-o") + flags+=("--valuesFile=") + flags+=("--context=") + flags+=("--istioNamespace=") + two_word_flags+=("-i") + flags+=("--kubeconfig=") + two_word_flags+=("-c") + flags+=("--log_output_level=") + flags+=("--namespace=") + two_word_flags+=("-n") + + must_have_one_flag=() + must_have_one_noun=() + noun_aliases=() +} + +_istioctl_proxy-config_bootstrap() +{ + last_command="istioctl_proxy-config_bootstrap" + + command_aliases=() + + commands=() + + flags=() + two_word_flags=() + local_nonpersistent_flags=() + flags_with_completion=() + flags_completion=() + + flags+=("--context=") + flags+=("--istioNamespace=") + two_word_flags+=("-i") + flags+=("--kubeconfig=") + two_word_flags+=("-c") + flags+=("--log_output_level=") + flags+=("--namespace=") + two_word_flags+=("-n") + flags+=("--output=") + two_word_flags+=("-o") + + must_have_one_flag=() + must_have_one_noun=() + noun_aliases=() +} + +_istioctl_proxy-config_cluster() +{ + last_command="istioctl_proxy-config_cluster" + + command_aliases=() + + commands=() + + flags=() + two_word_flags=() + local_nonpersistent_flags=() + flags_with_completion=() + flags_completion=() + + flags+=("--direction=") + flags+=("--fqdn=") + flags+=("--port=") + flags+=("--subset=") + flags+=("--context=") + flags+=("--istioNamespace=") + two_word_flags+=("-i") + flags+=("--kubeconfig=") + two_word_flags+=("-c") + flags+=("--log_output_level=") + flags+=("--namespace=") + two_word_flags+=("-n") + flags+=("--output=") + two_word_flags+=("-o") + + must_have_one_flag=() + must_have_one_noun=() + noun_aliases=() +} + +_istioctl_proxy-config_endpoint() +{ + last_command="istioctl_proxy-config_endpoint" + + command_aliases=() + + commands=() + + flags=() + two_word_flags=() + local_nonpersistent_flags=() + flags_with_completion=() + flags_completion=() + + flags+=("--address=") + flags+=("--cluster=") + flags+=("--port=") + flags+=("--status=") + flags+=("--context=") + flags+=("--istioNamespace=") + two_word_flags+=("-i") + flags+=("--kubeconfig=") + two_word_flags+=("-c") + flags+=("--log_output_level=") + flags+=("--namespace=") + two_word_flags+=("-n") + flags+=("--output=") + two_word_flags+=("-o") + + must_have_one_flag=() + must_have_one_noun=() + noun_aliases=() +} + +_istioctl_proxy-config_listener() +{ + last_command="istioctl_proxy-config_listener" + + command_aliases=() + + commands=() + + flags=() + two_word_flags=() + local_nonpersistent_flags=() + flags_with_completion=() + flags_completion=() + + flags+=("--address=") + flags+=("--port=") + flags+=("--type=") + flags+=("--context=") + flags+=("--istioNamespace=") + two_word_flags+=("-i") + flags+=("--kubeconfig=") + two_word_flags+=("-c") + flags+=("--log_output_level=") + flags+=("--namespace=") + two_word_flags+=("-n") + flags+=("--output=") + two_word_flags+=("-o") + + must_have_one_flag=() + must_have_one_noun=() + noun_aliases=() +} + +_istioctl_proxy-config_route() +{ + last_command="istioctl_proxy-config_route" + + command_aliases=() + + commands=() + + flags=() + two_word_flags=() + local_nonpersistent_flags=() + flags_with_completion=() + flags_completion=() + + flags+=("--name=") + flags+=("--context=") + flags+=("--istioNamespace=") + two_word_flags+=("-i") + flags+=("--kubeconfig=") + two_word_flags+=("-c") + flags+=("--log_output_level=") + flags+=("--namespace=") + two_word_flags+=("-n") + flags+=("--output=") + two_word_flags+=("-o") + + must_have_one_flag=() + must_have_one_noun=() + noun_aliases=() +} + +_istioctl_proxy-config() +{ + last_command="istioctl_proxy-config" + + command_aliases=() + + commands=() + commands+=("bootstrap") + if [[ -z "${BASH_VERSION}" || "${BASH_VERSINFO[0]}" -gt 3 ]]; then + command_aliases+=("b") + aliashash["b"]="bootstrap" + fi + commands+=("cluster") + if [[ -z "${BASH_VERSION}" || "${BASH_VERSINFO[0]}" -gt 3 ]]; then + command_aliases+=("c") + aliashash["c"]="cluster" + command_aliases+=("clusters") + aliashash["clusters"]="cluster" + fi + commands+=("endpoint") + if [[ -z "${BASH_VERSION}" || "${BASH_VERSINFO[0]}" -gt 3 ]]; then + command_aliases+=("endpoints") + aliashash["endpoints"]="endpoint" + command_aliases+=("ep") + aliashash["ep"]="endpoint" + fi + commands+=("listener") + if [[ -z "${BASH_VERSION}" || "${BASH_VERSINFO[0]}" -gt 3 ]]; then + command_aliases+=("l") + aliashash["l"]="listener" + command_aliases+=("listeners") + aliashash["listeners"]="listener" + fi + commands+=("route") + if [[ -z "${BASH_VERSION}" || "${BASH_VERSINFO[0]}" -gt 3 ]]; then + command_aliases+=("r") + aliashash["r"]="route" + command_aliases+=("routes") + aliashash["routes"]="route" + fi + + flags=() + two_word_flags=() + local_nonpersistent_flags=() + flags_with_completion=() + flags_completion=() + + flags+=("--output=") + two_word_flags+=("-o") + flags+=("--context=") + flags+=("--istioNamespace=") + two_word_flags+=("-i") + flags+=("--kubeconfig=") + two_word_flags+=("-c") + flags+=("--log_output_level=") + flags+=("--namespace=") + two_word_flags+=("-n") + + must_have_one_flag=() + must_have_one_noun=() + noun_aliases=() +} + +_istioctl_proxy-status() +{ + last_command="istioctl_proxy-status" + + command_aliases=() + + commands=() + + flags=() + two_word_flags=() + local_nonpersistent_flags=() + flags_with_completion=() + flags_completion=() + + flags+=("--context=") + flags+=("--istioNamespace=") + two_word_flags+=("-i") + flags+=("--kubeconfig=") + two_word_flags+=("-c") + flags+=("--log_output_level=") + flags+=("--namespace=") + two_word_flags+=("-n") + + must_have_one_flag=() + must_have_one_noun=() + noun_aliases=() +} + +_istioctl_register() +{ + last_command="istioctl_register" + + command_aliases=() + + commands=() + + flags=() + two_word_flags=() + local_nonpersistent_flags=() + flags_with_completion=() + flags_completion=() + + flags+=("--annotations=") + two_word_flags+=("-a") + flags+=("--labels=") + two_word_flags+=("-l") + flags+=("--serviceaccount=") + two_word_flags+=("-s") + flags+=("--context=") + flags+=("--istioNamespace=") + two_word_flags+=("-i") + flags+=("--kubeconfig=") + two_word_flags+=("-c") + flags+=("--log_output_level=") + flags+=("--namespace=") + two_word_flags+=("-n") + + must_have_one_flag=() + must_have_one_noun=() + noun_aliases=() +} + +_istioctl_validate() +{ + last_command="istioctl_validate" + + command_aliases=() + + commands=() + + flags=() + two_word_flags=() + local_nonpersistent_flags=() + flags_with_completion=() + flags_completion=() + + flags+=("--filename=") + two_word_flags+=("-f") + flags+=("--referential") + flags+=("-x") + flags+=("--context=") + flags+=("--istioNamespace=") + two_word_flags+=("-i") + flags+=("--kubeconfig=") + two_word_flags+=("-c") + flags+=("--log_output_level=") + flags+=("--namespace=") + two_word_flags+=("-n") + + must_have_one_flag=() + must_have_one_noun=() + noun_aliases=() +} + +_istioctl_verify-install() +{ + last_command="istioctl_verify-install" + + command_aliases=() + + commands=() + + flags=() + two_word_flags=() + local_nonpersistent_flags=() + flags_with_completion=() + flags_completion=() + + flags+=("--enableVerbose") + local_nonpersistent_flags+=("--enableVerbose") + flags+=("--filename=") + flags_with_completion+=("--filename") + flags_completion+=("__istioctl_handle_filename_extension_flag json|yaml|yml") + two_word_flags+=("-f") + flags_with_completion+=("-f") + flags_completion+=("__istioctl_handle_filename_extension_flag json|yaml|yml") + flags+=("--recursive") + flags+=("-R") + flags+=("--context=") + flags+=("--istioNamespace=") + two_word_flags+=("-i") + flags+=("--kubeconfig=") + two_word_flags+=("-c") + flags+=("--log_output_level=") + flags+=("--namespace=") + two_word_flags+=("-n") + + must_have_one_flag=() + must_have_one_noun=() + noun_aliases=() +} + +_istioctl_version() +{ + last_command="istioctl_version" + + command_aliases=() + + commands=() + + flags=() + two_word_flags=() + local_nonpersistent_flags=() + flags_with_completion=() + flags_completion=() + + flags+=("--output=") + two_word_flags+=("-o") + local_nonpersistent_flags+=("--output=") + flags+=("--remote") + local_nonpersistent_flags+=("--remote") + flags+=("--short") + flags+=("-s") + local_nonpersistent_flags+=("--short") + flags+=("--context=") + flags+=("--istioNamespace=") + two_word_flags+=("-i") + flags+=("--kubeconfig=") + two_word_flags+=("-c") + flags+=("--log_output_level=") + flags+=("--namespace=") + two_word_flags+=("-n") + + must_have_one_flag=() + must_have_one_noun=() + noun_aliases=() +} + +_istioctl_root_command() +{ + last_command="istioctl" + + command_aliases=() + + commands=() + commands+=("auth") + commands+=("authn") + commands+=("convert-ingress") + commands+=("dashboard") + if [[ -z "${BASH_VERSION}" || "${BASH_VERSINFO[0]}" -gt 3 ]]; then + command_aliases+=("d") + aliashash["d"]="dashboard" + command_aliases+=("dash") + aliashash["dash"]="dashboard" + fi + commands+=("deregister") + commands+=("experimental") + if [[ -z "${BASH_VERSION}" || "${BASH_VERSINFO[0]}" -gt 3 ]]; then + command_aliases+=("exp") + aliashash["exp"]="experimental" + command_aliases+=("x") + aliashash["x"]="experimental" + fi + commands+=("kube-inject") + commands+=("proxy-config") + if [[ -z "${BASH_VERSION}" || "${BASH_VERSINFO[0]}" -gt 3 ]]; then + command_aliases+=("pc") + aliashash["pc"]="proxy-config" + fi + commands+=("proxy-status") + if [[ -z "${BASH_VERSION}" || "${BASH_VERSINFO[0]}" -gt 3 ]]; then + command_aliases+=("ps") + aliashash["ps"]="proxy-status" + fi + commands+=("register") + commands+=("validate") + commands+=("verify-install") + commands+=("version") + + flags=() + two_word_flags=() + local_nonpersistent_flags=() + flags_with_completion=() + flags_completion=() + + flags+=("--context=") + flags+=("--istioNamespace=") + two_word_flags+=("-i") + flags+=("--kubeconfig=") + two_word_flags+=("-c") + flags+=("--log_output_level=") + flags+=("--namespace=") + two_word_flags+=("-n") + + must_have_one_flag=() + must_have_one_noun=() + noun_aliases=() +} + +__start_istioctl() +{ + local cur prev words cword + declare -A flaghash 2>/dev/null || : + declare -A aliashash 2>/dev/null || : + if declare -F _init_completion >/dev/null 2>&1; then + _init_completion -s || return + else + __istioctl_init_completion -n "=" || return + fi + + local c=0 + local flags=() + local two_word_flags=() + local local_nonpersistent_flags=() + local flags_with_completion=() + local flags_completion=() + local commands=("istioctl") + local must_have_one_flag=() + local must_have_one_noun=() + local last_command + local nouns=() + + __istioctl_handle_word +} + +if [[ $(type -t compopt) = "builtin" ]]; then + complete -o default -F __start_istioctl istioctl +else + complete -o default -o nospace -F __start_istioctl istioctl +fi + +# ex: ts=4 sw=4 et filetype=sh + +BASH_COMPLETION_EOF +} + +__istio_bash_source <(__istio_convert_bash_to_zsh) +_complete istio 2>/dev/null diff --git a/istio-1.3.5/tools/cache_buster.yaml b/istio-1.3.5/tools/cache_buster.yaml new file mode 100644 index 0000000..7ed8e32 --- /dev/null +++ b/istio-1.3.5/tools/cache_buster.yaml @@ -0,0 +1,31 @@ +apiVersion: "config.istio.io/v1alpha2" +kind: denier +metadata: + name: denyall +spec: + status: + code: 7 + message: Not allowed +--- +apiVersion: "config.istio.io/v1alpha2" +kind: checknothing +metadata: + name: denyrequest +spec: +--- +apiVersion: "config.istio.io/v1alpha2" +kind: rule +metadata: + name: mixercachebuster +spec: + # one direction 1->2 will use the cache, while 2->1 will not use the cache. + # TODO: parametrize the namespace of find a way to get short names to work: + # TODO: this appears to always bust the cache, even if dest is echosrv1 ! + match: destination.service == "echosrv1.istio.svc.cluster.local" && request.headers["x-request-id"] == "foo" + # test that denial does work + # match: destination.service == "echosrv1.istio.svc.cluster.local" && request.headers["x-forwarded-proto"] == "http" && source.service == "echosrv2.istio.svc.cluster.local" + actions: + # handler and instance names default to the rule's namespace. + - handler: denyall.denier + instances: + - denyrequest.checknothing diff --git a/istio-1.3.5/tools/checker/README.md b/istio-1.3.5/tools/checker/README.md new file mode 100644 index 0000000..4fd23ae --- /dev/null +++ b/istio-1.3.5/tools/checker/README.md @@ -0,0 +1,102 @@ +# Checker + +[Checker](checker.go) is an extensible go-file analyzer. It processes source codes in the following steps: +* Take a list of directory paths and recursively scan for go files +* Build abstract syntax trees for the relevant go files +* Apply Rule-based analysis +* Generate a report + +The design is pluggable, as different applications can implement different [Rule](rule.go)s for different analytic +requirements. + + +### Check + +The Check() function is the main entry point, which takes a list of file path (if empty, current directory is implied), +a RulesFactory, a [Whitelist](whitelist.go) , and a Report. + +The [RulesFactory](rule.go) and the [Whitelist](whitelist.go) are extension points which allow the caller (i.e. +application) to configure what [Rule](rule.go)s should apply to what files. + +```bash +func Check(paths []string, factory RulesFactory, whitelist *Whitelist, report *Report) error +``` + + +### Rule + +Application implements the [Rule](rule.go) interface, and provides the actual logic to produce diagnostic information, +using an abstract syntax tree built from a go file. Each [Rule](rule.go) is expected to run one specific check +(potentially using information from external systems) against the given syntax tree, and multiple [Rule](rule.go)s can +be implemented for different checks against the same tree (i.e. go file). This allows custom semantic analysis. + +```bash +type Rule interface { + // GetID returns ID of the rule in string + GetID() string + // Check conditions using the given node and produce report if needed. + Check(aNode ast.Node, fs *token.FileSet, lrp *Report) +} +``` + + +### RulesFactory + +Application implements the [RulesFactory](rule.go) interface to provide a mapping from file paths to their +corresponding rules. This allows fine grained control over what [Rule](rule.go)s should apply to what files. For +example, “_test.go” files can use a different set of rules from regular go files, or “mixer” files can have different +rules from “pilot” files. + +```bash +type RulesFactory interface { + // GetRules returns a list of rules used to check against the files. + GetRules(absp string, info os.FileInfo) []Rule +} +``` + + +### Whitelist + +In addition to [RulesFactory](rule.go), application can provide a [Whitelist](whitelist.go) to opt out selected files +from certain rules. This allows temporary rule disablement until the file is updated to comply with the rules, or an +exception mechanism to allow approved files break some rules. + +A [Whitelist](whitelist.go) object is backed by a map from string to a string slice, where the keys are file paths, and +the values are slices of rule IDs, as identified by return value of the GetID() method, in the [Rule](rule.go) +interface. + +```bash +func NewWhitelist(ruleWhitelist map[string][]string) *Whitelist { + return Whitelist{ruleWhitelist: ruleWhitelist} +} +``` + + +### Report + +[Report](report.go) is a utility used to accumulate rule diagnostic information for final consumption. When a +[Rule](rule.go) runs a check, it can add information to the [Report](report.go) using the AddItem() function to provide +file location information, and a diagnostic message. + +After all checks are done, the Items() function can be used to retrieve the formatted text based report as a string +slice. + +```bash +func (lr *Report) AddItem(pos token.Position, is string, msg string) + +func (lt *Report) Items() []string +``` + + +## Example Use Cases + +* The [Checker](checker.go) can go through all Test* functions in _test.go files, and create a warning if a test is + being skipped without having a github issue assigned (i.e. in the testing.T.skip() message). This allows us to + properly track all skipped tests, and make sure they are restored when the underlying issues are fixed. + +* The [Checker](checker.go) can go through all _test.go files and validate if the test is being run in CI. It can then + find all the dead tests for developers to either remove, or to hook them back up in the automatic tests. + +Information like these are valuable but are currently opaque to us (even codecov report cannot reveal these). The +extensible [Checker](checker.go) design opens up opportunities to add more code analysis, so we have better insight +into the Istio code base and maintain better code health. diff --git a/istio-1.3.5/tools/checker/checker.go b/istio-1.3.5/tools/checker/checker.go new file mode 100644 index 0000000..dd54d5c --- /dev/null +++ b/istio-1.3.5/tools/checker/checker.go @@ -0,0 +1,106 @@ +// Copyright 2018 Istio Authors. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package checker + +import ( + "fmt" + "go/ast" + "go/parser" + "go/token" + "os" + "path/filepath" + "strings" +) + +var ( + // IgnoreTestLinterData skips over unit tests + IgnoreTestLinterData = true +) + +// Check checks the list of files, and write to the given Report. +func Check(paths []string, factory RulesFactory, whitelist *Whitelist, report *Report) error { + // Empty paths means current dir. + if len(paths) == 0 { + paths = []string{"."} + } + + for _, path := range paths { + if !filepath.IsAbs(path) { + path, _ = filepath.Abs(path) + } + err := filepath.Walk(path, func(fpath string, info os.FileInfo, err error) error { + if err != nil { + return fmt.Errorf("pervent panic by handling failure accessing a path %q: %v", fpath, err) + } + rules := factory.GetRules(fpath, info) + if len(rules) > 0 { + fileCheck(fpath, rules, whitelist, report) + } + return nil + }) + if err != nil { + return fmt.Errorf("error visiting the path %q: %v", path, err) + } + } + return nil +} + +// fileCheck checks a file using the given rules, and write to the given Report. +func fileCheck(path string, rules []Rule, whitelist *Whitelist, report *Report) { + // TODO: skip over linter tests in a principled manner for all linters + if IgnoreTestLinterData && strings.Contains(path, "testlinter/testdata") { + return + } + + fs := token.NewFileSet() + astFile, err := parser.ParseFile(fs, path, nil, parser.Mode(0)) + if err != nil { + report.AddString(fmt.Sprintf("%v", err)) + return + } + v := FileVisitor{ + path: path, + rules: rules, + whitelist: whitelist, + fileset: fs, + report: report, + } + // Walk through the files + ast.Walk(&v, astFile) +} + +// FileVisitor visits the go file syntax tree and applies the given rules. +type FileVisitor struct { + path string + rules []Rule // rules to check + whitelist *Whitelist // rules to skip + fileset *token.FileSet + report *Report // report for linting process +} + +// Visit checks each node and runs the applicable checks. +func (fv *FileVisitor) Visit(node ast.Node) ast.Visitor { + if node == nil { + return nil + } + + // ApplyRules applies rules to node and generate lint report. + for _, rule := range fv.rules { + if !fv.whitelist.Apply(fv.path, rule) { + rule.Check(node, fv.fileset, fv.report) + } + } + return fv +} diff --git a/istio-1.3.5/tools/checker/envvarlinter/README.md b/istio-1.3.5/tools/checker/envvarlinter/README.md new file mode 100644 index 0000000..7a8b9b9 --- /dev/null +++ b/istio-1.3.5/tools/checker/envvarlinter/README.md @@ -0,0 +1,29 @@ +# envvarlinter + +envvarlinter ensures that non-test files don't use os.Getenv and os.LookupEnv and instead use the functions from pkg/env. + +envvarlinter is based on [Checker](../README.md), and this package provides the [custom rules](rules) implementation. + +# Whitelist + +If, for some reason, you want to disable lint rule for a file, you can add the file path and rule ID in +[whitelist.go](whitelist.go). Rule ID is the name of that rule file without `.go` extension. +You could also specify file path in regex. + +If you want to disable all rules for a file path, you can specify `*` as the ID. + +Example: +```base +var Whitelist = map[string][]string{ + "/istio/mixer/pkg/*": {"skip_issue", "short_skip"}, + "/istio/pilot/pkg/simply_test.go": {"*"}, +} +``` + +# Running testlinter + +There are two ways to run this linter. +```bash +go install +testlinter +``` diff --git a/istio-1.3.5/tools/checker/envvarlinter/envvar_test.go b/istio-1.3.5/tools/checker/envvarlinter/envvar_test.go new file mode 100644 index 0000000..0e385fe --- /dev/null +++ b/istio-1.3.5/tools/checker/envvarlinter/envvar_test.go @@ -0,0 +1,40 @@ +// Copyright 2019 Istio Authors. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package main + +import ( + "path/filepath" + "reflect" + "testing" +) + +func getAbsPath(path string) string { + if !filepath.IsAbs(path) { + path, _ = filepath.Abs(path) + } + return path +} + +func TestNoOSEnvRule(t *testing.T) { + rpts, _ := getReport([]string{"testdata/"}) + expectedRpts := []string{getAbsPath("testdata/envuse.go") + + ":6:6:os.Getenv is disallowed, please see pkg/env instead (no_os_env)", + getAbsPath("testdata/envuse.go") + + ":7:9:os.LookupEnv is disallowed, please see pkg/env instead (no_os_env)"} + + if !reflect.DeepEqual(rpts, expectedRpts) { + t.Errorf("lint reports don't match\nReceived: %v\nExpected: %v", rpts, expectedRpts) + } +} diff --git a/istio-1.3.5/tools/checker/envvarlinter/main.go b/istio-1.3.5/tools/checker/envvarlinter/main.go new file mode 100644 index 0000000..385805e --- /dev/null +++ b/istio-1.3.5/tools/checker/envvarlinter/main.go @@ -0,0 +1,53 @@ +// Copyright 2019 Istio Authors. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package main + +import ( + "flag" + "fmt" + "os" + + "istio.io/istio/tools/checker" +) + +func main() { + flag.Parse() + exitCode := 0 + + items, err := getReport(flag.Args()) + if err != nil { + fmt.Fprintln(os.Stderr, err.Error()) + exitCode = 2 + } else { + for _, r := range items { + fmt.Fprintln(os.Stderr, r) + exitCode = 2 + } + } + + os.Exit(exitCode) +} + +func getReport(args []string) ([]string, error) { + matcher := RulesMatcher{} + whitelist := checker.NewWhitelist(Whitelist) + report := checker.NewLintReport() + + err := checker.Check(args, &matcher, whitelist, report) + if err != nil { + return []string{}, err + } + return report.Items(), nil +} diff --git a/istio-1.3.5/tools/checker/envvarlinter/rules/no_os_env.go b/istio-1.3.5/tools/checker/envvarlinter/rules/no_os_env.go new file mode 100644 index 0000000..49e589d --- /dev/null +++ b/istio-1.3.5/tools/checker/envvarlinter/rules/no_os_env.go @@ -0,0 +1,47 @@ +// Copyright 2019 Istio Authors. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package rules + +import ( + "go/ast" + "go/token" + + "istio.io/istio/tools/checker" +) + +// NoOsEnv flags an error if os.Getenv or os.LookupEnv are used. +type NoOsEnv struct { +} + +// NewNoOsEnv creates and returns a NoOsEnv object. +func NewNoOsEnv() *NoOsEnv { + return &NoOsEnv{} +} + +// GetID returns skip_by_issue_rule. +func (lr *NoOsEnv) GetID() string { + return GetCallerFileName() +} + +// Check verifies there are no calls to os.Getenv or os.LookupEnv +func (lr *NoOsEnv) Check(aNode ast.Node, fs *token.FileSet, lrp *checker.Report) { + if ce, ok := aNode.(*ast.CallExpr); ok { + if MatchCallExpr(ce, "os", "Getenv") { + lrp.AddItem(fs.Position(ce.Pos()), lr.GetID(), "os.Getenv is disallowed, please see pkg/env instead") + } else if MatchCallExpr(ce, "os", "LookupEnv") { + lrp.AddItem(fs.Position(ce.Pos()), lr.GetID(), "os.LookupEnv is disallowed, please see pkg/env instead") + } + } +} diff --git a/istio-1.3.5/tools/checker/envvarlinter/rules/util.go b/istio-1.3.5/tools/checker/envvarlinter/rules/util.go new file mode 100644 index 0000000..aa6c33b --- /dev/null +++ b/istio-1.3.5/tools/checker/envvarlinter/rules/util.go @@ -0,0 +1,47 @@ +// Copyright 2019 Istio Authors. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package rules + +import ( + "go/ast" + "log" + "path/filepath" + "runtime" + "strings" +) + +// GetCallerFileName returns filename of caller without file extension. +func GetCallerFileName() string { + if _, filename, _, ok := runtime.Caller(1); ok { + fnBase := filepath.Base(filename) + fn := strings.Split(fnBase, ".") + if len(fn) > 0 { + return fn[0] + } + } else { + log.Print("Unable to get filename for caller.") + } + return "" +} + +// MatchCallExpr returns true if ce matches package name pn and method name mn. +func MatchCallExpr(ce *ast.CallExpr, pn string, mn string) bool { + if sel, ok := ce.Fun.(*ast.SelectorExpr); ok { + if pkg, ok := sel.X.(*ast.Ident); ok { + return pkg.String() == pn && sel.Sel.String() == mn + } + } + return false +} diff --git a/istio-1.3.5/tools/checker/envvarlinter/rules_matcher.go b/istio-1.3.5/tools/checker/envvarlinter/rules_matcher.go new file mode 100644 index 0000000..e80bdf4 --- /dev/null +++ b/istio-1.3.5/tools/checker/envvarlinter/rules_matcher.go @@ -0,0 +1,40 @@ +// Copyright 2019 Istio Authors. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package main + +import ( + "os" + "strings" + + "istio.io/istio/tools/checker/envvarlinter/rules" + + "istio.io/istio/tools/checker" +) + +// RulesMatcher filters out test files. +type RulesMatcher struct { +} + +// GetRules checks path absp and decides whether absp is a test file. It returns true and test type +// for a test file. If path absp should be skipped, it returns false. +func (rf *RulesMatcher) GetRules(absp string, info os.FileInfo) []checker.Rule { + // Skip path which is a directory, a go test file, or not a go file at all. + paths := strings.Split(absp, "/") + if len(paths) == 0 || info.IsDir() || strings.HasSuffix(absp, "_test.go") || !strings.HasSuffix(absp, ".go") { + return []checker.Rule{} + } + + return []checker.Rule{rules.NewNoOsEnv()} +} diff --git a/istio-1.3.5/tools/checker/envvarlinter/testdata/envuse.go b/istio-1.3.5/tools/checker/envvarlinter/testdata/envuse.go new file mode 100644 index 0000000..ea1e32e --- /dev/null +++ b/istio-1.3.5/tools/checker/envvarlinter/testdata/envuse.go @@ -0,0 +1,8 @@ +package testdata + +import "os" + +func Envuse() { + _ = os.Getenv("DONTDOIT") + _, _ = os.LookupEnv("ANDDONTDOTHISEITHER") +} diff --git a/istio-1.3.5/tools/checker/envvarlinter/whitelist.go b/istio-1.3.5/tools/checker/envvarlinter/whitelist.go new file mode 100644 index 0000000..30778f3 --- /dev/null +++ b/istio-1.3.5/tools/checker/envvarlinter/whitelist.go @@ -0,0 +1,20 @@ +// Copyright 2019 Istio Authors. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package main + +// Whitelist contains pairs of file and rule IDs. Each file maps to an array of rules which +// should not apply to that file. Each rule is represented by its unique rule ID, which is the +// file name of that rule without ".go" extension in the rules package. +var Whitelist = map[string][]string{} diff --git a/istio-1.3.5/tools/checker/report.go b/istio-1.3.5/tools/checker/report.go new file mode 100644 index 0000000..590eaab --- /dev/null +++ b/istio-1.3.5/tools/checker/report.go @@ -0,0 +1,51 @@ +// Copyright 2018 Istio Authors. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package checker + +import ( + "fmt" + "go/token" +) + +// Report populates lint report. +type Report struct { + items []string +} + +// NewLintReport creates and returns a Report object. +func NewLintReport() *Report { + return &Report{} +} + +// Items returns formatted report as a string slice. +func (lr *Report) Items() []string { + return lr.items +} + +// AddItem creates a new lint error report. +func (lr *Report) AddItem(pos token.Position, id string, msg string) { + item := fmt.Sprintf("%v:%v:%v:%s (%s)", + pos.Filename, + pos.Line, + pos.Column, + msg, + id) + lr.AddString(item) +} + +// AddString creates a new string line in report. +func (lr *Report) AddString(msg string) { + lr.items = append(lr.items, msg) +} diff --git a/istio-1.3.5/tools/checker/rule.go b/istio-1.3.5/tools/checker/rule.go new file mode 100644 index 0000000..4291da4 --- /dev/null +++ b/istio-1.3.5/tools/checker/rule.go @@ -0,0 +1,35 @@ +// Copyright 2018 Istio Authors. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package checker + +import ( + "go/ast" + "go/token" + "os" +) + +// Rule is interface for defining lint rules. +type Rule interface { + // GetID returns ID of the rule in string, ID is equal to the file name of that rule. + GetID() string + // Check verifies if aNode passes rule check. If verification fails lrp creates a report. + Check(aNode ast.Node, fs *token.FileSet, lrp *Report) +} + +// RulesFactory is interface to get Rules from a file path. +type RulesFactory interface { + // GetRules returns a list of rules used to check against the files. + GetRules(absp string, info os.FileInfo) []Rule +} diff --git a/istio-1.3.5/tools/checker/testlinter/README.md b/istio-1.3.5/tools/checker/testlinter/README.md new file mode 100644 index 0000000..02f4901 --- /dev/null +++ b/istio-1.3.5/tools/checker/testlinter/README.md @@ -0,0 +1,96 @@ +# testlinter + +testlinter applies different linter rules to test files according to their categories, based on file paths and names. +It is run as part of the Istio pre-submit linter check. Whitelisting allows rule breaking exceptions, and temporarily +opt-out. + +testlinter is based on [Checker](../README.md), and this package provides the [custom rules](rules) implementation. + + +## End To End Tests + +All "_test.go" files in a "e2e" directory hierarchy are considered as end to end tests. + +Example: +```bash +/istio/tests/e2e/tests/simple/simple_test.go +``` + +#### Rules + +1. All skipped tests must be associated with an github issue. +1. All tests should be skipped if testing.short() is true. This makes it easier to filter out long running tests + using “go test -short ./…”.. Example (from [golang testing doc](https://golang.org/pkg/testing/)): +```bash + func TestTimeConsuming(t *testing.T) { + if testing.Short() { + t.Skip("skipping test in short mode.") + } + ... + } +``` + + +## Integration Tests + +All "_test.go" files in an "integration" directory hierarchy, or with "_integ_test.go" suffix are considered as +integration tests. + +Example: +```bash +/istio/tests/integration/tests/simple/simple_tests.go +/istio/mixer/simple_integ_tests.go + +``` + +#### Rules + +1. All skipped tests must be associated with an github issue. +1. All tests should be skipped if testing.short() is true. (TBD) + + +## Unit Tests + +All "_test.go" files that are not integration tests and end to end tests are considered as unit tests. Most tests +are supposed to be in this category. + +Example: +```bash +/istio/mixer/simple_tests.go + +``` + +#### Rules + +1. All skipped tests must be associated with an github issue. +1. Must not fork a new process. +1. Must not sleep, as unit tests are supposed to finish quickly. (Open to debate) + + + +# Whitelist +If, for some reason, you want to disable lint rule for a file, you can add the file path and rule ID in +[whitelist.go](whitelist.go). Rule ID is the name of that rule file without `.go` extension. +You could also specify file path in regex. + +If you want to disable all rules for a file path, you can specify `*` as the ID. + +Example: +```base +var Whitelist = map[string][]string{ + "/istio/mixer/pkg/*": {"skip_issue", "short_skip"}, + "/istio/pilot/pkg/simply_test.go": {"*"}, +} +``` + +# Running testlinter +There are two ways to run this linter. +```bash +go install +testlinter +``` + +```bash +go install +gometalinter --config=gometalinter.json +``` diff --git a/istio-1.3.5/tools/checker/testlinter/e2etest_lint_test.go b/istio-1.3.5/tools/checker/testlinter/e2etest_lint_test.go new file mode 100644 index 0000000..5566ea0 --- /dev/null +++ b/istio-1.3.5/tools/checker/testlinter/e2etest_lint_test.go @@ -0,0 +1,52 @@ +// Copyright 2018 Istio Authors. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package main + +import ( + "reflect" + "testing" + + "istio.io/istio/tools/checker" + "istio.io/istio/tools/checker/testlinter/rules" +) + +func TestE2eTestSkipByIssueRule(t *testing.T) { + clearLintRulesList() + LintRulesList[E2eTest] = []checker.Rule{rules.NewSkipByIssue()} + + rpts, _ := getReport([]string{"testdata/"}) + expectedRpts := []string{ + getAbsPath("testdata/e2e/e2e_test.go") + ":12:2:Only t.Skip() is allowed and t.Skip() should contain an url to GitHub issue. (skip_issue)", + } + + if !reflect.DeepEqual(rpts, expectedRpts) { + t.Errorf("lint reports don't match\nReceived: %v\nExpected: %v", rpts, expectedRpts) + } +} + +func TestE2eTestSkipByShortRule(t *testing.T) { + clearLintRulesList() + LintRulesList[E2eTest] = []checker.Rule{rules.NewSkipByShort()} + + rpts, _ := getReport([]string{"testdata/"}) + expectedRpts := []string{getAbsPath("testdata/e2e/e2e_test.go") + + ":11:1:Missing either 'if testing.Short() { t.Skip() }' or 'if !testing.Short() {}' (short_skip)", + getAbsPath("testdata/e2e/e2e_test.go") + + ":27:1:Missing either 'if testing.Short() { t.Skip() }' or 'if !testing.Short() {}' (short_skip)"} + + if !reflect.DeepEqual(rpts, expectedRpts) { + t.Errorf("lint reports don't match\nReceived: %v\nExpected: %v", rpts, expectedRpts) + } +} diff --git a/istio-1.3.5/tools/checker/testlinter/integtest_lint_test.go b/istio-1.3.5/tools/checker/testlinter/integtest_lint_test.go new file mode 100644 index 0000000..8ac6018 --- /dev/null +++ b/istio-1.3.5/tools/checker/testlinter/integtest_lint_test.go @@ -0,0 +1,56 @@ +// Copyright 2018 Istio Authors. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package main + +import ( + "reflect" + "testing" + + "istio.io/istio/tools/checker" + "istio.io/istio/tools/checker/testlinter/rules" +) + +func TestIntegTestSkipByIssueRule(t *testing.T) { + clearLintRulesList() + LintRulesList[IntegTest] = []checker.Rule{rules.NewSkipByIssue()} + + rpts, _ := getReport([]string{"testdata/"}) + expectedRpts := []string{ + getAbsPath("testdata/integration/integtest_test.go") + ":12:2:Only t.Skip() is allowed and t.Skip() should contain an url to GitHub issue. (skip_issue)", + getAbsPath("testdata/integtest_integ_test.go") + ":12:2:Only t.Skip() is allowed and t.Skip() should contain an url to GitHub issue. (skip_issue)"} + + if !reflect.DeepEqual(rpts, expectedRpts) { + t.Errorf("lint reports don't match\nReceived: %v\nExpected: %v", rpts, expectedRpts) + } +} + +func TestIntegTestSkipByShortRule(t *testing.T) { + clearLintRulesList() + LintRulesList[IntegTest] = []checker.Rule{rules.NewSkipByShort()} + + rpts, _ := getReport([]string{"testdata/"}) + expectedRpts := []string{getAbsPath("testdata/integration/integtest_test.go") + + ":11:1:Missing either 'if testing.Short() { t.Skip() }' or 'if !testing.Short() {}' (short_skip)", + getAbsPath("testdata/integration/integtest_test.go") + + ":27:1:Missing either 'if testing.Short() { t.Skip() }' or 'if !testing.Short() {}' (short_skip)", + getAbsPath("testdata/integtest_integ_test.go") + + ":11:1:Missing either 'if testing.Short() { t.Skip() }' or 'if !testing.Short() {}' (short_skip)", + getAbsPath("testdata/integtest_integ_test.go") + + ":27:1:Missing either 'if testing.Short() { t.Skip() }' or 'if !testing.Short() {}' (short_skip)"} + + if !reflect.DeepEqual(rpts, expectedRpts) { + t.Errorf("lint reports don't match\nReceived: %v\nExpected: %v", rpts, expectedRpts) + } +} diff --git a/istio-1.3.5/tools/checker/testlinter/lint_rules_list.go b/istio-1.3.5/tools/checker/testlinter/lint_rules_list.go new file mode 100644 index 0000000..28e9cd1 --- /dev/null +++ b/istio-1.3.5/tools/checker/testlinter/lint_rules_list.go @@ -0,0 +1,34 @@ +// Copyright 2018 Istio Authors. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package main + +import ( + "istio.io/istio/tools/checker" + "istio.io/istio/tools/checker/testlinter/rules" +) + +// LintRulesList is a map that maps test type to list of lint rules. Linter applies corresponding +// list of lint rules to each type of tests. +var LintRulesList = map[TestType][]checker.Rule{ + UnitTest: { // list of rules which should apply to unit test file + rules.NewSkipByIssue(), + }, + IntegTest: { // list of rules which should apply to integration test file + rules.NewSkipByIssue(), + }, + E2eTest: { // list of rules which should apply to e2e test file + rules.NewSkipByIssue(), + }, +} diff --git a/istio-1.3.5/tools/checker/testlinter/main.go b/istio-1.3.5/tools/checker/testlinter/main.go new file mode 100644 index 0000000..4713072 --- /dev/null +++ b/istio-1.3.5/tools/checker/testlinter/main.go @@ -0,0 +1,52 @@ +// Copyright 2018 Istio Authors. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package main + +import ( + "flag" + "fmt" + "os" + + "istio.io/istio/tools/checker" +) + +func main() { + flag.Parse() + exitCode := 0 + + items, err := getReport(flag.Args()) + if err != nil { + fmt.Fprintln(os.Stderr, err.Error()) + exitCode = 2 + } else { + for _, r := range items { + fmt.Fprintln(os.Stderr, r) + exitCode = 2 + } + } + os.Exit(exitCode) +} + +func getReport(args []string) ([]string, error) { + matcher := RulesMatcher{} + whitelist := checker.NewWhitelist(Whitelist) + report := checker.NewLintReport() + + err := checker.Check(args, &matcher, whitelist, report) + if err != nil { + return []string{}, err + } + return report.Items(), nil +} diff --git a/istio-1.3.5/tools/checker/testlinter/rules/no_goroutine.go b/istio-1.3.5/tools/checker/testlinter/rules/no_goroutine.go new file mode 100644 index 0000000..d167392 --- /dev/null +++ b/istio-1.3.5/tools/checker/testlinter/rules/no_goroutine.go @@ -0,0 +1,42 @@ +// Copyright 2018 Istio Authors. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package rules + +import ( + "go/ast" + "go/token" + + "istio.io/istio/tools/checker" +) + +// NoGoroutine requires that go f(x, y, z) is not allowed. +type NoGoroutine struct{} + +// NewNoGoroutine creates and returns a NoGoroutine object. +func NewNoGoroutine() *NoGoroutine { + return &NoGoroutine{} +} + +// GetID returns no_goroutine_rule. +func (lr *NoGoroutine) GetID() string { + return GetCallerFileName() +} + +// Check verifies if aNode is not goroutine. If verification fails lrp creates new report. +func (lr *NoGoroutine) Check(aNode ast.Node, fs *token.FileSet, lrp *checker.Report) { + if gs, ok := aNode.(*ast.GoStmt); ok { + lrp.AddItem(fs.Position(gs.Pos()), lr.GetID(), "goroutine is disallowed.") + } +} diff --git a/istio-1.3.5/tools/checker/testlinter/rules/no_short.go b/istio-1.3.5/tools/checker/testlinter/rules/no_short.go new file mode 100644 index 0000000..b8f1650 --- /dev/null +++ b/istio-1.3.5/tools/checker/testlinter/rules/no_short.go @@ -0,0 +1,44 @@ +// Copyright 2018 Istio Authors. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package rules + +import ( + "go/ast" + "go/token" + + "istio.io/istio/tools/checker" +) + +// NoShort requires that testing.Short() is not allowed. +type NoShort struct{} + +// NewNoShort creates and returns a NoShort object. +func NewNoShort() *NoShort { + return &NoShort{} +} + +// GetID returns no_short_rule. +func (lr *NoShort) GetID() string { + return GetCallerFileName() +} + +// Check verifies if aNode is not testing.Short(). If verification lrp creates new report. +func (lr *NoShort) Check(aNode ast.Node, fs *token.FileSet, lrp *checker.Report) { + if ce, ok := aNode.(*ast.CallExpr); ok { + if MatchCallExpr(ce, "testing", "Short") { + lrp.AddItem(fs.Position(ce.Pos()), lr.GetID(), "testing.Short() is disallowed.") + } + } +} diff --git a/istio-1.3.5/tools/checker/testlinter/rules/no_sleep.go b/istio-1.3.5/tools/checker/testlinter/rules/no_sleep.go new file mode 100644 index 0000000..3f55edb --- /dev/null +++ b/istio-1.3.5/tools/checker/testlinter/rules/no_sleep.go @@ -0,0 +1,44 @@ +// Copyright 2018 Istio Authors. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package rules + +import ( + "go/ast" + "go/token" + + "istio.io/istio/tools/checker" +) + +// NoSleep requires that time.Sleep() is not allowed. +type NoSleep struct{} + +// NewNoSleep creates and returns a NoSleep object. +func NewNoSleep() *NoSleep { + return &NoSleep{} +} + +// GetID returns no_sleep_rule. +func (lr *NoSleep) GetID() string { + return GetCallerFileName() +} + +// Check verifies if aNode is not time.Sleep. If verification fails lrp creates a new report. +func (lr *NoSleep) Check(aNode ast.Node, fs *token.FileSet, lrp *checker.Report) { + if ce, ok := aNode.(*ast.CallExpr); ok { + if MatchCallExpr(ce, "time", "Sleep") { + lrp.AddItem(fs.Position(ce.Pos()), lr.GetID(), "time.Sleep() is disallowed.") + } + } +} diff --git a/istio-1.3.5/tools/checker/testlinter/rules/short_skip.go b/istio-1.3.5/tools/checker/testlinter/rules/short_skip.go new file mode 100644 index 0000000..faacff6 --- /dev/null +++ b/istio-1.3.5/tools/checker/testlinter/rules/short_skip.go @@ -0,0 +1,98 @@ +// Copyright 2018 Istio Authors. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package rules + +import ( + "go/ast" + "go/token" + "strings" + + "istio.io/istio/tools/checker" +) + +// ShortSkip requires that a test function should have one of these pattern. +// Pattern 1 +// func TestA(t *testing.T) { +// if !testing.Short() { +// ... +// } +// } +// +// Pattern 2 +// func TestB(t *testing.T) { +// if testing.Short() { +// t.Skip("xxx") +// } +// ... +// } +type ShortSkip struct{} + +// NewSkipByShort creates and returns a ShortSkip object. +func NewSkipByShort() *ShortSkip { + return &ShortSkip{} +} + +// GetID returns skip_by_short_rule. +func (lr *ShortSkip) GetID() string { + return GetCallerFileName() +} + +// Check verifies if aNode is a valid t.Skip(). If verification fails lrp creates a new report. +// There are two examples for valid t.Skip(). +// case 1: +// func Testxxx(t *testing.T) { +// if !testing.Short() { +// ... +// } +// } +// case 2: +// func Testxxx(t *testing.T) { +// if testing.Short() { +// t.Skip("xxx") +// } +// ... +// } +func (lr *ShortSkip) Check(aNode ast.Node, fs *token.FileSet, lrp *checker.Report) { + if fn, isFn := aNode.(*ast.FuncDecl); isFn && strings.HasPrefix(fn.Name.Name, "Test") { + if len(fn.Body.List) == 0 { + lrp.AddItem(fs.Position(aNode.Pos()), lr.GetID(), "Missing either 'if testing.Short() { t.Skip() }' or 'if !testing.Short() {}'") + } else if len(fn.Body.List) == 1 { + if ifStmt, ok := fn.Body.List[0].(*ast.IfStmt); ok { + if uExpr, ok := ifStmt.Cond.(*ast.UnaryExpr); ok { + if call, ok := uExpr.X.(*ast.CallExpr); ok && uExpr.Op == token.NOT { + if MatchCallExpr(call, "testing", "Short") { + return + } + } + } + } + } else { + if ifStmt, ok := fn.Body.List[0].(*ast.IfStmt); ok { + if call, ok := ifStmt.Cond.(*ast.CallExpr); ok { + if MatchCallExpr(call, "testing", "Short") && len(ifStmt.Body.List) > 0 { + if exprStmt, ok := ifStmt.Body.List[0].(*ast.ExprStmt); ok { + if call, ok := exprStmt.X.(*ast.CallExpr); ok { + if MatchCallExpr(call, "t", "Skip") { + return + } + } + } + } + } + } + } + lrp.AddItem(fs.Position(aNode.Pos()), lr.GetID(), "Missing either 'if testing.Short() { t.Skip() }' or 'if !testing.Short() {}'") + } +} diff --git a/istio-1.3.5/tools/checker/testlinter/rules/skip_issue.go b/istio-1.3.5/tools/checker/testlinter/rules/skip_issue.go new file mode 100644 index 0000000..59912a4 --- /dev/null +++ b/istio-1.3.5/tools/checker/testlinter/rules/skip_issue.go @@ -0,0 +1,64 @@ +// Copyright 2018 Istio Authors. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package rules + +import ( + "go/ast" + "go/token" + + "istio.io/istio/tools/checker" +) + +// SkipIssue requires that a `t.Skip()` call in test function should contain url to a issue. +// This helps to keep tracking of the issue that causes a test to be skipped. +// For example, this is a valid call, +// t.Skip("https://github.com/istio/istio/issues/6012") +// t.SkipNow() and t.Skipf() are not allowed. +type SkipIssue struct { + skipArgsRegex string // Defines arg in t.Skip() that should match. +} + +// NewSkipByIssue creates and returns a SkipIssue object. +func NewSkipByIssue() *SkipIssue { + return &SkipIssue{ + skipArgsRegex: `https:\/\/github\.com\/istio\/istio\/issues\/[0-9]+`, + } +} + +// GetID returns skip_by_issue_rule. +func (lr *SkipIssue) GetID() string { + return GetCallerFileName() +} + +// Check returns verifies if aNode is a valid t.Skip(), or aNode is not t.Skip(), t.SkipNow(), +// and t.Skipf(). If verification fails lrp creates a new report. +// This is an example for valid call t.Skip("https://github.com/istio/istio/issues/6012") +// These calls are not valid: +// t.Skip("https://istio.io/"), +// t.SkipNow(), +// t.Skipf("https://istio.io/%d", x). +func (lr *SkipIssue) Check(aNode ast.Node, fs *token.FileSet, lrp *checker.Report) { + if fn, isFn := aNode.(*ast.FuncDecl); isFn { + for _, bd := range fn.Body.List { + if ok, _ := matchFunc(bd, "t", "SkipNow"); ok { + lrp.AddItem(fs.Position(bd.Pos()), lr.GetID(), "Only t.Skip() is allowed and t.Skip() should contain an url to GitHub issue.") + } else if ok, _ := matchFunc(bd, "t", "Skipf"); ok { + lrp.AddItem(fs.Position(bd.Pos()), lr.GetID(), "Only t.Skip() is allowed and t.Skip() should contain an url to GitHub issue.") + } else if ok, fcall := matchFunc(bd, "t", "Skip"); ok && !matchFuncArgs(fcall, lr.skipArgsRegex) { + lrp.AddItem(fs.Position(bd.Pos()), lr.GetID(), "Only t.Skip() is allowed and t.Skip() should contain an url to GitHub issue.") + } + } + } +} diff --git a/istio-1.3.5/tools/checker/testlinter/rules/util.go b/istio-1.3.5/tools/checker/testlinter/rules/util.go new file mode 100644 index 0000000..73399f8 --- /dev/null +++ b/istio-1.3.5/tools/checker/testlinter/rules/util.go @@ -0,0 +1,79 @@ +// Copyright 2018 Istio Authors. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package rules + +import ( + "go/ast" + "go/token" + "log" + "path/filepath" + "regexp" + "runtime" + "strings" +) + +// GetCallerFileName returns filename of caller without file extension. +func GetCallerFileName() string { + if _, filename, _, ok := runtime.Caller(1); ok { + fnBase := filepath.Base(filename) + fn := strings.Split(fnBase, ".") + if len(fn) > 0 { + return fn[0] + } + } else { + log.Print("Unable to get filename for caller.") + } + return "" +} + +// MatchCallExpr returns true if ce matches package name pn and method name mn. +func MatchCallExpr(ce *ast.CallExpr, pn string, mn string) bool { + if sel, ok := ce.Fun.(*ast.SelectorExpr); ok { + if pkg, ok := sel.X.(*ast.Ident); ok { + return pkg.String() == pn && sel.Sel.String() == mn + } + } + return false +} + +// matchFuncArgs returns true if args in fcall matches argsR. argsR is regex. +func matchFuncArgs(fcall *ast.CallExpr, argsR string) bool { + if len(fcall.Args) == 1 && len(argsR) > 0 { + if blit, ok := fcall.Args[0].(*ast.BasicLit); ok { + if blit.Kind == token.STRING { + matched, _ := regexp.MatchString(argsR, blit.Value) + return matched + } + } + } + return false +} + +// matchFunc returns true if bd matches packageName and methodName, and returns CallExpr +// element in bd for args check. +func matchFunc(bd ast.Stmt, packageName string, methodName string) (bool, *ast.CallExpr) { + if exprStmt, ok := bd.(*ast.ExprStmt); ok { + if call, ok := exprStmt.X.(*ast.CallExpr); ok { + if fun, ok := call.Fun.(*ast.SelectorExpr); ok { + if astid, ok := fun.X.(*ast.Ident); ok { + if astid.String() == packageName && fun.Sel.String() == methodName { + return true, call + } + } + } + } + } + return false, nil +} diff --git a/istio-1.3.5/tools/checker/testlinter/rules_matcher.go b/istio-1.3.5/tools/checker/testlinter/rules_matcher.go new file mode 100644 index 0000000..df471a9 --- /dev/null +++ b/istio-1.3.5/tools/checker/testlinter/rules_matcher.go @@ -0,0 +1,68 @@ +// Copyright 2018 Istio Authors. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package main + +import ( + "os" + "strings" + + "istio.io/istio/tools/checker" +) + +// TestType is type ID of tests +type TestType int + +// All types of tests to parse. +const ( + UnitTest TestType = iota // UnitTest == 0 + IntegTest TestType = iota // IntegTest == 1 + E2eTest TestType = iota // E2eTest == 2 +) + +// RulesMatcher filters out test files and detects test type. +type RulesMatcher struct { +} + +// GetRules checks path absp and decides whether absp is a test file. It returns true and test type +// for a test file. If path absp should be skipped, it returns false. +// If one of the following cases meet, path absp is a valid path to test file. +// (1) e2e test file +// .../e2e/.../*_test.go +// (2) integration test file +// .../integration/.../*_test.go +// .../integration/.../*_integ_test.go +// .../*_integ_test.go +// (3) unit test file +// .../*_test.go +func (rf *RulesMatcher) GetRules(absp string, info os.FileInfo) []checker.Rule { + // Skip path which is not go test file or is a directory. + paths := strings.Split(absp, "/") + if len(paths) == 0 || info.IsDir() || !strings.HasSuffix(absp, "_test.go") { + return []checker.Rule{} + } + + for _, path := range paths { + if path == "e2e" { + return LintRulesList[E2eTest] + } else if path == "integration" { + return LintRulesList[IntegTest] + } + } + if strings.HasSuffix(paths[len(paths)-1], "_integ_test.go") { + // Integration tests can be in non integration directories. + return LintRulesList[IntegTest] + } + return LintRulesList[UnitTest] +} diff --git a/istio-1.3.5/tools/checker/testlinter/testdata/e2e/e2e_test.go b/istio-1.3.5/tools/checker/testlinter/testdata/e2e/e2e_test.go new file mode 100644 index 0000000..27d3fc8 --- /dev/null +++ b/istio-1.3.5/tools/checker/testlinter/testdata/e2e/e2e_test.go @@ -0,0 +1,74 @@ +package testdata + +import ( + "testing" +) + +func SetCount() {} +func Count(n int) int { return n } + +// nolint: testlinter +func TestE2eInvalidSkip(t *testing.T) { + t.Skip("invalid t.Skip without url to GitHub issue.") + SetCount() + if Count(1) != 1 { + t.Error("expected 1") + } + if Count(2) != 2 { + t.Error("expected 2") + } + if Count(3) != 3 { + t.Error("expected 3") + } + t.Skip("https://github.com/istio/istio/issues/6041") +} + +// nolint: testlinter +func TestE2eNoShort(t *testing.T) { + SetCount() + if Count(1) != 1 { + t.Error("expected 1") + } + if Count(2) != 2 { + t.Error("expected 2") + } + + if Count(3) != 3 { + t.Error("expected 3") + } +} + +// nolint: testlinter +func TestE2eSkipAtTop(t *testing.T) { + if testing.Short() { + t.Skip("skipping integration test in short mode.") + } + SetCount() + if Count(5) != 5 { + t.Error("expected 5") + } + if Count(7) != 7 { + t.Error("expected 7") + } + + if Count(9) != 9 { + t.Error("expected 9") + } +} + +// nolint: testlinter +func TestE2eSkipAtTop2(t *testing.T) { + if !testing.Short() { + SetCount() + if Count(5) != 5 { + t.Error("expected 5") + } + if Count(7) != 7 { + t.Error("expected 7") + } + + if Count(9) != 9 { + t.Error("expected 9") + } + } +} diff --git a/istio-1.3.5/tools/checker/testlinter/testdata/integration/integtest_test.go b/istio-1.3.5/tools/checker/testlinter/testdata/integration/integtest_test.go new file mode 100644 index 0000000..573615b --- /dev/null +++ b/istio-1.3.5/tools/checker/testlinter/testdata/integration/integtest_test.go @@ -0,0 +1,74 @@ +package testdata + +import ( + "testing" +) + +func SetCount() {} +func Count(n int) int { return n } + +// nolint: testlinter +func TestIntegInvalidSkip(t *testing.T) { + t.Skip("invalid t.Skip without url to GitHub issue.") + SetCount() + if Count(1) != 1 { + t.Error("expected 1") + } + if Count(2) != 2 { + t.Error("expected 2") + } + if Count(3) != 3 { + t.Error("expected 3") + } + t.Skip("https://github.com/istio/istio/issues/6041") +} + +// nolint: testlinter +func TestIntegNoShort(t *testing.T) { + SetCount() + if Count(1) != 1 { + t.Error("expected 1") + } + if Count(2) != 2 { + t.Error("expected 2") + } + + if Count(3) != 3 { + t.Error("expected 3") + } +} + +// nolint: testlinter +func TestIntegSkipAtTop(t *testing.T) { + if testing.Short() { + t.Skip("skipping integration test in short mode.") + } + SetCount() + if Count(5) != 5 { + t.Error("expected 5") + } + if Count(7) != 7 { + t.Error("expected 7") + } + + if Count(9) != 9 { + t.Error("expected 9") + } +} + +// nolint: testlinter +func TestIntegSkipAtTop2(t *testing.T) { + if !testing.Short() { + SetCount() + if Count(5) != 5 { + t.Error("expected 5") + } + if Count(7) != 7 { + t.Error("expected 7") + } + + if Count(9) != 9 { + t.Error("expected 9") + } + } +} diff --git a/istio-1.3.5/tools/checker/testlinter/testdata/integtest_integ_test.go b/istio-1.3.5/tools/checker/testlinter/testdata/integtest_integ_test.go new file mode 100644 index 0000000..573615b --- /dev/null +++ b/istio-1.3.5/tools/checker/testlinter/testdata/integtest_integ_test.go @@ -0,0 +1,74 @@ +package testdata + +import ( + "testing" +) + +func SetCount() {} +func Count(n int) int { return n } + +// nolint: testlinter +func TestIntegInvalidSkip(t *testing.T) { + t.Skip("invalid t.Skip without url to GitHub issue.") + SetCount() + if Count(1) != 1 { + t.Error("expected 1") + } + if Count(2) != 2 { + t.Error("expected 2") + } + if Count(3) != 3 { + t.Error("expected 3") + } + t.Skip("https://github.com/istio/istio/issues/6041") +} + +// nolint: testlinter +func TestIntegNoShort(t *testing.T) { + SetCount() + if Count(1) != 1 { + t.Error("expected 1") + } + if Count(2) != 2 { + t.Error("expected 2") + } + + if Count(3) != 3 { + t.Error("expected 3") + } +} + +// nolint: testlinter +func TestIntegSkipAtTop(t *testing.T) { + if testing.Short() { + t.Skip("skipping integration test in short mode.") + } + SetCount() + if Count(5) != 5 { + t.Error("expected 5") + } + if Count(7) != 7 { + t.Error("expected 7") + } + + if Count(9) != 9 { + t.Error("expected 9") + } +} + +// nolint: testlinter +func TestIntegSkipAtTop2(t *testing.T) { + if !testing.Short() { + SetCount() + if Count(5) != 5 { + t.Error("expected 5") + } + if Count(7) != 7 { + t.Error("expected 7") + } + + if Count(9) != 9 { + t.Error("expected 9") + } + } +} diff --git a/istio-1.3.5/tools/checker/testlinter/testdata/unit_test.go b/istio-1.3.5/tools/checker/testlinter/testdata/unit_test.go new file mode 100644 index 0000000..ea243ae --- /dev/null +++ b/istio-1.3.5/tools/checker/testlinter/testdata/unit_test.go @@ -0,0 +1,71 @@ +package testdata + +import ( + "testing" + "time" +) + +// nolint: testlinter +func TestInvalidSkip(t *testing.T) { + t.Skip("invalid skip without url to GitHub issue.") + SetCount() + if Count(1) != 1 { + t.Error("expected 1") + } + if Count(2) != 2 { + t.Error("expected 2") + } + if Count(3) != 3 { + t.Error("expected 3") + } + t.Skip("https://github.com/istio/istio/issues/6041") +} + +// nolint: testlinter +func TestInvalidShort(t *testing.T) { + SetCount() + if Count(1) != 1 { + t.Error("expected 1") + } + if Count(2) != 2 { + t.Error("expected 2") + } + + if testing.Short() { + t.Skip("skipping uint test in short mode.") + } + + if Count(3) != 3 { + t.Error("expected 3") + } +} + +// nolint: testlinter +func TestInvalidSleep(t *testing.T) { + SetCount() + if Count(1) != 1 { + t.Error("expected 1") + } + if Count(2) != 2 { + t.Error("expected 2") + } + time.Sleep(100 * time.Millisecond) + + if Count(3) != 3 { + t.Error("expected 3") + } +} + +// nolint: testlinter +func TestInvalidGoroutine(t *testing.T) { + go SetCount() + if Count(5) != 5 { + t.Error("expected 5") + } + if Count(7) != 7 { + t.Error("expected 7") + } + if Count(9) != 9 { + t.Error("expected 9") + } +} diff --git a/istio-1.3.5/tools/checker/testlinter/testlinter b/istio-1.3.5/tools/checker/testlinter/testlinter new file mode 100755 index 0000000000000000000000000000000000000000..15d25f21348e21322b7f71ce0242f3172e2e6e5a GIT binary patch literal 2928760 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
xk=PPs~-L`(kcV-0_)62 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ℑ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 zΥ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%0D?||A&!(o}_V|#B7^? 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

-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≪2-?q~qZY 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%0D`N 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÷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 z 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%0D*%?Pk-Qep6*i+8X+sHJoU1Jxnso+!u2>+%= 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%0A_q_;<|;stz5?{rz=FnQewg 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

C7tG}1Jl;D zF{R%wRW;URFTK2lWRtNiVM(&F2crHK4})d2rUrk_lskv^fI3TARp{Qj3pe_|Jvl{B z?;2VtmZVdwS!8?DJw`gmsCUiL@yUL>O=-a)OQ#J3|8bM8$Y8=)B`9{A;K`gjI*qUX z$~lQ9CT?Wk(ViX200BUnBMZrOFfuOr49Y2e4vh)m;}31x`)@&CY}zvh>*B7wz6kz8Q6X47<#Xjf$1-u0I%bYF zZsAU~sLEC{G?m1n6*8UJJ=q>}jev=>iFlB9bne>jFMQVO2v`X}Mu}kCUodoEbKnlF ztD!Bxq)I$*Lp?Kq4^lBxP_edT6Fb&owUX`886U|!wGjxGif9&~Yn}ZZj~I9Z(aHg( zg;g2>%DiPI9W6!7n(qDq67hKw{9j_ZX%5TGA_i9kpCa)J-mNUkeoGf$E zievQ)^gbxyR5nG649hl~`aQgnY8FOO*sFqKyJ(g3A6&(Nya*7Riq1pSwOp7H=DmT| zf6`gG(7=wj7zk4w_7EQklu6F9IgWg2J}|?ZhgK7#YIhP0>>xriEDmVsoOv=-s*Vep z)GY8)wg8cc{;>Y{N8FK0F^pz65Ke9~+z!(Luu|G`)V@GfKQnrv8F9aD*#MG+hi3*- zY9(4Vx%qGYnq4o=0G)ss6?KN{GtFu>4wzLY8s~ShY(s|53BmJ>Y?Q*{mhD6cx71?0 z#k$_RPWYOXz{ea$rQ{I@`toa_OB2VMtaMZ9Fq$9v5EYQ__c$sI91V=tOi)SlTmq|@8d$&X z_Vg18QPpj>H=EBYGuZbI@N2kAR73@q?p#k7Gun-t3q|N!$I2hDx80wj5ikGJH4pKP zv@BquRyM6k(Sh=0iI!5zlO*+mVX^$G-p7dt7=90^b<9_|HEcE@t9Ps|V77Yti_a>j z<)buy>7!Z+m%+TtU?@7r?-FCSmJl9V)!?l>`}2*ap^m>IN3P{X^`^W=f8<1QfViVo zX$Nfj6%reZ0roc?n!$~V(CK?60{iUMv$Bja_?Kv}!tR*Zd)z2uZR7N0zm%EpeVO_< zFbsOL0PIMY>6Wjeip_p?R$y(znk@YcKs#4x>e#xWi6FPH zImPw}7DRnECF|%>K;Jv;R}I%rJM=6vAz7i4p2^(k@WvshJ3`t>0i{^X9nzmEW%#^@j!;EV%ZznAzwsMD7^O8nB8XG*&1|| zL(iYx2)4(uQ-8UpzR;+n%N%Mdz-guA5!p^)(zxmxHtuCHphlP6Q&)tRVYNj)%*usz z=aMTAmkUGj*vkVMx5UE$ z-$2MAaOqW_ ziNoH?$d-+<&OA(n22Q@GnX#3{uzp?MxdfCF_$1$n%<%pXIl{I&*L26D9M$t;`7b-ds=87%i_xLu<_<;o@ojwDUmJYgf?`U7IGo5F=}L^6dGe=N8M8wZUvhlISH>(}eH4vUJjTRVG@= zv;aVmLY<1O{+;0IYxWLOGkjYd#GFeuq^cAi&WAArZ2bRYR@bqYN+jc0OHb&0pkePo zZ*$1z-dg`ionf-dO0rL&xXAiOJF4FSXsc1gaDDgwxyu{Cj9PGAS}~N9M?enesCMdl z-J(6Exv?>HD*=!i37AD8G^_Q88tE}BppMBIRZ9YeUc82Opa2F7>dPknlVjxM4WI6A zdEbs^O#xU0fPwsI2~0#_?ot&AYr(o!9uz&d^%}6B`D~|a!3r0m7zHP)`hGKJJH|05 zAK^tdfKGwzXp*HsgHr^1nnS9YzkMBjcjCs{x8>?VW&XBejv>jmEv5r44Wlh4-TzXT zE>l9#*s$1z5>Fv*GEa<0+L}HH?sB z9_tW`du=(9Y&@_fYvkP+U-*ah!Es$bMs!n`X|lgF`Fbw-td3z&Zc=T0=#Qw9IL#`= z^H=%?E9P-0j&S+G?ligzKi%mj^^vP{h|VZ7vDXtZ%LA!tt&{hrM6fQ%0xoFk^Zk(M zlJAjJ*wosO9<7zCpYA(Cj%FKv+g(VvQ8ciw>U!ym)0}zr>~Y58Qyh1GT{uG?9|5$3 zk*V7#7Ix($K1uLF4+w?3tV*H;P)I4wIx8TR^=5%+hPlHR8kIqv=9IkF7OJwkDV^>i zZZGYgTVe1Y@~CEgMS_66Tmon2D9PIeNH(cWPxkM-tSM~>*|G;-%O?QnHl%7*8T*MZ zndxkaS9?XdTB=r_Kg`LPEeN-4E{3-%x*q)P^e(mu6{Gzt#3GXTPaDostd!)-2pDbe z{?()Wk2yn=x^)^_mQ|xW)`kOF2&00dgIT9Vh4$~%HZrd=bEP6ZueEvzBYMwY3oJQ@ zzgiA^Ca2L%tl1pjRab_^wHE!3R$Zd#4?))*8YF@FjHb2n#J1ttvNzsYSw=NaP|DEm zO;*<8^P<=+Bw=U3+kc_OS%1Zv5~Tnr{Tx}C`j@RI;Q*zDjQqj#3;a`ZlDwUZok!F+ z6RBl6@qZlGS7>uDp_h*+-51?W{IP=9b1)lsu7ZW}M6zo?yBbkkL7xtCnt`0&dc>H7 zqDf_Gnb^#QH{lFf21V>gG$nu}upBd*g*t;O{0PNKWUhMOq#5rkZ;8?-iqw@hytY_O ze|?iL;kS@``?BG)*=yMR$HZb}l)=r5Coo{M?NXh`z0#*l^O=5s?X$ z-zt=mU-OH^)HLlE<_W@m;A`1FBIP<7o=`=u&xJuK>dE6uQo6l|S`M!wSQd{@5ZS4MxYcxa2GLalnImkDXruNsCXM!E!VwkiO?yU6{=)Z1Y2otdS`t9r}%Xeprp3}~1D zZr_)m-L3WZk=C{)iXY8!bTCYovOlH$3xUB+Py7Y4H=vr^xJku`G!1B!)UEF{dVWu>9R{hj^*PqQNa8Wl~_U=|iASC#El6Kxi=79XzD9LNKBu#Dt=Y7(_q0 z$O!i$mntMY3M+c!$wa6355OWzZTDf3bTgaklgULH1wY69cv{U!uQ5HI%oinFt{zcZ z!(h0i@woYR`UxWO>Pa5`TG(uK@~`2y1uzz2MicW0Wsvk4d08Om)sC{ww-plGM@Jsx zV#OEYuo{2RS4}iwq7sJRni$|8oZCeKuMpV#oKQg8&&fBcV(m5DvdJOQA(ewhmw$-Q zEguVft?#y;m)T{n@3kI`qQ+X|)cRQc9WaK|i9K%LnUru2+}GtfF zP?{{0@$*hXK>7aLw-eqyv29o{NRQj|k%2n^u>YrU*YI?ZcW8-&vgS@@A|b**MBr_1JL!E_D57Rm+}Re(HX1s@sdvo zS7{sCxwu*)gHF#wh+tY6AgvOB3Ba75@ND{Ty|XQ=9(+%@m{7P;Cp$3+>*g)b-ISjK zua5JHPTM71P(F8T6HdR&0cpd8p1p}zuv?w+a{4bWaYK9R>J8carm!efp@AlCUU3l7 z@3pTSFpspcy$2fkRL0sM#7mlb3}X7GT->R9w1NDTmg#NX>-dR)YEJe>q*Sn)2WY;M zzUY888^BK`%-I^6tD+bs`Qfj}=f@%dkn*)e<&^fc^G7qUC+5>5x@8O4*nDom#(!LU zf&96Uhc%-7Ake9Gb|1hRv#94aCBMOKr(?`o$tLV+(?oIfxiQ4g7>k{2P6twIes2vy zX56f61(QPW`byfp76r}c!sxf{zXPCLO1;p?X#`*?yJlAiXAQBIHX##ZDzL4i4ZuAN zjjcweqk$!_q{^wD7#1ekk(1N}Aw?}vS^)0FjK$aO^sv=}omagc52Bdi^xFZr4g8!jC8eV3ZzmLi*Si59@Yf!wnkR~MxsSj%f~ zPMP+2M07fLdbF=0<^Nsge@mQ}Y8>0F^5>d+)v1+`ehLu5(Z0O&+?@4!FHe@DEJaKR z6{KkEO7*%Ij$W7h)8(sT*QmA4G{uZFhryWm72R)AdfNU6emeuI_jUX;v!UcMhl z+az@W)^yvVPMGhSD@rZo#QgCzt484r?J27p19W@eJu;pN%j}u;Ycgg5@_)f6P^fJL zEPfVbYLk3P4IwsI*ZOMJEV=WPYX5rJ$QHQ2M1AHqGIq$h60%ZYi;GY@pCijz# zTiN6Kf|6O%{@ld2rU(I!>`+~_>zdPJPg}A%mNP6mU_vo;U)l80w|gWCUgT>;+{^lO z;Y`~j(|U|#R|0kkeS|t^{f_e1rI3G?<+mm7y;8X>Omg?LK5!vL8VZ1St4`4j5Xjia8R^)gwGn3A~SzOoBt8EGgW zP`|?2E&dd7=s1No6@ns5kJ%MBbW0lGI6a);{+48naVDWB(-s0C(px9+ui>|uByY%V zDyb)uD+fxhxTE%i(Zw@3N62S2VTH?dgMLqU%K27=b1^nf2Lzu-(c!TtylyO;x`n(| z^CJ6TQAdAtA^auc$B&K(Q8^^B1JKx@$Ug&Kq6s82yAXTX6 zlZB|-;j&oPed|fwp!DT!zLx=P1mILc=U5d{iB^#I5Z>&6Y}?r#Ee?+~m3;n3t|hvk zIjDOc+QrjG;cGYhR8Y;JNkwug3>jkr2d+2Sg)L+V^8QmKwdZ;;YdhwsCcF#KTWws{ z`6_i#;Dgxt=!5h2iici^8;G5v&A&v6pp0`wx^Zfr2L%*IwV9X>&3=wv!chz%krm3e zk}iaKD{@aSU1n>X%KS&auo@NY8BDt+oo(>suXhS>PfhjYc4T{4TKMFHp=}!)f?S!Vz%vcVPs3tK%bInv zWs%fpg7B`>TSN#pyVzdZwuyrN6YJQngZq0S^gPW|GV4oOF=fY!!xS}Ct%kGQL`IQl zKhZ(_iK6qJD5l^NFXY$)ic&YJh1*0E#oBm-i>@RNdy@Xas-bA;`&@FX zw)h6!Xd48)zVibIwuM{}aahW_VYfL4v{os10o3$5V)GX!Wz_%-=pCx$f^7e_7~^-5 zdoZa#{1{)juV3s}FubVJKm(8D?uZS-bY88_U$ z6(JNlrBy}2w3aUr70h%pP!|^JVry{w{&HiQxW8D`pQrcnx4E0ezn8S_pk>Str!Lr$)lAlF8$IiNpK zz=|5O$saD*0+5(M^{>d1jny{wR}G3`~(#x7$_f;YDMSSNdEtzS!E?ffC)Zz z5Ga2HNL-hrmTRxq0CKS$k@J14V+cG=)b^gV+mqbm|ZR&2r3;eK|@X zHnq~s$died+k9KXS8Bu+F0%?DA%6(e>ITQ>ZSUB>uZ*5Z=G>4|zLn9g{H7newy%i} z_-g8lF919n4Z^+o#guq?v+L>>SurPTYyR+O%-9Zh@DQ2bSorzl-VC$7dAwH;1*H3**G%zc zq}pJ++%`=ep#NWZr}>ZMqZ=rGLICxV1iB$XH-iDNc~7s-0Zavz67E|`aERlL`Y>C0 zW>K{^gpv>Y2jDOHq5y)d5M2NhzoS=a@fuHH^v@Gdj5FtU2~(Puk(M5uF^#DP4nAYhlHeKGB<_xlJ|CJ=GWiYn$Eg+ z+@2t=4Un3Afum_sjE?o!K#uB#oMUR9G1io(cR=5G_eMM6z=9lPBU2501S^A}NKA zzMF0FrqQUtnp(rBWM&+A+yI?P|3*d>PUZfQra6sc^fB1V>X|n+dNhuL$x8xZkD_Ue zN$nN2O1xrw-ZDOmBZaNvO|V02iMURGtL(40-)h8@%@#X8B?}Fd^==eUQtJteQ7v!* zjJ)kx(NAq%MPDC=!*(FCaQIN(ZQy+3OBA~nM>8;;xWmilO7=++JyB`^!z6J?M{inFBdbgBz#QNC}>o=6OIvn=%cVROz6yowK zCK;%=kaQQwj6{TW6agV$400J!vGnfI$H4kdzY8!0)oEPnqnXpaJrgxLAW$yc?_?8V zRt=2EIo+g+TdN;~*BDc@)u!GD!Af4MOmI4fs-?96^1e(p7+lO#m)@?0|h>a!~p#N40veuAzm zCq&EBa(7IC1zZxQ6Or0Ir4$zL6$4IW*YpyO1!qRj?K24r6yok)Is z@RLv`APdO#+qSUz>rT`6Ck8)eS;=`dMGOPD!Ww5bbWEj}SGX(;rnn_?BVYOh$m^|r z^c^3PCcUkF{&j0qk|-!BJ4r85*BMh(EtP41WbH z+#bbGAeTf@x?$(KsVyEzeG$WIo@hj_L5f1SL`Sg*f z$2+P1o z@1@QjZ$XGD7An#nzQyQ+>gBsIKv0HreD0&+%Q2q)Y3)l(Bi9Jc-plb@FJ+OX+jxx? z{AcW3at$wQ?@56Mg_2a5FvgSA*7wA};go#iE-i z5dFVY#9IWofrh(tGY}ITDD|Q`$c*%L4Krma(VFx#M86NIp-YiPdu|i=uR;3v0wxwq zWV({k2W#r)QEa15bFr}bnb#g!uVU$Zywq!!$`D?M8Af@4^}wbRW(3L{hB zj0do0Q4hUP24yoj{NFA`d7K8|CT`<(91`Z(^geDTuZkwF;U?SAV$5Wt_K@lfEq(Vz z+X04Ay@sBq_mp=xaxy7TmO6cmKpHkTA-%GLKBx&t3^Ohb= z9lfRU=Q=>mg{mAc47YC(E)g}M)7Q$~VvIkC3-79VFj;Iptjmz^;bSRz0d1i zXnY?F&#w92?-;XQHc(!YNwMvGBr@jXOVQ-#8v_gz3xi>;xONDUGi)Ku5Yh%li0CLn z+VBt}OszzZ_KIK0{~1~^gGzr`QfGhV>5-oKo|3rUwiEMZZ!7Fgc$ZOxPx>u^XO1&6OJ$0mCufPb)*0LVZmf#yClBK-B%Mx zeDO)j1*(F|4^FS%qI}AJ%{DSD0e^!)#s&bRoGS--yrzeK%DQ8A)+#)s%60W{o+X-E8=LN=xH} zq8%&E_Cu}1E57<{-9XAaDLSC@V`Uio2&?JxZ-vpX;hT;ZI@Nij5a(y?LYK4T!rr3mVzQS4Y&=L&(Q@9Wo53d4h)$n>o3$sfi%oBP@=XXW;pV zMu9)PTKmnyf1EFmGGe`7KvwB=$^Nk=$)Bshy9UJ}!E^{X#?Y+;c&LW3Irz4+kp7P)jr zjW);~2Fv7*VQ0&prX|t<8g#J3vMhjN>g(n-)|yooC^O>C#Gs~`I}>^D?P?eArK_KNovj}S#qV1?|Z zy(0hmN4M6PJ84zpQ`4eg(Ntd2rklN2|8%w8zv&#{Kr2(OAtv}<9jsqq;V~1(tlvr~ z*g6(Jq6#_f9wlH*YHtd@cL$tY6Rs^lcXved>=1eY9NsWxd)!==(fP1#=k9 zXZYOTP>UON5domhn(n(RA(TYBe4;IyPqPy5?>?$7?S4_F`u<+sTQ$>$P+&Q4Fo#gh z{gIXR;<7K_)*-P#OoRrd>Pyj;`6Q?pY4cX*YDic+vBj^> zyN1EI#nMQJGt$1>p#8NG!bkKQ1|odW*loTOK0sxlcA~FbFTRJn@w2o`bNS)O zo%_kv!jjS$n->noCl%)~?Zitm!oE)7<|>h3iHIyCyza+?Z#N{_9Gj0mU99H!1a<4n zJ{#LDPX9!@Hxod=i4+1kF5{QQDT_X+qfK&M)4kla)Tv%yw4;!B5)(csj}Oo6DOH`A zky}g*UxqhhX1c!`4KCd%>m&oewuyePGa6UIV;W6rl3dUR#Kdh`iH8<0X~1I%7pk0B z?F0q&le2uZVP98?NBwPIVZBKE28GIw`udYu~Q z0bhLfLkiV_YmaKx@5s!h@2c*zUjXDSQVNH?#E*L|CU0f(F4&xkfoj^CAbGK_)?Ife z&ByCU)+E)VpkZqOKU2r2IsBrZGCsw9cMoO0YuxbUAr$o^ z%-r}ukT4rONUy~8?$58!dZl8x8nAF;t)I-je|pYy@o3X8)ET$dz)4E=UP7# zHz9U3p=ulbPFAhX>+M(F!t^6ue3g+x_SKI|{t`APQgA_r*`H`Of)6H;+zz#YGLL84 ze$){6pd(Yay$u<-;H#cOyA(&rU@PJpqjjG&GE68A^8*b`873a|xlvoUSF*W7!ms)-p$_#vpGQM+Y`Ond^In zE$l?q2cGWF=^t{#`0H&0cc9$hltn!)2`qJF`&}?pq+tz3O{x%PPbD?Exs|F# z2u^Dfh1vXZLAPZZ&!&XcRc3{&!+q6S3D|6+ks6&Hyu*hBJQz>@^|I$Sto=DcBxFe0 zH-5s!<^q-71_6eOqkvVnp$MT|py?9xx$g=-`MSvOX{|fY$&LFpJ%;o)*Q0jY^lFi) z^tQ6HRtiPRm|t(1S(e@<=KM4ytSe2VpRyiNhN)$&aagq_Pk4sGdU_{fm_SFgzR#dZ zKx3eDlUNM6pl+FrnytS=tCh{$kW=Gu@AC-?mtKKA#}RuC;a|wD#{poW3%-tYz3;3q z_2FF{&b*LH%!#q+*Q(^PDUr8qg3&8YIK`W#8C=j3V&(371Wp(df`9a4g=zZ>v6*tj zeDLtK1U@al#3<31LoR(ttyNviy!=}e*oDiMy*Y=MD-d!N{NUzyHtRXfMujrCjnk7; zi^^KY2s$DoZO0n?5V7{~>8 z!j7W%7l(}-!pGHoFUmG6Fi6W*E7qAb`ts%(hatv~T49L$UhY_xCCX!UiE+|5+h<@+o1xgvALNq!8B5|@e8WMX z_`e5-Q$+Thzk^%ej72^L+sKcYn^5=~Z7Y7?gLGL?_=Zc{_(9N#!@JnM(EaQUjyj<5 zaKbBNpPI+@?mbpoR|7xqCNQ4L}oZ$=w+FRAJPR*!X)jM-b~k{H?NyIBFKp{wezouj zk8~KB{j;T>-wNpk1BSov(yaOdGQOL9fR!LAJpxqZkfY<@MPXabZqK8o=@7@2t`T@P zr|)C3E9Ou|LR*L3D{D9jBn}`-hje#KcPZWZ-#owf{Q?`V9c$K_xaXd|*Jz{P3?_0agVMXEVhbAEYB*X6 z!`)$*vH*bW^i+f4i@*J?`2N!-i-=R^m}6U6&rQ0(xP1n6-;P7D?O4+Lc8tjH-tBqL z@EQT|8h<-J>}_fHvZHQx0*#}xJtVIAfHcEU#7#C2ct5YW=|yg#By-(Qj0{zScllFV zwsnR9#JNiefgU2RC4OC_PORy&(SbTXouV$CxeXFFn8;pJS|deaIn3NMzqp&w=Wck% zrF)O&I;0v}Kf*OWDzU&nYj-If?eIpg+VO(+-{CgDl4uyg z(St<9H*(9Uk{6};Ev6xL#Y0ITde9Gq9B#u;ul8n0$0bU%C zVFUC%0h&M15G}Uzas(Mc&2Cnjl9xuKt}#{Yo`tTsCW**0N77OZ`B)LxRXuLzlZ&pm z=fXMfCi|SAGP5be9hVAQs)b6LnTr>GIq!!yw7J_reJ@JdbTQebA3a^35Nd@;zeYizw0tMA^W-15`T@(R*8^NMb&%5nNqvwZ)uUDUR=* zK>`E5iEaWGW;r@%{3SCTjr?#))wWp4__M7OrM(ZhjVf5 zS|rC`Q%pCys)?X_kygdr4Fd2AoCa}Y&6rz}11vr0)a)wyGs#@mnNp38}T>n0cf&boF;XLJ9*F-;GX8oNUWn zAVTR&1fX1@4zwn4VPR_%$5e^aRq^K+QN-RBOL};po^Wc(P1U8 z>J$HO3ME;SXIYg$6O?^EA0hB1UZy3J-W_K7=(9PZH?V%JlUYamAM>)&x7%Ax-w6cT zD!L&={sepCtrDipW)eonY{VYP@Dtm#y$3Q0q273W>G}@}F#ABWWOB)tB0kcr!R%jW zPbF~nX41)u+%;lFzw%LoP^FyU9u44#MOt-*WWFqz+Ci|I&N|6oOi|k-kmb{*e^uwZE1*5wtbJ$( zLBG#8?kUzd^O*A=GU&y%hW)OM1_z}+cN7s>yTTnQ+wJhfK*_DQuEerUz;`W{Cda5} zd`7gdIReL0@%&u@>M&eJ@<3pg@pveJ+yv9j!gFj*loIRfRH)q^Re1Tg7k2DO1s_RN zHka(mlUn>hU-4Q)F8skX8BAxf#C^~Q;hXBwx4aAk^)Ia0(6|U=Q2$*xjI?L&$qfZW z2=t0#donq`t|y$lF<5%RN`M?#j`)G4rMI$+4m$>Q_9?!o=@B$An$3F2r;-?W{omy` zl8^^ry-Pifr!^$bQ;LUto|oVN>ugm-h2Q-I-s--SD_^@lHXm-U=^k{!@mZ^8tp{49 z&e_-UzAw+no9KGM1UWOv+|&Qm1sKApA)m^;1ljtl05}hO1b{R2l%Cd5WJ7BgJ(sk$ z$&*fy^xcQS9ayqaX-6y{bhIsZ2O2$s7pZM3N;8xUf=p@l*J5T*8J%oTLVSpa*X@8?ULaOy_(z3sy+QUEIsp2 z^q@D%FC3~8Z*KX4CWhSUDs3W)I+0VyWKLT2JL`X%FLcbgFXN|f$#!QH=-PhC;~ zv|6#&w$7DXH(Kz7@~^mV#K1yO#c49(6XGMaLUZ+*8#(@J*bMpm7rH> z1DHr^B+_D|i1}~dZ)7hzW`>ceH_L_N?DN(yW&GhRr!2(Q%(q)MQtBg=1?Q!U+&?j@XDhWU?hc9xY<*69_Xt8(xiRowLpa9te5xwRyV zIRF-kFJsiPZGCjY1t;Q2z69bGkk`t=`<4cP)|!VUbxfkOk9C)&S{z^nvaX+Q+tJdESLZT!HfK9Kn^3Z5`3 zJ%scuvReg9T1q1y7j51{zhzhV->opXIU}Sax+8(V>eYQ-W?qEwQ#L;Xx|~^Hvxdv| zep??M06m_wgdaLBeI8k`n-pz;GT!PdQ=G-_U+&SdZP7l0n@+|Jg)APQbZP98%;UTU z+z%{|LYtQ77|ML83T%L;<2rTPr)THp-WY*N}b^O-6qXNGai*1rIWeWz&e*GWzN=?x72eC9qR zbKVOVl*z0tCsv^k<(~Ats!H-wfGN97YY5=Ml*0IseR0~jO;&BQI!^c=y)*nzj2v0V zBA8*<2p8F=ySZ1d?=@d7<@I3mW{~1@DbD;Mv4p06;$+04G@$Y?5# zeEiyb!Fy%nVNS1gYNPVZ1t231jm~@8U#ZX<4gkm2hB`--r}~*Lnr(@7jH-( z{xo$q*nD`+6(;)p)K^meb($`qw{IT(U`)qc-NV&_=|?rs13RY@T8u(E&O8C-_vovA zx(Doi$2$*h)|Z6$vb01HY3YxLRcWLRj8X|G)k-akS5Pf#Sf7PIC5&hq`0kl6Z%(uz z{r=me#H}PrYbpIg@l^q*_S*Z3=A_<)hF?t?*qckJ?s2Y;($4#x!K+P7HN#}~;#P0n zpt+n$E+365TY=R_#nE3}b2tnphV~Y89I`+fYHrD?-Rp&LJ+e>a7@nz~v!VAqH+ErW zOL7#4+to$_vid2bbYyqO#lO|561^3mY&k=F;A~sj@Ae}RV%!nYWT-?IqwpPP{xS$u z`ir^^+=Z;JztjG&8M!z+h-pW;wJ>mQVQPgP*!{c$WDFD6)R~p^T35Kwh!ux3FJJ~@ z*Tir&gg>+&Ejv=x)BY9@O>d9hZ}x-$w5=;#XT*xZnHPyTdYNc0Nh7Ya1A#+)L^T1* zPs){=n0qBQ-cvg2l{bzlKw8<7)4Q8uP1YorG^s*Ig0_1Y9=uiXYPl1n#cB1Y%_@t- zyU~q#0y{8EI|VHmhHCX&vV2sXIy4ktmhB}hC0M>)bfNDWToNzaB?L!IGQjt*X?9bFY!L{t-U zdB!)BH?Dl$?-e(t;CS_?t-Zir@FlR-MJ5gpSk~Sd6o4l2=B?`XRu^pIi2L@g1U&12 z04a2CBztoB%JwdN?~VQhH?~8dth{PF7h0oXkV8*xrXdi4ziNx zTy+RMxVt_X?9Hs=q^yEA#}PP>Gal?I3}h~_ks@&PSdYvakDZ&{lY-nnoCDuk`=ogr zWfPIoyTfyNcwsm-Orq0u-G3kgF5RK?CZB4IcJ@9JXXKR`_SFaIn>i7D^s_N10+|73 z-L;}82$>;$ugdzw${#36-b# zC9XaHE;uPN`qmHS!G7{uxG<<){Gvey_qPcT`Rh)1<$E|MS|S$D^~{x_rhtB>#lLsL zzVrlnB(5#yu%)4r(^O&C?VBGER1}7o13cD9VKh`Ap-1Ykj&Bt+WqW7EEX6ZR)EOay zQqekP{@7cst@j6p2pV>=(&BD7Ds{WhL>2#DGhsc^cZH@(dATRTkA{_3SflM&pmu4= z61SegXTBHFf>(BQ4!M%0SRpy(0Na0g-6y1~AOQIPR3ys`5E4-P>0$S7RP z>sxTgg6NcNBSU|urOL1%3JU7%d`s-+Up+#41lRq+7&}h~SxG@1FI(>-qV|+;CH#)5 zKc3;O`6ODsOT?adY_`mGfW3~a`kUS_(g6zPr4^#h-8$;=+i|{=^TEz3B~_-vcXjzu z=jI@QZ<Lb`3L?yFBfcqh450;gXZ(=r&NTKR=JMeO_%N zK}kvA+frUwWW^x~iYhMRMqXqm7D5U`6A_g*{$i$tQ)__-L_6A8XznrT^jN$An{c$4 zNpf_YEz$#SdcQO|!x%`$I^{ih< z91s}6-kdfEv}V4rME*fSRPh2M?BqQ_F5(OTyEsK>CboMB5PRvcD`@id5M%HwGTb!r zh!HFg?@Cl?m>yOXPhphEL zL-(L9vLu?*`u%*-Yb5Z)b~J+6N7dvD3f}JlYYWkA!zo)rt*`J}?0IgR;wFiGlwsGp z8>0yH!e^c+6(aWk;yK33I=teyxMNaoSc?`Xd3x%}kxE3Jh_g8JPtd}cVKj7@dzR*@ zwb~piv*3XEu@|&}{&j^>6NW2CcG3W9)^RPuzO!LGFI*jE6|sD?D(EDI1WRD;R_h;< zfwP7Oeq+c_sB$MrU;OxYvp~Y}`^okX<(qA=t3vM1H=H?Llews~j`k5J@Zj)z34wie zE|s3lcdNLfW4q&22bR2Rr`K&LNtXn1+Jd?Rdjji3fu*^B>?IRubBX!fC#`n<1a07{d#PX7-O9g%SVJ< z8Ku;ZZdr8V!+3T;%y9c=cfg09p*S7~NjqIWM30n{R?yTQ zDf@+rPQ^@NM+~C(;;0raMNPl{p-v>gyyb0Qrg7BTgl#U?G7V7XJ_kmBYY}r}0Y2f2 ztZ6GVPJBcKKwr!h*}tsO%-bc|yrK@pN5uZU-x*uvmeS>GP#VOv*#-QML=WFCh}~pb z-Cd-{!`LKc9s`|8C$o}4@$ymxLrA8HvdP{2bVSpti+vPFYC0mw71#j$0P~925K5ls z6@M3HLvzL%Fvk>7({Xs0U8KtqymdNdp%`S!e};(un<50rVAPAt6+O~D$1Dy@0cb!s zzRVYIDzA^0E{yQy#P)W1HB9yG4Gt%|te177Jp<2|-#iA6Uz1OvKeRrIWWK!rOBP)1 zX`aecp24UF4``szE&_Et?!mTx?DXi}Yim+kCdpWRmIv#LjgWy9jQWZQa`f}_5~mNZ z6dAxJ_k1Kp0E~O^oXeIO*jv5eGbQn9eP54v6QU9{y;7(bNA&d>P7>zF9%pj#OkGvG z6Ec&+X;*Dk;H@2^72kJRTxto35O_Ux4qQ`M4cN&@i&F$vphQb%G4)F#Nw>O$S1=d) zv@u9o!kh)zaACou7eGd3s@b9r=n&J1rO3=ZsM4l3!FO7o@94GIHP;o1FYVRiM#FED z>{$gzs#H%)9+@_ZAzn42md2I-%ppzNnWg1G?Q7-lIZ12M;A(< zo8$AuKX7Fl@W_01ko|v>G(-%Y0M1(zFEe6K}R>xFyAnsLD7J- zVAddmqK_Yq_i4>}#m$=Z$=&Z;X<|f7Z zUSBd#W~gbeopIa+hX54Py<#PJ>F=qdRA|&Eh<>uWr-M001SZZ>Y2$gVej|f1avflH zz21Ofk&l4UE_7J(1O*C^UwHV995N%&$A==-%5W?lngm6gQwU z7$nBbvYqBCVq4r~z^wGf!q9JhMw@fEad`tW&y&TOGi9u(e9=QXNXSAeygqD#e_&H) z(0W+{39VRynIqJ7AWseQ6E32XzOAG?ATyw&_G-Z&qH6F3VWB=PUxXI1`#>TxTa(5&76w z>|R&={N>65O=FoXOQ*n-G>bE$m*IbstS0lJDl(|GqNV}4BDPL=s_>xXQHF=Iec|Yd zYg2Z{e!OG3F24iWp6gJe2+7$CX*H(A+J5%GO?|7k#c!X~AQurbx4Fw^qCo zQ5k0~`*}tz4FeNAZJauxj#mf2jlTB8uo-1?KOI_CEKw>a7qe~RTdDqVT(l%N z3tg3m@U-s7@0oNrR{tY9upK+zHLwD^4I5XnyQNMGvLovlg;xFIK3ATJsi&2KT81BXLs51mS=wA|VE&h!KQSQKV4$r%Y_<%> zlr`!$Tkd4_ilVeL)~krM z=5u^m=hd@@&m=hgfZexz4|SwL#HVjG`AkyjQL}`B!x(D>K(n<8+VI;f=q>mFRPDE| zw&L%WgN|ixY?E1Mc#+Sw%s^qGiPHv|?gdj3x72gsla`?}QM!V8SfvE}732IhJlGdD zrpg6RGHxVTGA$Zs{#c%-En8Za_HKW=ByfJl5#J48x z9^^#2brGS4t-Bf9zatfYd%c|F*_ZkegEzeL{$BI2xuGG^?c&=XgYoZzvqd>T_hAgG ze}>>4D+&gnklsw|GN3RVSYu{10ekQqFG?wUZh!9;PfVvzDx1hf8HQF}SGz8oaE8!k z#NybFhJ@{^_5b)#;3|2Vn5Lh{L06`ovTy~>C6o&wZIuIl5<6!ZDgXY4% z&-l<`tJc>OiL~QJ!{^J@UzHs`r++ld#wSd9u&L(<8$7nDxK+X|QgQ-0WM-DY9@s2m8pR|KCvWG4yYl!V zufIkUfom2-ZvC<8Te>NN_x>909buPz;LVc@g%)9GLjMjg;-We94TFT<j~iceM1SdSg~=;Ze>l6;Gm2P$2#HxQ$NAS?-L_>sDe zaoLM>5Uimwjp_CUO30gOIn>jv259`*yWzH-ZvSDMSFSByD4y*);pB`z=)~OlwpF&B zz4!3g0RAeFnySV zsuP0?Z31aWx0*`d(|-Bcxoj5ZyH_^h1n(19%@p{a53lIIm#4r%7oDvTRlD6|1Pgg; zb5@+WeV6om9P7cYOnukYQJ9ZCWpK~JTq)tR4?J^@UsMk0O?V5+Up}U*J}SmuS~ced z{LD@E#q8Gnm$PHxmTJ}{w6sm+gijd1nVq7^vPmPlq>4m$m$*9Gh$gypaz!0p!5Pdya!_;v4ODmdk(v$OK?Bel?2%{NA)ljYzkI(~Wo)J!be zd(Oh6fm*!^oDs9vB7%6!;Z~=fp~rUP2wVLuh27J-OMYu!lJ>ag*F{=p^d3Z!z#ryH z-{n(M&&I^7ZBuLKB~<+`I;OTwKJxfh&ax(VP}LQ*%?)6xmxb--S- zdF(@EnrIdDlh4_S;L(gX83&$N;Tt(=xFSNPFZAzQ)HHR0{YtxnH4Kh z)2+-=6J+?0jSq*$T1W_yf4+KXeT}eZFTffNFKkhG4SnBJhRLCs*mah$ z{*%Q^h1BCg;f91iAHzAK{77&%MBhyR7+y6x7d>7HzL8Mxm6=Xci}T-VtfHFV>$gGr z22LANu!Zs6WJQ^-`g2MTMbVD5mnu>-vg9>FJ2{P(@-%rPKAW1P+jOP?RNn=jT2r?IORcjJ10{h=I!QTW0>$0RmeR2~nd zYCB6$j$KeL97U&!%(TzrRN93`JoE$m1Ugy$9FwWiq$>9^Q?=*B4>cuO6fda4s(^I% zp=iOoo+d1ur)h37!{V-I^-7M8U`}r8syvhqP_tLlG!Z^7h*rGac7~7R|m&H+p6M%iqOr7LT|F1o%=7+e@~GKr{^QGcX0cYA_nZ9zv}fu zLF%fywU8u`B(H^eWknb^tgt5?6ST{Yby)4Nb?Zxy^k*N+Ke@$)b}Ic5c)mMe?Dxm8 zmbrc$9i~O>7S+vy42OE;V#&)Udg_tNU(nJN^q`rl&w%=fv_I=woSn1TvBcZkQ{G`qrO;ewvX9Fn8F?AY0q_=iTyVFl0e{5C|LU*hbHKU~102<^v-pal~xPBVHFJPFljKTF536@{c9 z@CIC-r!CZ9&Ys6YEIkzU@#Aw6Kp13+nX9@X47dGm7G9xK2((`F%P=A?qNhh#@{r`t z)YC9#2q3yesoUrBxk4;06;MTfmt!_qxu%ef!!*2skGXJY0uMK7llLAs#SK|xVN^qM z94(=E-*{g_rF6qNInya}lT?gA9Z45e^7_!xGI$d|&6kw_l%HBjNSG&AHcg<1N};b1 zly*FORF3LWONMkuXALG6TR062?_zWlAC<&L{jRR3DP94Hl92JCEUi;sR7eAw0cTDm zC_Pt9B2d#Robw6uxF%@xDTm9}>$;cM+@PXD7)vO@0Hnau zIjf)gPlA-1pzzr19(fTE23vS%;M!ce05!Vp(RWOy00~c&D=gZ~d-{QI{fVIswD^XU zK{^*XPkloyQ8zP=XrDKX3S4(mb}(FC6c!x(1SYnjl4_)^bP!J2(6V#!#yqt6(?4TvN?54!(z8eVsf*D}{132rtH`xt0Y@gltyQ zN0yvZ*Myekk(O;TvFeA)zbKL_I*XiiT^oW;z7pT&9^BJRw%WCG6n#1Jpwx?B;{ans z*fw1WBFhaaI+L`aSjn8we8xT>t~dP|&XymYdg&r}A(IoBJ_I<1UbUy8uiGRC?VjiZ zF+2Q++^8FD@E;e#Yto(whuu86+nP4`KsAAD)a%k$(*3M=K3TEmmZy~}j2~3nGxA{w z(P!fh=%f3_GLQ#YIYx3w5d68Vy#iJVuMAM$R5VgwGo4pho0{zX>_H2gb!32Fi$5aE zGg#kMX>|H}W8-W}+Nyqju1eO8N3mL2lD~(gzSt`=?Tn*DD+JP`(fvyo1biLYy}O=Z z*nXUL$67J};Yf3-Df2eDX~9c%?ufRPzDpZaL6*?DCPn3yF8i1MZ*gbV5BjGM!(tVM zgKfu&cLl*K$lI+!fCS(86Con>TVA!=xO_Z|d~gC~K_(QR*SS)*6bSVKmgc`CTB_?e zzU(vEa(#{ag0=Xtzu1q|UM)q3ySj0}$;VzF<_DHP zcA~zh%L`@F3$lAt|9V*^J8{gK1(tmOYu=OLF$>~}4XZC@qju_A_clX&1!L5}ncIS) zW!>-B=0e2sk@Enxoj(jTkrcuLah4O{LxVzc0^OE&t|^u zD1+vMW*EN1_NCLP`9a)xqEvL2JeUprS;27_DB^eNhks&v)ec9)!T(NK@P>q{Tvw56Vn zKfL7EpPx7#G6h7TP*`ZPGUh`p73WS1N%0|CEm>T1Ed4X@UuJz1yXK(bFBzLcZJ*~V zDvozT2p3xD)eJ(AJBKrts<;fT;7~|1HH(+6?AI z0?Uy)>-b0U&prRRGITo;Z5_@8FvCjx0IbZBdHn9h$P_ z1NIVv-8r*I@>Bjm!qAx6ryDA3&zi=O--egmn+V@TR7?Bwvkt_!JLO3B1PViHwSWVlWoy z1~oA4mGXi+v{QPX6g9Awp~Vq}56zQ(*UZT}?8!NuUjv8@I^fV9<8rA-;!RW}3NS2T z;fKdu+hI@}Vc)_bO!;RXe%*(T!(^X~`MI`N3;*>k=y$4H*g}i7xax-3t4k%jGPSEc`)IPKs5~-s!R{#Hkj|etTiy%Q0Dfpju$!?g1= zS$bD(>sD{vJG7wcPYc0GsCG--a_qGO;3udn2(wdXtJ!FpcKm1rfD_&X->Fd=@7tw4 ziGs9`P#Go+{~+=W%q(z3UFyIaJ{9eOpT-zIMY7)0kE@a2>TCWI+?#qD*Ul*6k2zws zW62(szF&caC7+f|^m|69gN-LyKSKGJ>XB)>Ank4J+&L(I^HKYBi z#$gjnX%8@e>Z-c%*BaTGRTvyYV(kl-rS)$ILhJvVpS=g?>`aL8D3wRwz|i(!ejiSR zJd;6TW$4I_ibeq1xBz(5_mRRNV!OZAmYGdN>L-OY*s}#M#hfr=m8{(tlQXttKS+iT z@uv!DYzhH5$eGnZ8Ls^}rD$5DN3!Yw<^>X$q;CQ&T@uj=RO}4ih^ruCtoWz>8vIxJdB z!HCpwDcECaFS0clo`K`QTg3W~b;GeG+Vq~)c+i<`aUyul!j>`~zJ0`9d2r@+5R@MJ$QaOdB$0F%G$AM#uD9sGX(8jReB^{SW=0DZ;$$hBn)CSOd|iWWP; zAPhE$hZJT6hh4(r2TS^*al$@A87%1Y!GA@(slkn=UMyk@5C(3Cxn%&z-5%Kqg?9cL z1*xnyjSnyhGmQ$s+Dm{#ORT=n#GjG@kRIyRr%B^ol@@NXo+pJ;U|8qRP)Y+8Y}Thg z2)Difk0m*HAOXa7|4(de$2CCcHA#K%UxF|57LwmX8Ol|P|3pL5L&A-D3f`nz54t>@ zyBq|%SKuBPG%#(Eg2|WGi;j_P2OTf2W6QKaX?L_H07SOih;#vF6=TM2Xd){l7ntr~ zKj=$`U=xdv%+GvYN|0ElLvMI%U4s7}+~fFyaK-FH;uOU-*5w}t`4F6Dd`J(7E1REy znTr~35y*?c$rvJi&@!Yql|{bj^)?mBY$8OQpBkS3uoXrbH@S-Cpohy#_g;#g{y@QW zfJf`Vo4Ss4D^!-iGptZy)NR7JR1OIrR5Ij|;w0i!k@6>3qX}BGK=??CL0I*a0STFp znMb8-ZWFI7E=IXT2o4_%_h*y(Nr!*Jjp+f0rd2v~O+Lxm(E|+2!Z#qKe*A&$;A~X< zV*UVisv|x#I7#qVRq%CilJ5l@+^_~KEW^FH>*hNNUmVm`S9EQp{cC`2is{(GpEfAb znHDk!Dy7%I9bLkCk%92#*z$tI3A-#01f8x9WUD?jvq|!VBpz|A$eYFtI?&KBHrQi0 z>Sk{Dh#xHY!KuC=e!#(d6d|wvgxBb9L6p2+Jz$6@U)7AJUOnBm+}&hbU9+g9jDLr= zBpeCB0M_od~TU?a8R>}w;;gE3mtl6StB+?Knit&+p)(-j5Az^UOxek-0_*KXq>)#wXko#y_UW&ssGZ+1qM(-hOHSu1ur8{0UIOx2&t1L&hl8& zi~J0PMI-4IvMXi**z;wuNz&f5+u_&_LuSlp1{`_jyx&jR#!U{Q`re^}w5LQ3g~z*K zlV=C<|3pW!I!hl-T>Z2VA$I!XRZ1U`kjAWpMLOa!B>bF78aQRU6=_@oO#Z_rdtfjN zcsgURtyoB^)nUsN-c*)}Z)cSX<92rVJq=(xZFoOnm#Z*#-I%_7Va*|+S`Qh2|Ig$twkqy-bIVS_hXI>8fH^<#O6Hk0v4HI?JBpILB(G$xXKC4BSHcP4?qsSUcb1yPQpw{}~ZSjAV0nYe)E`|lU zwN63fTXcu1RAaQ!w=mE7J7p|Wv=eoJY6Enp22TCMvJe8C@P0+Yv;O}mBF3^);L z{WmE}86wE2HYra+zF(2n^>0 zW`PsZETOQD2PU@=m~q3hjY^;vd6nT!tUyvGlR``u7>zdsC7tW}+Bg5>zr;N<(z-bc47%R{XqK@)tP3>mfL0 z=3ahur7Oo`#sFAJqL!0}O3)DHmOS9(%oIo0VZ%>jD1_k&OK(qI|1FIX|23k=k+0P@ zenFpnzl3_Bd#TFWmb*K?IKz~z-ZHsEt)Kx?6O5=eRgxXAc`k4n_zy1YyTq5TI-NwERl#IQJ7ZflaN^KO zuZ|5)VP<*Y#P=c#m;>g#Bl@rwt2s$eVnZA%+{1K3nh#JZV=i*escVQODNQ>>h^Ha- z^g}m?nv+NtER(g!{(T?w5YQ?&P@%n{ITcU?#!tuNAG1DB8_ZU5eHqg;%e-3tb9ZB? z)IjX+n^-m~OX~hq6Z7aJ3}KGqh!oII>zmU_sSOIFK&y#zZYvmKcThI-KMtCTBrkfL zzD@`4u4XoFNfBQbc(N*e`Z@aBg_og!minA@RQJc>!7>zKe6XbJYDRiMc7!gqUicE( zxFIaJQ*Eh0^S-NiCRCqbsk_n8%*y5+KPG3+F-z(3G1y}@KukX*vi*1sst(`7*+&?K z!Pz*{f;^>L{vyFNjk?wZya@+mRC=r}3bUI-?$mM$%@kn=bGenV|BMys;%K?3W*_Rz zVm)~6;!2X|bGQcU3CVlw-q4^apWq6SOI{fs`g0D&pA0l?s=6nJ7z`lx#D<(w0QR@O?9DLb9RXG0_rc&W6hlf9s|b{3s&YQ4kEUh6minHXXax{Iiy zkI@Y+<@LKU2V`Kzv%F|`k)&JE*iiQ%*JPmA`9t4C)LsauV2Ga5$Os0F@SXO{wlQfd ze)HS_Hf55J?e@4i^wY2CEbS4DaiG}1TPOGV@T^8m&u2K8t|7< z*B$jk-@Zfu3GoJD<_?C5B~*w3A|bp`5|Zy>vXc@c$Cny3B zbN#6fKl<|zWyzn#8`17c>~NYQ;W!#}X*l{bq<^foen(@)cc~ON$IjfIzU7Dkdcy8U zj&UyWai*%laVo`2@BE`&eUe-~!pxiFn}6kol!C}>Rf_M)_HMs^>%7&_WXqmdhB^0~ zah?kCc>GiV>hc3kKczqzP~!+sj|_ISPk?I1mHDv!z_?m-uHAyW04>$O(H zfmcBqsn02_r7Fc<;4!6zP~bl@e=^|@ohQFdCl+tuus*>-nbMWiCw;#w*BZT}G7 zH}u&h?2VCG_{>+)oi9am=?-$2E50Isoj@LP9_*YM-+ad?r;}VDQ%{=15=4AaL2r3U zEBhK^aC)>4!C7*4;NMyA8E0RdvnB)+taBR}ZBMZPDJ~AnM60CEa84Hq~QI(jd z)|0J5oK&f-qbeF?N(-j?*m=9Une3K#R2C8346*~yq&u&e^3)0zAhmzvCN0Mgs%Cup zj~i4N3s&=SH`mRoo*G@!GSmx0HB526Kxc+hkcnr3%q6aO3U5_MVdzVNj0=KICfY)) zg6WXLMM;yDNontrBC|&DvWiBHS7#MrNwPIBA%VuE(DEA~aV3fT%4?B8nV>m>c0wsBRu$?nkAT#*3fi0tcR z=&GJlTP2=YDjQiZdfGx|m{)m(6_8WeLbaAznPfDS-w(D5S)0rML|kivI@tQxx0ftv z6Z?9z?pJnKL~fy4cZPW4gIvov9Kzv!QI&DB;)JPBF< zbqK;OLhzcK?CiI;(8&DU zr`*`B!HmVndf9!~)@$e$y;&$mc{Wvv9VL&S`%1`%ojx_Lr<-VqLM7+QAA8vq-^$9tPTIlKKN7L z&MI$Iz?cv9gf8I(aYp6-b@9eQ+f=Gn$^_T_&Z-tE&I&C-k zoJ3&pz7R_;_=%mi&`{!SQuBoP$6EiY>D>+B=KWnFBITJd82*)@dCjdl!jtX5V4pHF z0H6t1uxOq4R`aIBRlD8sqd8H|HC2*~NWQBvGT8eB3zDF|-o@N8046|%*F{xkJ~sS~ ziR>R^#DLodA%v~cjJs<0yN(DUXHGIp*>TC|zQa1kv`!7)aF&+bWhvQlFS0~xGSjL) zkX+HGlay+=8meU07wfcNzjXVQBWy=g+uLAi3uK%`ij6|Txz0ca0T_f0zljd$D}tOc zQZzdVCAb)~J-}~u9{)Ru7XK~Vi=?*MrdWsw6k5Di?^6|7cyQMAC2J9(tp%P{iUB|B|@ot>BR5cb<7d{ z)fkOUpak=@ps>%!m~|=EGkaw=72DO~Y?(3U@3|DcZAE3xt0}0okS->X zH1L%u;qPg18kY<1ULPB=RgJhVtoH)ld9{A3tbUYn8^A32Lx!pHB8Qzn`0)DS{@B%j zrsFjLn?US z2*JYtBu6ega;Cp8-CGq*KWHJ@3ggU4>T;1eIg1Apj zP8U}U;n8Sc=>F!WJCI?Uo~f1Spf3vZ4t;IJP`XII2ab++ePp}x#d=nJ{Rc9t<2<6R zd4)fG+gSfcOqX_P&9cV=m~fzAhXiK;C1!Z%wj`sM67%_&pWzmDg!a)nSHub{>##ui z)l&g-l*G%SeXSpN$8N1NNW1Z3Gby?h1hEPVN6?>Z)0yx1;pi!xVTZou0^W??Qlz;V z7hK$#=gxt6gsjD->*%2jb>g3zjSg))VpIVI?*L^tMq){Gnc=T0S|9nsB|O*xD$(OQ z`8`0DXpw@C<(jv52EvRi@Q8^5O@74zjafLKLeGs`@T3d;XY$e=Z%`zWtILhVxptnv zv_O(-)_00F*Tw0eJTW*n0ih98ucaG8xS>QQ{=wl@6rve%%YxP0ifm;yK(Ld3sm7LbzE1DQKd6ERyrH9#~)aqo!R*w z-)9Z3#eL3wJ`q0&dqb?(`h6c`u-HkXIpqq7Q61yls6ULibdHb=@i-Csm$jX3gsJ>? z>h`peqi(h@L-)7bOk^W!R63lwS0#G+V%vD_BDs$MY@Kvh-lvlFqhjS#uFpJEbL~{( ze~=Wgu}|V`WT)y;{dIoAMut2tdLL**(iawHQKp}YfW75gp6e{uD$zl#o5EUOATxtt z;xb5C|{%!Y!QE==;1TCn13qmYW=I$%g{Bcc(HuIufH8? zra2WF8b2H&H>e1dQ_~!a&H$Mr6K$7p~A0zbWHJu}DpY%5OsblGI z=qieVHA;Yw!Fq_GP)wcKBuuDeVhMU5jiZ@FeW)2fG^KIE2(KIqL7VUn5MOu{?U6d8 zw6tFIe{+ctHAbGpt(Crs4H)T*vE;&IM_tz@`e<6$*fB|@8O&%-cEc^Igb={AXe}2o zpVqq^t3Um9{yKOk$S(Y&mO@pFU*BwMlQ35f-w9L^;I1z|N0H&O_ z(&m#!%6km}sp89F;_r7AhMoYv$%rVdGU$JYCPZPm)t~|&(Dcf0!T`i8h_HvV9Wftu zp~vdTB}xYmdUOT)LKBzQH9KB%z`GC2XT|z>RuU_cV|rG;ezmS6>C4`x*{-cA|Hso; z$3@vhZHshEH%NCkEFj3zAuTN-T>{b}QVJ}vq;z*TNQfZpBGL^jEG0;H$9wy{-~0Uo z{FrpFbz*fH%CSi$l18U?>Df_3?>~7TMXFfTwf*`h5$0f53Pi1q z*)_Z$t4On=M_n(2?YG%t;kS1{7TsSjU4B^?rHt{QV2`S-?q7E5s)o5bd?2Z*BhNR?4@|Zw0 z1{pU!sMVDN_sml~NTZk_X&=f%Do;I|yV#N96wBg<7Qe4+VXVKg z7S)<~W@JTL9I_{hvy@HGd|xzkZpyFhaDP$5mLvo_K@@F=r*Z)S%R&M_qG4Nt`N+u0vG+`Ql#{5iU`M0dh?3WMgvKsRP`NGpr9>Mv(M&+C!F8 zz;C8j`%_Dyi}cJb8#v`wsj-II!FBziEt7h9)RWC-n$){}F#KJ439&9^jDE0$+Oqf< z+ol{UeqacLTax;Yn4Qf%$aN?Xo|W%ViI-3TIHTJ>ZL1tvZj{Ou&`HRQ?peW7449gYdJIaT@)PrdFLmYL8A5f(~3OdlZWH->Ow)6q@%_;mGK z2fGie5bX1#Ni&P}zitXEy-Z`}@ilk6N#n5t&2RmD?U$*ag;Pgbj_b5k^^ zR(=*q#aFvTUGy7Mm>(V#b)I}6ta)4N9Vlc4<`9$vV@JDkOr8nO?EXLV9~ea#!XW1E#gw6ROFcKiu|kH@S}@H9GhRr=Bn|+pXL5CTN$%` zu<|6IxC@Awf&d;5Q*M^pTVI{vCsAYwytX)9yk6~*7IL52YE|LfwC@EaP2eQ8?+Zps z4E<}7=3wlXIR9p_>w7gvK`79m@2a_=oBr!P>(8A z16E^PO5UAMT(gV8*S9}i(YStBHm5#KbqdWS$5r}CLhj5$$;n^RKpW?6l(K}S^mW&f z8=ZOPR)m*4F6HHQQ|i2mfUcXGjpP?i?f0X=WA^3Jryepf){mDgEE&n@&r-~7#hGHC z$39cMpm}yAb0~?a@H8Tp_*tq9+?qI|9<4U9znljL%@}>!ubZb3%M49k(YOmuUxW*5 z4IQ268EJ_2`_LX?FF7Cyq~QH3_)puv8h+#^zOS-1s6kaGGO^Bdo^%O{m+Oh|(LuPp zWX^OBAlBfcuIW_e)lDIVrxpqYSyoBkq~xg5FjTAIleR1y2Gp4e1?x9@-(@~Jk}p0M zziyfIGqsNVPTI$gjNb?eul#oBDRhpYG#PiD^5Y92>?pr>406n$8kBirA*Yx;f3Wp7(+^{ZfW2kGNl0tm%248zoVA-pdlgTeX4i1hh zO~K?T&_uW7!MN%mDLgPVL)*6Dq+;k9;b z4uV_)*jHjPpcc^*cqB)ODE~+LPLcB_7tIgEiKPCgOK{Zm;^KCwo_@#>cG@3WOT97DS5N*sKIM% z^#UyVCt%Smi1qENVY^LPF!6dTE6odX6Rr?42cXG~@5o1sa=ccHT-HcCen^Lj=CQ2c zyAdwkWC52#NMklFW)q80%y4v$8Ez1-pv5N~2E>{*+L_dpr1ZzQ;EEET1fMh#-Nx`V z6XZ*DEP7CgmF_*`8jB8G{f7^k#Qv@lo_m;m!DS$6UbuaM z&UkIyZ9Jm6M)e zOyOIMecG#asu*fRXJgMjd9h}u{yThKx1TWrG_|%z>)9SCUQ9*vc&o$e4Ix~f>BiTM~*SGNp(UT{3 z`61m)yZ1ZC9-=^QRE_Zj#5b?{_v0B#`in?mzWEBbX)#RUG{+V$1awTaPUB_0D8lN5 zbZUEkGD3JQ#>GZ}*mKvQ;_Mj+w?>&$7IREt7aX%*tJOl+u%|dfRtHtJ;W2&x#m_?a zMq(rn%U7}WpoO#06-ki1qIWI|>;vw)L349@&hds9`8!|_SZODT!P_;}q5JteGPhm- z3ebU+Z*!ZCMTQ6ga>|?yBL01rJ>MJ|FP!YF(<0=ES3UJ3c`*5%7dm3H{N%EiHavvI zfIE56fqz@bQDgn_&53wBGsIW#|9^UEnP-RS@lY@Nsr*rL@`}FFkPR{s(mY%&2r;sm z^m>USh1<=g^|bLSxshq9fExQ+XaqjkP~e;Cr+dq(@b!sXLB$=ffU;BBzalmEC4nYY zbkihHtf&}!{u-z0)SyP)6*(?`M@&SA(rP(qwSO$FQoCd!EwLKHFG~wxJ&sp6p{)}47m^;hN!8Ko7|3X zpa7lbqe^a`>u(wl`LyPajE^7fO@DfJSSiIz*I8+ablDT)JQE>n^m@h+1*71^bk8%l zRUrL6FW`5$$Mjd1gv=NN5>YMhY#>A}o?`jtMChLyakt{xQ*RtZp&j9g>VYuM%65h5*d%ta9 z<0~Ybp2X$gzLKQTPlAolU#PKg)3i!*stB9wc<_X{aH2~;?!AEEpkEnU8i5}iH=bf zp`+PunLxj$nfI49(g8K<*Zt z+Si3&MHf$y63ulQ!i`>N7mS{ZgkuWo17mU8zrFSwzA10!_0iSZdxMv*Ho!I)I9|gI zP+9QIK0Jtgk&8BqjjIk{&e{#+)LYK#?f}JIB(b4W%t|4vYo6g+VESG zx^Hv~!Fmr>XULYJY+tq-H=Pi`vJf|(w_02Iy+1{V{6XpjZsisv7OGh)Jx5tad^N4UAM8By^kj4K4%9mNvc;kjy!bvKwmb=b?=$n1VZe==LvQ4^tjX z+85*Ax8Z_eTv7g9(>S3)s-wqY|UZ6o`s?-yEmgNz4f z4TA5nH`crCq6a(ij40ZDbR;`=l|O%Yad~rz*?(^uFIy{No%UmJo$Q=!-+#hDgt5f6 zQm;Gt7TEm{YqFnLrKtfAzzYyJMwAljP0g+H{R1JI;>)ish`bggbi1(G^!|zPyO%eT zOn6#4*ASdtBje@jTq(}Rcp6m;g{{Du>-3+`ZuAlPo^w?v6kOHXntBl6}B!{-O<(aoGpW!P4$IsLsOlJMA!~I7NL;!4_BCG7C)-S;unr^ z*ql?@AXCO{MfYrS1v~!Ll-mo{hkxtedH=D>v=^m~ft8;ff;g}2cCZ`X(n!Wb2QJ2pZRvyL{{<7oXSbf z5920BkUhNqZ&(6WxO90J{cB*SS|+re*)X&%pj6G(_)U&DK6n6LlqK-x0Uwh?mIOYU zhb7dveUv`vgOob)BN`^)w&#<@@94cTXZ?NzsCS9fZZ)t4mw#QEPapWgJ{D%)?TKvSFBpdrPMWAY}0nzS2B zsH>BbLT>)wx-?Dk_y9tKxk&qh66+DKb;^5OY0Ub-?tqlVE_*qrK+_m{gT z$*AhdgJAtUmi)QZ_=-C=gY^Eabq33^H;tqg7JVD_lj@J4n9E6-u>yC>@AOS>YFDBj zF!D1217B1A3@MEe$k3?=?1=v5E@3a7g;Gu4(*W^*LpSz>nh3*q8c-z>fau04FGzsu z)J~;)_s@w^FEP9j@e3cGxrGs4t5H?6;4Y}VC~Mf7rL00rA&^-~;`>h6)bgY3$!3+dvxT2xje-de@PwD`4CSHsuDi6<9CEQz#u zPQDY8n%jt_DKnPto{3HC?#KQrgW6sjRM$qXy4gSF>F*!$e2%_7)YTok9FwPjW!ycb z*h|3SS!x5tT_~%~u&zVmN}@on6Jp#2n|g5TsP#g@X{gLYJ4xA6KD%l;c2BZi-Zl4^ zc6#8y!YeIzw@+xoF7-WJkVUTrC&6Gf)scqV7%p5nT9MA6Xpx%H7#M!u9HRfz0=`ccX6k-ALrHFnKm+%y zhMEnr)pANn(%q2OL-(5)GrrJI!xQhcUvDIZqPdCl0{>aVGOMB*!ciT8cf%Egk`Ppe z9aSAUn^ zaJLr;4<9}49Yf~k3YdcziTMJdP!=CI|< zq!(7LqQ<$AtaKnHyi$0GD>WGzqvTOoh+xu|+`)ApQ z1FV&-!ThzF+O}Cm&gKl)hDe=_Fbj^Z@MF-EIow^Tkd~R;!5CwA6mdHakM&jUI zBi1!*=Ax}mG&l{7dFYm8{#*Y7zFIbJb$97T)%S&=N>Ql4KvEZq_Sj{(^kjb7)VH;F zQ&;&Ur{4)h<>X$&r|gY8wHh{0%t5I1JG$F!4($3UBYAooAKR3=tM7A|%~chQzSXr|5KX#!lJOhkG9GVbC8ub>sg~u`isgl*Zc43lyB70h&s(AH zzmfJ3u-U1#ppaxZK1I7pg?L5b z);pyNcqC{0amnbi;7sp7KyTpmNchGXv8)JLkICpx#^w{n3U_J=_A69B{ps{?QRMNe$ zYqsm7(>vPL@5Vn6xW+a(cbRVTePt_}HQ3!RpwO8XzUSou^Pk|>4`wIir1Ltw*Y9RH zkbG6A{yP&tp1aY!2%4x~q0{83u}JJf?faX5&7Q*g7XXGbcL%cy`r)>O+7WXfrIWs) z8w9QrB)=@bAw>vV@F(LgNL-L%j(2H*ZhvWsKLr0N^~(Ybd-Va6Czy_WpIt(zROywZ zeAkCAVXN^(67iMV-(@N!lfDA&%IIPivjwV{QXO(|1@&-dDA;Rp!U4ykh<@5%t!H;rRK1|9%KC%Fo%$rE{*?Nv)w|t|48X^ zwmYSaSzJ~+GJapkL-)$DeM>Qf(oLyHZZpIjFeOMh-3Wcr0woOGKS;MmhgWcsjImDh zH&Au!;4E6O==y64C^yR$W&A8Y_8)Nu>>5k-pv(`zjIhUd>YV>GT5{NOMM4DL@`IlG zuGCHc`4PJPbLmggSeg8mtJi(2iF4)`<0?4oN!$6^c#*+I(lxlLvZ*KVjjH+gHlpDK zBuGb|Ye>s14z0e|B7+9ztt-`5gddF!Lre~T8t>w_fQonbp!y~(+TxY=p4Y!T5k#hi zz}m)1Dr(>A{;D=esVd!zkdm!*BJ0>N|6UOSTEq50sz0j>lUClxtK=4sXM80!*E?<1 zh-a`lAnX)6P>SrPy)4)Kfqdx!$=ncYXB`!ElAK}h9jP|hAf7{+EmyT*$lkeqt`&wl zrT`*2pcUG=K&NY%jqIF6d(AxhJqc9*`z<{jJ1F`e7f-(qGmMz)0t`gei@EscL)dy1v5>pt;Ul`tYK$pZHKh_}4%8T@|VVY2?g48C9!L0S1YRvMl zq+$4h8g4`=m-_yyI^^_Zv$`BH*CoACUr}JaE z?G90&TxKa%Wm87paC^4vyIWY!Sb>;C9<%?3xa3Cs<9>9y&=Mn2$iz7dEXd|qb?5rt z=KMZ2d&>X4^j(qpN6q#9=#lLuC?HP;T?`yOT%7VRMTGDymaZN)hHU@7%dO>~X{TQX z%EWV`>r8SXro!I#-tNG%0CLv4VT(aBdLkbXxW2R|K3i7j%N|QVO~8D|vAt5|Y7fsD zgtq>w*V4t9!C97b$G=;gTp%T0NrBU>nTHtGGp>e?uEyri)E+orl=V*u-x@-3C1@hM z?Q=r1nK!Z=*6LJ~)W&nlPsVA|vH4E|UmQfIhoFHz6`n9}gicJ~?STj5qhRSX`z>`q z&RcEo+5C!_JG;cge%`2di|!B7IvWN2AzQCD6mE>PI;!9Dp^zE(K_cRqTv%mr@42)} zTL1);c1gopV3aPX=qC4}AE#J7PImQTeu4W`9|g&jN^Sx2L8I5chSSS zWBGY}48AU>#dh|#GI9$fl$97|%}dPY=RZB zRZ12>N!THkN#6BTd{mm5q=)2YWAOpu)X#G^&1j-YR6tQkm-H&^@x|x$tA}Dy-XKx8 zpdx-fwjlm9x_jd4&PNi33{q$FquAF8b<-rVX4@KWmcGrrSJ8Xs7I8fD`ei?M=N1}lz>XB=?uu@)JNI6aaz zlQ`qG8``XD99Mna#S|^$OOIy6w1Lk<=pAMi4e^Gn{F=J41l zT{)T(9$U2X-36Sr^oQqX>EKIlV|CGO&U=p=4-=^LJ$xYOZ^60!oY$+vb1PYkIJ)5W z47)9)wd8WGA`Kv2WZcIAzE1qmdk}uB#$Rsi5Jjb9&D0@pEjD~_QBYHAv?}n=j5ta_z``A8~OqD6P&`p@iN#Icf)_>rE zPj+@5>>9B6Ye&!WORMN^kMoos+W8=9J6y_!<=RfF5ceaGhK|n2z=T0Cw8e@=a^2QR z1o6?0tmB6^%I?KDlWmS`$-tkjvD(pZ7B*J_YnMwptd>lt?kv~Q*~z~#+b9>oeD6p` zE1RF448Y|g%Yqk#|Bb@MiOqE{%-fT#@kty@-k3DmN|baih-X=Z>KnH27al9+g6=Ef zt};4bQsR)_fzPffO{~)x?f&T}beY|#0Fw;k=)oTA^Cnvv8HhJ`99yI;_;c7dm?aqK zH6nx$q}y=jVvhBRkfpD3HvMMEJ=coJ{B{j_Sgu^cIDDgg9nx+i&{k9_28tdUc4-~9 z&WyY_Dr;v2;ZFIMUYWM9iyfM#M#U~*d_(sIsRUG+9gd-oPIyG`s!KuwFIyee&$=jp zP%Dc_X{G&G{hE$d0yA(czaVj=aWv%ic<)Vg!PfC!?mR8JZ;*PMG-oI3fl9bWJhvvb zQPnMhLEeWz`cfAq^M!Wdw)+0@)408_ZdrqKic9mqqU=X@({hvy&WEf#g%5Xv;u+`` zGEQi*?Vs3Ly%@+l%q-2dv7Zphq0W~oLq~Fs`68r8 zXfdE4G@koR6elc>R9PbLhN!G|B1R2aw9E4RubiMT(`O1jpX{0)f!VoEsQzVq$+Y*@ zyAew3qp=Xz9{lEWkaSSWHHYVCIh6RBCE%M0sbwzDp*#eqsJ1Y%{nN4@;8=`;(m^&} z(qP&jqLb-okl#r}p6toxw9im33(MIRzeMH1ljdSv>Ks^XNd|pP+ik|Y0r(ppUP{zpJ`3t+XLv%m#8~tk0?l(U6K4x=wPO6d&R2Y^yHOQ1OB%%pOaUACN;hI5<>P_QeDzw3p} zWk20e@E5Jx(fGlK4-%$*%EKG2`a$tQg8^!l7{VWMlx$I`RdXRQ;nn!(6vPNu55xS# zE4f~qwazENXy>;F6f(*7=#nzU{!%&N`5GjKs6GFu@11-9emzP1N6GaJMxD99y`A)J zw_14*Gz*)8Wr`8*j#En8Cx zEB-ezgb=e7g1ky<$MraQEB+&LI*88JSHWJq&i#l7()|?3wkbiR*0VSJ?b-F@KJ`=u zD${NXbi;CdampiGHHbt)veU)~iVJPZJ@cN>cha*BiDLjJW3Npto>J`zvyrzTj;M@eB>b=EL)9lWOa#vgj;j@06J)-|__Z>pc@EPKYj2W_``BO5hj z)^2m+0^VH;n%>{E)gbSqv#=Y#;RJA+R@s#ZV&dnBelS69q%4^wcfqV(U}^3iwy#JR zhQVC8w8re8tQ0R~Zt91Gvg>OgM~~vMXnX%D8fX?&mlR+I)%0Ly48e`vc3%U!MxIC{*I#uOzRX}Nl<^4vi{|+FNAZo zN>d%t^xf_Ah!s$9p4xFxJ98{Q(S}8dDz}EFd=PzZWF4QnSm!&)9vJ>aBgi zY5dHL(NR)M}PlA=9iHDY8d^NAL6mY}NZ+@0ZS z;Bo9^PD#LpdmJ5&>jaX^gfFVZ^q!v`Z^t)(9V>$&UH#izS%zRArQ3?frq16FKZsdS z)OtFojYu6e8#l+8^(t}frN6r97`6c*!92k>TZBd63xO(lk;zdVC3I6EXr9Cp5>Hl) zm8UkEj{7$-y%C*rP*}UuB++`mQsK_J)I}Z#Vq=6mjUs-|9%`kk7de!(bJC^4;^UxTSMpQsZVp;Ky+;leBgH`|JC6Z;o zaE!$r7ukzl4et{oZe-3{F!u;FS-DC(WPne_xS(D5$QMnt+}R%z02BguW9 z6MTBEW-B9_6vU}1gW{X*H?)!U<+b~|91a>Hf+<7>FwHhtbF0n=rgybsco&yyj74M*1Y=q{i8FuKKa6>y;x zB?WbG^brooTEaJgMuuBC{FHT7ySzmjP)7v$IZhp!2X*22cGa>aOA9uL`~b6{fg<`Q z1zyc-qejBj6LMzQQuF83iz>u|^nlzF1nf3RrEvGPpf`F_Sy@a<`QOPFKG3MnQr(V< z{JoON)u`lHyY_?PzRqc_Zo4JBo@Sz8;+L^{bP#TVqwgD1@4I*Bm~1F`7s|0Y#@s0e zR88d|NNd3{-U8Khx(V4(-GZVB8>2Eqr|9WvrGHjEBf9bmH}c(aS{PG$5Lx^FCT5J8 zJe{&fual-NJpczBH{Y~pEEInFWcdMB)o2J+4|x`pVqQabE$&en_hk4poEB)EF?b)b zA*m%Woy6Sc^p*|qbAjZ@Rp#NukL;Kr}Q=AzG6 zy4Gc7uV{JsIcbk{Kxg4!?vrv7v0%GKI{WkrT^zFyo(pHL<_q;lkuT3Lg#290uH^GH zA^bELgiW0S7Zdg9Yqypj4KBKk54lir0m99xbN6V|#)DV@RzAeLm zK=p>~*PJ^sF46+TLJ1=WW)kT!#Qd1?6xs3OH-B^=xd9DYYs0M){Rck`Bo8U`5p|%HDX;ot-Qft{|2a#H6$mX+JUy4o=b-i8w6@SM2aT zB=>zo=pjerLVjZ~ZPrrfOVfG6wBJ1J)9z>qJx8d(slLE1$uab&MdBH2 zS2_81G%dgCP0zStV!H}#DwMaGjvg0C!p01lrwM^a0J^>tk(imugoA)YmYT7MgvR7g zOpj7Eh$jh_vu6|?8%y6SYG)Pyd{;S!+QiNd`{B){)O@30eG8iqp;A&^*|{mQNC9!^qRlPcr%VHCfwLas|6l51 z!MQS!+NEAETcZ(?Am(QRRbM6!(*N{-ec`Q3hx6X5N+}ubT)cpMx=!>aC?xMf&^*wqK7bWr0Nu{%}ye?1BsJ+AO(%*K~rQ$Py7Ge`y?^tfyp zI~NAOchJ%aG5Zcxs7!C_4}-9(I_F4udQVJKSqmVe)!Ir5rO3T!?R2ec!P+RW{7*(s z$JIUXNb_($UMN{=H<(Xv=scP6xTMgi_LBez;s%(_>dwSQka@@0tzEFg^2{ z&%eT<8*&pj+#bL93R2NM08DL()HiZwI(@@(&7B==hHB4aKlu~;sJ+t_=-K0wvacp2 z8JNsNd2*boqhVej()`dpq+ZAgSHUA4J`J9j=l<2zBgJwFQOuWdKc2Zql=( z=y)c%tEw)Xq2?O%D*?IzbKE2JIAJ`-M}m0CrT|;yqy%j10_f5I3>^10yyL?%mLI|L zh%dV;S|_&j0Q0y%duqS>_hrp=sq7!oVe3kBfN2`r+cE*Id5`SvWI8~>Oe+r>7^I_E6i1#d9i4b9_G)shQE3E$ z7;TA(eoW;)liTgb7cvUZ5s?wj^$iHTw{dsvH?yRY4B^GoW(Pqur5#wJE!70*DMM?7*|)%#2m50hj$L z0$?tpvBm37y6YQq#53gA9ijutiA8-5TpuMCJLqLc4>}3>zR<5+5SIseMUOOx&uJaf zM;{*(l-7_rnLtLFZY24fVr{uR1b>c}0{0GUxoyjGA9-kEOF4Lto1zR=QO`+wL`{-yqD9eaRRA~(LGe*?BvI-3Xh|Ih7XibmDB zl)01319%a~X5-|=zwhZnqZJKb_ zGXWz-@-gfDu6DX(8Fxm0Uf>Lk(DE)*Vf+WQTcF^TP95i1bc8jt_*g5iq}8J z@fTOu9<15`6!_hvDPg+oa`=K0VWgMA^J9JBq6nDWja}o}Bc?IdZ19Z)P52a2EZG#0 z7Lg^U%I`T*sF@64GqT!P~r^C?{#kkupo0`T9vY zr&QPyxuv#$C6&A{MjFJkC-$RcUV_Qfpovu8A#9*{6?dq54;BJr{2e|huAC-n)%Yn# zwETxC=7e;@iN+zm#1W+Q|zSw^4EI;f;I<$6Evh}ael*A=HY$Ol4Q?sFC`(5%fis)P*dR6IZ6@GZWskA;OSx0`A z3K6U-9ANPVOJ{RiwV|#}N=eZZ3$QO0+P#weiIi7@Dxl77XW6UA6g&DbuX5-Wbv=P- z(&iw>%saHNpY7bDy)0j@<)ZD&3e@y{T)}in6Z$L3P7fLJ^sr7WFGUDy6y<~?(_#Sp z1HzVYBdB3Y=aKWjNrqXCycEeEb^CBR@?S{NE%A=gyF6lRR%nb%D>XKimOz=1T4=bm zkD`&zxv~e$@iM6Lr#d~xzR&c@2sZsZ==?w!Q1AL(*0IHnog@|d(2@Za`0SVA!HE$q zlCeek9I=Oxo@pW^T%i3E<|CPLLR;Y}{A}zoWsX8pYyy zzPyVBoFIOB*!bmFFR)uS^=-o_Rq3?^z7>62YWx*z6SJZ=^Zqq=i2f&rGZh57p9bhN zJ%=ZXeF1XsCjU?HDjq2K!@wBb_mRF0{q{eUYY>kS!J#>$hK1OUXtIt(h9b_q0Bk=x zbnR{eZcoNX#c+3g;0!H5VWFQL(0GjfJ-hxFgOE#8_bZ@>re7w+Fds1FC&uV`+=6(x zLjV@k1(A)}#yMlUK^*#o_8ZwAujf#7{d`@IKx?QhP9UVkAGR0^2h&?VkcfRO@h)j% z4T!w&m>g&WYp}Znrd2}Zo@eTABoSg71zr>u)LS-5?ajYxVb`Flgw+`{HfC6}T#v`^ z1rP|ZH$I%Ww3oC2K1fTn*@c3Qb?jh`o8oRbI)@vdAXz57Pc#VxUu(9EYBE;|qJ6!z z5&cCxHT_B`@qaa1YzE8N_hY7a<|k=o2IRm#t{4)KG`QSll*M!k5Z;GZl$u4fyeyTQ zh@PAHgyl&1+ehPL)X8*Go1yi9ve%3jLnPb*pKPH7m4^F)EFB z9yAyl9TgF0!aK-6F|Ka^N6I@bS2~V+Qq?<<#VL2pS|9y+GYqR-6^}|MVrO}3$5Lg%4U&(kj>c>d@=nW zlnasewRwcWBCY7pQ^!jrokDV6B1k-7takz$%ehpA!r3$P6fy^SiGjyJWV$J!(d^gh^v4+b^f8nr3yueSjdI6?%T{ci8pB-{L)1h^FMY zeEJ1&UCDg;3uMXUOcfya%W;*`{T){PI$CG^d_yOS??0D~t5yGFu1~*L@ExlmUv~pY z^N~VgMpTK3Mx1%bHH29Z_n=+iQB=;q-8EtQQ@^e0!}K_zZr1c7%vqd3LI~YL=;npnFZxn`8t-_x(b^<;l34-=Oyj zHZ#mXDKoG~IiP%eMEFn9AN*3d%FVUE>whDXovUt!`&uUbj@WO;3s`XLd)Exuk6;PY z7{&Jk-Jz1_(@&JRNr|{*(Jmyu8+~;t}`$Qk{dpX(gTJS#f_$6Y=Ce6f6% z=xv)k9Lv}M%}F0)QX_?1vx3r1;Op&pTERJSU)_Y^Wpu#4JRwo}$T5=QBOWBB8aVYChDYAHnz-j;Dhm zFCdVqNz0fo?CBWCgCW?6CXTiA%;(v&@p`xr5i?e}?UU5^&!PracD=jh+T3r3oNqQV ze_W6320lm{3T{;j;24D((FXk@~+& z?_aLnoG+3QB{V4)JXo%(!abAH`;!yRHBV&Q`yYvdikk2auzdIpSl5n2@j@LC__+}- z+DXA4(M@Hq&Q*azNGiC1%pe0?x%l;QnW>muDYhd(*zlVd8gx&6z5ilW zx?%d>-G*=&v_(j}QEC5)HTIkATjxJ$X(zT2h_>{v5@m;==0@}ouFlJP zz}yJcp&^t9S2CN!4xx74lyb_x?#eT?2b9s_L*MF<17!0m14!2)mfUp;~jvM=z7K>_}7N+{X z755H+932$o;Qg26h{aYsY451D=OtH~4DTIxrmTyf%el9N zc4SI7^=s`&>&>LS=RgEB?>Xz%r$B=r-}GC#B%e%H~GjNiqL zhwGt4>%6L6jtfw06rjXjNE{Os53^BSIPNvM%D*c>hP*s|r{A0l$T`x}5$u|t&TAO*#qWSEa)z>;c>~D;9LhL=tQpsnw`bX4+wNvQ? znWPHd${sR3%1Z3E`mlBq(q27jq{?2`S@_#4MW1Sp}3JMCge*o|=C>wHE&yxSY7q;(NUNJ>G^L*CQ4U{gWe2Yp6_+h04t{ zk)_n+N$r%^`@Ca>-1N0Tc>7=V32SC1pug@$W}yzpoS245 z*C1Y=VlUp($l!s~qf(iUbpb9)?8zf* zfv&x?a<~khxvx)&a6wUpWT6y1^gN(uDKYf)W8_zfTMQZ&)4{^=4x%`SbbTz}pzB{( zAV)_nRnB9Pz!;&|S93fPOBho4#E&sa_QCNp5dwrg#DqftX6_LNt98Q7O1 zP_-EYpV3PASg4AX$3@&>jk!m#7YNegpDZ7LLRuA*(ZhywIva$1o3>+YY?jvm7oG_d>!!Z@Ci2MU`W53q0#8;^ zue6^o!IYtBXAmTNs(6448sC*4BrHtXZE}uzcE_P zh3_l>MqM4~u5!g>$(NTucAm5@<7CV$vrVjFNHEpJmP%u~oeJb363QYrePS8pP^iP% z2z4qBGI&es^2ZedD}u_YiJj_y%AFw(O^NHwR;_~bP;pw~7p$wSq+!+{zUW}zSz>Nt zMo=5KJaXC19xLcOHpCX<77MjeahQEnDG4-jDe8qfQd1C^6FjX0xfqEz=*> zX71OyW1>|PC$yl`+a;^-N~*J@%#7xW$T>3M_`pU6;_579yyJslrQ6tgAWXvT)wv5W zYh;x@*xCwtN!=h%Ed?8qAv$EdUOefySwlqP+V4dZHZI8m{24y2cKk^GX0TI27a!sg zvpE$1V7nfZN|*n8aw4a{Nc!gsQ1qnO!W$9d`iLLhz~-aoQ(j?yH>mxyzoLYiwS*5F zpY@WHZbLdL>6aukV_nkg$)3hqR}#xVZ8XRp(3)IZXvJ{CTH_5fwkE5zwMpl+6(*m% z9ELAK?=G!Z?T0X=TNnB+t~=|LRpI`ZFTW6BU-I~?6JOWzisCdZgVEGyck>+&idUyesnA>WyR~n zs^j4O!r7jIkT8EPhue#m2C{|7yu{-aJYKb!JPeUj{cSw8=+u&$?i2l^InH>wbm10S zf7iy0A1b~5&36WV#B5v@!wtFPUv1-eVl|?nCo4)83aAQI7ncNcjLhMx4ji1KG6kFS zvh*^fv>q1 z-_ed&;L#pA#DC>ehCoXYv(yP85kj4Lav2`4%BT~RY?9B;&7m9hy{gPQ5onUjur(rBV zb+h6*FAAj{VQ)-h+I^b*|Il>RVNrB%TSP>5@)GSda#h?vj=+X?E!lknUKz zyO9p*?(T+fe1F&X5A5zWGv}O{^Td5WF{eM4$86dSXqD;ssHj#~C_TnyifQ_DwB9f5oN!ogx zlYQlJacv1`C8~3>2y-H{9$);8OmZWGpK>_z0Y_tsGl5FgDg!xsVK*zxzAgNwp?l(C`4bO`i3lx zO~*X2E|oGY`BCfyD4k z@3SdcH4M$z*jZ&XmoeJOes#pD-%vd%H`gwX*0(d@F0J~Y7d2448l{0`#q?P($vbB5 z5kcSHBcbuRkb1*Fb7ANkmR1##R)~7)p(Z!>XPzB?uLxuH#iq5Wj`^T?3v)5J^uS;! z8CuE8WfRJz-uns^NW=S*Y@X3dNn`mLbs33T6ZKI&ds){b@#*MxvL$B@b(0<^5)ntW z%QHRuzJOsvH8QvzYVh0*`~j!`xom(C1x>S(kty}|yE%!XGT)bSETRs4Oh7La9tQKISILS`^KlXi@7s*Po#8YlQWZ#-!>GfIB2vc&`q8!Qo|V zA~|-?QHghm7;>gLhvUT{8F{N$T=!VVbYwo$h$Y~+&9c4a`?8T_jybk=EE=AkbLtOpmfK}jlgEFbI^qU5_6H0!aGH@8SZ#D z(V51P1>K9}*nDV1jjYMpLG`lQWa;O7husBx*_heLepdeXF?#2uQKcl1Uk>Jsi)()y zv62HMS3-o2KR4PR@>f$}xDIn1^bQX3UozJUTq-@O16_d1NFbvVKeN}OS`Rxbm481? z+W-5Fd0}nr*}e~TL5O#xM7ff8;oXgq$n?l{!?&SBh))EXvFD4gmC2|v2W9613Sf_PsYXg4| zkV+eB?3AOV3c4EZHQ3s^JKe1tckb}IhMr6;4bs$2NX6^@P1Y1wg)3CAy}yc7sCpCC zU-(VqtBD1_;!k(*!G%O6O_QTHWwuJ@xmdptC*Pe|MBCV2D!^zK*eU#c)iHUtgOTLXAq2csHpQcDAZlB=5|IpMtf5E3qr^d?#B4Ik~mPTnNfmV z#?Cy<(>KE1hyU;BACZ6H5rdH21uOqnDUBI+10zG!{rs0k8<9WB1PEuuX1f`yVMmb zi+vv#hp(gfWkE*z<+F@}viYws%+>Tp*V*<$d}ML?gGJ>YT^$W;brlzjPp4C-Gs#uw zYCm;rZ2}HoRdOMy8H@9(wkEQ^>+1@KFVHHv!@iUbQx&QWgO>ZV1Y<QyV+?{|s7J(X;VW9~T zR5Jc$p7SVu*(gP3WKKlg=C_d!V}E_%B6&C4(Xez&`TL24zv2-)xg3~|@&9zGuF_J)UnzsujYXInEI~2NNP`%53b*-)*BS>Kw`(_p+rsnMIuWsYYRG+7XohB zT(o@bA6L|@v{Sc8Bgvmc72SgrQOb`}SkafDhqt`gjy%7Yffp+cYs(gKp1$$K3*Me4 z)*jrJYzyS(V|buwPa%mjfE!ulNKtn0Yxj$P;;{dn3&|gJ4ZIL;lKs)+Al<;%cpc<) z40hqF81WjUcw>8HwO!aMB5Gx#Ik(_D{qiEOkDe{9#{#qEQ}xE{^0BpvChfVF?CbpV zB_V(CncE&~h($R*1M$;tIgKYXspi~Pdr*Q*I#c;ubo5f`8JbZ6k4?_+B1nCPCbJuT z%0Y#|(JQ#5qsx*mq@-@>bFpg-8eg6j8mQS}%N(k$9=fHu?kAWouVX!VPo_otZPWvW zNhXE=IQ%u-ZPu0yQIo0K34i9{=_+FsA*l@cBHNWwEK=R85h$$4);3ab%%S$edDKT( zN+xlIagMR`rjoqrgFvsTdbd+b!C(n3x6ou5%G`0+lZb=**o(-SkI_DsxAKm;mU=f% zyL$grs~1U!&BVBUUysA|u(oBS?do%CM#AOa4nhh7R+KiZCNyJ zS<~x{oj{sF%qis$2mN(r_m`fiz87mzkslf{i9)Uc49~1rV=8b@5hTP*x+k$|fxeS* zUy5oB|J%^MkM-q%)W#=RXnrC{&e_^U0B=U$zZ6MGZ#d{c#@Gho$XN7wqVSK?mZP3@ z?-fZ5O7e^#Dko67&+P|^S-DJHgBZ#KguI+HZpp9XhD5QBrFMFVUYg77muOKxD~(#c zVlT=zA~FAk*CQ=4FhfG5nA{@7VXzI-Z|!Xg>Lhsp03j~3wn#8q&$cqojQb6aXh?cQeZBG>N@;Q_3G^4G`u z3C)E3QtqA2LP{dVE;WTf255kUj+}?I>5$wVP6fTn>`_tLBloB4H+`k~fwtX%LS;?4 zAWZ&9)GnWtwV8J~qB#}YL~Z2{ISpv`r*7}`-uxqOXdbhcob|X)#|m~>Pp>o55Pn4Z zuZw)E+!XJ>VW>n9bFy}h`;~a8!OP_K6ZuSx`paTJ*bniCATjy3NuBghOll};%7$Xo zOl}7&vU_U|T)ay`7HcPY%^9!p9)<9N=gv!2^-oD~Z(=n%G+nlci3N4oF0}$lRDezii2dsURXlGGnv=P`il{eylKO z0f;uC2?LSe&d-PN{lc%<+Y|dE=%N5?{)qXJbzgd#R%;<5@JI3iXU(Wn*I9B{!~mrVZP44fj8DX22mgi3PJ~@k$!W?3&19eNG3)x|FjgDE2o|llgCj@&=3cNN8 zY-;9!JEw%FPI*HDEe%3O1Dj*tv2T02|2B8O04W=6C#h6f(+ko%O)zJ1CCv+bBsaa9 zHgAm@y}+tr`vuJ(Tz;=>N8b!Gcxe(a|Fk(V(zGG-@Ra^$uM~GRS^Gvlw5Ta!rhVW^xG=wC;poA zgT3!j2%uEs4$Y;WjMk}MFnL-@(gT$S&_&uxe|6K75nUbL^z@TqXl+xF6^kNL5Ly@a z$)qF4l!;4=J7`B^(`v~@1P=E_TCGV+TB&ks;Da;978uD?f`pR-|^ZZ z`^2A9^_W1Pj!W5<5u)zu_gubNdz5ld&hKrwQ3MhI1vV4ZY z+CIlO&;i3f^;p`u@Ew7dHDkRG@5pc0&oeF*ioQkwoST=QHpC6}AsCvaEkKac2TrMP{WX9}R*1Rs?y8SvN~qlo41n&1nVvm>F2+=UCS1caQp< z3v_uGo`qNoq{kJQ5Xv$uy70t(a(<50g!CV*iVUNWW%<7atKs3bjt_1fjk7+AFelc1 z?Bh)^z6gY1{=u`5hT!_3GHIYC6bB zC)SB>jy$@`(HGEM$?c+J)ZyKS}?N9%|;N8>g} zm7G|=2khAv;+_O6fWJO((+;XKoF=a+N%`-=P_j4~3H(1l3lmp)MWdp}bN~m3K>)3v zP1cOb>CIPc;tYCsc42@g$#}&i6)&(FXkK)yDxSRO3mkSw@xG{lKw1H|4bZR9ytL(+ zSjM?=_94r*#KNf8qYD+|ZuFArdZ?{e%HtPRYcoy&Bk4(7p>MMk9cp5~{FRY;sEFJ- z(HKZN=6cHmy*NBli;UQqzh@BKAlEh;^^g-qSC()>ZCXBz2LE%r%t?y8=pX3OS7z5p zKM&e=-;TlMJ~G&c`*16VaBPbrB9agPxWebJ=wyUpk}$rARx=EjRc+I_<#e(C<8Lmf zUb4=Kqgn{ofQ!xj-dV13lv3*p+hNewk*zRF+kRsxx_HK4Hs4ueWI{kXk8=FCvlyjs zIq3SPolG(AS@6ru7KcZ&q}N95`uO4QYSGWWCBR(k7k;O?*c9tCjWBd7gZs@RzXuB~ zsbd;2<))!pN)pA6Rc;qio+)-|{Q3NnAuZaOxp25i=%(CnN?C=O9+(H^tNjfK<)51J z&e@n0FY{rni*MPaWS2%o`Y5i#<1cLL1RZ45LK)a(jReO6w#8ggz2B+M1<9ALu6BQS z4Mx5Y7mIe%tpF+#EG5{FZb2i?{7jn%+H4>%8LU4^WGi&rb+5UwdopneWlJJ76BNli z2B_P@O&qgs>RCtsQb=Nq5y%S-!VTO>21eHO9eG!pWh(H(z7<3T{Lg&`f*j#V_?O_= zQi+d86MxvVWlCL@7{jq34WRdNYVe1ga5spwTC+f=vGl1WJI406rtfvv)vd_fHD1+u zDfM@C-;7-S=&6JfH^KHzngT}NCADvCHKi0_{X|H6zirtUqZUomnVOI)j*;TU-lpwW z4GeNsMEo4CfSgkl{6zbvm>YU^A|0K%1lx7{arfJsy2f?*;R?r4#YcXI93UTmMid5i zr1Plvvk)SYt74t$J{6oqNzXV$0GRm3TZq?+O&HiQA-{;iN$XOTCs;z=$kV)0!=Vm= z#^1%TMCTa>1PA5h2&jc7kE7Gb;@ya=DyTPp&Z#^}S&}$$Q1^9`QKgDc&)J9c2b=Y{ z6hEOud}KX8OgZ3+1j||E*4_a{S-6G2q(p=Jfui)T}m!TxE7Z3ryx z`8h6F=1izu81KBrMgCDO>lw8fcQ!o)@Gj1)owDiSCBlPbY3Iy=^y(gW&MT^auDuV& zri#;?Yj(PJp4F}bcYq%MFdMVQle0Z{((|(!xo*p*hpq6n2SG1#5AymN zuJ3m8A91S?y|cV(hvoB%0y?IqYIFJ+y{n53@K#>` zHlU#Ab?)Ukh0HK#ReB_Gp`wK307YC1cdp`}8rM8T8hzfXYhhk^Gthbis#cKFQF&3* zuAh^`5!QdVU#425Z-u3Mr|SrbVO<0jaa1jtGW&x-@L1mWK8AWD>w}%M% z58)!QEpPos4BNoS2N{W(m=soXYohsiGv}rE9+Tc8npSxzkiCe)jn$}RhmL5Y4|YKd zp~0KsVxiLM%bL-R0jt+Pfo)<^_hyF1W2^4%j@DyeBoe?T|zRYHZ00#(rrOiTl5JlHVa0IYWs?2DX7JbML&0*&QfCbI&0XZp6zP#!e5n;K|F~JBCR&~F9I8wHcpkOkxWTCY*#<7(rJ`DRH7HTvg=#c?Um4!56{)|HgOSH(Q?{u@(u+hNrNwe5Uz+IbZX z1O~;%{E|@}6h^o9w0i$z)dup=^i>w*3drvRnLOhKKL>o*>`H4RI`I0l1^a{7|D7(6 zO5xJCFL;Uw3VCEvprZo+JAb(El*meWU1ZvyUF)%4ax&H`^oH%#Vdb}>zF3<3gJolo< z;G2>%BMnLicwOT7lLprs9%={p=2FOydOK&H^yqHo)ro?~@YUzDv74dYE_nOCr2?rD z^Khlljt(S)adF?2^N;;**MNsY4*{a)7>WuolJ_)JR{g1D$I-}QK-ed5vrQB;TsU%H zT9@m&H92^5&EEDQUIdGO`I-Wn|5}jc;~_x+)znwIC=0~-Y-0CzCg8)ChObb@t)Ar7i~j>f{F7&d3B|u< z!+Ya}>ncKbs9#1;ueVKKZ>xMh4B;JLeur|0N83YZi4z`#P0tpd#~z4L`ywz8&NEF% zj`b{L{rz_cS0)*1T}_0P>`x^xXe$RgXOy}NR@UMXKj4WMLuf1X7Mok?@{9LsKqH7u z{2yN2*iBqojk3CpOq5*%8gNh}iV;h<0=3a^p{&63x&xK_(^EAiY{J`zlw!3-)?T}@ zILh{2evuN!U~Ub(uL3qytKzu=kOE;=;L*NeYeoTtPt&~mZ~zNbZwA!F6?k$kUOb-) zO~pre5t6aG#-NGOh~uP36zF^~9* zSOYo*_ag+^ys{u4eXKL7^RdM2d+ybAIkvoGFmO&HSc9ufE`89uT+A0(T;QgSy)4Ke zbAMCA2uud~QA)iYYJ6~2@cgBo9vZFUTE&-DLJyTJWG2!8mAi8jyAh@b9;!fJ5L~4k znN8ckt5I^tAArOXYWEA@oYQMs;4G3WspKbMz~fKMWZZH3pZc`9L`(V z_~!WMrdp9gH_pJ$}Qa6kjFjP@2;tVYPw<3xKYGRL}1c+xEiR{vzeYDeL0W(peQ+bPsV9k*b zb=`t3W(lvCMsDAWa74zxjuws zTi4lA;y*4|s6c@s^tohk?40;-Q^`Erd8m|wu6liYcQAu6B$6yP0wOg*=4OHG0g>_z zA~%?|%qBhTa7K{K7DlFYcih@QrCehXJ}$};og1L|1H^j5Tu z>&ZZrc+hV2wF7V3yJnQDh;Q!2ekxKmga#6~8w!VE)r8Xiw=d!$F_`WK!lPV;jwK9n zxwPLF=~CSy-kfr3Xuew2-19(r;<0#Q;I4jRT6i8MtAq|GL1GS=CZhBy#&CknI&B)L z2F?z8vet>#LmcFy@V>IJ5B%W7KBs(+AjiadNEMXdJ420bV_`_0Amw2OK#fpZftUPg zqJRTstN16M}erTa<^#APVp?#*y2j`P^ zxBH_e`#xPK0`*x6(uYbnEE9TfxFJSDV-zqwF8vqrw)_Its;!s;V>7q2mifSDehri+ z8}pK`hDrRjPlJ<9A5Q!h=KAMi{%)Aa4S_^?z>tY4LsNAIx*(%SD zSPu08@cd`+0OI`Ed)f>ONiT(>MCcfQ9C{P-KiA@AI`}@0RFa*}Fa>I~Fs4RJU;8@` z3jX)W&RX&#tp7j6rU=D9a^q+)ebzH{XH)+wKFD9{oDMWwxMg?zn`SJ@TJ z>8|bk76_ab?4p%TKYYa0s)~qfi_UvOKi(xFI}*$Tw#OVN4;c#zb(Lk#gS=Za0uxPZvvw`WsEe3hbr{W3bc9eZAn)GfT#WQ3r=^=w8Y23Wz>?~*DyA& z=!m$LM^;WATeZ#SElx#9GluOfox8{9bY!=m{_jbxC-21FnT&_&#{W_>Cx3Z|bnj+1 z-VFqgiGE4{iy>>_#^(hJE65u%?c-d^n2pCtWMq~{9NKdzAbGUt#r2IAoU4uTrpgp{ z%#_Tu2FV!id^RPp{1TTh!IqhG%F#%*`zb7|vjsV*b7UuARKl>5Z3{a_Xw`%x@G%`q z6%=p{nFYqT$E3-0BR4j=vYL>^4*#H>OM#@RK{s{-G4i|Gf;*|(4_&1fZ~CiWNI4PAcDew7t zhf|dhp^`Meel2?;2fUYfEPFPDo?vevA)%O&(YC1Sn~>W2o1!Azq zYau5WYpJox*m!nWy;zM~ShkgJI3?>V0ohf#sIWc8E|jP(ClHAGn@#T84WX>~pZ^Z> zx&GYgQis#Hq>$_7Ud{TQDtFg*0pA;LOFAz6GqRSH`~%$J)+>z;MJy^s28(cE)KghE z*;83gHT1wl5jtaPTA(eZvOz;L8Sk2Gxvsv8RnXxWA9gc|(QYb`5g0#p%k~Mqh@Fc} zX7J=^bD*&61CY_z;-(vfnjZ`u21=^y#;Ep_fcPV$tIbO6yq9sW#{4ewuo8ODNmne# z9v##t1fXxP9<7~?Lu5y1JwRKjZ8WvcpOexS5SFHd@!n@-p-CKAK3KL83e*}UAnRvJ z^hqaWwwbUI5^INSI*dLQx-+SfV=yXST)U}p3s%bzC;~Eo%@tW8S5057uY2?k^jn#A zHbV7rMSjGEp?pQv71wF$LPwS&mP19JEHNE%uPJkz&<*=OA*-_M7s38Q*dxV%{y6z4 zyJ@T6E#I087gK^6`x`g3<@C8XCDF4z#+qrlQLo0|Cj`40efFX9qQ?QMlrORj`D|X3 z=TNpot1ZLev2{4lfp?F5XBuZ3pk?!@(RDMLW?AkmQXG$uJsfAgO)OJxS2R(|= zHYZ1Uze{@>;Wz!_z0P{6rht+wz3}Y_de{#%t)?AOoN$;{!8;TFI$$v=VBZ%sk5g@O za+F;jg#ut3(@d{1beO8=Mh&ZaU#G}UPHDjcz_jo@P+q9i_l>yiyYx@Z?@4Ym)*HQx z_@NOolSD>yv!c&ZBf|BMn->}Q{ba58BudaFQ_%?8cP35Ef zb~+@6@r~Vo5QxmuGNX4XWKXPJ1aKeam(YpOhoQsjG*sEkIN%K5g&}2VTcD>cs&bw! z$_QA@WE7EHGwmtWo#_MbL{_^#ql~Kpml;s|{Jfkrj~GR3lK&cm1^*S#g&WPq)th?$x!?wcp>rC!Ipxi=-$3p9E-lS*fTXp-=1Kg@Rr? z1>IF2u8*dUVhWD}Z2&&i<$4$3R?V_3Jr@m9z95L~yyPP-i>($IT`g#-wRp}F+V$=E z{6#dH{#|41vXm~cZ%cD-ccDIqxmg`=_a$)snZ6&9if05Kt_RghaUl2DVg;>F!65)QdDH35IaL3Qlo2ymvf7`ndfY zlw|mCB=B`{7=IIcU_HSxz20Yf_ZmwLR`A|+;KcdQ)3fje$4;|LnQ>K#&yRASGOnAQ z#J>1-(2hgN|zX$Y*K2MT9Rl>Uet%xJeD3hpBc)Snk-3prZ8jY1-&< zI?p3kz8cpt^`C9&>N)x9si12o@(zB%a%A~{(jZt!LuC~0TqYkhH%zy>W>dX7pX6kY zzSsNfN`JT*?uw+I`c5ZdU81o&$-w#Av&#KC9K&zcN&c@q4fVFrzohNqk`tjdXA^Z(nTCp?UXJE`Qg>~ ztCDy==i15XH}=Mh25Bd1^uP*40)HAR!k$Lt5>{6CY!b5XqU+RivJs0gN2#=vG~}kP zwI0Oi_ir@av+bVcGMwZ})>dzUkZSyzA#aX@WI{fyq?@Y`Un-cKHx6k3Uz*W=2aB2V z>03OwZ#1$9gjjdWOt zD*?yVR0hVfhDx3n1e6VEd%%C;T6r(Jz1aZ&H^<+BG*d={GTk#X^lMbGlP}bR&Xg=O zCnNlqWZ$H0cUTKtG!AIvTjFpln?Jl{ z>(rXZUL~lw7{YRwnEf76bPE5+<)*_Yd6`^M;dHf)`pVFvpR5DIBm-HE#S$+UGmB6C zyE=^S35qOtED6nhD{A{&n#T8<2wap?ZADk8NzN|Zsz`||n%tv)+il&JsZxN_ZR)^mrm@`P=b87_SqQ9WX#UoXhbmb~q|rP7fc z|Bgf9iU6zajJxiA-QBqa=hO3MobXaCPkhlgE6MIeV_9<=Eq&?=U$WnKTqBBHz7Q5! zeau|mu}AH(3OnhsF#C}WRrcPJi~7rQJwik2$g)&uKG)$VJD1??SnyE}53RBZ_#5lz zOBLvJuUvu#5w(y1B!()%w@;E6=Zrn)yjr-0+_n}YDcU~r&QzlaWq~>gJv!-Ji^IVq zpSvwTWu)Z8Sf6T=E-Jo_zdV4?>$SEC=7bkb&#aSkk(0Hgb7FKq9fc^@Wq(QQV=~ zr=LW2NM>Sj9<1B9!zUe#?o2~tVCpfC;=hz#1&+#TMn)qaV2m~R4EGEJ#FKIfJIY}b zz)J)e{n*pVsXRO8+;f-1wGdVItTONnr7f%SHVaV=m=7*Wru%9Kt}E~V2JdErio+o+ z>}goJlOqv}Dj6Z8QPLTHlai{k8901>4Ou02vWj`=iU;zuvlGYPWS&imv}CC zw*^!j31N8|Lp=8~>we#~8i7z)XE>wzw}dF1;;pje#c^SexJE)cY|mQJX(a9*{!y5N zKo_s2iNHtAFFm!b=1#BK-@VLM=DKI9%>Pc!K&<30ve*h)rcpJ zri*Ii@>dQPqO{0h5awbSfO0{%nnf{9ZxmtcGO!=Hug?|{(q3(&)*Fe8(!*;FKR+59 zI?Wv%uZC88o-APc`lcuMvtRa19pjPQ07FT;1uLMvN)2QSwb|psP=iKF(P$;SWsBH& zcI3b`Ir>|rk9ht%!{}nT<_o7q1)sJ^#y6cXhOlkzMm@Bh1}&kO5AwttSX+F zdVdMJkQ<>T%8|x<`GPfyR2cchmVAA2GCUC*Ww&FZDsH$2Q1x!P1o2s!y-uIdMXX%p zvxxeJ`jvEpTcJ+C=5TymH0UZ z;$Cj>%b(=u0@GO>7s+$s*jEvMM+6Y`8h!rcOCZDeXM+D%LmJe2hXa}`nDdAM8mSk( zAN%VNahK{lY-|joiYHHAiP^HfD_YJ`^woIVe7u9PsUCx z9aZ>(elPwjX3C&;S&s+)3RM-oGgpDFq{NRWuhDy*3@4;BcyHZ| zK&7na2K{L7bd~&hLCZUk&7DqtHmmaUtfo`$b_0JK-taGbt6>)9T<`mYU9RO{qyJRF zp?oZ^>rSnB@HAn|FX5LO8yI61K7$AQKyV?1W#vgc&a^}RgjbEM>uqn4eWK$Jp;+9v zXM;9?_L1g*ZV3!#bST%6^+AF@B(%~9GPbHRY+*(Ka?g(imNg$qrIS8Gw!Z{JY0W`E zpDaxh+mGY1`Koy4_7%!v#_mi3{y9AwG}ht5VJu;g%hu`LBEbvc-(Va@I1SdiOqbX0 zy{97I7eZZoi1`~&Y$$#Fs;=esN1U?rzZI$~r;o@QB)kgWr0Fi9<6wX*R!Y7Nsa&y ziSLhkgeRTvOY7U`_ODlQZXU@Ongc~48@4GFT0v+Ed^ofx0jz)ngJ=Zfqoa-PO9))< zky~{iL%9{KZ~9pDVU)~CENT7|jwvP5{A$di);!lhcIDiOBi5+z!rBMez7XYmcjwmEe@RyBN=*e#k111lbI%hm{8%(`8V3$VhL)8(*)gJ29)jRiB29P$y_fhDvi0`E7MN)^l@yh=7^ zq%(Yr zgce%Wz{RvE-#}r6O^j_|liXOgojrQ7hOc(c{L6u3fj@rn%h3GzIeC{MW{r|Wc{evF z9^aCx8aK%pv}vH2fnh6^urzaX4y1z{H<4g-q;+Zv!|N6KS^Qy?@)!{;^z-FYIivV! zY_1rf(a;}z20ku1gRMThl#9~?h2RpSGnWv{)p}ap)D}xmH(&-^Jy(TgW&`V!IWd7s z>$FLN*7CWy0ClMXThH`!Hh?0;Hp zw9`0*Z=kAz_P63XVp2&Gv99s2uOKg1!BQYFr?k$KbU2~XBfZ@zcW*tojNm$TK^OLn zd0Zd#BP46%F0OtD85ZUcouc?IOF7IF9s2auQdS#p8jHx=brd2Z95UW zGdUX!ORiT(wyaW44(j$-?HyaVGfgt^u36(uv91os$}iznsfK;jh90TOz;qSvsv54H z4{58IF_nFuUf+Z`$gc^2SHKQ))V%eqCB2C`F46dJjhnfw*6HZ*IvjpIWh-(OP z@3$DCOh!vT>inK81KTZo>^85A>v&<*0K;sepsrqTbeBek{G-w?>{O>@+FQ7wl8L zzS%-hv`Ld~x1Mdx+K+dW9h%alh<@lGThjm7`=a!nKvk88v_%zdTOdtjWO{TkO~frX@xFjIyG)W@?3{@` zxtn|oqSIMB^Ux%fu0A__e*F|ANnN)T1WVwCiW1#)3dqbGO9;QMBM}?$Y2POF@*5Sl zL3aJX752$bh%);&yKmV(wd=#9S$)?~+vo3i&o67{xr%^-GrSd9WbeX|g2u2$*9$DB zi&DCDklh(bjsGt0_IBO$`Gl}O@FKd{hF%Aux}&jV6%&-XaMO_|m@7=Ya`>*~kL_}jr+t;pk z;+D!6(+uee#otJiS>H-wB(deH)|%$IwR{XN{`+|jt zklH@kXdRXje=-;zkIyx-b`2dJ6!LKsjeg&XFz>L5DFr8@@tzxrn`9(gtk7|*bxiA5 z0)JHXQO6`tzoRK{O=G_YAd&o!i}0>$FFS!m%Z(b_k~XwjZvZ3$2d$<=3stO9YQa|Q zs|lGEa$xz{^o0M#H)`WN`vZ{o0Z2N#P9Aw^d5u!dY{ImHTaOLWHmGr%Rs8OOJCo@TD&-?ANI@_VrOUI29?y@UPnkeBJ#V3}fvA|K| z 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 z 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 literal 0 HcmV?d00001 diff --git a/istio-1.3.5/tools/checker/testlinter/unittest_lint_test.go b/istio-1.3.5/tools/checker/testlinter/unittest_lint_test.go new file mode 100644 index 0000000..100b9fd --- /dev/null +++ b/istio-1.3.5/tools/checker/testlinter/unittest_lint_test.go @@ -0,0 +1,105 @@ +// Copyright 2018 Istio Authors. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package main + +import ( + "path/filepath" + "reflect" + "testing" + + "istio.io/istio/tools/checker" + "istio.io/istio/tools/checker/testlinter/rules" +) + +func getAbsPath(path string) string { + if !filepath.IsAbs(path) { + path, _ = filepath.Abs(path) + } + return path +} + +func clearLintRulesList() { + checker.IgnoreTestLinterData = false + delete(LintRulesList, UnitTest) + delete(LintRulesList, IntegTest) + delete(LintRulesList, E2eTest) +} + +func TestUnitTestSkipByIssueRule(t *testing.T) { + clearLintRulesList() + LintRulesList[UnitTest] = []checker.Rule{rules.NewSkipByIssue()} + + rpts, _ := getReport([]string{"testdata/"}) + expectedRpts := []string{getAbsPath("testdata/unit_test.go") + + ":10:2:Only t.Skip() is allowed and t.Skip() should contain an url to GitHub issue. (skip_issue)"} + + if !reflect.DeepEqual(rpts, expectedRpts) { + t.Errorf("lint reports don't match\nReceived: %v\nExpected: %v", rpts, expectedRpts) + } +} + +func TestUnitTestNoShortRule(t *testing.T) { + clearLintRulesList() + LintRulesList[UnitTest] = []checker.Rule{rules.NewNoShort()} + + rpts, _ := getReport([]string{"testdata/"}) + expectedRpts := []string{getAbsPath("testdata/unit_test.go") + ":34:5:testing.Short() is disallowed. (no_short)"} + + if !reflect.DeepEqual(rpts, expectedRpts) { + t.Errorf("lint reports don't match\nReceived: %v\nExpected: %v", rpts, expectedRpts) + } +} + +func TestUnitTestNoSleepRule(t *testing.T) { + clearLintRulesList() + LintRulesList[UnitTest] = []checker.Rule{rules.NewNoSleep()} + + rpts, _ := getReport([]string{"testdata/"}) + expectedRpts := []string{getAbsPath("testdata/unit_test.go") + ":52:2:time.Sleep() is disallowed. (no_sleep)"} + + if !reflect.DeepEqual(rpts, expectedRpts) { + t.Errorf("lint reports don't match\nReceived: %v\nExpected: %v", rpts, expectedRpts) + } +} + +func TestUnitTestNoGoroutineRule(t *testing.T) { + clearLintRulesList() + LintRulesList[UnitTest] = []checker.Rule{rules.NewNoGoroutine()} + + rpts, _ := getReport([]string{"testdata/"}) + expectedRpts := []string{getAbsPath("testdata/unit_test.go") + ":61:2:goroutine is disallowed. (no_goroutine)"} + + if !reflect.DeepEqual(rpts, expectedRpts) { + t.Errorf("lint reports don't match\nReceived: %v\nExpected: %v", rpts, expectedRpts) + } +} + +func TestUnitTestWhitelist(t *testing.T) { + clearLintRulesList() + LintRulesList[UnitTest] = []checker.Rule{rules.NewSkipByIssue(), + rules.NewNoShort(), + rules.NewNoSleep(), + rules.NewNoGoroutine()} + Whitelist = make(map[string][]string) + Whitelist["testdata/unit_test.go"] = []string{"skip_by_issue_rule", "no_short_rule", + "no_sleep_rule", "no_goroutine_rule"} + + rpts, _ := getReport([]string{"testdata/*"}) + expectedRpts := []string{} + + if (len(rpts) > 0 || len(expectedRpts) > 0) && !reflect.DeepEqual(rpts, expectedRpts) { + t.Errorf("lint reports don't match\nReceived: %v\nExpected: %v", rpts, expectedRpts) + } +} diff --git a/istio-1.3.5/tools/checker/testlinter/whitelist.go b/istio-1.3.5/tools/checker/testlinter/whitelist.go new file mode 100644 index 0000000..2cae85e --- /dev/null +++ b/istio-1.3.5/tools/checker/testlinter/whitelist.go @@ -0,0 +1,20 @@ +// Copyright 2018 Istio Authors. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package main + +// Whitelist contains pairs of file and rule IDs. Each file maps to an array of rules which +// should not apply to that file. Each rule is represented by its unique rule ID, which is the +// file name of that rule without ".go" extension in the rules package. +var Whitelist = map[string][]string{} diff --git a/istio-1.3.5/tools/checker/whitelist.go b/istio-1.3.5/tools/checker/whitelist.go new file mode 100644 index 0000000..c20a0a5 --- /dev/null +++ b/istio-1.3.5/tools/checker/whitelist.go @@ -0,0 +1,57 @@ +// Copyright 2018 Istio Authors. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package checker + +import ( + "log" + "path/filepath" +) + +// Whitelist determines if rules are whitelisted for the given paths. +type Whitelist struct { + // Map from path to whitelisted rules. + ruleWhitelist map[string][]string +} + +// NewWhitelist creates and returns a Whitelist object. +func NewWhitelist(ruleWhitelist map[string][]string) *Whitelist { + return &Whitelist{ruleWhitelist: ruleWhitelist} +} + +// Apply returns true if the given rule is whitelisted for the given path. +func (wl *Whitelist) Apply(path string, rule Rule) bool { + for _, skipRule := range wl.getWhitelistedRules(path) { + if skipRule == rule.GetID() { + return true + } + } + return false +} + +// getWhitelistedRules returns the whitelisted rule given the path +func (wl *Whitelist) getWhitelistedRules(path string) []string { + // Check whether path is whitelisted + for wp, whitelistedRules := range wl.ruleWhitelist { + // filepath.Match is needed for canonical matching + matched, err := filepath.Match(wp, path) + if err != nil { + log.Printf("file match returns error: %v", err) + } + if matched { + return whitelistedRules + } + } + return []string{} +} diff --git a/istio-1.3.5/tools/convert_RbacConfig_to_ClusterRbacConfig.sh b/istio-1.3.5/tools/convert_RbacConfig_to_ClusterRbacConfig.sh new file mode 100755 index 0000000..926edca --- /dev/null +++ b/istio-1.3.5/tools/convert_RbacConfig_to_ClusterRbacConfig.sh @@ -0,0 +1,48 @@ +#!/bin/bash +set -e +set -u + +# This script is provided to help converting RbacConfig to ClusterRbacConfig automatically. The RbacConfig +# will be deleted after the corresponding ClusterRbacConfig is successfully applied. +# The RbacConfig is deprecated by ClusterRbacConfig due to an implementation bug that could cause the +# RbacConfig to be namespace scoped in some cases. The ClusterRbacConfig has exactly same specification +# as the RbacConfig, but with correctly implemented cluster scope. + +RBAC_CONFIGS=$(kubectl get RbacConfig --all-namespaces --no-headers --ignore-not-found) +if [ "${RBAC_CONFIGS}" == "" ] +then + echo "RbacConfig not found" + exit 0 +fi + +RBAC_CONFIG_COUNT=$(echo "${RBAC_CONFIGS}" | wc -l) +if [ "${RBAC_CONFIG_COUNT}" -ne 1 ] +then + echo "${RBAC_CONFIGS}" + echo "found ${RBAC_CONFIG_COUNT} RbacConfigs, expecting only 1. Please delete extra RbacConfigs and execute again." + exit 1 +fi + +NS=$(echo "${RBAC_CONFIGS}" | cut -f 1 -d ' ') +echo "converting RbacConfig in namespace $NS to ClusterRbacConfig" + +SPEC=$(kubectl get RbacConfig default -n "${NS}" -o yaml | sed -n -e '/spec:/,$p') + +cat < 1: + target_dir = sys.argv[1] + +# Converts Fortio result output data into a CSV line. +def csv_line(data): + rawLabels = data['Labels'].split() + + labels = ",".join([l for l in rawLabels if l[0] != 'Q' and l[0] != 'T' and l[0] != 'C']) + + qps = data['RequestedQPS'] + duration = data['RequestedDuration'] + clients = data['NumThreads'] + min = data['DurationHistogram']['Min'] + max = data['DurationHistogram']['Max'] + avg = data['DurationHistogram']['Avg'] + + p50 = [e['Value'] for e in data['DurationHistogram']['Percentiles'] if e['Percentile'] == 50][0] + p75 = [e['Value'] for e in data['DurationHistogram']['Percentiles'] if e['Percentile'] == 75][0] + p90 = [e['Value'] for e in data['DurationHistogram']['Percentiles'] if e['Percentile'] == 90][0] + p99 = [e['Value'] for e in data['DurationHistogram']['Percentiles'] if e['Percentile'] == 99][0] + p99d9 = [e['Value'] for e in data['DurationHistogram']['Percentiles'] if e['Percentile'] == 99.9][0] + + return ("%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s" % (labels, qps, duration, clients, min, max, avg, p50, p75, p90, p99, p99d9)) + +# Print the header line +print("Label,Driver,Target,qps,duration,clients,min,max,avg,p50,p75,p90,p99,p99.9") + +# For each json file in current dir, interpret it as Fortio result json file and print a csv line for it. +for fn in os.listdir(target_dir): + fullfn = os.path.join(target_dir, fn) + if os.path.isfile(fullfn) and fullfn.endswith('.json'): + with open(fullfn) as f: + data = json.load(f) + print(csv_line(data)) + diff --git a/istio-1.3.5/tools/docker-dev/Dockerfile b/istio-1.3.5/tools/docker-dev/Dockerfile new file mode 100644 index 0000000..dfe56f1 --- /dev/null +++ b/istio-1.3.5/tools/docker-dev/Dockerfile @@ -0,0 +1,73 @@ +FROM docker:stable as docker + +FROM ubuntu:xenial +ARG goversion=1.12.5 +ARG user +ARG group +ARG uid=1000 +ARG gid=1000 + +SHELL ["/bin/bash", "-o", "pipefail", "-c"] + +# Install development packages. +RUN apt-get update && apt-get -qqy install --no-install-recommends \ +autoconf=2.69-9 \ +autotools-dev=20150820.1 \ +build-essential=12.1ubuntu2 \ +ca-certificates=20170717~16.04.2 \ +curl=7.47.0-1ubuntu2.13 \ +git=1:2.7.4-0ubuntu1.6 \ +libtool=2.4.6-0.1 \ +lsb-release=9.20160110ubuntu0.2 \ +make=4.1-6 \ +sudo=1.8.16-0ubuntu1.7 \ +bash-completion=1:2.1-4.2ubuntu1.1 \ +jq=1.5+dfsg-1ubuntu0.1 \ +tmux=2.1-3build1 \ +vim=2:7.4.1689-3ubuntu1.3 \ +&& rm -rf /var/lib/apt/lists/* + +# Create user and allow sudo without password. +RUN addgroup --quiet --gid $gid $group \ +&& adduser --quiet --disabled-password --gecos ",,,," --uid $uid --ingroup $group $user \ +&& echo "${user} ALL=(ALL:ALL) NOPASSWD: ALL" > /etc/sudoers.d/$user + +# Install Docker CLI. +COPY --from=docker /usr/local/bin/docker /usr/local/bin/docker + +# Fix the Docker socket access rights at login time to allow non-root access. +RUN echo "sudo chmod o+rw /var/run/docker.sock" >> /home/${user}/.bashrc + +# Install Go. +RUN curl -s -Lo - https://dl.google.com/go/go${goversion}.linux-amd64.tar.gz | tar -C /usr/local -xzf - \ +&& echo "# Go environment." >> /home/${user}/.bashrc \ +&& echo "export GOROOT=/usr/local/go" >> /home/${user}/.bashrc \ +&& echo "export GOPATH=~/go" >> /home/${user}/.bashrc \ +&& echo "export PATH=\$GOROOT/bin:\$GOPATH/out/linux_amd64/release:\$GOPATH/bin:\$PATH" >> /home/${user}/.bashrc \ +&& echo "export GO111MODULE=on" >> /home/${user}/.bashrc \ +&& mkdir -p /home/${user}/go + +# Install KIND 0.3.0. +# Cf. https://github.com/kubernetes-sigs/kind +RUN GO111MODULE="on" GOROOT=/usr/local/go GOPATH=/home/${user}/go /usr/local/go/bin/go get sigs.k8s.io/kind@v0.3.0 + +# Install Helm's latest release. +RUN curl -s -Lo - https://git.io/get_helm.sh | /bin/bash + +# Install gcloud and kubectl. +RUN echo "deb http://packages.cloud.google.com/apt cloud-sdk-$(lsb_release -c -s) main" | tee -a /etc/apt/sources.list.d/google-cloud-sdk.list \ +&& curl -s https://packages.cloud.google.com/apt/doc/apt-key.gpg | apt-key add - \ +&& apt-get update && apt-get -qqy install --no-install-recommends \ +google-cloud-sdk=254.0.0-0 \ +kubectl=1.15.0-00 \ +&& rm -rf /var/lib/apt/lists/* + +# Install bash completion files. +RUN /home/${user}/go/bin/kind completion bash > /etc/bash_completion.d/kind \ +&& /usr/local/bin/helm completion bash > /etc/bash_completion.d/helm \ +&& /usr/bin/kubectl completion bash > /etc/bash_completion.d/kubectl \ +&& curl -s -Lo - https://raw.githubusercontent.com/docker/cli/master/contrib/completion/bash/docker > /etc/bash_completion.d/docker + +USER $user +WORKDIR /home/$user/go/src/istio.io/istio +ENTRYPOINT ["/bin/bash", "-c"] diff --git a/istio-1.3.5/tools/docker-dev/README.md b/istio-1.3.5/tools/docker-dev/README.md new file mode 100644 index 0000000..ce131ca --- /dev/null +++ b/istio-1.3.5/tools/docker-dev/README.md @@ -0,0 +1,67 @@ +# Istio Development Environment in Docker + +This `Dockerfile` creates an Ubuntu-based Docker image for developing on Istio. + +## Image Configuration + +* The base Istio development tools and the following additional tools are installed, with Bash completion configured: + * [Docker CLI](https://docs.docker.com/engine/reference/commandline/cli/) + * [Google Cloud SDK (gcloud)](https://cloud.google.com/sdk/gcloud/) + * [kubectl](https://kubernetes.io/docs/reference/kubectl/kubectl/) + * [Kubernetes IN Docker (KIND)](https://github.com/kubernetes-sigs/kind) + * [Helm](https://helm.sh/) +* A user with the same name as the local host user is created. That user has full sudo rights without password. +* The following volumes are mounted from the host into the container to share development files and configuration: + * Go directory: `$(GOPATH)` → `/home/$(USER)/go` + * Google Cloud SDK config: `$(HOME)/.config/gcloud` → `/home/$(USER)/.config/gcloud` + * Kubernetes config: `$(HOME)/.kube` → `/home/$(USER)/.kube` + * Docker socket, to access Docker from within the container: `/var/run/docker.sock` → `/var/run/docker.sock` +* The working directory is `/home/$user/go/src/istio.io/istio`. + +## Creating The Container + +To create your dev container, run: + +``` +make dev-shell +``` + +The first time this target it run, a Docker image named `istio/dev:USER` is created, where USER is your local username. +Any subsequent run won't rebuild the image unless the `Dockerfile` is modified. + +The first time this target is run, a container named `istio-dev` is run with this image, and an interactive shell is executed in the container. +Any subsequent run won't restart the container and will only start an additional interactive shell. + + +## Kubernetes Cluster Creation Using KIND + +A Kubernetes can be created using KIND. For instance, to create a cluster named `blah` with 2 workers, run the following command within the container: + +``` +export CLUSTER_NAME="blah" + +kind create cluster --name="$CLUSTER_NAME" --config=- < $KUBECONFIG +``` + +## Removing The Container + +``` +docker stop istio-dev +docker rm istio-dev +``` \ No newline at end of file diff --git a/istio-1.3.5/tools/dump_kubernetes.sh b/istio-1.3.5/tools/dump_kubernetes.sh new file mode 100755 index 0000000..6118100 --- /dev/null +++ b/istio-1.3.5/tools/dump_kubernetes.sh @@ -0,0 +1,341 @@ +#!/bin/bash +# +# Uses kubectl to collect cluster information. +# Dumps: +# - Logs of every container of every pod of every namespace. +# - Resource configurations for ingress, endpoints, custom resource +# definitions, configmaps, secrets (names only) and "all" as defined by +# kubectl. + +COREDUMP_DIR="/var/lib/istio" + +# Limit total log size to 100MB by default +DEFAULT_MAX_LOG_BYTES=100000000 + +error() { + echo "$*" >&2 +} + +usage() { + error 'Collect all possible data from a Kubernetes cluster using kubectl.' + error '' + error 'Usage:' + error ' dump_kubernetes.sh [options]' + error '' + error 'Options:' + error ' -d, --output-directory directory to output files; defaults to' + error ' "istio-dump"' + error ' -z, --archive if present, archives and removes the output' + error ' directory' + error ' -q, --quiet if present, do not log' + error ' -m, --max-bytes max total bytes, 0=no limit, default='${DEFAULT_MAX_LOG_BYTES} + error ' -l, --label if set, dump logs only for pods with given labels e.g. "-l app=pilot -l istio=galley"' + error ' -n, --namespace if set, dump logs only for pods in the given namespaces e.g. "-n default -n istio-system"' + error ' --error-if-nasty-logs if present, exit with 255 if any logs' + error ' contain errors' + exit 1 +} + +log() { + local msg="${1}" + if [ "${QUIET}" = false ]; then + printf '%s\n' "${msg}" + fi +} + +parse_args() { + local max_bytes="${DEFAULT_MAX_LOG_BYTES}" + while [ "$#" -gt 0 ]; do + case "${1}" in + -d|--output-directory) + local out_dir="${2}" + shift 2 # Shift past option and value. + ;; + -z|--archive) + local should_archive=true + shift # Shift past flag. + ;; + -q|--quiet) + local quiet=true + shift # Shift past flag. + ;; + --error-if-nasty-logs) + local should_check_logs_for_errors=true + shift # Shift past flag. + ;; + -m|--max-bytes) + max_bytes="${2}" + shift 2 + ;; + -l|--label) + pod_labels+="${2} " + shift 2 + ;; + -n|--namespace) + namespaces+="${2} " + shift 2 + ;; + *) + usage + ;; + esac + done + + readonly OUT_DIR="${out_dir:-istio-dump}" + readonly SHOULD_ARCHIVE="${should_archive:-false}" + readonly QUIET="${quiet:-false}" + readonly SHOULD_CHECK_LOGS_FOR_ERRORS="${should_check_logs_for_errors:-false}" + readonly LOG_DIR="${OUT_DIR}/logs" + readonly RESOURCES_FILE="${OUT_DIR}/resources.yaml" + readonly ISTIO_RESOURCES_FILE="${OUT_DIR}/istio-resources.yaml" + readonly MAX_LOG_BYTES="${max_bytes}" +} + +check_prerequisites() { + local prerequisites=$* + for prerequisite in ${prerequisites}; do + if ! command -v "${prerequisite}" > /dev/null; then + error "\"${prerequisite}\" is required. Please install it." + return 1 + fi + done +} + +dump_time() { + mkdir -p "${OUT_DIR}" + date -u > "${OUT_DIR}/DUMP_TIME" +} + +# mv_unless_max_exceeded src_file dest_file performs mv src_file dest_file unless the global variable stored_log_bytes +# would exceed max_log_bytes. +# If total not exceeded, file is moved and max_log_bytes updated, otherwise an error is logged. +# src_file is always deleted when calling this function. +mv_unless_max_exceeded() { + local src_file="${1}" + local dst_file="${2}" + + file_size=$(wc -c "${src_file}" | awk '{print $1}') + local nsb=$((stored_log_bytes + file_size)) + + if (("${nsb}" > "${MAX_LOG_BYTES}")); then + log "Not storing ${log_file} because appending its ${file_size} bytes would exceed max logged bytes ${MAX_LOG_BYTES}" + rm "${src_file}" + else + dirn=$(dirname "${dst_file}") + mkdir -p "${dirn}" + mv "${src_file}" "${dst_file}" + stored_log_bytes="${nsb}" + fi +} + +dump_logs_for_container() { + local namespace="${1}" + local pod="${2}" + local container="${3}" + + log "Retrieving logs for ${namespace}/${pod}/${container}" + + mkdir -p "${LOG_DIR}/${namespace}/${pod}" + local log_file_head="${LOG_DIR}/${namespace}/${pod}/${container}" + local temp_log_file="${LOG_DIR}/temp_log_file.log" + + local log_file="${log_file_head}.log" + kubectl logs --namespace="${namespace}" "${pod}" "${container}" \ + > "${temp_log_file}" + mv_unless_max_exceeded "${temp_log_file}" "${log_file}" + + local filter="?(@.name == \"${container}\")" + local json_path='{.status.containerStatuses['${filter}'].restartCount}' + local restart_count + restart_count=$(kubectl get --namespace="${namespace}" \ + pod "${pod}" -o=jsonpath="${json_path}") + # (There will be no restart_count if the pod status is for example "Pending") + if [ -n "${restart_count}" ] && [ "${restart_count}" -gt 0 ]; then + log "Retrieving previous logs for ${namespace}/${pod}/${container}" + + local log_previous_file + log_previous_file="${log_file_head}_previous.log" + kubectl logs --namespace="${namespace}" \ + --previous "${pod}" "${container}" \ + > "${temp_log_file}" + mv_unless_max_exceeded "${temp_log_file}" "${log_previous_file}" + fi +} + +copy_core_dumps_if_istio_proxy() { + local namespace="${1}" + local pod="${2}" + local container="${3}" + local got_core_dump=false + + if [ "istio-proxy" = "${container}" ]; then + local out_dir="${LOG_DIR}/${namespace}/${pod}" + mkdir -p "${out_dir}" + local core_dumps + core_dumps=$(kubectl exec -n "${namespace}" "${pod}" -c "${container}" -- \ + find ${COREDUMP_DIR} -name 'core.*') + for f in ${core_dumps}; do + local out_file + out_file="${out_dir}/$(basename "${f}")" + + kubectl exec -n "${namespace}" "${pod}" -c "${container}" -- \ + cat "${f}" > "${out_file}" + + log "Copied ${namespace}/${pod}/${container}:${f} to ${out_file}" + got_core_dump=true + done + fi + if [ "${got_core_dump}" = true ]; then + return 254 + fi +} + +# Run functions on each container. Each argument should be a function which +# takes 3 args: ${namespace} ${pod} ${container}. +# If any of the called functions returns error, tap_containers returns +# immediately with that error. +tap_containers() { + local functions=("$@") + if [ -z "${namespaces}" ]; then + namespaces=$(kubectl get \ + namespaces -o=jsonpath="{.items[*].metadata.name}") + fi + for namespace in ${namespaces}; do + local pods="" + if [ -n "${pod_labels}" ]; then + for label in $pod_labels; do + pods+=$(kubectl get --namespace="${namespace}" -l"${label}" \ + pods -o=jsonpath='{.items[*].metadata.name}')" " + done + else + pods=$(kubectl get --namespace="${namespace}" \ + pods -o=jsonpath='{.items[*].metadata.name}') + fi + for pod in ${pods}; do + local containers + containers=$(kubectl get --namespace="${namespace}" \ + pod "${pod}" -o=jsonpath='{.spec.containers[*].name}') + for container in ${containers}; do + for f in "${functions[@]}"; do + "${f}" "${namespace}" "${pod}" "${container}" || return $? + done + done + done + done + + return 0 +} + +dump_kubernetes_resources() { + log "Retrieving Kubernetes resource configurations" + + mkdir -p "${OUT_DIR}" + # Only works in Kubernetes 1.8.0 and above. + kubectl get --all-namespaces --export \ + all,jobs,ingresses,endpoints,customresourcedefinitions,configmaps,secrets,events \ + -o yaml > "${RESOURCES_FILE}" +} + +dump_istio_custom_resource_definitions() { + log "Retrieving Istio resource configurations" + + local istio_resources + # Trim to only first field; join by comma; remove last comma. + istio_resources=$(kubectl get customresourcedefinitions \ + --no-headers 2> /dev/null \ + | cut -d ' ' -f 1 \ + | tr '\n' ',' \ + | sed 's/,$//') + + if [ -n "${istio_resources}" ]; then + kubectl get "${istio_resources}" --all-namespaces -o yaml \ + > "${ISTIO_RESOURCES_FILE}" + fi +} + +dump_resources() { + dump_kubernetes_resources + dump_istio_custom_resource_definitions + + mkdir -p "${OUT_DIR}" + kubectl cluster-info dump > "${OUT_DIR}/cluster-info.dump.txt" + kubectl describe pods -n istio-system > "${OUT_DIR}/istio-system-pods.txt" + kubectl get events --all-namespaces -o wide > "${OUT_DIR}/events.txt" +} + +dump_pilot_url(){ + local pilot_pod=$1 + local url=$2 + local dname=$3 + local outfile + + outfile="${dname}/$(basename "${url}")" + + log "Fetching ${url} from pilot" + kubectl -n istio-system exec -i -t "${pilot_pod}" -c istio-proxy -- \ + curl "http://localhost:8080/${url}" > "${outfile}" +} + +dump_pilot() { + local pilot_pod + pilot_pod=$(kubectl -n istio-system get pods -l istio=pilot \ + -o jsonpath='{.items[*].metadata.name}') + + if [ -n "${pilot_pod}" ]; then + local pilot_dir="${OUT_DIR}/pilot" + mkdir -p "${pilot_dir}" + + dump_pilot_url "${pilot_pod}" debug/configz "${pilot_dir}" + dump_pilot_url "${pilot_pod}" debug/endpointz "${pilot_dir}" + dump_pilot_url "${pilot_pod}" debug/adsz "${pilot_dir}" + dump_pilot_url "${pilot_pod}" debug/authenticationz "${pilot_dir}" + dump_pilot_url "${pilot_pod}" metrics "${pilot_dir}" + fi +} + +archive() { + local parent_dir + parent_dir=$(dirname "${OUT_DIR}") + local dir + dir=$(basename "${OUT_DIR}") + + pushd "${parent_dir}" > /dev/null || exit + tar -czf "${dir}.tar.gz" "${dir}" + popd > /dev/null || exit + + log "Wrote ${parent_dir}/${dir}.tar.gz" +} + +check_logs_for_errors() { + log "Searching logs for errors." + grep -R --include "${LOG_DIR}/*.log" --ignore-case -e 'segmentation fault' +} + +main() { + local exit_code=0 + parse_args "$@" + check_prerequisites kubectl + dump_time + dump_pilot + dump_resources + tap_containers "dump_logs_for_container" "copy_core_dumps_if_istio_proxy" + exit_code=$? + + if [ "${SHOULD_CHECK_LOGS_FOR_ERRORS}" = true ]; then + if ! check_logs_for_errors; then + exit_code=255 + fi + fi + + if [ "${SHOULD_ARCHIVE}" = true ] ; then + archive + rm -r "${OUT_DIR}" + fi + log "Wrote to ${OUT_DIR}" + + return ${exit_code} +} + +stored_log_bytes=0 + +main "$@" diff --git a/istio-1.3.5/tools/githubContrib/Contributions.txt b/istio-1.3.5/tools/githubContrib/Contributions.txt new file mode 100644 index 0000000..d086fbc --- /dev/null +++ b/istio-1.3.5/tools/githubContrib/Contributions.txt @@ -0,0 +1,2 @@ +Here is the current (as of January 2018) alphabetical list of companies and the number of contributors: +Apache.org (1), Apprenda (1), Calcotestudios (1), CMU (1), Google (34), Hashbangbash (1), Hootsuite (1), Ibm (11), Redhat (2), Unknown (12) diff --git a/istio-1.3.5/tools/hyperistio/README.md b/istio-1.3.5/tools/hyperistio/README.md new file mode 100644 index 0000000..6cbac8d --- /dev/null +++ b/istio-1.3.5/tools/hyperistio/README.md @@ -0,0 +1,5 @@ +HyperIstio is a standalone server including multiple istio components, with default +configuration suited for local testing. + +- config defaults to tests/testdata/config +- default ports used diff --git a/istio-1.3.5/tools/hyperistio/hyperistio.go b/istio-1.3.5/tools/hyperistio/hyperistio.go new file mode 100644 index 0000000..92a94f0 --- /dev/null +++ b/istio-1.3.5/tools/hyperistio/hyperistio.go @@ -0,0 +1,200 @@ +// Copyright 2018 Istio Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package main + +import ( + "flag" + "fmt" + "log" + "os" + "os/signal" + "syscall" + "time" + + "github.com/gogo/protobuf/types" + + meshconfig "istio.io/api/mesh/v1alpha1" + + mixerEnv "istio.io/istio/mixer/test/client/env" + "istio.io/istio/pilot/pkg/bootstrap" + "istio.io/istio/pilot/pkg/proxy/envoy" + "istio.io/istio/pilot/pkg/serviceregistry" + agent "istio.io/istio/pkg/bootstrap" + "istio.io/istio/pkg/config/mesh" + "istio.io/istio/pkg/keepalive" + "istio.io/istio/pkg/test/env" + "istio.io/istio/tests/util" +) + +var ( + runEnvoy = flag.Bool("envoy", true, "Start envoy") +) + +// hyperistio runs all istio components in one binary, using a directory based config by +// default. It is intended for testing/debugging/prototyping. +func main() { + flag.Parse() + err := startAll() + if err != nil { + log.Fatal("Failed to start ", err) + } + sigs := make(chan os.Signal, 1) + signal.Notify(sigs, syscall.SIGINT, syscall.SIGTERM) + <-sigs + + //select{} +} + +func startAll() error { + err := startPilot() + if err != nil { + return err + } + + err = startMixer() + if err != nil { + return err + } + + // Mixer test servers + srv, err := mixerEnv.NewHTTPServer(7070) + if err != nil { + return err + } + errCh := srv.Start() + if err = <-errCh; err != nil { + log.Fatalf("backend server start failed %v", err) + } + + go util.RunHTTP(7072, "v1") + go util.RunGRPC(7073, "v1", "", "") + go util.RunHTTP(7074, "v2") + go util.RunGRPC(7075, "v2", "", "") + if *runEnvoy { + err = startEnvoy() + if err != nil { + return err + } + } + + return nil +} + +func startMixer() error { + srv, err := mixerEnv.NewMixerServer(9091, false, false, "") + if err != nil { + return err + } + errCh := srv.Start() + if err = <-errCh; err != nil { + log.Fatalf("mixer start failed %v", err) + } + + go func() { + for { + r := srv.GetReport() + fmt.Println("MixerReport: ", r) + } + }() + + return nil +} + +func startEnvoy() error { + cfg := &meshconfig.ProxyConfig{ + DiscoveryAddress: "localhost:8080", + ConfigPath: env.IstioOut, + BinaryPath: env.IstioBin + "/envoy", + ServiceCluster: "test", + CustomConfigFile: env.IstioSrc + "/tools/packaging/common/envoy_bootstrap_v2.json", + ConnectTimeout: types.DurationProto(5 * time.Second), // crash if not set + DrainDuration: types.DurationProto(30 * time.Second), // crash if 0 + StatNameLength: 189, + } + cfgF, err := agent.WriteBootstrap(cfg, "sidecar~127.0.0.2~a~a", 1, []string{}, nil, os.Environ(), []string{}, "60s") + if err != nil { + return err + } + stop := make(chan error) + envoyLog, err := os.Create(env.IstioOut + "/envoy_hyperistio_sidecar.log") + if err != nil { + envoyLog = os.Stderr + } + _, err = agent.RunProxy(cfg, "node", 1, cfgF, stop, envoyLog, envoyLog, []string{ + "--disable-hot-restart", // "-l", "trace", + }) + return err +} + +// startPilot with defaults: +// - http port 15007 +// - grpc on 15010 +// - grpcs in 15011 - certs from PILOT_CERT_DIR or ./tests/testdata/certs/pilot +// - mixer set to localhost:9091 (runs in-process), +//- http proxy on 15002 (so tests can be run without iptables) +//- config from $ISTIO_CONFIG dir (defaults to in-source tests/testdata/config) +func startPilot() error { + stop := make(chan struct{}) + + mcfg := mesh.DefaultMeshConfig() + mcfg.ProxyHttpPort = 15002 + + // Create a test pilot discovery service configured to watch the tempDir. + args := bootstrap.PilotArgs{ + Namespace: "testing", + DiscoveryOptions: envoy.DiscoveryServiceOptions{ + HTTPAddr: ":15007", + GrpcAddr: ":15010", + SecureGrpcAddr: ":15011", + EnableCaching: true, + EnableProfiling: true, + }, + + Mesh: bootstrap.MeshArgs{ + MixerAddress: "localhost:9091", + RdsRefreshDelay: types.DurationProto(10 * time.Millisecond), + }, + Config: bootstrap.ConfigArgs{ + KubeConfig: env.IstioSrc + "/tests/util/kubeconfig", + }, + Service: bootstrap.ServiceArgs{ + // Using the Mock service registry, which provides the hello and world services. + Registries: []string{ + string(serviceregistry.MockRegistry)}, + }, + MeshConfig: &mcfg, + KeepaliveOptions: keepalive.DefaultOption(), + } + bootstrap.PilotCertDir = env.IstioSrc + "/tests/testdata/certs/pilot" + + bootstrap.FilepathWalkInterval = 5 * time.Second + // Static testdata, should include all configs we want to test. + args.Config.FileDir = os.Getenv("ISTIO_CONFIG") + if args.Config.FileDir == "" { + args.Config.FileDir = env.IstioSrc + "/tests/testdata/config" + } + log.Println("Using mock configs: ", args.Config.FileDir) + // Create and setup the controller. + s, err := bootstrap.NewServer(args) + if err != nil { + return err + } + + // Start the server. + if err := s.Start(stop); err != nil { + return err + } + return nil +} diff --git a/istio-1.3.5/tools/hyperistio/hyperistio_test.go b/istio-1.3.5/tools/hyperistio/hyperistio_test.go new file mode 100644 index 0000000..a8b4dbc --- /dev/null +++ b/istio-1.3.5/tools/hyperistio/hyperistio_test.go @@ -0,0 +1,75 @@ +// Copyright 2018 Istio Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package main + +import ( + "fmt" + "net/http" + "net/http/httputil" + "net/url" + "strings" + "testing" +) + +var ( + client *http.Client +) + +func init() { + proxyURL, _ := url.Parse("http://localhost:15002") + client = &http.Client{Transport: &http.Transport{Proxy: http.ProxyURL(proxyURL)}} +} + +// Minimal test to check the standalone server runs with some valid config. +func TestAppend(t *testing.T) { + res, err := get(t) + if err != nil { + return + } + if !strings.Contains(res, "Istio-Custom-Header=user-defined-value") { + t.Error("Header not found in ", res) + return + } +} + +func TestByon(t *testing.T) { + res, err := get(t) + if err != nil { + return + } + // The request header will be the original one, from the request, even if the + // request is sent to byon.test.istio.io + if !strings.Contains(res, "Host=mybyon.test.istio.io") { + t.Error("Header not found in ", res) + return + } + t.Log(res) +} + +// get returns the body of the request, after making basic checks on the response +func get(t *testing.T) (string, error) { + res, err := client.Get("http://mybyon.test.istio.io/foo") + if err != nil { + t.Error(err) + return "", err + } + resdmp, _ := httputil.DumpResponse(res, true) + ress := string(resdmp) + if res.StatusCode != 200 { + t.Error("Invalid response code ", res.StatusCode) + return "", fmt.Errorf("invalid response code %d: %s", res.StatusCode, ress) + } + return ress, nil +} diff --git a/istio-1.3.5/tools/hyperistio/index.html b/istio-1.3.5/tools/hyperistio/index.html new file mode 100644 index 0000000..7b228f9 --- /dev/null +++ b/istio-1.3.5/tools/hyperistio/index.html @@ -0,0 +1,42 @@ + + + + + Istio Debug + + + +

+ + + \ No newline at end of file diff --git a/istio-1.3.5/tools/istio-docker.mk b/istio-1.3.5/tools/istio-docker.mk new file mode 100644 index 0000000..6dd95c8 --- /dev/null +++ b/istio-1.3.5/tools/istio-docker.mk @@ -0,0 +1,391 @@ +## Copyright 2018 Istio Authors +## +## Licensed under the Apache License, Version 2.0 (the "License"); +## you may not use this file except in compliance with the License. +## You may obtain a copy of the License at +## +## http://www.apache.org/licenses/LICENSE-2.0 +## +## Unless required by applicable law or agreed to in writing, software +## distributed under the License is distributed on an "AS IS" BASIS, +## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +## See the License for the specific language governing permissions and +## limitations under the License. + +.PHONY: docker +.PHONY: docker.all +.PHONY: docker.save +.PHONY: docker.push + +# Docker target will build the go binaries and package the docker for local testing. +# It does not upload to a registry. +docker: build-linux test-bins-linux docker.all + +# Add new docker targets to the end of the DOCKER_TARGETS list. +DOCKER_TARGETS:=docker.pilot docker.proxy_debug docker.proxytproxy docker.proxyv2 docker.app docker.app_sidecar docker.test_policybackend \ + docker.proxy_init docker.mixer docker.mixer_codegen docker.citadel docker.galley docker.sidecar_injector docker.kubectl docker.node-agent-k8s + +$(ISTIO_DOCKER) $(ISTIO_DOCKER_TAR): + mkdir -p $@ + +.SECONDEXPANSION: #allow $@ to be used in dependency list + +# generated content +$(ISTIO_DOCKER)/istio_ca.crt $(ISTIO_DOCKER)/istio_ca.key: ${GEN_CERT} | ${ISTIO_DOCKER} + ${GEN_CERT} --key-size=2048 --out-cert=${ISTIO_DOCKER}/istio_ca.crt \ + --out-priv=${ISTIO_DOCKER}/istio_ca.key --organization="k8s.cluster.local" \ + --mode=self-signed --ca=true +$(ISTIO_DOCKER)/node_agent.crt $(ISTIO_DOCKER)/node_agent.key: ${GEN_CERT} $(ISTIO_DOCKER)/istio_ca.crt $(ISTIO_DOCKER)/istio_ca.key + ${GEN_CERT} --key-size=2048 --out-cert=${ISTIO_DOCKER}/node_agent.crt \ + --out-priv=${ISTIO_DOCKER}/node_agent.key --organization="NodeAgent" \ + --mode=signer --host="nodeagent.google.com" --signer-cert=${ISTIO_DOCKER}/istio_ca.crt \ + --signer-priv=${ISTIO_DOCKER}/istio_ca.key + +# directives to copy files to docker scratch directory + +# tell make which files are copied from $(ISTIO_OUT_LINUX) and generate rules to copy them to the proper location: +# generates rules like the following: +# $(ISTIO_DOCKER)/pilot-agent: $(ISTIO_OUT_LINUX)/pilot-agent | $(ISTIO_DOCKER) +# cp $(ISTIO_OUT_LINUX)/$FILE $(ISTIO_DOCKER)/($FILE) +DOCKER_FILES_FROM_ISTIO_OUT_LINUX:=pkg-test-echo-cmd-client pkg-test-echo-cmd-server \ + pilot-discovery pilot-agent sidecar-injector mixs mixgen \ + istio_ca node_agent node_agent_k8s galley istio-iptables +$(foreach FILE,$(DOCKER_FILES_FROM_ISTIO_OUT_LINUX), \ + $(eval $(ISTIO_DOCKER)/$(FILE): $(ISTIO_OUT_LINUX)/$(FILE) | $(ISTIO_DOCKER); cp $(ISTIO_OUT_LINUX)/$(FILE) $(ISTIO_DOCKER)/$(FILE))) + +# rule for the test certs. +$(ISTIO_DOCKER)/certs: + cp -a tests/testdata/certs $(ISTIO_DOCKER)/. + +# tell make which files are copied from the source tree and generate rules to copy them to the proper location: +# TODO(sdake) $(NODE_AGENT_TEST_FILES) $(GRAFANA_FILES) +DOCKER_FILES_FROM_SOURCE:=tools/packaging/common/istio-iptables.sh docker/ca-certificates.tgz \ + tests/testdata/certs/cert.crt tests/testdata/certs/cert.key tests/testdata/certs/cacert.pem +# generates rules like the following: +# $(ISTIO_DOCKER)/tools/packaging/common/istio-iptables.sh: $(ISTIO_OUT)/tools/packaging/common/istio-iptables.sh | $(ISTIO_DOCKER) +# cp $FILE $$(@D)) +$(foreach FILE,$(DOCKER_FILES_FROM_SOURCE), \ + $(eval $(ISTIO_DOCKER)/$(notdir $(FILE)): $(FILE) | $(ISTIO_DOCKER); cp $(FILE) $$(@D))) + + +# tell make which files are copied from ISTIO_BIN and generate rules to copy them to the proper location: +# generates rules like the following: +# $(ISTIO_DOCKER)/kubectl: $(ISTIO_BIN)/kubectl | $(ISTIO_DOCKER) +# cp $(ISTIO_BIN)/kubectl $(ISTIO_DOCKER)/kubectl +DOCKER_FILES_FROM_ISTIO_BIN:=kubectl +$(foreach FILE,$(DOCKER_FILES_FROM_ISTIO_BIN), \ + $(eval $(ISTIO_BIN)/$(FILE): ; bin/testEnvLocalK8S.sh getDeps)) +$(foreach FILE,$(DOCKER_FILES_FROM_ISTIO_BIN), \ + $(eval $(ISTIO_DOCKER)/$(FILE): $(ISTIO_BIN)/$(FILE) | $(ISTIO_DOCKER); cp $(ISTIO_BIN)/$(FILE) $(ISTIO_DOCKER)/$(FILE))) + +# pilot docker images + +docker.proxy_init: BUILD_ARGS=--build-arg BASE_VERSION=${BASE_VERSION} +docker.proxy_init: pilot/docker/Dockerfile.proxy_init +docker.proxy_init: $(ISTIO_DOCKER)/istio-iptables.sh +docker.proxy_init: $(ISTIO_DOCKER)/istio-iptables + $(DOCKER_RULE) + +docker.sidecar_injector: BUILD_ARGS=--build-arg BASE_VERSION=${BASE_VERSION} +docker.sidecar_injector: pilot/docker/Dockerfile.sidecar_injector +docker.sidecar_injector:$(ISTIO_DOCKER)/sidecar-injector + $(DOCKER_RULE) + +# BUILD_PRE tells $(DOCKER_RULE) to run the command specified before executing a docker build +# BUILD_ARGS tells $(DOCKER_RULE) to execute a docker build with the specified commands + +docker.proxy_debug: BUILD_PRE=$(if $(filter 1,${USE_LOCAL_PROXY}),,mv envoy-debug-${PROXY_REPO_SHA} envoy &&) chmod 755 envoy pilot-agent && +docker.proxy_debug: BUILD_ARGS=--build-arg proxy_version=istio-proxy:${PROXY_REPO_SHA} --build-arg istio_version=${VERSION} --build-arg BASE_VERSION=${BASE_VERSION} --build-arg ISTIO_API_SHA=${ISTIO_PROXY_ISTIO_API_SHA_LABEL} --build-arg ENVOY_SHA=${ISTIO_PROXY_ENVOY_SHA_LABEL} +docker.proxy_debug: pilot/docker/Dockerfile.proxy_debug +docker.proxy_debug: tools/packaging/common/envoy_bootstrap_v2.json +docker.proxy_debug: tools/packaging/common/envoy_bootstrap_drain.json +docker.proxy_debug: install/gcp/bootstrap/gcp_envoy_bootstrap.json +docker.proxy_debug: $(ISTIO_DOCKER)/ca-certificates.tgz +docker.proxy_debug: ${ISTIO_ENVOY_LINUX_DEBUG_PATH} +docker.proxy_debug: $(ISTIO_OUT_LINUX)/pilot-agent +docker.proxy_debug: pilot/docker/Dockerfile.proxyv2 +docker.proxy_debug: pilot/docker/envoy_pilot.yaml.tmpl +docker.proxy_debug: pilot/docker/envoy_policy.yaml.tmpl +docker.proxy_debug: pilot/docker/envoy_telemetry.yaml.tmpl + $(DOCKER_RULE) + +# The file must be named 'envoy', depends on the release. +${ISTIO_ENVOY_LINUX_RELEASE_DIR}/envoy: ${ISTIO_ENVOY_LINUX_RELEASE_PATH} + mkdir -p $(DOCKER_BUILD_TOP)/proxyv2 + cp ${ISTIO_ENVOY_LINUX_RELEASE_PATH} ${ISTIO_ENVOY_LINUX_RELEASE_DIR}/envoy + +# Downloads WASM Plugins and adds to proxyv2. +${ISTIO_OUT}/wasm: + @bin/wasm_plugins.sh ${ISTIO_OUT} + +$(ISTIO_DOCKER)/wasm: ${ISTIO_OUT}/wasm + cp -r ${ISTIO_OUT}/wasm $(ISTIO_DOCKER)/wasm + +# Default proxy image. +docker.proxyv2: BUILD_PRE=chmod 755 envoy pilot-agent && +docker.proxyv2: BUILD_ARGS=--build-arg proxy_version=istio-proxy:${PROXY_REPO_SHA} --build-arg istio_version=${VERSION} --build-arg ISTIO_API_SHA=${ISTIO_PROXY_ISTIO_API_SHA_LABEL} --build-arg ENVOY_SHA=${ISTIO_PROXY_ENVOY_SHA_LABEL} --build-arg BASE_VERSION=${BASE_VERSION} +docker.proxyv2: tools/packaging/common/envoy_bootstrap_v2.json +docker.proxyv2: tools/packaging/common/envoy_bootstrap_drain.json +docker.proxyv2: install/gcp/bootstrap/gcp_envoy_bootstrap.json +docker.proxyv2: $(ISTIO_DOCKER)/ca-certificates.tgz +docker.proxyv2: $(ISTIO_DOCKER)/wasm +docker.proxyv2: $(ISTIO_ENVOY_LINUX_RELEASE_DIR)/envoy +docker.proxyv2: $(ISTIO_OUT_LINUX)/pilot-agent +docker.proxyv2: pilot/docker/Dockerfile.proxyv2 +docker.proxyv2: pilot/docker/envoy_pilot.yaml.tmpl +docker.proxyv2: pilot/docker/envoy_policy.yaml.tmpl +docker.proxyv2: tools/packaging/common/istio-iptables.sh +docker.proxyv2: pilot/docker/envoy_telemetry.yaml.tmpl + $(DOCKER_RULE) + +# Proxy using TPROXY interception - but no core dumps +docker.proxytproxy: BUILD_ARGS=--build-arg proxy_version=istio-proxy:${PROXY_REPO_SHA} --build-arg istio_version=${VERSION} --build-arg ISTIO_API_SHA=${ISTIO_PROXY_ISTIO_API_SHA_LABEL} --build-arg ENVOY_SHA=${ISTIO_PROXY_ENVOY_SHA_LABEL} --build-arg BASE_VERSION=${BASE_VERSION} +docker.proxytproxy: tools/packaging/common/envoy_bootstrap_v2.json +docker.proxytproxy: tools/packaging/common/envoy_bootstrap_drain.json +docker.proxytproxy: install/gcp/bootstrap/gcp_envoy_bootstrap.json +docker.proxytproxy: $(ISTIO_DOCKER)/ca-certificates.tgz +docker.proxytproxy: $(ISTIO_ENVOY_LINUX_RELEASE_DIR)/envoy +docker.proxytproxy: $(ISTIO_OUT_LINUX)/pilot-agent +docker.proxytproxy: pilot/docker/Dockerfile.proxytproxy +docker.proxytproxy: pilot/docker/envoy_pilot.yaml.tmpl +docker.proxytproxy: pilot/docker/envoy_policy.yaml.tmpl +docker.proxytproxy: tools/packaging/common/istio-iptables.sh +docker.proxytproxy: pilot/docker/envoy_telemetry.yaml.tmpl + $(DOCKER_RULE) + +docker.pilot: BUILD_ARGS=--build-arg BASE_VERSION=${BASE_VERSION} +docker.pilot: $(ISTIO_OUT_LINUX)/pilot-discovery +docker.pilot: tests/testdata/certs/cacert.pem +docker.pilot: pilot/docker/Dockerfile.pilot + $(DOCKER_RULE) + +# Test application +docker.app: pkg/test/echo/docker/Dockerfile.app +docker.app: $(ISTIO_OUT_LINUX)/pkg-test-echo-cmd-client +docker.app: $(ISTIO_OUT_LINUX)/pkg-test-echo-cmd-server +docker.app: $(ISTIO_DOCKER)/certs + mkdir -p $(ISTIO_DOCKER)/testapp + cp -r $^ $(ISTIO_DOCKER)/testapp +ifeq ($(DEBUG_IMAGE),1) + # It is extremely helpful to debug from the test app. The savings in size are not worth the + # developer pain + cp $(ISTIO_DOCKER)/testapp/Dockerfile.app $(ISTIO_DOCKER)/testapp/Dockerfile.appdbg + sed -e "s,FROM \${BASE_DISTRIBUTION},FROM $(HUB)/proxy_debug:$(TAG)," $(ISTIO_DOCKER)/testapp/Dockerfile.appdbg > $(ISTIO_DOCKER)/testapp/Dockerfile.appd +endif + time (cd $(ISTIO_DOCKER)/testapp && \ + docker build -t $(HUB)/app:$(TAG) -f Dockerfile.app .) + + +# Test application bundled with the sidecar (for non-k8s). +docker.app_sidecar: tools/packaging/common/envoy_bootstrap_v2.json +docker.app_sidecar: tools/packaging/common/envoy_bootstrap_drain.json +docker.app_sidecar: tools/packaging/common/istio-iptables.sh +docker.app_sidecar: tools/packaging/common/istio-start.sh +docker.app_sidecar: tools/packaging/common/istio-node-agent-start.sh +docker.app_sidecar: tools/packaging/deb/postinst.sh +docker.app_sidecar: pkg/test/echo/docker/echo-start.sh +docker.app_sidecar: $(ISTIO_DOCKER)/ca-certificates.tgz +docker.app_sidecar: $(ISTIO_DOCKER)/certs +docker.app_sidecar: $(ISTIO_ENVOY_LINUX_RELEASE_DIR)/envoy +docker.app_sidecar: $(ISTIO_OUT_LINUX)/pilot-agent +docker.app_sidecar: $(ISTIO_OUT_LINUX)/node_agent +docker.app_sidecar: $(ISTIO_OUT_LINUX)/pkg-test-echo-cmd-client +docker.app_sidecar: $(ISTIO_OUT_LINUX)/pkg-test-echo-cmd-server +docker.app_sidecar: pkg/test/echo/docker/Dockerfile.app_sidecar +docker.app_sidecar: pilot/docker/envoy_pilot.yaml.tmpl +docker.app_sidecar: pilot/docker/envoy_policy.yaml.tmpl +docker.app_sidecar: pilot/docker/envoy_telemetry.yaml.tmpl + $(DOCKER_RULE) + +# Test policy backend for mixer integration +docker.test_policybackend: BUILD_ARGS=--build-arg BASE_VERSION=${BASE_VERSION} +docker.test_policybackend: mixer/docker/Dockerfile.test_policybackend +docker.test_policybackend: $(ISTIO_OUT_LINUX)/mixer-test-policybackend + $(DOCKER_RULE) + +docker.kubectl: BUILD_ARGS=--build-arg BASE_VERSION=${BASE_VERSION} +docker.kubectl: docker/Dockerfile$$(suffix $$@) + $(DOCKER_RULE) + +# mixer docker images + +docker.mixer: BUILD_ARGS=--build-arg BASE_VERSION=${BASE_VERSION} +docker.mixer: mixer/docker/Dockerfile.mixer +docker.mixer: $(ISTIO_DOCKER)/mixs +docker.mixer: $(ISTIO_DOCKER)/ca-certificates.tgz + $(DOCKER_RULE) + +# mixer codegen docker images +docker.mixer_codegen: BUILD_ARGS=--build-arg BASE_VERSION=${BASE_VERSION} +docker.mixer_codegen: mixer/docker/Dockerfile.mixer_codegen +docker.mixer_codegen: $(ISTIO_DOCKER)/mixgen + $(DOCKER_RULE) + +# galley docker images + +docker.galley: BUILD_ARGS=--build-arg BASE_VERSION=${BASE_VERSION} +docker.galley: galley/docker/Dockerfile.galley +docker.galley: $(ISTIO_DOCKER)/galley + $(DOCKER_RULE) + +# security docker images + +docker.citadel: BUILD_ARGS=--build-arg BASE_VERSION=${BASE_VERSION} +docker.citadel: security/docker/Dockerfile.citadel +docker.citadel: $(ISTIO_DOCKER)/istio_ca +docker.citadel: $(ISTIO_DOCKER)/ca-certificates.tgz + $(DOCKER_RULE) + +docker.citadel-test: BUILD_ARGS=--build-arg BASE_VERSION=${BASE_VERSION} +docker.citadel-test: security/docker/Dockerfile.citadel-test +docker.citadel-test: $(ISTIO_DOCKER)/istio_ca +docker.citadel-test: $(ISTIO_DOCKER)/istio_ca.crt +docker.citadel-test: $(ISTIO_DOCKER)/istio_ca.key + $(DOCKER_RULE) + +docker.node-agent: BUILD_ARGS=--build-arg BASE_VERSION=${BASE_VERSION} +docker.node-agent: security/docker/Dockerfile.node-agent +docker.node-agent: $(ISTIO_DOCKER)/node_agent + $(DOCKER_RULE) + +docker.node-agent-k8s: BUILD_ARGS=--build-arg BASE_VERSION=${BASE_VERSION} +docker.node-agent-k8s: security/docker/Dockerfile.node-agent-k8s +docker.node-agent-k8s: $(ISTIO_DOCKER)/node_agent_k8s + $(DOCKER_RULE) + +docker.node-agent-test: BUILD_ARGS=--build-arg BASE_VERSION=${BASE_VERSION} +docker.node-agent-test: security/docker/Dockerfile.node-agent-test +docker.node-agent-test: $(ISTIO_DOCKER)/node_agent +docker.node-agent-test: $(ISTIO_DOCKER)/istio_ca.crt +docker.node-agent-test: $(ISTIO_DOCKER)/node_agent.crt +docker.node-agent-test: $(ISTIO_DOCKER)/node_agent.key + $(DOCKER_RULE) + +docker.base: docker/Dockerfile.base + $(DOCKER_RULE) + +# $@ is the name of the target +# $^ the name of the dependencies for the target +# Rule Steps # +############## +# 1. Make a directory $(DOCKER_BUILD_TOP)/%@ +# 2. This rule uses cp to copy all dependency filenames into into $(DOCKER_BUILD_TOP/$@ +# 3. This rule then changes directories to $(DOCKER_BUID_TOP)/$@ +# 4. This rule runs $(BUILD_PRE) prior to any docker build and only if specified as a dependency variable +# 5. This rule finally runs docker build passing $(BUILD_ARGS) to docker if they are specified as a dependency variable + +# DOCKER_BUILD_VARIANTS ?=default distroless +DOCKER_BUILD_VARIANTS ?=default +DEFAULT_DISTRIBUTION=default +DOCKER_RULE=$(foreach VARIANT,$(DOCKER_BUILD_VARIANTS), time (mkdir -p $(DOCKER_BUILD_TOP)/$@ && cp -r $^ $(DOCKER_BUILD_TOP)/$@ && cd $(DOCKER_BUILD_TOP)/$@ && $(BUILD_PRE) docker build $(BUILD_ARGS) --build-arg BASE_DISTRIBUTION=$(VARIANT) -t $(HUB)/$(subst docker.,,$@):$(subst -$(DEFAULT_DISTRIBUTION),,$(TAG)-$(VARIANT)) -f Dockerfile$(suffix $@) . ); ) + +# This target will package all docker images used in test and release, without re-building +# go binaries. It is intended for CI/CD systems where the build is done in separate job. +docker.all: $(DOCKER_TARGETS) + +# for each docker.XXX target create a tar.docker.XXX target that says how +# to make a $(ISTIO_OUT_LINUX)/docker/XXX.tar.gz from the docker XXX image +# note that $(subst docker.,,$(TGT)) strips off the "docker." prefix, leaving just the XXX + +# create a DOCKER_TAR_TARGETS that's each of DOCKER_TARGETS with a tar. prefix +DOCKER_TAR_TARGETS:= +$(foreach TGT,$(filter-out docker.app,$(DOCKER_TARGETS)),$(eval tar.$(TGT): $(TGT) | $(ISTIO_DOCKER_TAR) ; \ + $(foreach VARIANT,$(DOCKER_BUILD_VARIANTS), time ( \ + docker save -o ${ISTIO_DOCKER_TAR}/$(subst docker.,,$(TGT))$(subst -$(DEFAULT_DISTRIBUTION),,-$(VARIANT)).tar $(HUB)/$(subst docker.,,$(TGT)):$(subst -$(DEFAULT_DISTRIBUTION),,$(TAG)-$(VARIANT)) && \ + gzip ${ISTIO_DOCKER_TAR}/$(subst docker.,,$(TGT))$(subst -$(DEFAULT_DISTRIBUTION),,-$(VARIANT)).tar \ + ); \ + ))) + +tar.docker.app: docker.app | $(ISTIO_DOCKER_TAR) + time ( docker save -o ${ISTIO_DOCKER_TAR}/app.tar $(HUB)/app:$(TAG) && \ + gzip ${ISTIO_DOCKER_TAR}/app.tar ) + +# create a DOCKER_TAR_TARGETS that's each of DOCKER_TARGETS with a tar. prefix DOCKER_TAR_TARGETS:= +$(foreach TGT,$(DOCKER_TARGETS),$(eval DOCKER_TAR_TARGETS+=tar.$(TGT))) + +# this target saves a tar.gz of each docker image to ${ISTIO_OUT_LINUX}/docker/ +docker.save: $(DOCKER_TAR_TARGETS) + +# for each docker.XXX target create a push.docker.XXX target that pushes +# the local docker image to another hub +# a possible optimization is to use tag.$(TGT) as a dependency to do the tag for us +$(foreach TGT,$(filter-out docker.app,$(DOCKER_TARGETS)),$(eval push.$(TGT): | $(TGT) ; \ + time (set -e && for distro in $(DOCKER_BUILD_VARIANTS); do tag=$(TAG)-$$$${distro}; docker push $(HUB)/$(subst docker.,,$(TGT)):$$$${tag%-$(DEFAULT_DISTRIBUTION)}; done))) + +push.docker.app: docker.app + time (docker push $(HUB)/app:$(TAG)) + +define run_vulnerability_scanning + $(eval RESULTS_DIR := vulnerability_scan_results) + $(eval CURL_RESPONSE := $(shell curl -s --create-dirs -o $(RESULTS_DIR)/$(1) -w "%{http_code}" http://imagescanner.cloud.ibm.com/scan?image="docker.io/$(2)")) \ + $(if $(filter $(CURL_RESPONSE), 200), (mv $(RESULTS_DIR)/$(1) $(RESULTS_DIR)/$(1).json)) +endef + +# create a DOCKER_PUSH_TARGETS that's each of DOCKER_TARGETS with a push. prefix +DOCKER_PUSH_TARGETS:= +$(foreach TGT,$(DOCKER_TARGETS),$(eval DOCKER_PUSH_TARGETS+=push.$(TGT))) + +# Will build and push docker images. +docker.push: $(DOCKER_PUSH_TARGETS) + +# Scan images for security vulnerabilities using the ImageScanner tool +docker.scan_images: $(DOCKER_PUSH_TARGETS) + $(foreach TGT,$(DOCKER_TARGETS),$(call run_vulnerability_scanning,$(subst docker.,,$(TGT)),$(HUB)/$(subst docker.,,$(TGT)):$(TAG))) + +# Base image for 'debug' containers. +# You can run it first to use local changes (or guarantee it is built from scratch) +docker.basedebug: + docker build -t istionightly/base_debug -f docker/Dockerfile.xenial_debug docker/ + +# Run this target to generate images based on Bionic Ubuntu +# This must be run as a first step, before the 'docker' step. +docker.basedebug_bionic: + docker build -t istionightly/base_debug_bionic -f docker/Dockerfile.bionic_debug docker/ + docker tag istionightly/base_debug_bionic istionightly/base_debug + +# Run this target to generate images based on Debian Slim +# This must be run as a first step, before the 'docker' step. +docker.basedebug_deb: + docker build -t istionightly/base_debug_deb -f docker/Dockerfile.deb_debug docker/ + docker tag istionightly/base_debug_deb istionightly/base_debug + +# Job run from the nightly cron to publish an up-to-date xenial with the debug tools. +docker.push.basedebug: docker.basedebug + docker push istionightly/base_debug:latest + +# Build a dev environment Docker image. +DEV_IMAGE_NAME = istio/dev:$(USER) +DEV_CONTAINER_NAME = istio-dev +DEV_GO_VERSION = 1.12.5 +tools/docker-dev/image-built: tools/docker-dev/Dockerfile + @echo "building \"$(DEV_IMAGE_NAME)\" Docker image" + @docker build \ + --build-arg goversion="$(DEV_GO_VERSION)" \ + --build-arg user="${shell id -un}" \ + --build-arg group="${shell id -gn}" \ + --build-arg uid="${shell id -u}" \ + --build-arg gid="${shell id -g}" \ + --tag "$(DEV_IMAGE_NAME)" - < tools/docker-dev/Dockerfile + @touch $@ + +# Start a dev environment Docker container. +.PHONY = dev-shell clean-dev-shell +dev-shell: tools/docker-dev/image-built + @if test -z "$(shell docker ps -a -q -f name=$(DEV_CONTAINER_NAME))"; then \ + echo "starting \"$(DEV_CONTAINER_NAME)\" Docker container"; \ + docker run --detach \ + --name "$(DEV_CONTAINER_NAME)" \ + --volume "$(GOPATH):/home/$(USER)/go:consistent" \ + --volume "$(HOME)/.config/gcloud:/home/$(USER)/.config/gcloud:cached" \ + --volume "$(HOME)/.kube:/home/$(USER)/.kube:cached" \ + --volume /var/run/docker.sock:/var/run/docker.sock \ + "$(DEV_IMAGE_NAME)" \ + 'while true; do sleep 60; done'; fi + @echo "executing shell in \"$(DEV_CONTAINER_NAME)\" Docker container" + @docker exec --tty --interactive "$(DEV_CONTAINER_NAME)" /bin/bash + +clean-dev-shell: + docker rm -f "$(DEV_CONTAINER_NAME)" || true + if test -n "$(shell docker images -q $(DEV_IMAGE_NAME))"; then \ + docker rmi -f "$(shell docker images -q $(DEV_IMAGE_NAME))" || true; fi + rm -f tools/docker-dev/image-built diff --git a/istio-1.3.5/tools/istio-iptables/main.go b/istio-1.3.5/tools/istio-iptables/main.go new file mode 100644 index 0000000..efb536b --- /dev/null +++ b/istio-1.3.5/tools/istio-iptables/main.go @@ -0,0 +1,520 @@ +// Copyright 2019 Istio Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package main + +import ( + "flag" + "fmt" + "net" + "os" + "strings" + + "istio.io/pkg/env" + + dep "istio.io/istio/tools/istio-iptables/pkg/dependencies" +) + +type NetworkRange struct { + IsWildcard bool + IPNets []*net.IPNet +} + +func split(s string) []string { + if s == "" { + return nil + } + return strings.Split(s, ",") +} + +func separateV4V6(cidrList string) (NetworkRange, NetworkRange, error) { + if cidrList == "*" { + return NetworkRange{IsWildcard: true}, NetworkRange{IsWildcard: true}, nil + } + ipv6Ranges := NetworkRange{IsWildcard: false, IPNets: make([]*net.IPNet, 0)} + ipv4Ranges := NetworkRange{IsWildcard: false, IPNets: make([]*net.IPNet, 0)} + for _, ipRange := range split(cidrList) { + ip, ipNet, err := net.ParseCIDR(ipRange) + if err != nil { + _, err = fmt.Fprintf(os.Stderr, "Ignoring error for bug compatibility with istio-iptables.sh: %s\n", err.Error()) + if err != nil { + return ipv4Ranges, ipv6Ranges, err + } + continue + } + if ip.To4() != nil { + ipv4Ranges.IPNets = append(ipv4Ranges.IPNets, ipNet) + } else { + ipv6Ranges.IPNets = append(ipv6Ranges.IPNets, ipNet) + } + } + return ipv4Ranges, ipv6Ranges, nil +} + +func run(args []string, flagSet *flag.FlagSet) { + + proxyUID := "" + proxyGID := "" + inboundInterceptionMode := env.RegisterStringVar("ISTIO_INBOUND_INTERCEPTION_MODE", "", "").Get() + inboundTProxyMark := env.RegisterStringVar("ISTIO_INBOUND_TPROXY_MARK", "1337", "").Get() + inboundTProxyRouteTable := env.RegisterStringVar("ISTIO_INBOUND_TPROXY_ROUTE_TABLE", "133", "").Get() + inboundPortsInclude := env.RegisterStringVar("ISTIO_INBOUND_PORTS", "", "").Get() + inboundPortsExclude := env.RegisterStringVar("ISTIO_LOCAL_EXCLUDE_PORTS", "", "").Get() + outboundIPRangesInclude := env.RegisterStringVar("ISTIO_SERVICE_CIDR", "", "").Get() + outboundIPRangesExclude := env.RegisterStringVar("ISTIO_SERVICE_EXCLUDE_CIDR", "", "").Get() + outboundPortsExclude := env.RegisterStringVar("ISTIO_LOCAL_OUTBOUND_PORTS_EXCLUDE", "", "").Get() + kubevirtInterfaces := "" + var enableInboundIPv6s net.IP + + proxyPort := env.RegisterStringVar("ENVOY_PORT", "15001", "").Get() + inboundCapturePort := env.RegisterStringVar("INBOUND_CAPTURE_PORT", "15006", "").Get() + flagSet.StringVar(&proxyPort, "p", proxyPort, + "Specify the envoy port to which redirect all TCP traffic (default $ENVOY_PORT = 15001)") + flagSet.StringVar(&inboundCapturePort, "z", inboundCapturePort, + "Port to which all inbound TCP traffic to the pod/VM should be redirected to (default $INBOUND_CAPTURE_PORT = 15006)") + flagSet.StringVar(&proxyUID, "u", proxyUID, + "Specify the UID of the user for which the redirection is not applied. Typically, this is the UID of the proxy container") + flagSet.StringVar(&proxyGID, "g", proxyGID, + "Specify the GID of the user for which the redirection is not applied. (same default value as -u param)") + flagSet.StringVar(&inboundInterceptionMode, "m", inboundInterceptionMode, + "The mode used to redirect inbound connections to Envoy, either \"REDIRECT\" or \"TPROXY\"") + flagSet.StringVar(&inboundPortsInclude, "b", inboundPortsInclude, + "Comma separated list of inbound ports for which traffic is to be redirected to Envoy (optional). "+ + "The wildcard character \"*\" can be used to configure redirection for all ports. An empty list will disable") + flagSet.StringVar(&inboundPortsExclude, "d", inboundPortsExclude, + "Comma separated list of inbound ports to be excluded from redirection to Envoy (optional). "+ + "Only applies when all inbound traffic (i.e. \"*\") is being redirected (default to $ISTIO_LOCAL_EXCLUDE_PORTS)") + flagSet.StringVar(&outboundIPRangesInclude, "i", outboundIPRangesInclude, + "Comma separated list of IP ranges in CIDR form to redirect to envoy (optional). "+ + "The wildcard character \"*\" can be used to redirect all outbound traffic. An empty list will disable all outbound") + flagSet.StringVar(&outboundIPRangesExclude, "x", outboundIPRangesExclude, + "Comma separated list of IP ranges in CIDR form to be excluded from redirection. "+ + "Only applies when all outbound traffic (i.e. \"*\") is being redirected (default to $ISTIO_SERVICE_EXCLUDE_CIDR)") + flagSet.StringVar(&outboundPortsExclude, "o", outboundPortsExclude, + "Comma separated list of outbound ports to be excluded from redirection to Envoy (optional") + flagSet.StringVar(&kubevirtInterfaces, "k", kubevirtInterfaces, + "Comma separated list of virtual interfaces whose inbound traffic (from VM) will be treated as outbound (optional)") + + var dryRun bool + flagSet.BoolVar(&dryRun, "dryRun", false, "Do not call any external dependencies like iptables") + err := flagSet.Parse(args) + if err != nil { + return + } + + var ext dep.Dependencies + if dryRun { + ext = &dep.StdoutStubDependencies{} + } else { + ext = &dep.RealDependencies{} + } + + defer func() { + ext.RunOrFail(dep.IPTABLESSAVE) + ext.RunOrFail(dep.IP6TABLESSAVE) + }() + + // TODO: more flexibility - maybe a whitelist of users to be captured for output instead of a blacklist. + if proxyUID == "" { + usr, err := ext.LookupUser() + var userID string + // Default to the UID of ENVOY_USER and root + if err != nil { + userID = "1337" + } else { + userID = usr.Uid + } + // If ENVOY_UID is not explicitly defined (as it would be in k8s env), we add root to the list, + // for ca agent. + proxyUID = userID + ",0" + } + + // for TPROXY as its uid and gid are same + if proxyGID == "" { + proxyGID = proxyUID + } + + podIP, err := ext.GetLocalIP() + if err != nil { + panic(err) + } + // Check if pod's ip is ipv4 or ipv6, in case of ipv6 set variable + // to program ip6tablesOrFail + if podIP.To4() == nil { + enableInboundIPv6s = podIP + } + // + // Since OUTBOUND_IP_RANGES_EXCLUDE could carry ipv4 and ipv6 ranges + // need to split them in different arrays one for ipv4 and one for ipv6 + // in order to not to fail + ipv4RangesExclude, ipv6RangesExclude, err := separateV4V6(outboundIPRangesExclude) + if err != nil { + panic(err) + } + if ipv4RangesExclude.IsWildcard { + panic("Invalid value for OUTBOUND_IP_RANGES_EXCLUDE") + } + + ipv4RangesInclude, ipv6RangesInclude, err := separateV4V6(outboundIPRangesInclude) + if err != nil { + panic(err) + } + + // Remove the old chains, to generate new configs. + ext.RunQuietlyAndIgnore(dep.IPTABLES, "-t", "nat", "-D", "PREROUTING", "-p", "tcp", "-j", "ISTIO_INBOUND") + ext.RunQuietlyAndIgnore(dep.IPTABLES, "-t", "mangle", "-D", "PREROUTING", "-p", "tcp", "-j", "ISTIO_INBOUND") + ext.RunQuietlyAndIgnore(dep.IPTABLES, "-t", "nat", "-D", "OUTPUT", "-p", "tcp", "-j", "ISTIO_OUTPUT") + // Flush and delete the istio chains. + ext.RunQuietlyAndIgnore(dep.IPTABLES, "-t", "nat", "-F", "ISTIO_OUTPUT") + ext.RunQuietlyAndIgnore(dep.IPTABLES, "-t", "nat", "-X", "ISTIO_OUTPUT") + ext.RunQuietlyAndIgnore(dep.IPTABLES, "-t", "nat", "-F", "ISTIO_INBOUND") + ext.RunQuietlyAndIgnore(dep.IPTABLES, "-t", "nat", "-X", "ISTIO_INBOUND") + ext.RunQuietlyAndIgnore(dep.IPTABLES, "-t", "mangle", "-F", "ISTIO_INBOUND") + ext.RunQuietlyAndIgnore(dep.IPTABLES, "-t", "mangle", "-X", "ISTIO_INBOUND") + ext.RunQuietlyAndIgnore(dep.IPTABLES, "-t", "mangle", "-F", "ISTIO_DIVERT") + ext.RunQuietlyAndIgnore(dep.IPTABLES, "-t", "mangle", "-X", "ISTIO_DIVERT") + ext.RunQuietlyAndIgnore(dep.IPTABLES, "-t", "mangle", "-F", "ISTIO_TPROXY") + ext.RunQuietlyAndIgnore(dep.IPTABLES, "-t", "mangle", "-X", "ISTIO_TPROXY") + // Must be last, the others refer to it + ext.RunQuietlyAndIgnore(dep.IPTABLES, "-t", "nat", "-F", "ISTIO_REDIRECT") + ext.RunQuietlyAndIgnore(dep.IPTABLES, "-t", "nat", "-X", "ISTIO_REDIRECT") + ext.RunQuietlyAndIgnore(dep.IPTABLES, "-t", "nat", "-F", "ISTIO_IN_REDIRECT") + ext.RunQuietlyAndIgnore(dep.IPTABLES, "-t", "nat", "-X", "ISTIO_IN_REDIRECT") + + if len(flagSet.Args()) > 0 && flagSet.Arg(0) == "clean" { + fmt.Println("Only cleaning, no new rules added") + return + } + // Dump out our environment for debugging purposes. + fmt.Println("Environment:") + fmt.Println("------------") + fmt.Printf("ENVOY_PORT=%s\n", os.Getenv("ENVOY_PORT")) + fmt.Printf("INBOUND_CAPTURE_PORT=%s\n", os.Getenv("INBOUND_CAPTURE_PORT")) + fmt.Printf("ISTIO_INBOUND_INTERCEPTION_MODE=%s\n", os.Getenv("ISTIO_INBOUND_INTERCEPTION_MODE")) + fmt.Printf("ISTIO_INBOUND_TPROXY_MARK=%s\n", os.Getenv("ISTIO_INBOUND_TPROXY_MARK")) + fmt.Printf("ISTIO_INBOUND_TPROXY_ROUTE_TABLE=%s\n", os.Getenv("ISTIO_INBOUND_TPROXY_ROUTE_TABLE")) + fmt.Printf("ISTIO_INBOUND_PORTS=%s\n", os.Getenv("ISTIO_INBOUND_PORTS")) + fmt.Printf("ISTIO_LOCAL_EXCLUDE_PORTS=%s\n", os.Getenv("ISTIO_LOCAL_EXCLUDE_PORTS")) + fmt.Printf("ISTIO_SERVICE_CIDR=%s\n", os.Getenv("ISTIO_SERVICE_CIDR")) + fmt.Printf("ISTIO_SERVICE_EXCLUDE_CIDR=%s\n", os.Getenv("ISTIO_SERVICE_EXCLUDE_CIDR")) + fmt.Println("") + fmt.Println("Variables:") + fmt.Println("----------") + fmt.Printf("PROXY_PORT=%s\n", proxyPort) + fmt.Printf("PROXY_INBOUND_CAPTURE_PORT=%s\n", inboundCapturePort) + fmt.Printf("PROXY_UID=%s\n", proxyUID) + fmt.Printf("INBOUND_INTERCEPTION_MODE=%s\n", inboundInterceptionMode) + fmt.Printf("INBOUND_TPROXY_MARK=%s\n", inboundTProxyMark) + fmt.Printf("INBOUND_TPROXY_ROUTE_TABLE=%s\n", inboundTProxyRouteTable) + fmt.Printf("INBOUND_PORTS_INCLUDE=%s\n", inboundPortsInclude) + fmt.Printf("INBOUND_PORTS_EXCLUDE=%s\n", inboundPortsExclude) + fmt.Printf("OUTBOUND_IP_RANGES_INCLUDE=%s\n", outboundIPRangesInclude) + fmt.Printf("OUTBOUND_IP_RANGES_EXCLUDE=%s\n", outboundIPRangesExclude) + fmt.Printf("OUTBOUND_PORTS_EXCLUDE=%s\n", outboundPortsExclude) + fmt.Printf("KUBEVIRT_INTERFACES=%s\n", kubevirtInterfaces) + // Print "" instead of to produce same output as script and satisfy golden tests + if enableInboundIPv6s == nil { + fmt.Printf("ENABLE_INBOUND_IPV6=%s\n", "") + } else { + fmt.Printf("ENABLE_INBOUND_IPV6=%s\n", enableInboundIPv6s) + } + fmt.Println("") + + if enableInboundIPv6s != nil { + ext.RunOrFail(dep.IP, "-6", "addr", "add", "::6/128", "dev", "lo") + } + + // Create a new chain for redirecting outbound traffic to the common Envoy port. + // In both chains, '-j RETURN' bypasses Envoy and '-j ISTIO_REDIRECT' + // redirects to Envoy. + ext.RunOrFail(dep.IPTABLES, "-t", "nat", "-N", "ISTIO_REDIRECT") + ext.RunOrFail(dep.IPTABLES, "-t", "nat", "-A", "ISTIO_REDIRECT", "-p", "tcp", "-j", "REDIRECT", "--to-port", proxyPort) + // Use this chain also for redirecting inbound traffic to the common Envoy port + // when not using TPROXY. + ext.RunOrFail(dep.IPTABLES, "-t", "nat", "-N", "ISTIO_IN_REDIRECT") + + // PROXY_INBOUND_CAPTURE_PORT should be used only user explicitly set INBOUND_PORTS_INCLUDE to capture all + if inboundPortsInclude == "*" { + ext.RunOrFail(dep.IPTABLES, "-t", "nat", "-A", "ISTIO_IN_REDIRECT", "-p", "tcp", "-j", "REDIRECT", "--to-port", inboundCapturePort) + } else { + ext.RunOrFail(dep.IPTABLES, "-t", "nat", "-A", "ISTIO_IN_REDIRECT", "-p", "tcp", "-j", "REDIRECT", "--to-port", proxyPort) + } + + var table string + // Handling of inbound ports. Traffic will be redirected to Envoy, which will process and forward + // to the local service. If not set, no inbound port will be intercepted by istio iptablesOrFail. + if inboundPortsInclude != "" { + if inboundInterceptionMode == "TPROXY" { + // When using TPROXY, create a new chain for routing all inbound traffic to + // Envoy. Any packet entering this chain gets marked with the ${INBOUND_TPROXY_MARK} mark, + // so that they get routed to the loopback interface in order to get redirected to Envoy. + // In the ISTIO_INBOUND chain, '-j ISTIO_DIVERT' reroutes to the loopback + // interface. + // Mark all inbound packets. + ext.RunOrFail(dep.IPTABLES, "-t", "mangle", "-N", "ISTIO_DIVERT") + ext.RunOrFail(dep.IPTABLES, "-t", "mangle", "-A", "ISTIO_DIVERT", "-j", "MARK", "--set-mark", inboundTProxyMark) + ext.RunOrFail(dep.IPTABLES, "-t", "mangle", "-A", "ISTIO_DIVERT", "-j", "ACCEPT") + // Route all packets marked in chain ISTIO_DIVERT using routing table ${INBOUND_TPROXY_ROUTE_TABLE}. + ext.RunOrFail(dep.IP, "-f", "inet", "rule", "add", "fwmark", inboundTProxyMark, "lookup", inboundTProxyRouteTable) + // In routing table ${INBOUND_TPROXY_ROUTE_TABLE}, create a single default rule to route all traffic to + // the loopback interface. + err = ext.Run(dep.IP, "-f", "inet", "route", "add", "local", "default", "dev", "lo", "table", inboundTProxyRouteTable) + if err != nil { + ext.RunOrFail(dep.IP, "route", "show", "table", "all") + } + // Create a new chain for redirecting inbound traffic to the common Envoy + // port. + // In the ISTIO_INBOUND chain, '-j RETURN' bypasses Envoy and + // '-j ISTIO_TPROXY' redirects to Envoy. + ext.RunOrFail(dep.IPTABLES, "-t", "mangle", "-N", "ISTIO_TPROXY") + ext.RunOrFail(dep.IPTABLES, "-t", "mangle", "-A", "ISTIO_TPROXY", "!", "-d", "127.0.0.1/32", "-p", "tcp", "-j", "TPROXY", + "--tproxy-mark", inboundTProxyMark+"/0xffffffff", "--on-port", proxyPort) + + table = "mangle" + } else { + table = "nat" + } + ext.RunOrFail(dep.IPTABLES, "-t", table, "-N", "ISTIO_INBOUND") + ext.RunOrFail(dep.IPTABLES, "-t", table, "-A", "PREROUTING", "-p", "tcp", "-j", "ISTIO_INBOUND") + + if inboundPortsInclude == "*" { + // Makes sure SSH is not redirected + ext.RunOrFail(dep.IPTABLES, "-t", table, "-A", "ISTIO_INBOUND", "-p", "tcp", "--dport", "22", "-j", "RETURN") + // Apply any user-specified port exclusions. + if inboundPortsExclude != "" { + for _, port := range split(inboundPortsExclude) { + ext.RunOrFail(dep.IPTABLES, "-t", table, "-A", "ISTIO_INBOUND", "-p", "tcp", "--dport", port, "-j", "RETURN") + } + } + // Redirect remaining inbound traffic to Envoy. + if inboundInterceptionMode == "TPROXY" { + // If an inbound packet belongs to an established socket, route it to the + // loopback interface. + err := ext.Run(dep.IPTABLES, "-t", "mangle", "-A", "ISTIO_INBOUND", "-p", "tcp", "-m", "socket", "-j", "ISTIO_DIVERT") + if err != nil { + fmt.Println("No socket match support") + } + // Otherwise, it's a new connection. Redirect it using TPROXY. + ext.RunOrFail(dep.IPTABLES, "-t", "mangle", "-A", "ISTIO_INBOUND", "-p", "tcp", "-j", "ISTIO_TPROXY") + } else { + ext.RunOrFail(dep.IPTABLES, "-t", "nat", "-A", "ISTIO_INBOUND", "-p", "tcp", "-j", "ISTIO_IN_REDIRECT") + } + } else { + // User has specified a non-empty list of ports to be redirected to Envoy. + for _, port := range split(inboundPortsInclude) { + if inboundInterceptionMode == "TPROXY" { + err := ext.Run(dep.IPTABLES, "-t", "mangle", "-A", "ISTIO_INBOUND", "-p", "tcp", "--dport", port, "-m", "socket", "-j", "ISTIO_DIVERT") + if err != nil { + fmt.Println("No socket match support") + } + err = ext.Run(dep.IPTABLES, "-t", "mangle", "-A", "ISTIO_INBOUND", "-p", "tcp", "--dport", port, "-m", "socket", "-j", "ISTIO_DIVERT") + if err != nil { + fmt.Println("No socket match support") + } + ext.RunOrFail(dep.IPTABLES, "-t", "mangle", "-A", "ISTIO_INBOUND", "-p", "tcp", "--dport", port, "-j", "ISTIO_TPROXY") + } else { + ext.RunOrFail(dep.IPTABLES, "-t", "nat", "-A", "ISTIO_INBOUND", "-p", "tcp", "--dport", port, "-j", "ISTIO_IN_REDIRECT") + } + } + } + } + // TODO: change the default behavior to not intercept any output - user may use http_proxy or another + // iptablesOrFail wrapper (like ufw). Current default is similar with 0.1 + // Create a new chain for selectively redirecting outbound packets to Envoy. + ext.RunOrFail(dep.IPTABLES, "-t", "nat", "-N", "ISTIO_OUTPUT") + // Jump to the ISTIO_OUTPUT chain from OUTPUT chain for all tcp traffic. + ext.RunOrFail(dep.IPTABLES, "-t", "nat", "-A", "OUTPUT", "-p", "tcp", "-j", "ISTIO_OUTPUT") + + // Apply port based exclusions. Must be applied before connections back to self are redirected. + if outboundPortsExclude != "" { + for _, port := range split(outboundPortsExclude) { + ext.RunOrFail(dep.IPTABLES, "-t", "nat", "-A", "ISTIO_OUTPUT", "-p", "tcp", "--dport", port, "-j", "RETURN") + } + } + + // 127.0.0.6 is bind connect from inbound passthrough cluster + ext.RunOrFail(dep.IPTABLES, "-t", "nat", "-A", "ISTIO_OUTPUT", "-o", "lo", "-s", "127.0.0.6/32", "-j", "RETURN") + + if env.RegisterStringVar("DISABLE_REDIRECTION_ON_LOCAL_LOOPBACK", "", "").Get() == "" { + // Redirect app calls back to itself via Envoy when using the service VIP or endpoint + // address, e.g. appN => Envoy (client) => Envoy (server) => appN. + ext.RunOrFail(dep.IPTABLES, "-t", "nat", "-A", "ISTIO_OUTPUT", "-o", "lo", "!", "-d", "127.0.0.1/32", "-j", "ISTIO_IN_REDIRECT") + } + + for _, uid := range split(proxyUID) { + // Avoid infinite loops. Don't redirect Envoy traffic directly back to + // Envoy for non-loopback traffic. + ext.RunOrFail(dep.IPTABLES, "-t", "nat", "-A", "ISTIO_OUTPUT", "-m", "owner", "--uid-owner", uid, "-j", "RETURN") + } + + for _, gid := range split(proxyGID) { + // Avoid infinite loops. Don't redirect Envoy traffic directly back to + // Envoy for non-loopback traffic. + ext.RunOrFail(dep.IPTABLES, "-t", "nat", "-A", "ISTIO_OUTPUT", "-m", "owner", "--gid-owner", gid, "-j", "RETURN") + } + // Skip redirection for Envoy-aware applications and + // container-to-container traffic both of which explicitly use + // localhost. + ext.RunOrFail(dep.IPTABLES, "-t", "nat", "-A", "ISTIO_OUTPUT", "-d", "127.0.0.1/32", "-j", "RETURN") + // Apply outbound IPv4 exclusions. Must be applied before inclusions. + for _, cidr := range ipv4RangesExclude.IPNets { + ext.RunOrFail(dep.IPTABLES, "-t", "nat", "-A", "ISTIO_OUTPUT", "-d", cidr.String(), "-j", "RETURN") + } + + for _, internalInterface := range split(kubevirtInterfaces) { + ext.RunOrFail(dep.IPTABLES, "-t", "nat", "-I", "PREROUTING", "1", "-i", internalInterface, "-j", "RETURN") + } + // Apply outbound IP inclusions. + if ipv4RangesInclude.IsWildcard { + // Wildcard specified. Redirect all remaining outbound traffic to Envoy. + ext.RunOrFail(dep.IPTABLES, "-t", "nat", "-A", "ISTIO_OUTPUT", "-j", "ISTIO_REDIRECT") + for _, internalInterface := range split(kubevirtInterfaces) { + ext.RunOrFail(dep.IPTABLES, "-t", "nat", "-I", "PREROUTING", "1", "-i", internalInterface, "-j", "ISTIO_REDIRECT") + } + } else if len(ipv4RangesInclude.IPNets) > 0 { + // User has specified a non-empty list of cidrs to be redirected to Envoy. + for _, cidr := range ipv4RangesInclude.IPNets { + for _, internalInterface := range split(kubevirtInterfaces) { + ext.RunOrFail(dep.IPTABLES, "-t", "nat", "-I", "PREROUTING", "1", "-i", internalInterface, "-d", cidr.String(), "-j", "ISTIO_REDIRECT") + } + ext.RunOrFail(dep.IPTABLES, "-t", "nat", "-A", "ISTIO_OUTPUT", "-d", cidr.String(), "-j", "ISTIO_REDIRECT") + } + // All other traffic is not redirected. + ext.RunOrFail(dep.IPTABLES, "-t", "nat", "-A", "ISTIO_OUTPUT", "-j", "RETURN") + } + // If ENABLE_INBOUND_IPV6 is unset (default unset), restrict IPv6 traffic. + if enableInboundIPv6s != nil { + // Remove the old chains, to generate new configs. + ext.RunQuietlyAndIgnore(dep.IP6TABLES, "-t", "nat", "-D", "PREROUTING", "-p", "tcp", "-j", "ISTIO_INBOUND") + ext.RunQuietlyAndIgnore(dep.IP6TABLES, "-t", "mangle", "-D", "PREROUTING", "-p", "tcp", "-j", "ISTIO_INBOUND") + ext.RunQuietlyAndIgnore(dep.IP6TABLES, "-t", "nat", "-D", "OUTPUT", "-p", "tcp", "-j", "ISTIO_OUTPUT") + // Flush and delete the istio chains. + ext.RunQuietlyAndIgnore(dep.IP6TABLES, "-t", "nat", "-F", "ISTIO_OUTPUT") + ext.RunQuietlyAndIgnore(dep.IP6TABLES, "-t", "nat", "-X", "ISTIO_OUTPUT") + ext.RunQuietlyAndIgnore(dep.IP6TABLES, "-t", "nat", "-F", "ISTIO_INBOUND") + ext.RunQuietlyAndIgnore(dep.IP6TABLES, "-t", "nat", "-X", "ISTIO_INBOUND") + ext.RunQuietlyAndIgnore(dep.IP6TABLES, "-t", "mangle", "-F", "ISTIO_INBOUND") + ext.RunQuietlyAndIgnore(dep.IP6TABLES, "-t", "mangle", "-X", "ISTIO_INBOUND") + ext.RunQuietlyAndIgnore(dep.IP6TABLES, "-t", "mangle", "-F", "ISTIO_DIVERT") + ext.RunQuietlyAndIgnore(dep.IP6TABLES, "-t", "mangle", "-X", "ISTIO_DIVERT") + ext.RunQuietlyAndIgnore(dep.IP6TABLES, "-t", "mangle", "-F", "ISTIO_TPROXY") + ext.RunQuietlyAndIgnore(dep.IP6TABLES, "-t", "mangle", "-X", "ISTIO_TPROXY") + + ext.RunQuietlyAndIgnore(dep.IP6TABLES, "-t", "nat", "-F", "ISTIO_REDIRECT") + ext.RunQuietlyAndIgnore(dep.IP6TABLES, "-t", "nat", "-X", "ISTIO_REDIRECT") + ext.RunQuietlyAndIgnore(dep.IP6TABLES, "-t", "nat", "-F", "ISTIO_IN_REDIRECT") + ext.RunQuietlyAndIgnore(dep.IP6TABLES, "-t", "nat", "-X", "ISTIO_IN_REDIRECT") + // Create a new chain for redirecting outbound traffic to the common Envoy port. + // In both chains, '-j RETURN' bypasses Envoy and '-j ISTIO_REDIRECT' + // redirects to Envoy. + ext.RunOrFail(dep.IP6TABLES, "-t", "nat", "-N", "ISTIO_REDIRECT") + ext.RunOrFail(dep.IP6TABLES, "-t", "nat", "-A", "ISTIO_REDIRECT", "-p", "tcp", "-j", "REDIRECT", "--to-port", proxyPort) + // Use this chain also for redirecting inbound traffic to the common Envoy port + // when not using TPROXY. + ext.RunOrFail(dep.IP6TABLES, "-t", "nat", "-N", "ISTIO_IN_REDIRECT") + if inboundPortsInclude == "*" { + ext.RunOrFail(dep.IP6TABLES, "-t", "nat", "-A", "ISTIO_IN_REDIRECT", "-p", "tcp", "-j", "REDIRECT", "--to-port", inboundCapturePort) + } else { + ext.RunOrFail(dep.IP6TABLES, "-t", "nat", "-A", "ISTIO_IN_REDIRECT", "-p", "tcp", "-j", "REDIRECT", "--to-port", proxyPort) + } + // Handling of inbound ports. Traffic will be redirected to Envoy, which will process and forward + // to the local service. If not set, no inbound port will be intercepted by istio iptablesOrFail. + if inboundPortsInclude != "" { + table = "nat" + ext.RunOrFail(dep.IP6TABLES, "-t", table, "-N", "ISTIO_INBOUND") + ext.RunOrFail(dep.IP6TABLES, "-t", table, "-A", "PREROUTING", "-p", "tcp", "-j", "ISTIO_INBOUND") + + if inboundPortsInclude == "*" { + // Makes sure SSH is not redirected + ext.RunOrFail(dep.IP6TABLES, "-t", table, "-A", "ISTIO_INBOUND", "-p", "tcp", "--dport", "22", "-j", "RETURN") + // Apply any user-specified port exclusions. + if inboundPortsExclude != "" { + for _, port := range split(inboundPortsExclude) { + ext.RunOrFail(dep.IP6TABLES, "-t", table, "-A", "ISTIO_INBOUND", "-p", "tcp", "--dport", port, "-j", "RETURN") + } + } + } else { + // User has specified a non-empty list of ports to be redirected to Envoy. + for _, port := range split(inboundPortsInclude) { + ext.RunOrFail(dep.IP6TABLES, "-t", "nat", "-A", "ISTIO_INBOUND", "-p", "tcp", "--dport", port, "-j", "ISTIO_IN_REDIRECT") + } + } + } + // Create a new chain for selectively redirecting outbound packets to Envoy. + ext.RunOrFail(dep.IP6TABLES, "-t", "nat", "-N", "ISTIO_OUTPUT") + // Jump to the ISTIO_OUTPUT chain from OUTPUT chain for all tcp traffic. + ext.RunOrFail(dep.IP6TABLES, "-t", "nat", "-A", "OUTPUT", "-p", "tcp", "-j", "ISTIO_OUTPUT") + // Apply port based exclusions. Must be applied before connections back to self are redirected. + if outboundPortsExclude != "" { + for _, port := range split(outboundPortsExclude) { + ext.RunOrFail(dep.IP6TABLES, "-t", "nat", "-A", "ISTIO_OUTPUT", "-p", "tcp", "--dport", port, "-j", "RETURN") + } + } + + // ::6 is bind connect from inbound passthrough cluster + ext.RunOrFail(dep.IP6TABLES, "-t", "nat", "-A", "ISTIO_OUTPUT", "-o", "lo", "-s", "::6/128", "-j", "RETURN") + + // Redirect app calls to back itself via Envoy when using the service VIP or endpoint + // address, e.g. appN => Envoy (client) => Envoy (server) => appN. + ext.RunOrFail(dep.IP6TABLES, "-t", "nat", "-A", "ISTIO_OUTPUT", "-o", "lo", "!", "-d", "::1/128", "-j", "ISTIO_IN_REDIRECT") + + for _, uid := range split(proxyUID) { + // Avoid infinite loops. Don't redirect Envoy traffic directly back to + // Envoy for non-loopback traffic. + ext.RunOrFail(dep.IP6TABLES, "-t", "nat", "-A", "ISTIO_OUTPUT", "-m", "owner", "--uid-owner", uid, "-j", "RETURN") + } + + for _, gid := range split(proxyGID) { + // Avoid infinite loops. Don't redirect Envoy traffic directly back to + // Envoy for non-loopback traffic. + ext.RunOrFail(dep.IP6TABLES, "-t", "nat", "-A", "ISTIO_OUTPUT", "-m", "owner", "--gid-owner", gid, "-j", "RETURN") + } + // Skip redirection for Envoy-aware applications and + // container-to-container traffic both of which explicitly use + // localhost. + ext.RunOrFail(dep.IP6TABLES, "-t", "nat", "-A", "ISTIO_OUTPUT", "-d", "::1/128", "-j", "RETURN") + // Apply outbound IPv6 exclusions. Must be applied before inclusions. + for _, cidr := range ipv6RangesExclude.IPNets { + ext.RunOrFail(dep.IP6TABLES, "-t", "nat", "-A", "ISTIO_OUTPUT", "-d", cidr.String(), "-j", "RETURN") + } + // Apply outbound IPv6 inclusions. + if ipv6RangesInclude.IsWildcard { + // Wildcard specified. Redirect all remaining outbound traffic to Envoy. + ext.RunOrFail(dep.IP6TABLES, "-t", "nat", "-A", "ISTIO_OUTPUT", "-j", "ISTIO_REDIRECT") + for _, internalInterface := range split(kubevirtInterfaces) { + ext.RunOrFail(dep.IP6TABLES, "-t", "nat", "-I", "PREROUTING", "1", "-i", internalInterface, "-j", "RETURN") + } + } else if len(ipv6RangesInclude.IPNets) > 0 { + // User has specified a non-empty list of cidrs to be redirected to Envoy. + for _, cidr := range ipv6RangesInclude.IPNets { + for _, internalInterface := range split(kubevirtInterfaces) { + ext.RunOrFail(dep.IP6TABLES, "-t", "nat", "-I", "PREROUTING", "1", "-i", internalInterface, "-d", cidr.String(), "-j", "ISTIO_REDIRECT") + } + ext.RunOrFail(dep.IP6TABLES, "-t", "nat", "-A", "ISTIO_OUTPUT", "-d", cidr.String(), "-j", "ISTIO_REDIRECT") + } + // All other traffic is not redirected. + ext.RunOrFail(dep.IP6TABLES, "-t", "nat", "-A", "ISTIO_OUTPUT", "-j", "RETURN") + } + } else { + // Drop all inbound traffic except established connections. + ext.RunQuietlyAndIgnore(dep.IP6TABLES, "-F", "INPUT") + ext.RunQuietlyAndIgnore(dep.IP6TABLES, "-A", "INPUT", "-m", "state", "--state", "ESTABLISHED", "-j", "ACCEPT") + ext.RunQuietlyAndIgnore(dep.IP6TABLES, "-A", "INPUT", "-i", "lo", "-d", "::1", "-j", "ACCEPT") + ext.RunQuietlyAndIgnore(dep.IP6TABLES, "-A", "INPUT", "-j", "REJECT") + } +} + +func main() { + run(os.Args[1:], flag.CommandLine) +} diff --git a/istio-1.3.5/tools/istioctl.bash b/istio-1.3.5/tools/istioctl.bash new file mode 100644 index 0000000..690fe1b --- /dev/null +++ b/istio-1.3.5/tools/istioctl.bash @@ -0,0 +1,2024 @@ +# bash completion for istioctl -*- shell-script -*- + +__istioctl_debug() +{ + if [[ -n ${BASH_COMP_DEBUG_FILE} ]]; then + echo "$*" >> "${BASH_COMP_DEBUG_FILE}" + fi +} + +# Homebrew on Macs have version 1.3 of bash-completion which doesn't include +# _init_completion. This is a very minimal version of that function. +__istioctl_init_completion() +{ + COMPREPLY=() + _get_comp_words_by_ref "$@" cur prev words cword +} + +__istioctl_index_of_word() +{ + local w word=$1 + shift + index=0 + for w in "$@"; do + [[ $w = "$word" ]] && return + index=$((index+1)) + done + index=-1 +} + +__istioctl_contains_word() +{ + local w word=$1; shift + for w in "$@"; do + [[ $w = "$word" ]] && return + done + return 1 +} + +__istioctl_handle_reply() +{ + __istioctl_debug "${FUNCNAME[0]}" + case $cur in + -*) + if [[ $(type -t compopt) = "builtin" ]]; then + compopt -o nospace + fi + local allflags + if [ ${#must_have_one_flag[@]} -ne 0 ]; then + allflags=("${must_have_one_flag[@]}") + else + allflags=("${flags[*]} ${two_word_flags[*]}") + fi + COMPREPLY=( $(compgen -W "${allflags[*]}" -- "$cur") ) + if [[ $(type -t compopt) = "builtin" ]]; then + [[ "${COMPREPLY[0]}" == *= ]] || compopt +o nospace + fi + + # complete after --flag=abc + if [[ $cur == *=* ]]; then + if [[ $(type -t compopt) = "builtin" ]]; then + compopt +o nospace + fi + + local index flag + flag="${cur%=*}" + __istioctl_index_of_word "${flag}" "${flags_with_completion[@]}" + COMPREPLY=() + if [[ ${index} -ge 0 ]]; then + PREFIX="" + cur="${cur#*=}" + ${flags_completion[${index}]} + if [ -n "${ZSH_VERSION}" ]; then + # zsh completion needs --flag= prefix + eval "COMPREPLY=( \"\${COMPREPLY[@]/#/${flag}=}\" )" + fi + fi + fi + return 0; + ;; + esac + + # check if we are handling a flag with special work handling + local index + __istioctl_index_of_word "${prev}" "${flags_with_completion[@]}" + if [[ ${index} -ge 0 ]]; then + ${flags_completion[${index}]} + return + fi + + # we are parsing a flag and don't have a special handler, no completion + if [[ ${cur} != "${words[cword]}" ]]; then + return + fi + + local completions + completions=("${commands[@]}") + if [[ ${#must_have_one_noun[@]} -ne 0 ]]; then + completions=("${must_have_one_noun[@]}") + fi + if [[ ${#must_have_one_flag[@]} -ne 0 ]]; then + completions+=("${must_have_one_flag[@]}") + fi + COMPREPLY=( $(compgen -W "${completions[*]}" -- "$cur") ) + + if [[ ${#COMPREPLY[@]} -eq 0 && ${#noun_aliases[@]} -gt 0 && ${#must_have_one_noun[@]} -ne 0 ]]; then + COMPREPLY=( $(compgen -W "${noun_aliases[*]}" -- "$cur") ) + fi + + if [[ ${#COMPREPLY[@]} -eq 0 ]]; then + declare -F __custom_func >/dev/null && __custom_func + fi + + # available in bash-completion >= 2, not always present on macOS + if declare -F __ltrim_colon_completions >/dev/null; then + __ltrim_colon_completions "$cur" + fi + + # If there is only 1 completion and it is a flag with an = it will be completed + # but we don't want a space after the = + if [[ "${#COMPREPLY[@]}" -eq "1" ]] && [[ $(type -t compopt) = "builtin" ]] && [[ "${COMPREPLY[0]}" == --*= ]]; then + compopt -o nospace + fi +} + +# The arguments should be in the form "ext1|ext2|extn" +__istioctl_handle_filename_extension_flag() +{ + local ext="$1" + _filedir "@(${ext})" +} + +__istioctl_handle_subdirs_in_dir_flag() +{ + local dir="$1" + pushd "${dir}" >/dev/null 2>&1 && _filedir -d && popd >/dev/null 2>&1 +} + +__istioctl_handle_flag() +{ + __istioctl_debug "${FUNCNAME[0]}: c is $c words[c] is ${words[c]}" + + # if a command required a flag, and we found it, unset must_have_one_flag() + local flagname=${words[c]} + local flagvalue + # if the word contained an = + if [[ ${words[c]} == *"="* ]]; then + flagvalue=${flagname#*=} # take in as flagvalue after the = + flagname=${flagname%=*} # strip everything after the = + flagname="${flagname}=" # but put the = back + fi + __istioctl_debug "${FUNCNAME[0]}: looking for ${flagname}" + if __istioctl_contains_word "${flagname}" "${must_have_one_flag[@]}"; then + must_have_one_flag=() + fi + + # if you set a flag which only applies to this command, don't show subcommands + if __istioctl_contains_word "${flagname}" "${local_nonpersistent_flags[@]}"; then + commands=() + fi + + # keep flag value with flagname as flaghash + # flaghash variable is an associative array which is only supported in bash > 3. + if [[ -z "${BASH_VERSION}" || "${BASH_VERSINFO[0]}" -gt 3 ]]; then + if [ -n "${flagvalue}" ] ; then + flaghash[${flagname}]=${flagvalue} + elif [ -n "${words[ $((c+1)) ]}" ] ; then + flaghash[${flagname}]=${words[ $((c+1)) ]} + else + flaghash[${flagname}]="true" # pad "true" for bool flag + fi + fi + + # skip the argument to a two word flag + if __istioctl_contains_word "${words[c]}" "${two_word_flags[@]}"; then + c=$((c+1)) + # if we are looking for a flags value, don't show commands + if [[ $c -eq $cword ]]; then + commands=() + fi + fi + + c=$((c+1)) + +} + +__istioctl_handle_noun() +{ + __istioctl_debug "${FUNCNAME[0]}: c is $c words[c] is ${words[c]}" + + if __istioctl_contains_word "${words[c]}" "${must_have_one_noun[@]}"; then + must_have_one_noun=() + elif __istioctl_contains_word "${words[c]}" "${noun_aliases[@]}"; then + must_have_one_noun=() + fi + + nouns+=("${words[c]}") + c=$((c+1)) +} + +__istioctl_handle_command() +{ + __istioctl_debug "${FUNCNAME[0]}: c is $c words[c] is ${words[c]}" + + local next_command + if [[ -n ${last_command} ]]; then + next_command="_${last_command}_${words[c]//:/__}" + else + if [[ $c -eq 0 ]]; then + next_command="_istioctl_root_command" + else + next_command="_${words[c]//:/__}" + fi + fi + c=$((c+1)) + __istioctl_debug "${FUNCNAME[0]}: looking for ${next_command}" + declare -F "$next_command" >/dev/null && $next_command +} + +__istioctl_handle_word() +{ + if [[ $c -ge $cword ]]; then + __istioctl_handle_reply + return + fi + __istioctl_debug "${FUNCNAME[0]}: c is $c words[c] is ${words[c]}" + if [[ "${words[c]}" == -* ]]; then + __istioctl_handle_flag + elif __istioctl_contains_word "${words[c]}" "${commands[@]}"; then + __istioctl_handle_command + elif [[ $c -eq 0 ]]; then + __istioctl_handle_command + elif __istioctl_contains_word "${words[c]}" "${command_aliases[@]}"; then + # aliashash variable is an associative array which is only supported in bash > 3. + if [[ -z "${BASH_VERSION}" || "${BASH_VERSINFO[0]}" -gt 3 ]]; then + words[c]=${aliashash[${words[c]}]} + __istioctl_handle_command + else + __istioctl_handle_noun + fi + else + __istioctl_handle_noun + fi + __istioctl_handle_word +} + +_istioctl_auth() +{ + last_command="istioctl_auth" + + command_aliases=() + + commands=() + + flags=() + two_word_flags=() + local_nonpersistent_flags=() + flags_with_completion=() + flags_completion=() + + flags+=("--context=") + flags+=("--istioNamespace=") + two_word_flags+=("-i") + flags+=("--kubeconfig=") + two_word_flags+=("-c") + flags+=("--log_output_level=") + flags+=("--namespace=") + two_word_flags+=("-n") + + must_have_one_flag=() + must_have_one_noun=() + noun_aliases=() +} + +_istioctl_authn_tls-check() +{ + last_command="istioctl_authn_tls-check" + + command_aliases=() + + commands=() + + flags=() + two_word_flags=() + local_nonpersistent_flags=() + flags_with_completion=() + flags_completion=() + + flags+=("--context=") + flags+=("--istioNamespace=") + two_word_flags+=("-i") + flags+=("--kubeconfig=") + two_word_flags+=("-c") + flags+=("--log_output_level=") + flags+=("--namespace=") + two_word_flags+=("-n") + + must_have_one_flag=() + must_have_one_noun=() + noun_aliases=() +} + +_istioctl_authn() +{ + last_command="istioctl_authn" + + command_aliases=() + + commands=() + commands+=("tls-check") + + flags=() + two_word_flags=() + local_nonpersistent_flags=() + flags_with_completion=() + flags_completion=() + + flags+=("--context=") + flags+=("--istioNamespace=") + two_word_flags+=("-i") + flags+=("--kubeconfig=") + two_word_flags+=("-c") + flags+=("--log_output_level=") + flags+=("--namespace=") + two_word_flags+=("-n") + + must_have_one_flag=() + must_have_one_noun=() + noun_aliases=() +} + +_istioctl_convert-ingress() +{ + last_command="istioctl_convert-ingress" + + command_aliases=() + + commands=() + + flags=() + two_word_flags=() + local_nonpersistent_flags=() + flags_with_completion=() + flags_completion=() + + flags+=("--filenames=") + two_word_flags+=("-f") + flags+=("--output=") + two_word_flags+=("-o") + flags+=("--context=") + flags+=("--istioNamespace=") + two_word_flags+=("-i") + flags+=("--kubeconfig=") + two_word_flags+=("-c") + flags+=("--log_output_level=") + flags+=("--namespace=") + two_word_flags+=("-n") + + must_have_one_flag=() + must_have_one_noun=() + noun_aliases=() +} + +_istioctl_dashboard_controlz() +{ + last_command="istioctl_dashboard_controlz" + + command_aliases=() + + commands=() + + flags=() + two_word_flags=() + local_nonpersistent_flags=() + flags_with_completion=() + flags_completion=() + + flags+=("--ctrlz_port=") + flags+=("--context=") + flags+=("--istioNamespace=") + two_word_flags+=("-i") + flags+=("--kubeconfig=") + two_word_flags+=("-c") + flags+=("--log_output_level=") + flags+=("--namespace=") + two_word_flags+=("-n") + + must_have_one_flag=() + must_have_one_noun=() + noun_aliases=() +} + +_istioctl_dashboard_envoy() +{ + last_command="istioctl_dashboard_envoy" + + command_aliases=() + + commands=() + + flags=() + two_word_flags=() + local_nonpersistent_flags=() + flags_with_completion=() + flags_completion=() + + flags+=("--context=") + flags+=("--istioNamespace=") + two_word_flags+=("-i") + flags+=("--kubeconfig=") + two_word_flags+=("-c") + flags+=("--log_output_level=") + flags+=("--namespace=") + two_word_flags+=("-n") + + must_have_one_flag=() + must_have_one_noun=() + noun_aliases=() +} + +_istioctl_dashboard_grafana() +{ + last_command="istioctl_dashboard_grafana" + + command_aliases=() + + commands=() + + flags=() + two_word_flags=() + local_nonpersistent_flags=() + flags_with_completion=() + flags_completion=() + + flags+=("--context=") + flags+=("--istioNamespace=") + two_word_flags+=("-i") + flags+=("--kubeconfig=") + two_word_flags+=("-c") + flags+=("--log_output_level=") + flags+=("--namespace=") + two_word_flags+=("-n") + + must_have_one_flag=() + must_have_one_noun=() + noun_aliases=() +} + +_istioctl_dashboard_jaeger() +{ + last_command="istioctl_dashboard_jaeger" + + command_aliases=() + + commands=() + + flags=() + two_word_flags=() + local_nonpersistent_flags=() + flags_with_completion=() + flags_completion=() + + flags+=("--context=") + flags+=("--istioNamespace=") + two_word_flags+=("-i") + flags+=("--kubeconfig=") + two_word_flags+=("-c") + flags+=("--log_output_level=") + flags+=("--namespace=") + two_word_flags+=("-n") + + must_have_one_flag=() + must_have_one_noun=() + noun_aliases=() +} + +_istioctl_dashboard_kiali() +{ + last_command="istioctl_dashboard_kiali" + + command_aliases=() + + commands=() + + flags=() + two_word_flags=() + local_nonpersistent_flags=() + flags_with_completion=() + flags_completion=() + + flags+=("--context=") + flags+=("--istioNamespace=") + two_word_flags+=("-i") + flags+=("--kubeconfig=") + two_word_flags+=("-c") + flags+=("--log_output_level=") + flags+=("--namespace=") + two_word_flags+=("-n") + + must_have_one_flag=() + must_have_one_noun=() + noun_aliases=() +} + +_istioctl_dashboard_prometheus() +{ + last_command="istioctl_dashboard_prometheus" + + command_aliases=() + + commands=() + + flags=() + two_word_flags=() + local_nonpersistent_flags=() + flags_with_completion=() + flags_completion=() + + flags+=("--context=") + flags+=("--istioNamespace=") + two_word_flags+=("-i") + flags+=("--kubeconfig=") + two_word_flags+=("-c") + flags+=("--log_output_level=") + flags+=("--namespace=") + two_word_flags+=("-n") + + must_have_one_flag=() + must_have_one_noun=() + noun_aliases=() +} + +_istioctl_dashboard_zipkin() +{ + last_command="istioctl_dashboard_zipkin" + + command_aliases=() + + commands=() + + flags=() + two_word_flags=() + local_nonpersistent_flags=() + flags_with_completion=() + flags_completion=() + + flags+=("--context=") + flags+=("--istioNamespace=") + two_word_flags+=("-i") + flags+=("--kubeconfig=") + two_word_flags+=("-c") + flags+=("--log_output_level=") + flags+=("--namespace=") + two_word_flags+=("-n") + + must_have_one_flag=() + must_have_one_noun=() + noun_aliases=() +} + +_istioctl_dashboard() +{ + last_command="istioctl_dashboard" + + command_aliases=() + + commands=() + commands+=("controlz") + commands+=("envoy") + commands+=("grafana") + commands+=("jaeger") + commands+=("kiali") + commands+=("prometheus") + commands+=("zipkin") + + flags=() + two_word_flags=() + local_nonpersistent_flags=() + flags_with_completion=() + flags_completion=() + + flags+=("--context=") + flags+=("--istioNamespace=") + two_word_flags+=("-i") + flags+=("--kubeconfig=") + two_word_flags+=("-c") + flags+=("--log_output_level=") + flags+=("--namespace=") + two_word_flags+=("-n") + + must_have_one_flag=() + must_have_one_noun=() + noun_aliases=() +} + +_istioctl_deregister() +{ + last_command="istioctl_deregister" + + command_aliases=() + + commands=() + + flags=() + two_word_flags=() + local_nonpersistent_flags=() + flags_with_completion=() + flags_completion=() + + flags+=("--context=") + flags+=("--istioNamespace=") + two_word_flags+=("-i") + flags+=("--kubeconfig=") + two_word_flags+=("-c") + flags+=("--log_output_level=") + flags+=("--namespace=") + two_word_flags+=("-n") + + must_have_one_flag=() + must_have_one_noun=() + noun_aliases=() +} + +_istioctl_experimental_add-to-mesh_external-service() +{ + last_command="istioctl_experimental_add-to-mesh_external-service" + + command_aliases=() + + commands=() + + flags=() + two_word_flags=() + local_nonpersistent_flags=() + flags_with_completion=() + flags_completion=() + + flags+=("--annotations=") + two_word_flags+=("-a") + flags+=("--labels=") + two_word_flags+=("-l") + flags+=("--serviceaccount=") + two_word_flags+=("-s") + flags+=("--context=") + flags+=("--istioNamespace=") + two_word_flags+=("-i") + flags+=("--kubeconfig=") + two_word_flags+=("-c") + flags+=("--log_output_level=") + flags+=("--namespace=") + two_word_flags+=("-n") + + must_have_one_flag=() + must_have_one_noun=() + noun_aliases=() +} + +_istioctl_experimental_add-to-mesh_service() +{ + last_command="istioctl_experimental_add-to-mesh_service" + + command_aliases=() + + commands=() + + flags=() + two_word_flags=() + local_nonpersistent_flags=() + flags_with_completion=() + flags_completion=() + + flags+=("--injectConfigFile=") + flags+=("--injectConfigMapName=") + flags+=("--meshConfigFile=") + flags+=("--meshConfigMapName=") + flags+=("--valuesFile=") + flags+=("--context=") + flags+=("--istioNamespace=") + two_word_flags+=("-i") + flags+=("--kubeconfig=") + two_word_flags+=("-c") + flags+=("--log_output_level=") + flags+=("--namespace=") + two_word_flags+=("-n") + + must_have_one_flag=() + must_have_one_noun=() + noun_aliases=() +} + +_istioctl_experimental_add-to-mesh() +{ + last_command="istioctl_experimental_add-to-mesh" + + command_aliases=() + + commands=() + commands+=("external-service") + commands+=("service") + + flags=() + two_word_flags=() + local_nonpersistent_flags=() + flags_with_completion=() + flags_completion=() + + flags+=("--context=") + flags+=("--istioNamespace=") + two_word_flags+=("-i") + flags+=("--kubeconfig=") + two_word_flags+=("-c") + flags+=("--log_output_level=") + flags+=("--namespace=") + two_word_flags+=("-n") + + must_have_one_flag=() + must_have_one_noun=() + noun_aliases=() +} + +_istioctl_experimental_analyze() +{ + last_command="istioctl_experimental_analyze" + + command_aliases=() + + commands=() + + flags=() + two_word_flags=() + local_nonpersistent_flags=() + flags_with_completion=() + flags_completion=() + + flags+=("--use-kube") + flags+=("-k") + flags+=("--context=") + flags+=("--istioNamespace=") + two_word_flags+=("-i") + flags+=("--kubeconfig=") + two_word_flags+=("-c") + flags+=("--log_output_level=") + flags+=("--namespace=") + two_word_flags+=("-n") + + must_have_one_flag=() + must_have_one_noun=() + noun_aliases=() +} + +_istioctl_experimental_auth_check() +{ + last_command="istioctl_experimental_auth_check" + + command_aliases=() + + commands=() + + flags=() + two_word_flags=() + local_nonpersistent_flags=() + flags_with_completion=() + flags_completion=() + + flags+=("--all") + flags+=("-a") + flags+=("--file=") + two_word_flags+=("-f") + flags+=("--context=") + flags+=("--istioNamespace=") + two_word_flags+=("-i") + flags+=("--kubeconfig=") + two_word_flags+=("-c") + flags+=("--log_output_level=") + flags+=("--namespace=") + two_word_flags+=("-n") + + must_have_one_flag=() + must_have_one_noun=() + noun_aliases=() +} + +_istioctl_experimental_auth_validate() +{ + last_command="istioctl_experimental_auth_validate" + + command_aliases=() + + commands=() + + flags=() + two_word_flags=() + local_nonpersistent_flags=() + flags_with_completion=() + flags_completion=() + + flags+=("--file=") + two_word_flags+=("-f") + flags+=("--context=") + flags+=("--istioNamespace=") + two_word_flags+=("-i") + flags+=("--kubeconfig=") + two_word_flags+=("-c") + flags+=("--log_output_level=") + flags+=("--namespace=") + two_word_flags+=("-n") + + must_have_one_flag=() + must_have_one_noun=() + noun_aliases=() +} + +_istioctl_experimental_auth() +{ + last_command="istioctl_experimental_auth" + + command_aliases=() + + commands=() + commands+=("check") + commands+=("validate") + + flags=() + two_word_flags=() + local_nonpersistent_flags=() + flags_with_completion=() + flags_completion=() + + flags+=("--context=") + flags+=("--istioNamespace=") + two_word_flags+=("-i") + flags+=("--kubeconfig=") + two_word_flags+=("-c") + flags+=("--log_output_level=") + flags+=("--namespace=") + two_word_flags+=("-n") + + must_have_one_flag=() + must_have_one_noun=() + noun_aliases=() +} + +_istioctl_experimental_convert-ingress() +{ + last_command="istioctl_experimental_convert-ingress" + + command_aliases=() + + commands=() + + flags=() + two_word_flags=() + local_nonpersistent_flags=() + flags_with_completion=() + flags_completion=() + + flags+=("--context=") + flags+=("--istioNamespace=") + two_word_flags+=("-i") + flags+=("--kubeconfig=") + two_word_flags+=("-c") + flags+=("--log_output_level=") + flags+=("--namespace=") + two_word_flags+=("-n") + + must_have_one_flag=() + must_have_one_noun=() + noun_aliases=() +} + +_istioctl_experimental_dashboard() +{ + last_command="istioctl_experimental_dashboard" + + command_aliases=() + + commands=() + + flags=() + two_word_flags=() + local_nonpersistent_flags=() + flags_with_completion=() + flags_completion=() + + flags+=("--context=") + flags+=("--istioNamespace=") + two_word_flags+=("-i") + flags+=("--kubeconfig=") + two_word_flags+=("-c") + flags+=("--log_output_level=") + flags+=("--namespace=") + two_word_flags+=("-n") + + must_have_one_flag=() + must_have_one_noun=() + noun_aliases=() +} + +_istioctl_experimental_describe_pod() +{ + last_command="istioctl_experimental_describe_pod" + + command_aliases=() + + commands=() + + flags=() + two_word_flags=() + local_nonpersistent_flags=() + flags_with_completion=() + flags_completion=() + + flags+=("--ignoreUnmeshed") + flags+=("--context=") + flags+=("--istioNamespace=") + two_word_flags+=("-i") + flags+=("--kubeconfig=") + two_word_flags+=("-c") + flags+=("--log_output_level=") + flags+=("--namespace=") + two_word_flags+=("-n") + + must_have_one_flag=() + must_have_one_noun=() + noun_aliases=() +} + +_istioctl_experimental_describe() +{ + last_command="istioctl_experimental_describe" + + command_aliases=() + + commands=() + commands+=("pod") + + flags=() + two_word_flags=() + local_nonpersistent_flags=() + flags_with_completion=() + flags_completion=() + + flags+=("--context=") + flags+=("--istioNamespace=") + two_word_flags+=("-i") + flags+=("--kubeconfig=") + two_word_flags+=("-c") + flags+=("--log_output_level=") + flags+=("--namespace=") + two_word_flags+=("-n") + + must_have_one_flag=() + must_have_one_noun=() + noun_aliases=() +} + +_istioctl_experimental_kube-uninject() +{ + last_command="istioctl_experimental_kube-uninject" + + command_aliases=() + + commands=() + + flags=() + two_word_flags=() + local_nonpersistent_flags=() + flags_with_completion=() + flags_completion=() + + flags+=("--filename=") + two_word_flags+=("-f") + flags+=("--output=") + two_word_flags+=("-o") + flags+=("--context=") + flags+=("--istioNamespace=") + two_word_flags+=("-i") + flags+=("--kubeconfig=") + two_word_flags+=("-c") + flags+=("--log_output_level=") + flags+=("--namespace=") + two_word_flags+=("-n") + + must_have_one_flag=() + must_have_one_noun=() + noun_aliases=() +} + +_istioctl_experimental_manifest_apply() +{ + last_command="istioctl_experimental_manifest_apply" + + command_aliases=() + + commands=() + + flags=() + two_word_flags=() + local_nonpersistent_flags=() + flags_with_completion=() + flags_completion=() + + flags+=("--filename=") + two_word_flags+=("-f") + flags+=("--readiness-timeout=") + flags+=("--set=") + two_word_flags+=("-s") + flags+=("--wait") + flags+=("-w") + flags+=("--yes") + flags+=("-y") + flags+=("--context=") + flags+=("--dry-run") + flags+=("--istioNamespace=") + two_word_flags+=("-i") + flags+=("--kubeconfig=") + two_word_flags+=("-c") + flags+=("--log_output_level=") + flags+=("--logtostderr") + flags+=("--namespace=") + two_word_flags+=("-n") + flags+=("--verbose") + + must_have_one_flag=() + must_have_one_noun=() + noun_aliases=() +} + +_istioctl_experimental_manifest_diff() +{ + last_command="istioctl_experimental_manifest_diff" + + command_aliases=() + + commands=() + + flags=() + two_word_flags=() + local_nonpersistent_flags=() + flags_with_completion=() + flags_completion=() + + flags+=("--directory") + flags+=("-r") + flags+=("--ignore=") + flags+=("--select=") + flags+=("--context=") + flags+=("--dry-run") + flags+=("--istioNamespace=") + two_word_flags+=("-i") + flags+=("--kubeconfig=") + two_word_flags+=("-c") + flags+=("--log_output_level=") + flags+=("--logtostderr") + flags+=("--namespace=") + two_word_flags+=("-n") + flags+=("--verbose") + + must_have_one_flag=() + must_have_one_noun=() + noun_aliases=() +} + +_istioctl_experimental_manifest_generate() +{ + last_command="istioctl_experimental_manifest_generate" + + command_aliases=() + + commands=() + + flags=() + two_word_flags=() + local_nonpersistent_flags=() + flags_with_completion=() + flags_completion=() + + flags+=("--filename=") + two_word_flags+=("-f") + flags+=("--output=") + two_word_flags+=("-o") + flags+=("--set=") + two_word_flags+=("-s") + flags+=("--context=") + flags+=("--dry-run") + flags+=("--istioNamespace=") + two_word_flags+=("-i") + flags+=("--kubeconfig=") + two_word_flags+=("-c") + flags+=("--log_output_level=") + flags+=("--logtostderr") + flags+=("--namespace=") + two_word_flags+=("-n") + flags+=("--verbose") + + must_have_one_flag=() + must_have_one_noun=() + noun_aliases=() +} + +_istioctl_experimental_manifest_migrate() +{ + last_command="istioctl_experimental_manifest_migrate" + + command_aliases=() + + commands=() + + flags=() + two_word_flags=() + local_nonpersistent_flags=() + flags_with_completion=() + flags_completion=() + + flags+=("--context=") + flags+=("--dry-run") + flags+=("--istioNamespace=") + two_word_flags+=("-i") + flags+=("--kubeconfig=") + two_word_flags+=("-c") + flags+=("--log_output_level=") + flags+=("--logtostderr") + flags+=("--namespace=") + two_word_flags+=("-n") + flags+=("--verbose") + + must_have_one_flag=() + must_have_one_noun=() + noun_aliases=() +} + +_istioctl_experimental_manifest_versions() +{ + last_command="istioctl_experimental_manifest_versions" + + command_aliases=() + + commands=() + + flags=() + two_word_flags=() + local_nonpersistent_flags=() + flags_with_completion=() + flags_completion=() + + flags+=("--versionsURI=") + two_word_flags+=("-u") + flags+=("--context=") + flags+=("--dry-run") + flags+=("--istioNamespace=") + two_word_flags+=("-i") + flags+=("--kubeconfig=") + two_word_flags+=("-c") + flags+=("--log_output_level=") + flags+=("--logtostderr") + flags+=("--namespace=") + two_word_flags+=("-n") + flags+=("--verbose") + + must_have_one_flag=() + must_have_one_noun=() + noun_aliases=() +} + +_istioctl_experimental_manifest() +{ + last_command="istioctl_experimental_manifest" + + command_aliases=() + + commands=() + commands+=("apply") + commands+=("diff") + commands+=("generate") + commands+=("migrate") + commands+=("versions") + + flags=() + two_word_flags=() + local_nonpersistent_flags=() + flags_with_completion=() + flags_completion=() + + flags+=("--dry-run") + flags+=("--logtostderr") + flags+=("--verbose") + flags+=("--context=") + flags+=("--istioNamespace=") + two_word_flags+=("-i") + flags+=("--kubeconfig=") + two_word_flags+=("-c") + flags+=("--log_output_level=") + flags+=("--namespace=") + two_word_flags+=("-n") + + must_have_one_flag=() + must_have_one_noun=() + noun_aliases=() +} + +_istioctl_experimental_metrics() +{ + last_command="istioctl_experimental_metrics" + + command_aliases=() + + commands=() + + flags=() + two_word_flags=() + local_nonpersistent_flags=() + flags_with_completion=() + flags_completion=() + + flags+=("--context=") + flags+=("--istioNamespace=") + two_word_flags+=("-i") + flags+=("--kubeconfig=") + two_word_flags+=("-c") + flags+=("--log_output_level=") + flags+=("--namespace=") + two_word_flags+=("-n") + + must_have_one_flag=() + must_have_one_noun=() + noun_aliases=() +} + +_istioctl_experimental_profile_diff() +{ + last_command="istioctl_experimental_profile_diff" + + command_aliases=() + + commands=() + + flags=() + two_word_flags=() + local_nonpersistent_flags=() + flags_with_completion=() + flags_completion=() + + flags+=("--context=") + flags+=("--dry-run") + flags+=("--istioNamespace=") + two_word_flags+=("-i") + flags+=("--kubeconfig=") + two_word_flags+=("-c") + flags+=("--log_output_level=") + flags+=("--logtostderr") + flags+=("--namespace=") + two_word_flags+=("-n") + flags+=("--verbose") + + must_have_one_flag=() + must_have_one_noun=() + noun_aliases=() +} + +_istioctl_experimental_profile_dump() +{ + last_command="istioctl_experimental_profile_dump" + + command_aliases=() + + commands=() + + flags=() + two_word_flags=() + local_nonpersistent_flags=() + flags_with_completion=() + flags_completion=() + + flags+=("--config-path=") + two_word_flags+=("-p") + flags+=("--filename=") + two_word_flags+=("-f") + flags+=("--helm-values") + flags+=("--context=") + flags+=("--dry-run") + flags+=("--istioNamespace=") + two_word_flags+=("-i") + flags+=("--kubeconfig=") + two_word_flags+=("-c") + flags+=("--log_output_level=") + flags+=("--logtostderr") + flags+=("--namespace=") + two_word_flags+=("-n") + flags+=("--verbose") + + must_have_one_flag=() + must_have_one_noun=() + noun_aliases=() +} + +_istioctl_experimental_profile_list() +{ + last_command="istioctl_experimental_profile_list" + + command_aliases=() + + commands=() + + flags=() + two_word_flags=() + local_nonpersistent_flags=() + flags_with_completion=() + flags_completion=() + + flags+=("--context=") + flags+=("--dry-run") + flags+=("--istioNamespace=") + two_word_flags+=("-i") + flags+=("--kubeconfig=") + two_word_flags+=("-c") + flags+=("--log_output_level=") + flags+=("--logtostderr") + flags+=("--namespace=") + two_word_flags+=("-n") + flags+=("--verbose") + + must_have_one_flag=() + must_have_one_noun=() + noun_aliases=() +} + +_istioctl_experimental_profile() +{ + last_command="istioctl_experimental_profile" + + command_aliases=() + + commands=() + commands+=("diff") + commands+=("dump") + commands+=("list") + + flags=() + two_word_flags=() + local_nonpersistent_flags=() + flags_with_completion=() + flags_completion=() + + flags+=("--dry-run") + flags+=("--logtostderr") + flags+=("--verbose") + flags+=("--context=") + flags+=("--istioNamespace=") + two_word_flags+=("-i") + flags+=("--kubeconfig=") + two_word_flags+=("-c") + flags+=("--log_output_level=") + flags+=("--namespace=") + two_word_flags+=("-n") + + must_have_one_flag=() + must_have_one_noun=() + noun_aliases=() +} + +_istioctl_experimental_remove-from-mesh_external-service() +{ + last_command="istioctl_experimental_remove-from-mesh_external-service" + + command_aliases=() + + commands=() + + flags=() + two_word_flags=() + local_nonpersistent_flags=() + flags_with_completion=() + flags_completion=() + + flags+=("--context=") + flags+=("--istioNamespace=") + two_word_flags+=("-i") + flags+=("--kubeconfig=") + two_word_flags+=("-c") + flags+=("--log_output_level=") + flags+=("--namespace=") + two_word_flags+=("-n") + + must_have_one_flag=() + must_have_one_noun=() + noun_aliases=() +} + +_istioctl_experimental_remove-from-mesh_service() +{ + last_command="istioctl_experimental_remove-from-mesh_service" + + command_aliases=() + + commands=() + + flags=() + two_word_flags=() + local_nonpersistent_flags=() + flags_with_completion=() + flags_completion=() + + flags+=("--context=") + flags+=("--istioNamespace=") + two_word_flags+=("-i") + flags+=("--kubeconfig=") + two_word_flags+=("-c") + flags+=("--log_output_level=") + flags+=("--namespace=") + two_word_flags+=("-n") + + must_have_one_flag=() + must_have_one_noun=() + noun_aliases=() +} + +_istioctl_experimental_remove-from-mesh() +{ + last_command="istioctl_experimental_remove-from-mesh" + + command_aliases=() + + commands=() + commands+=("external-service") + commands+=("service") + + flags=() + two_word_flags=() + local_nonpersistent_flags=() + flags_with_completion=() + flags_completion=() + + flags+=("--context=") + flags+=("--istioNamespace=") + two_word_flags+=("-i") + flags+=("--kubeconfig=") + two_word_flags+=("-c") + flags+=("--log_output_level=") + flags+=("--namespace=") + two_word_flags+=("-n") + + must_have_one_flag=() + must_have_one_noun=() + noun_aliases=() +} + +_istioctl_experimental() +{ + last_command="istioctl_experimental" + + command_aliases=() + + commands=() + commands+=("add-to-mesh") + if [[ -z "${BASH_VERSION}" || "${BASH_VERSINFO[0]}" -gt 3 ]]; then + command_aliases+=("add") + aliashash["add"]="add-to-mesh" + fi + commands+=("analyze") + commands+=("auth") + commands+=("convert-ingress") + commands+=("dashboard") + commands+=("describe") + if [[ -z "${BASH_VERSION}" || "${BASH_VERSINFO[0]}" -gt 3 ]]; then + command_aliases+=("des") + aliashash["des"]="describe" + fi + commands+=("kube-uninject") + commands+=("manifest") + commands+=("metrics") + if [[ -z "${BASH_VERSION}" || "${BASH_VERSINFO[0]}" -gt 3 ]]; then + command_aliases+=("m") + aliashash["m"]="metrics" + fi + commands+=("profile") + commands+=("remove-from-mesh") + if [[ -z "${BASH_VERSION}" || "${BASH_VERSINFO[0]}" -gt 3 ]]; then + command_aliases+=("remove") + aliashash["remove"]="remove-from-mesh" + fi + + flags=() + two_word_flags=() + local_nonpersistent_flags=() + flags_with_completion=() + flags_completion=() + + flags+=("--context=") + flags+=("--istioNamespace=") + two_word_flags+=("-i") + flags+=("--kubeconfig=") + two_word_flags+=("-c") + flags+=("--log_output_level=") + flags+=("--namespace=") + two_word_flags+=("-n") + + must_have_one_flag=() + must_have_one_noun=() + noun_aliases=() +} + +_istioctl_kube-inject() +{ + last_command="istioctl_kube-inject" + + command_aliases=() + + commands=() + + flags=() + two_word_flags=() + local_nonpersistent_flags=() + flags_with_completion=() + flags_completion=() + + flags+=("--filename=") + two_word_flags+=("-f") + flags+=("--injectConfigFile=") + flags+=("--injectConfigMapName=") + flags+=("--meshConfigFile=") + flags+=("--meshConfigMapName=") + flags+=("--output=") + two_word_flags+=("-o") + flags+=("--valuesFile=") + flags+=("--context=") + flags+=("--istioNamespace=") + two_word_flags+=("-i") + flags+=("--kubeconfig=") + two_word_flags+=("-c") + flags+=("--log_output_level=") + flags+=("--namespace=") + two_word_flags+=("-n") + + must_have_one_flag=() + must_have_one_noun=() + noun_aliases=() +} + +_istioctl_proxy-config_bootstrap() +{ + last_command="istioctl_proxy-config_bootstrap" + + command_aliases=() + + commands=() + + flags=() + two_word_flags=() + local_nonpersistent_flags=() + flags_with_completion=() + flags_completion=() + + flags+=("--context=") + flags+=("--istioNamespace=") + two_word_flags+=("-i") + flags+=("--kubeconfig=") + two_word_flags+=("-c") + flags+=("--log_output_level=") + flags+=("--namespace=") + two_word_flags+=("-n") + flags+=("--output=") + two_word_flags+=("-o") + + must_have_one_flag=() + must_have_one_noun=() + noun_aliases=() +} + +_istioctl_proxy-config_cluster() +{ + last_command="istioctl_proxy-config_cluster" + + command_aliases=() + + commands=() + + flags=() + two_word_flags=() + local_nonpersistent_flags=() + flags_with_completion=() + flags_completion=() + + flags+=("--direction=") + flags+=("--fqdn=") + flags+=("--port=") + flags+=("--subset=") + flags+=("--context=") + flags+=("--istioNamespace=") + two_word_flags+=("-i") + flags+=("--kubeconfig=") + two_word_flags+=("-c") + flags+=("--log_output_level=") + flags+=("--namespace=") + two_word_flags+=("-n") + flags+=("--output=") + two_word_flags+=("-o") + + must_have_one_flag=() + must_have_one_noun=() + noun_aliases=() +} + +_istioctl_proxy-config_endpoint() +{ + last_command="istioctl_proxy-config_endpoint" + + command_aliases=() + + commands=() + + flags=() + two_word_flags=() + local_nonpersistent_flags=() + flags_with_completion=() + flags_completion=() + + flags+=("--address=") + flags+=("--cluster=") + flags+=("--port=") + flags+=("--status=") + flags+=("--context=") + flags+=("--istioNamespace=") + two_word_flags+=("-i") + flags+=("--kubeconfig=") + two_word_flags+=("-c") + flags+=("--log_output_level=") + flags+=("--namespace=") + two_word_flags+=("-n") + flags+=("--output=") + two_word_flags+=("-o") + + must_have_one_flag=() + must_have_one_noun=() + noun_aliases=() +} + +_istioctl_proxy-config_listener() +{ + last_command="istioctl_proxy-config_listener" + + command_aliases=() + + commands=() + + flags=() + two_word_flags=() + local_nonpersistent_flags=() + flags_with_completion=() + flags_completion=() + + flags+=("--address=") + flags+=("--port=") + flags+=("--type=") + flags+=("--context=") + flags+=("--istioNamespace=") + two_word_flags+=("-i") + flags+=("--kubeconfig=") + two_word_flags+=("-c") + flags+=("--log_output_level=") + flags+=("--namespace=") + two_word_flags+=("-n") + flags+=("--output=") + two_word_flags+=("-o") + + must_have_one_flag=() + must_have_one_noun=() + noun_aliases=() +} + +_istioctl_proxy-config_route() +{ + last_command="istioctl_proxy-config_route" + + command_aliases=() + + commands=() + + flags=() + two_word_flags=() + local_nonpersistent_flags=() + flags_with_completion=() + flags_completion=() + + flags+=("--name=") + flags+=("--context=") + flags+=("--istioNamespace=") + two_word_flags+=("-i") + flags+=("--kubeconfig=") + two_word_flags+=("-c") + flags+=("--log_output_level=") + flags+=("--namespace=") + two_word_flags+=("-n") + flags+=("--output=") + two_word_flags+=("-o") + + must_have_one_flag=() + must_have_one_noun=() + noun_aliases=() +} + +_istioctl_proxy-config() +{ + last_command="istioctl_proxy-config" + + command_aliases=() + + commands=() + commands+=("bootstrap") + if [[ -z "${BASH_VERSION}" || "${BASH_VERSINFO[0]}" -gt 3 ]]; then + command_aliases+=("b") + aliashash["b"]="bootstrap" + fi + commands+=("cluster") + if [[ -z "${BASH_VERSION}" || "${BASH_VERSINFO[0]}" -gt 3 ]]; then + command_aliases+=("c") + aliashash["c"]="cluster" + command_aliases+=("clusters") + aliashash["clusters"]="cluster" + fi + commands+=("endpoint") + if [[ -z "${BASH_VERSION}" || "${BASH_VERSINFO[0]}" -gt 3 ]]; then + command_aliases+=("endpoints") + aliashash["endpoints"]="endpoint" + command_aliases+=("ep") + aliashash["ep"]="endpoint" + fi + commands+=("listener") + if [[ -z "${BASH_VERSION}" || "${BASH_VERSINFO[0]}" -gt 3 ]]; then + command_aliases+=("l") + aliashash["l"]="listener" + command_aliases+=("listeners") + aliashash["listeners"]="listener" + fi + commands+=("route") + if [[ -z "${BASH_VERSION}" || "${BASH_VERSINFO[0]}" -gt 3 ]]; then + command_aliases+=("r") + aliashash["r"]="route" + command_aliases+=("routes") + aliashash["routes"]="route" + fi + + flags=() + two_word_flags=() + local_nonpersistent_flags=() + flags_with_completion=() + flags_completion=() + + flags+=("--output=") + two_word_flags+=("-o") + flags+=("--context=") + flags+=("--istioNamespace=") + two_word_flags+=("-i") + flags+=("--kubeconfig=") + two_word_flags+=("-c") + flags+=("--log_output_level=") + flags+=("--namespace=") + two_word_flags+=("-n") + + must_have_one_flag=() + must_have_one_noun=() + noun_aliases=() +} + +_istioctl_proxy-status() +{ + last_command="istioctl_proxy-status" + + command_aliases=() + + commands=() + + flags=() + two_word_flags=() + local_nonpersistent_flags=() + flags_with_completion=() + flags_completion=() + + flags+=("--context=") + flags+=("--istioNamespace=") + two_word_flags+=("-i") + flags+=("--kubeconfig=") + two_word_flags+=("-c") + flags+=("--log_output_level=") + flags+=("--namespace=") + two_word_flags+=("-n") + + must_have_one_flag=() + must_have_one_noun=() + noun_aliases=() +} + +_istioctl_register() +{ + last_command="istioctl_register" + + command_aliases=() + + commands=() + + flags=() + two_word_flags=() + local_nonpersistent_flags=() + flags_with_completion=() + flags_completion=() + + flags+=("--annotations=") + two_word_flags+=("-a") + flags+=("--labels=") + two_word_flags+=("-l") + flags+=("--serviceaccount=") + two_word_flags+=("-s") + flags+=("--context=") + flags+=("--istioNamespace=") + two_word_flags+=("-i") + flags+=("--kubeconfig=") + two_word_flags+=("-c") + flags+=("--log_output_level=") + flags+=("--namespace=") + two_word_flags+=("-n") + + must_have_one_flag=() + must_have_one_noun=() + noun_aliases=() +} + +_istioctl_validate() +{ + last_command="istioctl_validate" + + command_aliases=() + + commands=() + + flags=() + two_word_flags=() + local_nonpersistent_flags=() + flags_with_completion=() + flags_completion=() + + flags+=("--filename=") + two_word_flags+=("-f") + flags+=("--referential") + flags+=("-x") + flags+=("--context=") + flags+=("--istioNamespace=") + two_word_flags+=("-i") + flags+=("--kubeconfig=") + two_word_flags+=("-c") + flags+=("--log_output_level=") + flags+=("--namespace=") + two_word_flags+=("-n") + + must_have_one_flag=() + must_have_one_noun=() + noun_aliases=() +} + +_istioctl_verify-install() +{ + last_command="istioctl_verify-install" + + command_aliases=() + + commands=() + + flags=() + two_word_flags=() + local_nonpersistent_flags=() + flags_with_completion=() + flags_completion=() + + flags+=("--enableVerbose") + local_nonpersistent_flags+=("--enableVerbose") + flags+=("--filename=") + flags_with_completion+=("--filename") + flags_completion+=("__istioctl_handle_filename_extension_flag json|yaml|yml") + two_word_flags+=("-f") + flags_with_completion+=("-f") + flags_completion+=("__istioctl_handle_filename_extension_flag json|yaml|yml") + flags+=("--recursive") + flags+=("-R") + flags+=("--context=") + flags+=("--istioNamespace=") + two_word_flags+=("-i") + flags+=("--kubeconfig=") + two_word_flags+=("-c") + flags+=("--log_output_level=") + flags+=("--namespace=") + two_word_flags+=("-n") + + must_have_one_flag=() + must_have_one_noun=() + noun_aliases=() +} + +_istioctl_version() +{ + last_command="istioctl_version" + + command_aliases=() + + commands=() + + flags=() + two_word_flags=() + local_nonpersistent_flags=() + flags_with_completion=() + flags_completion=() + + flags+=("--output=") + two_word_flags+=("-o") + local_nonpersistent_flags+=("--output=") + flags+=("--remote") + local_nonpersistent_flags+=("--remote") + flags+=("--short") + flags+=("-s") + local_nonpersistent_flags+=("--short") + flags+=("--context=") + flags+=("--istioNamespace=") + two_word_flags+=("-i") + flags+=("--kubeconfig=") + two_word_flags+=("-c") + flags+=("--log_output_level=") + flags+=("--namespace=") + two_word_flags+=("-n") + + must_have_one_flag=() + must_have_one_noun=() + noun_aliases=() +} + +_istioctl_root_command() +{ + last_command="istioctl" + + command_aliases=() + + commands=() + commands+=("auth") + commands+=("authn") + commands+=("convert-ingress") + commands+=("dashboard") + if [[ -z "${BASH_VERSION}" || "${BASH_VERSINFO[0]}" -gt 3 ]]; then + command_aliases+=("d") + aliashash["d"]="dashboard" + command_aliases+=("dash") + aliashash["dash"]="dashboard" + fi + commands+=("deregister") + commands+=("experimental") + if [[ -z "${BASH_VERSION}" || "${BASH_VERSINFO[0]}" -gt 3 ]]; then + command_aliases+=("exp") + aliashash["exp"]="experimental" + command_aliases+=("x") + aliashash["x"]="experimental" + fi + commands+=("kube-inject") + commands+=("proxy-config") + if [[ -z "${BASH_VERSION}" || "${BASH_VERSINFO[0]}" -gt 3 ]]; then + command_aliases+=("pc") + aliashash["pc"]="proxy-config" + fi + commands+=("proxy-status") + if [[ -z "${BASH_VERSION}" || "${BASH_VERSINFO[0]}" -gt 3 ]]; then + command_aliases+=("ps") + aliashash["ps"]="proxy-status" + fi + commands+=("register") + commands+=("validate") + commands+=("verify-install") + commands+=("version") + + flags=() + two_word_flags=() + local_nonpersistent_flags=() + flags_with_completion=() + flags_completion=() + + flags+=("--context=") + flags+=("--istioNamespace=") + two_word_flags+=("-i") + flags+=("--kubeconfig=") + two_word_flags+=("-c") + flags+=("--log_output_level=") + flags+=("--namespace=") + two_word_flags+=("-n") + + must_have_one_flag=() + must_have_one_noun=() + noun_aliases=() +} + +__start_istioctl() +{ + local cur prev words cword + declare -A flaghash 2>/dev/null || : + declare -A aliashash 2>/dev/null || : + if declare -F _init_completion >/dev/null 2>&1; then + _init_completion -s || return + else + __istioctl_init_completion -n "=" || return + fi + + local c=0 + local flags=() + local two_word_flags=() + local local_nonpersistent_flags=() + local flags_with_completion=() + local flags_completion=() + local commands=("istioctl") + local must_have_one_flag=() + local must_have_one_noun=() + local last_command + local nouns=() + + __istioctl_handle_word +} + +if [[ $(type -t compopt) = "builtin" ]]; then + complete -o default -F __start_istioctl istioctl +else + complete -o default -o nospace -F __start_istioctl istioctl +fi + +# ex: ts=4 sw=4 et filetype=sh diff --git a/istio-1.3.5/tools/license/README.md b/istio-1.3.5/tools/license/README.md new file mode 100644 index 0000000..9fff6cf --- /dev/null +++ b/istio-1.3.5/tools/license/README.md @@ -0,0 +1,16 @@ +# Istio License Generation Guide +## Usage +Note: This tool requires https://github.com/benbalter/licensee for --summary and --match_detail to work. +The --branch flag is only used in generating links to licenses in the appropriate branch in istio/istio. +Licenses under manual_append have been manually copied and OK'd (usually because the package source only +contains a link). +#### Generate complete dump of every license, suitable for including in release build/binary image: + go run get_dep_licenses.go --branch release-1.0.1 +#### CSV format output with one package per line: + go run get_dep_licenses.go --summary --branch release-1.0.1 +#### Detailed info about how closely each license matches official text: + go run get_dep_licenses.go --match-detail --branch release-1.0.1 +#### Use a different branch from the current one. Will do git checkout to that branch and back to the current on completion. This can only be used from inside Istio repo: + go run get_dep_licenses.go --branch release-1.0.1 --checkout +#### Check if all licenses are Google approved. Outputs lists of restricted, reciprocal, missing, and unknown status licenses. + go run get_dep_licenses.go --check \ No newline at end of file diff --git a/istio-1.3.5/tools/license/get_dep_licenses.go b/istio-1.3.5/tools/license/get_dep_licenses.go new file mode 100644 index 0000000..9f185b6 --- /dev/null +++ b/istio-1.3.5/tools/license/get_dep_licenses.go @@ -0,0 +1,577 @@ +// Copyright 2018 Istio Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Binary get_dep_licenses outputs aggrerate license information for all transitive Istio dependencies. +// This tool requires https://github.com/benbalter/licensee to work. +// Usage: +// 1) Generate complete dump of every license, suitable for including in release build/binary image: +// go run get_dep_licenses.go --branch release-1.0.1 +// 2) CSV format output with one package per line: +// go run get_dep_licenses.go --summary --branch release-1.0.1 +// 3) Detailed info about how closely each license matches official text: +// go run get_dep_licenses.go --match-detail --branch release-1.0.1 +// 4) Use a different branch from the current one. Will do git checkout to that branch and back to the current on completion. +// This can only be used from inside Istio repo: +// go run get_dep_licenses.go --branch release-1.0.1 --checkout +// 5) Check if all licenses are Google approved. Outputs lists of restricted, reciprocal, missing, and unknown status licenses. +// go run get_dep_licenses.go --check +package main + +import ( + "bytes" + "encoding/json" + "flag" + "fmt" + "io/ioutil" + "log" + "os" + "os/exec" + "path/filepath" + "sort" + "strings" + "time" +) + +type licenseType int + +const ( + // licenseTypeApproved is definitely ok to use and modify. + licenseTypeApproved licenseType = iota + // licenseTypeReciprocal can be used but not modified. + licenseTypeReciprocal + // licenseTypeRestricted + licenseTypeRestricted +) + +var ( + // licenseStrToType are code that's definitely ok to use and modify. + licenseStrToType = map[string]licenseType{ + // licenseTypeApproved + "Apache-2.0": licenseTypeApproved, + "ISC": licenseTypeApproved, + "AFL-2.1": licenseTypeApproved, + "AFL-3.0": licenseTypeApproved, + "Artistic-1.0": licenseTypeApproved, + "Artistic-2.0": licenseTypeApproved, + "Apache-1.1": licenseTypeApproved, + "BSD-1-Clause": licenseTypeApproved, + "BSD-2-Clause": licenseTypeApproved, + "BSD-3-Clause": licenseTypeApproved, + "FTL": licenseTypeApproved, + "LPL-1.02": licenseTypeApproved, + "MS-PL": licenseTypeApproved, + "MIT": licenseTypeApproved, + "NCSA": licenseTypeApproved, + "OpenSSL": licenseTypeApproved, + "PHP-3.0": licenseTypeApproved, + "TCP-wrappers": licenseTypeApproved, + "W3C": licenseTypeApproved, + "Xnet": licenseTypeApproved, + "Zlib": licenseTypeApproved, + // licenseTypeReciprocal + "CC0-1.0": licenseTypeReciprocal, + "APSL-2.0": licenseTypeReciprocal, + "CDDL-1.0": licenseTypeReciprocal, + "CDDL-1.1": licenseTypeReciprocal, + "CPL-1.0": licenseTypeReciprocal, + "EPL-1.0": licenseTypeReciprocal, + "IPL-1.0": licenseTypeReciprocal, + "MPL-1.0": licenseTypeReciprocal, + "MPL-1.1": licenseTypeReciprocal, + "MPL-2.0": licenseTypeReciprocal, + "Ruby": licenseTypeReciprocal, + // licenseTypeRestricted + "GPL-1.0-only": licenseTypeRestricted, + "GPL-1.0-or-later": licenseTypeRestricted, + "GPL-2.0-only": licenseTypeRestricted, + "GPL-2.0-or-later": licenseTypeRestricted, + "GPL-3.0-only": licenseTypeRestricted, + "GPL-3.0-or-later": licenseTypeRestricted, + "LGPL-2.0-only": licenseTypeRestricted, + "LGPL-2.0-or-later": licenseTypeRestricted, + "LGPL-2.1-only": licenseTypeRestricted, + "LGPL-2.1-or-later": licenseTypeRestricted, + "LGPL-3.0-only": licenseTypeRestricted, + "LGPL-3.0-or-later": licenseTypeRestricted, + "NPL-1.0": licenseTypeRestricted, + "NPL-1.1": licenseTypeRestricted, + "OSL-1.0": licenseTypeRestricted, + "OSL-1.1": licenseTypeRestricted, + "OSL-2.0": licenseTypeRestricted, + "OSL-2.1": licenseTypeRestricted, + "OSL-3.0": licenseTypeRestricted, + "QPL-1.0": licenseTypeRestricted, + "Sleepycat": licenseTypeRestricted, + } + // knownUnknownLicenses are either missing or unknown to licensee, but were manually copied and /or reviewed + // and are considered ok, so the tool will not complain about these. + knownUnknownLicenses = map[string]bool{ + // "github.com/jmespath/go-jmespath": true, // Not in manual_append + // "github.com/alicebob/gopher-json": true, // Not in manual_append + "github.com/dchest/siphash": true, // in manual_append + "github.com/signalfx/com_signalfx_metrics_protobuf": true, // in manual_append + "github.com/bmizerany/assert": true, // has license in README.md + "github.com/kr/logfmt": true, // Readme mentions MIT license + } + // Ignored modules + ignoredModules = []string{ + "istio.io/istio", + } + // root is the root of Go src code. + root = filepath.Join(os.Getenv("GOPATH"), "src") + // istioSubdir is the subdir from src root where istio source is found. + istioSubdir = "istio.io/istio" + // istioRoot is the path we expect to find istio source under. + istioRoot = filepath.Join(root, istioSubdir) + // istioReleaseBranch is the branch to generate licenses for. + istioReleaseBranch = "" + // goModCache is the module cache relative to root + goModCache = "/pkg/mod/" +) + +// LicenseInfo describes a license. +type LicenseInfo struct { + packageName string + path string + licensePath string + licenseeOutput string + licenseTypeString string + licenseText string + exact bool + confidence string +} + +// LicenseInfos is a slice of LicenseInfo. +type LicenseInfos []*LicenseInfo + +// Len implements the sort.Interface interface. +func (s LicenseInfos) Len() int { + return len(s) +} + +// Less implements the sort.Interface interface. +func (s LicenseInfos) Less(i, j int) bool { + return s[i].packageName < s[j].packageName +} + +// Swap implements the sort.Interface interface. +func (s LicenseInfos) Swap(i, j int) { + s[i], s[j] = s[j], s[i] +} + +type Module struct { + Path string `json:"Path"` + Version string `json:"Version"` + Replace *Module `json:"Replace"` + Time time.Time `json:"Time"` + Main bool `json:"Main"` + Indirect bool `json:"Indirect"` + Dir string `json:"Dir"` + GoMod string `json:"GoMod"` + GoVersion string `json:"GoVersion"` +} + +func main() { + var summary, checkout, matchDetail, check bool + flag.BoolVar(&summary, "summary", false, "Generate a summary report.") + flag.BoolVar(&checkout, "checkout", false, "Checkout target branch, return to current branch on completion. Can only use from inside Istio git repo.") + flag.BoolVar(&matchDetail, "match_detail", false, "Show information about match closeness for inexact matches.") + flag.BoolVar(&check, "check", false, "Check licenses to see if they are Google approved. Exits with error if any unapproved licenses are found, "+ + "but success does not imply all licenses are approved.") + flag.StringVar(&istioReleaseBranch, "branch", "", "Istio release branch to use.") + flag.Parse() + + // Verify inputs. + if summary && matchDetail { + log.Fatal("--summary and --match_detail cannot both be set.") + } + + if istioReleaseBranch == "" && !check { + var err error + istioReleaseBranch, err = runBashWithModuleSupport("git", "rev-parse", "HEAD") + if err != nil { + log.Fatalf("Could not get current commit: %s", err) + } + istioReleaseBranch = strings.TrimSpace(istioReleaseBranch) + } + + // Everything happens from istio root. + if err := os.Chdir(istioRoot); err != nil { + log.Fatalf("Could not chdir to Istio root at %s", istioRoot) + } + + // Handle git checkouts if the release branch we want != current branch + var prevBranch string + if checkout { + // Save git branch to return to later. + pb, err := runBashWithModuleSupport("git", "rev-parse", "--abbrev-ref", "HEAD") + if err != nil { + log.Fatalf("Could not get current branch: %s", err) + } + prevBranch = strings.TrimSpace(pb) + + // Need to switch to branch we're getting the licenses for. + _, err = runBashWithModuleSupport("git", "checkout", istioReleaseBranch) + if err != nil { + log.Fatalf("Could not git checkout %s: %s", istioReleaseBranch, err) + } + } + defer func() { + if checkout { + // Get back to original branch. + + _, err := exec.Command("git", "checkout", prevBranch).Output() + if err != nil { + log.Fatalf("Could not git checkout back to original branch %s.", prevBranch) + } + } + }() + + // First, make sure all the modules are downloaded into the cache + out, err := runBashWithModuleSupport("go", "mod", "download") + if err != nil { + log.Fatalf("go mod download failed: %s with output:\n%s", err, out) + } + + // List all the modules using json as we want multiple fields (defined in Module struct) + out, err = runBashWithModuleSupport("go", "list", "-m", "-json", "all") + if err != nil { + log.Fatalf("go list module failed: %s with output:\n%s", err, out) + } + + // Unmarshall json output + var modules []Module + + // Need to add `,`` between arrays in json output and add [] + jsonified := "[\n" + strings.Replace(out, "}\n{", "},\n{", -1) + "\n]" + + err = json.Unmarshal([]byte(jsonified), &modules) + if err != nil { + log.Fatalf("Unmarshall failed: %s", err) + } + + var missing []string + + licensePath := make(map[string]string) + for _, m := range modules { + + // Skip ignored module + if contains(ignoredModules, m.Path) { + continue + } + lf, err := findLicenseFiles(m.Dir) + if err != nil || lf == nil { + if !knownUnknownLicenses[m.Path] { + missing = append(missing, m.Path) + licensePath[m.Path] = "" + } + continue + } + + // TODO: Process multiple licenses. For now use first one and otput a warning + licensePath[m.Path] = lf[0] + if len(lf) > 1 { + log.Printf("Module %s(%s) has multiple (%d) license files:%v\n", m.Path, m.Dir, len(lf), lf) + } + } + + // Get sorted list of licensePaths + var keys []string + for lp := range licensePath { + keys = append(keys, lp) + } + sort.Strings(keys) + + licenseTypes := make(map[string][]string) + var reciprocalList, restrictedList, missingList []string + unknownMap := make(map[string]string) + var licenses, exact, inexact LicenseInfos + for _, key := range keys { + lp := licensePath[key] + if lp == "" { + missingList = append(missingList, key) + continue + } + linfo := &LicenseInfo{} + if matchDetail || summary || check { + // This requires the external licensee program. + linfo, err = getLicenseeInfo(lp) + if err != nil { + log.Printf("licensee error: %s", err) + continue + } + } + linfo.packageName = strings.TrimPrefix(key, istioSubdir+"/vendor/") + linfo.licenseText = readFile(lp) + linfo.path = lp + linfo.licensePath = getLicensePath(lp) + licenses = append(licenses, linfo) + ltypeStr := linfo.licenseTypeString + if linfo.exact { + licenseTypes[ltypeStr] = append(licenseTypes[ltypeStr], key) + exact = append(exact, linfo) + } else { + inexact = append(inexact, linfo) + } + + log.Printf("Checking %s\n", linfo.packageName) + lt, ok := licenseStrToType[ltypeStr] + switch { + // No license was found by licensee. + case ltypeStr == "": + missingList = append(missingList, linfo.packageName) + // License was found but not in a definite category. + case !ok: + if !knownUnknownLicenses[linfo.packageName] { + unknownMap[linfo.packageName] = ltypeStr + } + case lt == licenseTypeApproved: + case lt == licenseTypeReciprocal: + reciprocalList = append(reciprocalList, linfo.packageName) + case lt == licenseTypeRestricted: + restrictedList = append(restrictedList, linfo.packageName) + } + } + + if check { + exitCode := 0 + if len(reciprocalList) > 0 { + fmt.Println("===========================================================") + fmt.Println("The following packages have reciprocal licenses (code may") + fmt.Println("be used but not modified):") + fmt.Println("===========================================================") + fmt.Println(strings.Join(reciprocalList, "\n")) + exitCode |= 1 + } + if len(missingList) > 0 { + fmt.Println("===========================================================") + fmt.Println("The following packages have missing licenses:") + fmt.Println("===========================================================") + fmt.Println(strings.Join(missingList, "\n")) + exitCode |= 2 + } + if len(unknownMap) > 0 { + fmt.Println("===========================================================") + fmt.Println("The following packages have unknown status licenses (legal") + fmt.Println("review required). ") + fmt.Println("===========================================================") + // Get sorted list of paths + var keys []string + for k := range unknownMap { + keys = append(keys, k) + } + sort.Strings(keys) + for _, k := range keys { + fmt.Printf("%s:%s\n", k, unknownMap[k]) + } + exitCode |= 4 + } + if len(restrictedList) > 0 { + fmt.Println("===========================================================") + fmt.Println("The following packages had RESTRICTED licenses!") + fmt.Println("Packages MUST BE REMOVED! ") + fmt.Println("===========================================================") + fmt.Println(strings.Join(restrictedList, "\n")) + exitCode |= 8 + } + os.Exit(exitCode) + return + } + + sort.Sort(licenses) + sort.Sort(exact) + sort.Sort(inexact) + + if summary { + for _, p := range missing { + fmt.Printf("%s, MISSING\n", p) + } + for _, l := range append(inexact, exact...) { + fmt.Printf("%s,%s,%s,%s\n", l.packageName, l.licensePath, l.licenseTypeString, l.confidence) + } + return + } + + if len(missing) > 0 { + fmt.Fprintln(os.Stderr, "===========================================================") + fmt.Fprintln(os.Stderr, "The following packages were missing license files.") + fmt.Fprintln(os.Stderr, "===========================================================") + for _, p := range missing { + fmt.Fprintln(os.Stderr, p) + } + os.Exit(2) + } + + if matchDetail { + fmt.Println() + fmt.Println("===========================================================") + fmt.Println("The following packages had inexact licenses:") + fmt.Println("===========================================================") + for _, l := range inexact { + fmt.Printf("Package: %s\n", l.packageName) + fmt.Printf("License Relative To Module Cache: %s\n", l.licensePath) + fmt.Printf("Match info:\n%s\n", l.licenseeOutput) + fmt.Printf("License text:\n%s\n", l.licenseText) + fmt.Println("-----------------------------------------------------------") + } + + fmt.Println() + fmt.Println("===========================================================") + fmt.Println("The following packages had exact licenses:") + fmt.Println("===========================================================") + for t, ps := range licenseTypes { + fmt.Printf("\nLicense type: %s\n", t) + sort.Strings(ps) + for _, p := range ps { + fmt.Printf(" %s\n", p) + } + } + } else { + fmt.Println("===========================================================") + fmt.Println("Package licenses") + fmt.Println("===========================================================") + + for _, l := range append(exact, inexact...) { + fmt.Printf("Package: %s\n", l.packageName) + fmt.Printf("License Relative To Module Cache: %s\n", l.licensePath) + fmt.Printf("License text:\n%s\n", l.licenseText) + fmt.Println("-----------------------------------------------------------") + } + + // Append manually added files. + manualAppendDir := filepath.Join(istioRoot, "tools/license/manual_append") + fs, err := ioutil.ReadDir(manualAppendDir) + if err != nil { + log.Fatalf("ReadDir: %s\n", err) + } + for _, f := range fs { + b, err := ioutil.ReadFile(filepath.Join(manualAppendDir, f.Name())) + if err != nil { + log.Fatalf("ReadFile (%s): %s\n", f.Name(), err) + } + fmt.Print(string(b)) + } + + } +} + +// runBashWithModuleSupport runs a bash command. If command is successful, returns output, otherwise returns stderr output as error. +func runBashWithModuleSupport(args ...string) (string, error) { + cmd := exec.Command(args[0], args[1:]...) + + // Turn on GoModule support + cmd.Env = os.Environ() + cmd.Env = append(cmd.Env, "GO111MODULE=on") + var out bytes.Buffer + var stderr bytes.Buffer + cmd.Stdout = &out + cmd.Stderr = &stderr + err := cmd.Run() + if err != nil { + return "", fmt.Errorf(fmt.Sprint(err) + ": " + stderr.String()) + } + return out.String(), nil +} + +// getLicensePath returns the license path relative to the Golang module cache. +// It removes any of the path bup to and including the go mode cache (GOPATH/pkg/mod) +func getLicensePath(path string) string { + index := strings.Index(path, goModCache) + if index < 0 { + return path + } + return path[index+len(goModCache):] +} + +func readFile(path string) string { + b, err := ioutil.ReadFile(path) + if err != nil { + return err.Error() + } + return string(b) +} + +func getLicenseeInfo(path string) (*LicenseInfo, error) { + outb, err := exec.Command("licensee", "detect", path).Output() + if err != nil { + return nil, err + } + out := string(outb) + + licenseTypeString := getMatchingValue(out, "License:") + confidence := getMatchingValue(out, " Confidence:") + if licenseTypeString == "NOASSERTION" { + licenseTypeString, confidence = getLicenseAndConfidence(out) + } + + return &LicenseInfo{ + licenseeOutput: out, + licenseTypeString: licenseTypeString, + confidence: confidence, + exact: strings.Contains(out, "Licensee::Matchers::Exact"), + }, nil +} + +func getMatchingValue(in, match string) string { + for _, l := range strings.Split(in, "\n") { + if strings.Contains(l, match) { + return strings.TrimSpace(strings.TrimPrefix(l, match)) + } + } + return "" +} + +// For NOASSERTION license type, it means we are below the match threshold. Still grab the closest match and output +// confidence value. +func getLicenseAndConfidence(in string) (string, string) { + for _, l := range strings.Split(in, "\n") { + if strings.Contains(l, " similarity:") { + fs := strings.Fields(l) + return fs[0], fs[2] + } + } + return "UNKNOWN", "" +} + +func findLicenseFiles(path string) ([]string, error) { + // This will find files matching one of the specifications in + // the root directory of the module + outb, err := exec.Command("find", path, // Uncomment to only return the upper most file "-maxdepth", "1", + "-iname", "licen[sc]e", + "-o", "-iname", "licen[sc]e.txt", + "-o", "-iname", "licen[sc]e.md", + "-o", "-iname", "licen[sc]e.code", + "-o", "-iname", "copying").Output() + if err != nil { + return nil, err + } + out := string(outb) + if strings.TrimSpace(out) != "" { + outv := strings.Split(out, "\n") + for strings.TrimSpace(outv[len(outv)-1]) == "" { + outv = outv[:len(outv)-1] + } + return outv, nil + } + return nil, nil +} + +func contains(strings []string, s string) bool { + for _, str := range strings { + if str == s { + return true + } + } + return false +} diff --git a/istio-1.3.5/tools/license/manual_append/signalfx.txt b/istio-1.3.5/tools/license/manual_append/signalfx.txt new file mode 100644 index 0000000..e9c1c46 --- /dev/null +++ b/istio-1.3.5/tools/license/manual_append/signalfx.txt @@ -0,0 +1,8 @@ +Package: github.com/signalfx/com_signalfx_metrics_protobuf +License URL: https://github.com/istio/istio/blob/release-1.0/vendor/github.com/signalfx/com_signalfx_metrics_protobuf +License text: +## License + +Apache Software License v2. Copyright © 2015-2017 SignalFx + +----------------------------------------------------------- diff --git a/istio-1.3.5/tools/license/manual_append/siphash.txt b/istio-1.3.5/tools/license/manual_append/siphash.txt new file mode 100644 index 0000000..8a1c42f --- /dev/null +++ b/istio-1.3.5/tools/license/manual_append/siphash.txt @@ -0,0 +1,133 @@ +Package: github.com/dchest/siphash +License URL: https://github.com/istio/istio/blob/release-1.0/vendor/github.com/dchest/siphash/README.md +License text: +## Public domain dedication + +Written by Dmitry Chestnykh and Damian Gryski. + +To the extent possible under law, the authors have dedicated all copyright +and related and neighboring rights to this software to the public domain +worldwide. This software is distributed without any warranty. +http://creativecommons.org/publicdomain/zero/1.0/ +Creative Commons Legal Code + +CC0 1.0 Universal + + CREATIVE COMMONS CORPORATION IS NOT A LAW FIRM AND DOES NOT PROVIDE + LEGAL SERVICES. DISTRIBUTION OF THIS DOCUMENT DOES NOT CREATE AN + ATTORNEY-CLIENT RELATIONSHIP. CREATIVE COMMONS PROVIDES THIS + INFORMATION ON AN "AS-IS" BASIS. CREATIVE COMMONS MAKES NO WARRANTIES + REGARDING THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS + PROVIDED HEREUNDER, AND DISCLAIMS LIABILITY FOR DAMAGES RESULTING FROM + THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS PROVIDED + HEREUNDER. + +Statement of Purpose + +The laws of most jurisdictions throughout the world automatically confer +exclusive Copyright and Related Rights (defined below) upon the creator +and subsequent owner(s) (each and all, an "owner") of an original work of +authorship and/or a database (each, a "Work"). + +Certain owners wish to permanently relinquish those rights to a Work for +the purpose of contributing to a commons of creative, cultural and +scientific works ("Commons") that the public can reliably and without fear +of later claims of infringement build upon, modify, incorporate in other +works, reuse and redistribute as freely as possible in any form whatsoever +and for any purposes, including without limitation commercial purposes. +These owners may contribute to the Commons to promote the ideal of a free +culture and the further production of creative, cultural and scientific +works, or to gain reputation or greater distribution for their Work in +part through the use and efforts of others. + +For these and/or other purposes and motivations, and without any +expectation of additional consideration or compensation, the person +associating CC0 with a Work (the "Affirmer"), to the extent that he or she +is an owner of Copyright and Related Rights in the Work, voluntarily +elects to apply CC0 to the Work and publicly distribute the Work under its +terms, with knowledge of his or her Copyright and Related Rights in the +Work and the meaning and intended legal effect of CC0 on those rights. + +1. Copyright and Related Rights. A Work made available under CC0 may be +protected by copyright and related or neighboring rights ("Copyright and +Related Rights"). Copyright and Related Rights include, but are not +limited to, the following: + + i. the right to reproduce, adapt, distribute, perform, display, + communicate, and translate a Work; + ii. moral rights retained by the original author(s) and/or performer(s); +iii. publicity and privacy rights pertaining to a person's image or + likeness depicted in a Work; + iv. rights protecting against unfair competition in regards to a Work, + subject to the limitations in paragraph 4(a), below; + v. rights protecting the extraction, dissemination, use and reuse of data + in a Work; + vi. database rights (such as those arising under Directive 96/9/EC of the + European Parliament and of the Council of 11 March 1996 on the legal + protection of databases, and under any national implementation + thereof, including any amended or successor version of such + directive); and +vii. other similar, equivalent or corresponding rights throughout the + world based on applicable law or treaty, and any national + implementations thereof. + +2. Waiver. To the greatest extent permitted by, but not in contravention +of, applicable law, Affirmer hereby overtly, fully, permanently, +irrevocably and unconditionally waives, abandons, and surrenders all of +Affirmer's Copyright and Related Rights and associated claims and causes +of action, whether now known or unknown (including existing as well as +future claims and causes of action), in the Work (i) in all territories +worldwide, (ii) for the maximum duration provided by applicable law or +treaty (including future time extensions), (iii) in any current or future +medium and for any number of copies, and (iv) for any purpose whatsoever, +including without limitation commercial, advertising or promotional +purposes (the "Waiver"). Affirmer makes the Waiver for the benefit of each +member of the public at large and to the detriment of Affirmer's heirs and +successors, fully intending that such Waiver shall not be subject to +revocation, rescission, cancellation, termination, or any other legal or +equitable action to disrupt the quiet enjoyment of the Work by the public +as contemplated by Affirmer's express Statement of Purpose. + +3. Public License Fallback. Should any part of the Waiver for any reason +be judged legally invalid or ineffective under applicable law, then the +Waiver shall be preserved to the maximum extent permitted taking into +account Affirmer's express Statement of Purpose. In addition, to the +extent the Waiver is so judged Affirmer hereby grants to each affected +person a royalty-free, non transferable, non sublicensable, non exclusive, +irrevocable and unconditional license to exercise Affirmer's Copyright and +Related Rights in the Work (i) in all territories worldwide, (ii) for the +maximum duration provided by applicable law or treaty (including future +time extensions), (iii) in any current or future medium and for any number +of copies, and (iv) for any purpose whatsoever, including without +limitation commercial, advertising or promotional purposes (the +"License"). The License shall be deemed effective as of the date CC0 was +applied by Affirmer to the Work. Should any part of the License for any +reason be judged legally invalid or ineffective under applicable law, such +partial invalidity or ineffectiveness shall not invalidate the remainder +of the License, and in such case Affirmer hereby affirms that he or she +will not (i) exercise any of his or her remaining Copyright and Related +Rights in the Work or (ii) assert any associated claims and causes of +action with respect to the Work, in either case contrary to Affirmer's +express Statement of Purpose. + +4. Limitations and Disclaimers. + + a. No trademark or patent rights held by Affirmer are waived, abandoned, + surrendered, licensed or otherwise affected by this document. + b. Affirmer offers the Work as-is and makes no representations or + warranties of any kind concerning the Work, express, implied, + statutory or otherwise, including without limitation warranties of + title, merchantability, fitness for a particular purpose, non + infringement, or the absence of latent or other defects, accuracy, or + the present or absence of errors, whether or not discoverable, all to + the greatest extent permissible under applicable law. + c. Affirmer disclaims responsibility for clearing rights of other persons + that may apply to the Work or any use thereof, including without + limitation any person's Copyright and Related Rights in the Work. + Further, Affirmer disclaims responsibility for obtaining any necessary + consents, permissions or other rights required for any use of the + Work. + d. Affirmer understands and acknowledges that Creative Commons is not a + party to this document and has no duty or obligation with respect to + this CC0 or use of the Work. +----------------------------------------------------------- diff --git a/istio-1.3.5/tools/packaging/common/envoy_bootstrap_drain.json b/istio-1.3.5/tools/packaging/common/envoy_bootstrap_drain.json new file mode 100644 index 0000000..2c63c08 --- /dev/null +++ b/istio-1.3.5/tools/packaging/common/envoy_bootstrap_drain.json @@ -0,0 +1,2 @@ +{ +} diff --git a/istio-1.3.5/tools/packaging/common/envoy_bootstrap_v2.json b/istio-1.3.5/tools/packaging/common/envoy_bootstrap_v2.json new file mode 100644 index 0000000..021bf27 --- /dev/null +++ b/istio-1.3.5/tools/packaging/common/envoy_bootstrap_v2.json @@ -0,0 +1,591 @@ +{ + "node": { + "id": "{{ .nodeID }}", + "cluster": "{{ .cluster }}", + "locality": { + {{ if .region }} + "region": "{{ .region }}", + {{ end }} + {{ if .zone }} + "zone": "{{ .zone }}", + {{ end }} + {{ if .sub_zone }} + "sub_zone": "{{ .sub_zone }}", + {{ end }} + }, + "metadata": {{ .meta_json_str }} + }, + "stats_config": { + "use_all_default_tags": false, + "stats_tags": [ + { + "tag_name": "cluster_name", + "regex": "^cluster\\.((.+?(\\..+?\\.svc\\.cluster\\.local)?)\\.)" + }, + { + "tag_name": "tcp_prefix", + "regex": "^tcp\\.((.*?)\\.)\\w+?$" + }, + { + "regex": "(response_code=\\.=(.+?);\\.;)|_rq(_(\\.d{3}))$", + "tag_name": "response_code" + }, + { + "tag_name": "response_code_class", + "regex": "_rq(_(\\dxx))$" + }, + { + "tag_name": "http_conn_manager_listener_prefix", + "regex": "^listener(?=\\.).*?\\.http\\.(((?:[_.[:digit:]]*|[_\\[\\]aAbBcCdDeEfF[:digit:]]*))\\.)" + }, + { + "tag_name": "http_conn_manager_prefix", + "regex": "^http\\.(((?:[_.[:digit:]]*|[_\\[\\]aAbBcCdDeEfF[:digit:]]*))\\.)" + }, + { + "tag_name": "listener_address", + "regex": "^listener\\.(((?:[_.[:digit:]]*|[_\\[\\]aAbBcCdDeEfF[:digit:]]*))\\.)" + }, + { + "tag_name": "mongo_prefix", + "regex": "^mongo\\.(.+?)\\.(collection|cmd|cx_|op_|delays_|decoding_)(.*?)$" + }, + { + "regex": "(reporter=\\.=(.+?);\\.;)", + "tag_name": "reporter" + }, + { + "regex": "(source_namespace=\\.=(.+?);\\.;)", + "tag_name": "source_namespace" + }, + { + "regex": "(source_workload=\\.=(.+?);\\.;)", + "tag_name": "source_workload" + }, + { + "regex": "(source_workload_namespace=\\.=(.+?);\\.;)", + "tag_name": "source_workload_namespace" + }, + { + "regex": "(source_principal=\\.=(.+?);\\.;)", + "tag_name": "source_principal" + }, + { + "regex": "(source_app=\\.=(.+?);\\.;)", + "tag_name": "source_app" + }, + { + "regex": "(source_version=\\.=(.+?);\\.;)", + "tag_name": "source_version" + }, + { + "regex": "(destination_namespace=\\.=(.+?);\\.;)", + "tag_name": "destination_namespace" + }, + { + "regex": "(destination_workload=\\.=(.+?);\\.;)", + "tag_name": "destination_workload" + }, + { + "regex": "(destination_workload_namespace=\\.=(.+?);\\.;)", + "tag_name": "destination_workload_namespace" + }, + { + "regex": "(destination_principal=\\.=(.+?);\\.;)", + "tag_name": "destination_principal" + }, + { + "regex": "(destination_app=\\.=(.+?);\\.;)", + "tag_name": "destination_app" + }, + { + "regex": "(destination_version=\\.=(.+?);\\.;)", + "tag_name": "destination_version" + }, + { + "regex": "(destination_service=\\.=(.+?);\\.;)", + "tag_name": "destination_service" + }, + { + "regex": "(destination_service_name=\\.=(.+?);\\.;)", + "tag_name": "destination_service_name" + }, + { + "regex": "(destination_service_namespace=\\.=(.+?);\\.;)", + "tag_name": "destination_service_namespace" + }, + { + "regex": "(request_protocol=\\.=(.+?);\\.;)", + "tag_name": "request_protocol" + }, + { + "regex": "(response_flags=\\.=(.+?);\\.;)", + "tag_name": "response_flags" + }, + { + "regex": "(connection_security_policy=\\.=(.+?);\\.;)", + "tag_name": "connection_security_policy" + }, + { + "regex": "(cache\\.(.+?)\\.)", + "tag_name": "cache" + } + ], + "stats_matcher": { + "inclusion_list": { + "patterns": [ + { + "prefix": "reporter=" + }, + {{- range $a, $s := .inclusionPrefix }} + { + "prefix": "{{$s}}" + }, + {{- end }} + {{- range $a, $s := .inclusionSuffix }} + { + "suffix": "{{$s}}" + }, + {{- end }} + {{- range $a, $s := .inclusionRegexps }} + { + "regex": "{{js $s}}" + }, + {{- end }} + ] + } + } + }, + "admin": { + "access_log_path": "/dev/null", + "address": { + "socket_address": { + "address": "{{ .localhost }}", + "port_value": {{ .config.ProxyAdminPort }} + } + } + }, + "dynamic_resources": { + "lds_config": { + "ads": {} + }, + "cds_config": { + "ads": {} + }, + "ads_config": { + "api_type": "GRPC", + "grpc_services": [ + { + "envoy_grpc": { + "cluster_name": "xds-grpc" + } + } + ] + } + }, + "static_resources": { + "clusters": [ + { + "name": "prometheus_stats", + "type": "STATIC", + "connect_timeout": "0.250s", + "lb_policy": "ROUND_ROBIN", + "hosts": [ + { + "socket_address": { + "protocol": "TCP", + "address": "{{ .localhost }}", + "port_value": {{ .config.ProxyAdminPort }} + } + } + ] + }, + { + "name": "xds-grpc", + "type": "STRICT_DNS", + "dns_refresh_rate": "{{ .dns_refresh_rate }}", + "dns_lookup_family": "{{ .dns_lookup_family }}", + "connect_timeout": "{{ .connect_timeout }}", + "lb_policy": "ROUND_ROBIN", + {{ if eq .config.ControlPlaneAuthPolicy 1 }} + {{ if .sds_uds_path }} + "tls_context": { + "common_tls_context": { + "alpn_protocols": [ + "h2" + ], + "tls_certificate_sds_secret_configs":[ + { + "name":"default", + "sds_config":{ + "api_config_source":{ + "api_type":"GRPC", + "grpc_services":[ + { + "google_grpc":{ + "target_uri": "{{ .sds_uds_path }}", + "channel_credentials":{ + "local_credentials":{ + } + }, + "call_credentials":[ + { + "from_plugin":{ + "name":"envoy.grpc_credentials.file_based_metadata", + "config":{ + "secret_data":{ + "filename": "{{ .sds_token_path }}" + }, + "header_key":"istio_sds_credentials_header-bin" + } + } + } + ], + "credentials_factory_name":"envoy.grpc_credentials.file_based_metadata", + "stat_prefix":"sdsstat" + } + } + ] + } + } + } + ], + "combined_validation_context":{ + "default_validation_context":{ + "verify_subject_alt_name":[ + {{- range $a, $s := .pilot_SAN }} + "{{$s}}" + {{- end}} + ] + }, + "validation_context_sds_secret_config":{ + "name":"ROOTCA", + "sds_config":{ + "api_config_source":{ + "api_type":"GRPC", + "grpc_services":[ + { + "google_grpc":{ + "target_uri": "{{ .sds_uds_path }}", + "channel_credentials":{ + "local_credentials":{ + } + }, + "call_credentials":[ + { + "from_plugin":{ + "name":"envoy.grpc_credentials.file_based_metadata", + "config":{ + "secret_data":{ + "filename": "{{ .sds_token_path }}" + }, + "header_key":"istio_sds_credentials_header-bin" + } + } + } + ], + "credentials_factory_name":"envoy.grpc_credentials.file_based_metadata", + "stat_prefix":"sdsstat" + } + } + ] + } + } + } + } + }, + }, + {{ else }} + "tls_context": { + "common_tls_context": { + "alpn_protocols": [ + "h2" + ], + "tls_certificates": [ + { + "certificate_chain": { + "filename": "/etc/certs/cert-chain.pem" + }, + "private_key": { + "filename": "/etc/certs/key.pem" + } + } + ], + "validation_context": { + "trusted_ca": { + "filename": "/etc/certs/root-cert.pem" + }, + "verify_subject_alt_name": [ + {{- range $a, $s := .pilot_SAN }} + "{{$s}}" + {{- end}} + ] + } + } + }, + {{ end }} + {{ end }} + "hosts": [ + { + "socket_address": {{ .pilot_grpc_address }} + } + ], + "circuit_breakers": { + "thresholds": [ + { + "priority": "DEFAULT", + "max_connections": 100000, + "max_pending_requests": 100000, + "max_requests": 100000 + }, + { + "priority": "HIGH", + "max_connections": 100000, + "max_pending_requests": 100000, + "max_requests": 100000 + } + ] + }, + "upstream_connection_options": { + "tcp_keepalive": { + "keepalive_time": 300 + } + }, + "http2_protocol_options": { } + } + {{ if .zipkin }} + , + { + "name": "zipkin", + "type": "STRICT_DNS", + "dns_refresh_rate": "{{ .dns_refresh_rate }}", + "dns_lookup_family": "{{ .dns_lookup_family }}", + "connect_timeout": "1s", + "lb_policy": "ROUND_ROBIN", + "hosts": [ + { + "socket_address": {{ .zipkin }} + } + ] + } + {{ else if .lightstep }} + , + { + "name": "lightstep", + "http2_protocol_options": {}, + {{ if .lightstepSecure }} + "tls_context": { + "common_tls_context": { + "alpn_protocols": [ + "h2" + ], + "validation_context": { + "trusted_ca": { + "filename": "{{ .lightstepCacertPath }}" + } + } + } + }, + {{ end }} + "type": "STRICT_DNS", + "dns_refresh_rate": "{{ .dns_refresh_rate }}", + "dns_lookup_family": "{{ .dns_lookup_family }}", + "connect_timeout": "1s", + "lb_policy": "ROUND_ROBIN", + "hosts": [ + { + "socket_address": {{ .lightstep }} + } + ] + } + {{ else if .datadog }} + , + { + "name": "datadog_agent", + "connect_timeout": "1s", + "type": "STRICT_DNS", + "dns_refresh_rate": "{{ .dns_refresh_rate }}", + "dns_lookup_family": "{{ .dns_lookup_family }}", + "lb_policy": "ROUND_ROBIN", + "hosts": [ + { + "socket_address": {{ .datadog }} + } + ] + } + {{ end }} + {{ if .envoy_metrics_service }} + , + { + "name": "envoy_metrics_service", + "type": "STRICT_DNS", + "dns_refresh_rate": "{{ .dns_refresh_rate }}", + "dns_lookup_family": "{{ .dns_lookup_family }}", + "connect_timeout": "1s", + "lb_policy": "ROUND_ROBIN", + "http2_protocol_options": {}, + "hosts": [ + { + "socket_address": {{ .envoy_metrics_service }} + } + ] + } + {{ end }} + {{ if .envoy_accesslog_service_address }} + , + { + "name": "envoy_accesslog_service", + "type": "STRICT_DNS", + {{ if .envoy_accesslog_service_tls }} + "tls_context": {{ .envoy_accesslog_service_tls }}, + {{ end }} + {{ if .envoy_accesslog_service_tcp_keepalive }} + "upstream_connection_options": {{ .envoy_accesslog_service_tcp_keepalive }}, + {{ end }} + "dns_refresh_rate": "{{ .dns_refresh_rate }}", + "dns_lookup_family": "{{ .dns_lookup_family }}", + "connect_timeout": "1s", + "lb_policy": "ROUND_ROBIN", + "http2_protocol_options": {}, + "hosts": [ + { + "socket_address": {{ .envoy_accesslog_service_address }} + } + ] + } + {{ end }} + ], + "listeners":[ + { + "address": { + "socket_address": { + "protocol": "TCP", + "address": "{{ .wildcard }}", + "port_value": 15090 + } + }, + "filter_chains": [ + { + "filters": [ + { + "name": "envoy.http_connection_manager", + "config": { + "codec_type": "AUTO", + "stat_prefix": "stats", + "route_config": { + "virtual_hosts": [ + { + "name": "backend", + "domains": [ + "*" + ], + "routes": [ + { + "match": { + "prefix": "/stats/prometheus" + }, + "route": { + "cluster": "prometheus_stats" + } + } + ] + } + ] + }, + "http_filters": { + "name": "envoy.router" + } + } + } + ] + } + ] + } + ] + } + {{ if .zipkin }} + , + "tracing": { + "http": { + "name": "envoy.zipkin", + "config": { + "collector_cluster": "zipkin", + "collector_endpoint": "/api/v1/spans", + "trace_id_128bit": "true", + "shared_span_context": "false" + } + } + } + {{ else if .lightstep }} + , + "tracing": { + "http": { + "name": "envoy.lightstep", + "config": { + "collector_cluster": "lightstep", + "access_token_file": "{{ .lightstepToken}}" + } + } + } + {{ else if .datadog }} + , + "tracing": { + "http": { + "name": "envoy.tracers.datadog", + "config": { + "collector_cluster": "datadog_agent", + "service_name": "{{ .cluster }}" + } + } + } + {{ else if .stackdriver }} + , + "tracing": { + "http": { + "name": "envoy.tracers.opencensus", + "config": { + "stackdriver_exporter_enabled": true, + "stackdriver_project_id": "{{ .stackdriverProjectID }}", + "stdout_exporter_enabled": {{ .stackdriverDebug }}, + "incoming_trace_context": ["CLOUD_TRACE_CONTEXT", "TRACE_CONTEXT", "GRPC_TRACE_BIN"], + "outgoing_trace_context": ["CLOUD_TRACE_CONTEXT", "TRACE_CONTEXT", "GRPC_TRACE_BIN"], + "trace_config":{ + "constant_sampler":{ + "decision": "ALWAYS_PARENT" + }, + "max_number_of_annotations": {{ .stackdriverMaxAnnotations }}, + "max_number_of_attributes": {{ .stackdriverMaxAttributes }}, + "max_number_of_message_events": {{ .stackdriverMaxEvents }}, + "max_number_of_links": 200, + } + } + }} + {{ end }} + {{ if or .envoy_metrics_service .statsd }} + , + "stats_sinks": [ + {{ if .envoy_metrics_service }} + { + "name": "envoy.metrics_service", + "config": { + "grpc_service": { + "envoy_grpc": { + "cluster_name": "envoy_metrics_service" + } + } + } + }, + {{ end }} + {{ if .statsd }} + { + "name": "envoy.statsd", + "config": { + "address": { + "socket_address": {{ .statsd }} + } + } + }, + {{ end }} + ] + {{ end }} +} diff --git a/istio-1.3.5/tools/packaging/common/istio-auth-node-agent.service b/istio-1.3.5/tools/packaging/common/istio-auth-node-agent.service new file mode 100644 index 0000000..8728d98 --- /dev/null +++ b/istio-1.3.5/tools/packaging/common/istio-auth-node-agent.service @@ -0,0 +1,12 @@ +[Unit] +Description=istio-auth-node-agent: The Istio auth node agent +Documentation=https://istio.io/ + +[Service] +ExecStart=/usr/local/bin/istio-node-agent-start.sh +Restart=always +StartLimitInterval=0 +RestartSec=10 + +[Install] +WantedBy=multi-user.target diff --git a/istio-1.3.5/tools/packaging/common/istio-ca.sh b/istio-1.3.5/tools/packaging/common/istio-ca.sh new file mode 100755 index 0000000..9defc95 --- /dev/null +++ b/istio-1.3.5/tools/packaging/common/istio-ca.sh @@ -0,0 +1,37 @@ +#!/bin/bash +# +# Copyright 2017 Istio Authors. All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +################################################################################ +# +# Script to configure and start the Istio sidecar. + +set -e + +# Set defaults +ISTIO_BIN_BASE=${ISTIO_BIN_BASE:-/usr/local/bin} +ISTIO_LOG_DIR=${ISTIO_LOG_DIR:-/var/log/istio} +ISTIO_CFG=${ISTIO_CFG:-/var/lib/istio} + +# Default kube config for istio components +# TODO: use different configs, with different service accounts, for ca/pilot/mixer +KUBECONFIG=${ISTIO_CFG}/kube.config + +# TODO: use separate user for ca +if [ "$(id -u)" = "0" ] ; then + exec su -s /bin/bash -c "${ISTIO_BIN_BASE}/istio_ca --self-signed-ca --kube-config ${KUBECONFIG} 2> ${ISTIO_LOG_DIR}/istio_ca.err.log > ${ISTIO_LOG_DIR}/istio_ca.log" istio-proxy +else + "${ISTIO_BIN_BASE}/istio_ca" --self-signed-ca --kube-config "${KUBECONFIG}" +fi diff --git a/istio-1.3.5/tools/packaging/common/istio-iptables.sh b/istio-1.3.5/tools/packaging/common/istio-iptables.sh new file mode 100755 index 0000000..178b026 --- /dev/null +++ b/istio-1.3.5/tools/packaging/common/istio-iptables.sh @@ -0,0 +1,624 @@ +#!/bin/bash +# +# Copyright 2017, 2018 Istio Authors. All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +################################################################################ +# +# Initialization script responsible for setting up port forwarding for Istio sidecar. + +function usage() { + echo "${0} -p PORT -u UID -g GID [-m mode] [-b ports] [-d ports] [-i CIDR] [-x CIDR] [-k interfaces] [-t] [-h]" + echo '' + # shellcheck disable=SC2016 + echo ' -p: Specify the envoy port to which redirect all TCP traffic (default $ENVOY_PORT = 15001)' + # shellcheck disable=SC2016 + echo ' -z: Port to which all inbound TCP traffic to the pod/VM should be redirected to. For REDIRECT only (default $INBOUND_CAPTURE_PORT = 15006)' + echo ' -u: Specify the UID of the user for which the redirection is not' + echo ' applied. Typically, this is the UID of the proxy container' + # shellcheck disable=SC2016 + echo ' (default to uid of $ENVOY_USER, uid of istio_proxy, or 1337)' + echo ' -g: Specify the GID of the user for which the redirection is not' + echo ' applied. (same default value as -u param)' + echo ' -m: The mode used to redirect inbound connections to Envoy, either "REDIRECT" or "TPROXY"' + # shellcheck disable=SC2016 + echo ' (default to $ISTIO_INBOUND_INTERCEPTION_MODE)' + echo ' -b: Comma separated list of inbound ports for which traffic is to be redirected to Envoy (optional). The' + echo ' wildcard character "*" can be used to configure redirection for all ports. An empty list will disable' + # shellcheck disable=SC2016 + echo ' all inbound redirection (default to $ISTIO_INBOUND_PORTS)' + echo ' -d: Comma separated list of inbound ports to be excluded from redirection to Envoy (optional). Only applies' + # shellcheck disable=SC2016 + echo ' when all inbound traffic (i.e. "*") is being redirected (default to $ISTIO_LOCAL_EXCLUDE_PORTS)' + echo ' -i: Comma separated list of IP ranges in CIDR form to redirect to envoy (optional). The wildcard' + echo ' character "*" can be used to redirect all outbound traffic. An empty list will disable all outbound' + # shellcheck disable=SC2016 + echo ' redirection (default to $ISTIO_SERVICE_CIDR)' + echo ' -x: Comma separated list of IP ranges in CIDR form to be excluded from redirection. Only applies when all ' + # shellcheck disable=SC2016 + echo ' outbound traffic (i.e. "*") is being redirected (default to $ISTIO_SERVICE_EXCLUDE_CIDR).' + echo ' -o: Comma separated list of outbound ports to be excluded from redirection to Envoy (optional).' + echo ' -k: Comma separated list of virtual interfaces whose inbound traffic (from VM)' + echo ' will be treated as outbound (optional)' + echo ' -t: Unit testing, only functions are loaded and no other instructions are executed.' + # shellcheck disable=SC2016 + echo '' +} + +function dump { + iptables-save + ip6tables-save +} + +function isValidIP() { + if isIPv4 "${1}"; then + true + elif isIPv6 "${1}"; then + true + else + false + fi +} +# +# Function return true if agrument is a valid ipv4 address +# +function isIPv4() { + local ipv4regexp="^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$" + if [[ ${1} =~ ${ipv4regexp} ]]; then + true + else + false + fi +} +# +# Function return true if agrument is a valid ipv6 address +# +function isIPv6() { + local ipv6section="^[0-9a-fA-F]{1,4}$" + addr="$1" + number_of_parts=0 + number_of_skip=0 + IFS=':' read -r -a addr <<< "$1" + if [ ${#addr[@]} -eq 0 ]; then + return 1 + fi + for part in "${addr[@]}"; do + # check to not exceed number of parts in ipv6 address + if [[ ${number_of_parts} -ge 8 ]]; then + return 1 + fi + if [[ ${number_of_parts} -eq 0 ]] && ! [[ ${part} =~ ${ipv6section} ]]; then + return 1 + fi + if ! [[ ${part} =~ ${ipv6section} ]]; then + if ! [[ "$part" == "" ]]; then + return 1 + else + # Found empty part, no more than 2 sections '::' are allowed in ipv6 address + if [[ "$number_of_skip" -ge 1 ]]; then + return 1 + fi + ((number_of_skip++)) + fi + fi + ((number_of_parts++)) + done + return 0 +} + +# Use a comma as the separator for multi-value arguments. +IFS=, + +# TODO: load all files from a directory, similar with ufw, to make it easier for automated install scripts +# Ideally we should generate ufw (and similar) configs as well, in case user already has an iptables solution. + +PROXY_PORT=${ENVOY_PORT:-15001} +PROXY_INBOUND_CAPTURE_PORT=${INBOUND_CAPTURE_PORT:-15006} +PROXY_UID= +PROXY_GID= +INBOUND_INTERCEPTION_MODE=${ISTIO_INBOUND_INTERCEPTION_MODE} +INBOUND_TPROXY_MARK=${ISTIO_INBOUND_TPROXY_MARK:-1337} +INBOUND_TPROXY_ROUTE_TABLE=${ISTIO_INBOUND_TPROXY_ROUTE_TABLE:-133} +INBOUND_PORTS_INCLUDE=${ISTIO_INBOUND_PORTS-} +INBOUND_PORTS_EXCLUDE=${ISTIO_LOCAL_EXCLUDE_PORTS-} +OUTBOUND_IP_RANGES_INCLUDE=${ISTIO_SERVICE_CIDR-} +OUTBOUND_IP_RANGES_EXCLUDE=${ISTIO_SERVICE_EXCLUDE_CIDR-} +OUTBOUND_PORTS_EXCLUDE=${ISTIO_LOCAL_OUTBOUND_PORTS_EXCLUDE-} +KUBEVIRT_INTERFACES= + +while getopts ":p:z:u:g:m:b:d:o:i:x:k:h:t" opt; do + case ${opt} in + p) + PROXY_PORT=${OPTARG} + ;; + z) + PROXY_INBOUND_CAPTURE_PORT=${OPTARG} + ;; + u) + PROXY_UID=${OPTARG} + ;; + g) + PROXY_GID=${OPTARG} + ;; + m) + INBOUND_INTERCEPTION_MODE=${OPTARG} + ;; + b) + INBOUND_PORTS_INCLUDE=${OPTARG} + ;; + d) + INBOUND_PORTS_EXCLUDE=${OPTARG} + ;; + i) + OUTBOUND_IP_RANGES_INCLUDE=${OPTARG} + ;; + x) + OUTBOUND_IP_RANGES_EXCLUDE=${OPTARG} + ;; + o) + OUTBOUND_PORTS_EXCLUDE=${OPTARG} + ;; + k) + KUBEVIRT_INTERFACES=${OPTARG} + ;; + t) + echo "Unit testing is specified..." + return + ;; + h) + usage + exit 0 + ;; + \?) + echo "Invalid option: -$OPTARG" >&2 + usage + exit 1 + ;; + esac +done + +trap dump EXIT + +# TODO: more flexibility - maybe a whitelist of users to be captured for output instead of a blacklist. +if [ -z "${PROXY_UID}" ]; then + # Default to the UID of ENVOY_USER and root + if ! PROXY_UID=$(id -u "${ENVOY_USER:-istio-proxy}"); then + PROXY_UID="1337" + fi + # If ENVOY_UID is not explicitly defined (as it would be in k8s env), we add root to the list, + # for ca agent. + PROXY_UID=${PROXY_UID},0 +fi +# for TPROXY as its uid and gid are same +if [ -z "${PROXY_GID}" ]; then +PROXY_GID=${PROXY_UID} +fi + +POD_IP=$(hostname --ip-address) +# Check if pod's ip is ipv4 or ipv6, in case of ipv6 set variable +# to program ip6tables +if isIPv6 "$POD_IP"; then + ENABLE_INBOUND_IPV6=$POD_IP +fi + +# +# Since OUTBOUND_IP_RANGES_EXCLUDE could carry ipv4 and ipv6 ranges +# need to split them in different arrays one for ipv4 and one for ipv6 +# in order to not to fail +pl='/*' +# +# Next two lines, read comma separated inclusion and exclusion lists into +# arrays, so each element could be validated individually. +# +IFS=',' read -ra EXCLUDE <<< "$OUTBOUND_IP_RANGES_EXCLUDE" +IFS=',' read -ra INCLUDE <<< "$OUTBOUND_IP_RANGES_INCLUDE" +ipv6_ranges_exclude=() +ipv4_ranges_exclude=() +for range in "${EXCLUDE[@]}"; do + r=${range%$pl} + if isValidIP "$r"; then + if isIPv4 "$r"; then + ipv4_ranges_exclude+=("$range") + elif isIPv6 "$r"; then + ipv6_ranges_exclude+=("$range") + fi + fi +done + +ipv6_ranges_include=() +ipv4_ranges_include=() +if [ "${OUTBOUND_IP_RANGES_INCLUDE}" == "*" ]; then + ipv6_ranges_include=("*") + ipv4_ranges_include=("*") +else + for range in "${INCLUDE[@]}"; do + r=${range%$pl} + if isValidIP "$r"; then + if isIPv4 "$r"; then + ipv4_ranges_include+=("$range") + elif isIPv6 "$r"; then + ipv6_ranges_include+=("$range") + fi + fi + done +fi + +# Remove the old chains, to generate new configs. +iptables -t nat -D PREROUTING -p tcp -j ISTIO_INBOUND 2>/dev/null +iptables -t mangle -D PREROUTING -p tcp -j ISTIO_INBOUND 2>/dev/null +iptables -t nat -D OUTPUT -p tcp -j ISTIO_OUTPUT 2>/dev/null + +# Flush and delete the istio chains. +iptables -t nat -F ISTIO_OUTPUT 2>/dev/null +iptables -t nat -X ISTIO_OUTPUT 2>/dev/null +iptables -t nat -F ISTIO_INBOUND 2>/dev/null +iptables -t nat -X ISTIO_INBOUND 2>/dev/null +iptables -t mangle -F ISTIO_INBOUND 2>/dev/null +iptables -t mangle -X ISTIO_INBOUND 2>/dev/null +iptables -t mangle -F ISTIO_DIVERT 2>/dev/null +iptables -t mangle -X ISTIO_DIVERT 2>/dev/null +iptables -t mangle -F ISTIO_TPROXY 2>/dev/null +iptables -t mangle -X ISTIO_TPROXY 2>/dev/null + +# Must be last, the others refer to it +iptables -t nat -F ISTIO_REDIRECT 2>/dev/null +iptables -t nat -X ISTIO_REDIRECT 2>/dev/null +iptables -t nat -F ISTIO_IN_REDIRECT 2>/dev/null +iptables -t nat -X ISTIO_IN_REDIRECT 2>/dev/null + +if [ "${1:-}" = "clean" ]; then + echo "Only cleaning, no new rules added" + exit 0 +fi + +# Dump out our environment for debugging purposes. +echo "Environment:" +echo "------------" +echo "ENVOY_PORT=${ENVOY_PORT-}" +echo "INBOUND_CAPTURE_PORT=${INBOUND_CAPTURE_PORT-}" +echo "ISTIO_INBOUND_INTERCEPTION_MODE=${ISTIO_INBOUND_INTERCEPTION_MODE-}" +echo "ISTIO_INBOUND_TPROXY_MARK=${ISTIO_INBOUND_TPROXY_MARK-}" +echo "ISTIO_INBOUND_TPROXY_ROUTE_TABLE=${ISTIO_INBOUND_TPROXY_ROUTE_TABLE-}" +echo "ISTIO_INBOUND_PORTS=${ISTIO_INBOUND_PORTS-}" +echo "ISTIO_LOCAL_EXCLUDE_PORTS=${ISTIO_LOCAL_EXCLUDE_PORTS-}" +echo "ISTIO_SERVICE_CIDR=${ISTIO_SERVICE_CIDR-}" +echo "ISTIO_SERVICE_EXCLUDE_CIDR=${ISTIO_SERVICE_EXCLUDE_CIDR-}" +echo +echo "Variables:" +echo "----------" +echo "PROXY_PORT=${PROXY_PORT}" +echo "PROXY_INBOUND_CAPTURE_PORT=${PROXY_INBOUND_CAPTURE_PORT}" +echo "PROXY_UID=${PROXY_UID}" +echo "INBOUND_INTERCEPTION_MODE=${INBOUND_INTERCEPTION_MODE}" +echo "INBOUND_TPROXY_MARK=${INBOUND_TPROXY_MARK}" +echo "INBOUND_TPROXY_ROUTE_TABLE=${INBOUND_TPROXY_ROUTE_TABLE}" +echo "INBOUND_PORTS_INCLUDE=${INBOUND_PORTS_INCLUDE}" +echo "INBOUND_PORTS_EXCLUDE=${INBOUND_PORTS_EXCLUDE}" +echo "OUTBOUND_IP_RANGES_INCLUDE=${OUTBOUND_IP_RANGES_INCLUDE}" +echo "OUTBOUND_IP_RANGES_EXCLUDE=${OUTBOUND_IP_RANGES_EXCLUDE}" +echo "OUTBOUND_PORTS_EXCLUDE=${OUTBOUND_PORTS_EXCLUDE}" +echo "KUBEVIRT_INTERFACES=${KUBEVIRT_INTERFACES}" +echo "ENABLE_INBOUND_IPV6=${ENABLE_INBOUND_IPV6}" +echo + + +set +o nounset +# Blindly add a ipv6 address. If it fails it's fine. +# Add local ipv6 address to lo. Used in redirecting unknown ipv6 traffic to original dst. +# This address does not show up in neigh table so each Pod/Vm will only see its own. Think about 127.0.0.6. +if [ -n "${ENABLE_INBOUND_IPV6}" ]; then + ip -6 addr add ::6/128 dev lo +fi + +set -o errexit +set -o nounset +set -o pipefail +set -x # echo on + +# Create a new chain for redirecting outbound traffic to the common Envoy port. +# In both chains, '-j RETURN' bypasses Envoy and '-j ISTIO_REDIRECT' +# redirects to Envoy. +iptables -t nat -N ISTIO_REDIRECT +iptables -t nat -A ISTIO_REDIRECT -p tcp -j REDIRECT --to-port "${PROXY_PORT}" + +# Use this chain also for redirecting inbound traffic to the common Envoy port +# when not using TPROXY. +iptables -t nat -N ISTIO_IN_REDIRECT + +# PROXY_INBOUND_CAPTURE_PORT should be used only user explicitly set INBOUND_PORTS_INCLUDE to capture all +if [ "${INBOUND_PORTS_INCLUDE}" == "*" ]; then + iptables -t nat -A ISTIO_IN_REDIRECT -p tcp -j REDIRECT --to-port "${PROXY_INBOUND_CAPTURE_PORT}" +else + iptables -t nat -A ISTIO_IN_REDIRECT -p tcp -j REDIRECT --to-port "${PROXY_PORT}" +fi + +# Handling of inbound ports. Traffic will be redirected to Envoy, which will process and forward +# to the local service. If not set, no inbound port will be intercepted by istio iptables. +if [ -n "${INBOUND_PORTS_INCLUDE}" ]; then + if [ "${INBOUND_INTERCEPTION_MODE}" = "TPROXY" ] ; then + # When using TPROXY, create a new chain for routing all inbound traffic to + # Envoy. Any packet entering this chain gets marked with the ${INBOUND_TPROXY_MARK} mark, + # so that they get routed to the loopback interface in order to get redirected to Envoy. + # In the ISTIO_INBOUND chain, '-j ISTIO_DIVERT' reroutes to the loopback + # interface. + # Mark all inbound packets. + iptables -t mangle -N ISTIO_DIVERT + iptables -t mangle -A ISTIO_DIVERT -j MARK --set-mark "${INBOUND_TPROXY_MARK}" + iptables -t mangle -A ISTIO_DIVERT -j ACCEPT + + # Route all packets marked in chain ISTIO_DIVERT using routing table ${INBOUND_TPROXY_ROUTE_TABLE}. + ip -f inet rule add fwmark "${INBOUND_TPROXY_MARK}" lookup "${INBOUND_TPROXY_ROUTE_TABLE}" + # In routing table ${INBOUND_TPROXY_ROUTE_TABLE}, create a single default rule to route all traffic to + # the loopback interface. + ip -f inet route add local default dev lo table "${INBOUND_TPROXY_ROUTE_TABLE}" || ip route show table all + + # Create a new chain for redirecting inbound traffic to the common Envoy + # port. + # In the ISTIO_INBOUND chain, '-j RETURN' bypasses Envoy and + # '-j ISTIO_TPROXY' redirects to Envoy. + iptables -t mangle -N ISTIO_TPROXY + iptables -t mangle -A ISTIO_TPROXY ! -d 127.0.0.1/32 -p tcp -j TPROXY --tproxy-mark "${INBOUND_TPROXY_MARK}/0xffffffff" --on-port "${PROXY_PORT}" + + table=mangle + else + table=nat + fi + iptables -t ${table} -N ISTIO_INBOUND + iptables -t ${table} -A PREROUTING -p tcp -j ISTIO_INBOUND + + if [ "${INBOUND_PORTS_INCLUDE}" == "*" ]; then + # Makes sure SSH is not redirected + iptables -t ${table} -A ISTIO_INBOUND -p tcp --dport 22 -j RETURN + # Apply any user-specified port exclusions. + if [ -n "${INBOUND_PORTS_EXCLUDE}" ]; then + for port in ${INBOUND_PORTS_EXCLUDE}; do + iptables -t ${table} -A ISTIO_INBOUND -p tcp --dport "${port}" -j RETURN + done + fi + # Redirect remaining inbound traffic to Envoy. + if [ "${INBOUND_INTERCEPTION_MODE}" = "TPROXY" ]; then + # If an inbound packet belongs to an established socket, route it to the + # loopback interface. + iptables -t mangle -A ISTIO_INBOUND -p tcp -m socket -j ISTIO_DIVERT || echo "No socket match support" + # Otherwise, it's a new connection. Redirect it using TPROXY. + iptables -t mangle -A ISTIO_INBOUND -p tcp -j ISTIO_TPROXY + else + iptables -t nat -A ISTIO_INBOUND -p tcp -j ISTIO_IN_REDIRECT + fi + else + # User has specified a non-empty list of ports to be redirected to Envoy. + for port in ${INBOUND_PORTS_INCLUDE}; do + if [ "${INBOUND_INTERCEPTION_MODE}" = "TPROXY" ]; then + iptables -t mangle -A ISTIO_INBOUND -p tcp --dport "${port}" -m socket -j ISTIO_DIVERT || echo "No socket match support" + iptables -t mangle -A ISTIO_INBOUND -p tcp --dport "${port}" -m socket -j ISTIO_DIVERT || echo "No socket match support" + iptables -t mangle -A ISTIO_INBOUND -p tcp --dport "${port}" -j ISTIO_TPROXY + else + iptables -t nat -A ISTIO_INBOUND -p tcp --dport "${port}" -j ISTIO_IN_REDIRECT + fi + done + fi +fi + +# TODO: change the default behavior to not intercept any output - user may use http_proxy or another +# iptables wrapper (like ufw). Current default is similar with 0.1 + +# Create a new chain for selectively redirecting outbound packets to Envoy. +iptables -t nat -N ISTIO_OUTPUT + +# Jump to the ISTIO_OUTPUT chain from OUTPUT chain for all tcp traffic. +iptables -t nat -A OUTPUT -p tcp -j ISTIO_OUTPUT + +# Apply port based exclusions. Must be applied before connections back to self +# are redirected. +if [ -n "${OUTBOUND_PORTS_EXCLUDE}" ]; then + for port in ${OUTBOUND_PORTS_EXCLUDE}; do + iptables -t nat -A ISTIO_OUTPUT -p tcp --dport "${port}" -j RETURN + done +fi + +# 127.0.0.6 is bind connect from inbound passthrough cluster +iptables -t nat -A ISTIO_OUTPUT -o lo -s 127.0.0.6/32 -j RETURN + +if [ -z "${DISABLE_REDIRECTION_ON_LOCAL_LOOPBACK-}" ]; then + # Redirect app calls back to itself via Envoy when using the service VIP or endpoint + # address, e.g. appN => Envoy (client) => Envoy (server) => appN. + iptables -t nat -A ISTIO_OUTPUT -o lo ! -d 127.0.0.1/32 -j ISTIO_IN_REDIRECT +fi + +for uid in ${PROXY_UID}; do + # Avoid infinite loops. Don't redirect Envoy traffic directly back to + # Envoy for non-loopback traffic. + iptables -t nat -A ISTIO_OUTPUT -m owner --uid-owner "${uid}" -j RETURN +done + +for gid in ${PROXY_GID}; do + # Avoid infinite loops. Don't redirect Envoy traffic directly back to + # Envoy for non-loopback traffic. + iptables -t nat -A ISTIO_OUTPUT -m owner --gid-owner "${gid}" -j RETURN +done + +# Skip redirection for Envoy-aware applications and +# container-to-container traffic both of which explicitly use +# localhost. +iptables -t nat -A ISTIO_OUTPUT -d 127.0.0.1/32 -j RETURN + +# Apply outbound IPv4 exclusions. Must be applied before inclusions. +if [ ${#ipv4_ranges_exclude[@]} -gt 0 ]; then + for cidr in "${ipv4_ranges_exclude[@]}"; do + iptables -t nat -A ISTIO_OUTPUT -d "${cidr}" -j RETURN + done +fi + +for internalInterface in ${KUBEVIRT_INTERFACES}; do + iptables -t nat -I PREROUTING 1 -i "${internalInterface}" -j RETURN +done + +# Apply outbound IP inclusions. +if [ ${#ipv4_ranges_include[@]} -gt 0 ]; then + if [ "${ipv4_ranges_include[0]}" == "*" ]; then + # Wildcard specified. Redirect all remaining outbound traffic to Envoy. + iptables -t nat -A ISTIO_OUTPUT -j ISTIO_REDIRECT + for internalInterface in ${KUBEVIRT_INTERFACES}; do + iptables -t nat -I PREROUTING 1 -i "${internalInterface}" -j ISTIO_REDIRECT + done + else + # User has specified a non-empty list of cidrs to be redirected to Envoy. + for cidr in "${ipv4_ranges_include[@]}"; do + for internalInterface in ${KUBEVIRT_INTERFACES}; do + iptables -t nat -I PREROUTING 1 -i "${internalInterface}" -d "${cidr}" -j ISTIO_REDIRECT + done + iptables -t nat -A ISTIO_OUTPUT -d "${cidr}" -j ISTIO_REDIRECT + done + # All other traffic is not redirected. + iptables -t nat -A ISTIO_OUTPUT -j RETURN + fi +fi + +# If ENABLE_INBOUND_IPV6 is unset (default unset), restrict IPv6 traffic. +set +o nounset +if [ -n "${ENABLE_INBOUND_IPV6}" ]; then + # Remove the old chains, to generate new configs. + ip6tables -t nat -D PREROUTING -p tcp -j ISTIO_INBOUND 2>/dev/null || true + ip6tables -t mangle -D PREROUTING -p tcp -j ISTIO_INBOUND 2>/dev/null || true + ip6tables -t nat -D OUTPUT -p tcp -j ISTIO_OUTPUT 2>/dev/null || true + + # Flush and delete the istio chains. + ip6tables -t nat -F ISTIO_OUTPUT 2>/dev/null || true + ip6tables -t nat -X ISTIO_OUTPUT 2>/dev/null || true + ip6tables -t nat -F ISTIO_INBOUND 2>/dev/null || true + ip6tables -t nat -X ISTIO_INBOUND 2>/dev/null || true + ip6tables -t mangle -F ISTIO_INBOUND 2>/dev/null || true + ip6tables -t mangle -X ISTIO_INBOUND 2>/dev/null || true + ip6tables -t mangle -F ISTIO_DIVERT 2>/dev/null || true + ip6tables -t mangle -X ISTIO_DIVERT 2>/dev/null || true + ip6tables -t mangle -F ISTIO_TPROXY 2>/dev/null || true + ip6tables -t mangle -X ISTIO_TPROXY 2>/dev/null || true + + # Must be last, the others refer to it + ip6tables -t nat -F ISTIO_REDIRECT 2>/dev/null || true + ip6tables -t nat -X ISTIO_REDIRECT 2>/dev/null|| true + ip6tables -t nat -F ISTIO_IN_REDIRECT 2>/dev/null || true + ip6tables -t nat -X ISTIO_IN_REDIRECT 2>/dev/null || true + + # Create a new chain for redirecting outbound traffic to the common Envoy port. + # In both chains, '-j RETURN' bypasses Envoy and '-j ISTIO_REDIRECT' + # redirects to Envoy. + ip6tables -t nat -N ISTIO_REDIRECT + ip6tables -t nat -A ISTIO_REDIRECT -p tcp -j REDIRECT --to-port "${PROXY_PORT}" + + # Use this chain also for redirecting inbound traffic to the common Envoy port + # when not using TPROXY. + ip6tables -t nat -N ISTIO_IN_REDIRECT + # PROXY_INBOUND_CAPTURE_PORT should be used only user explicitly set INBOUND_PORTS_INCLUDE to capture all + if [ "${INBOUND_PORTS_INCLUDE}" == "*" ]; then + ip6tables -t nat -A ISTIO_IN_REDIRECT -p tcp -j REDIRECT --to-port "${PROXY_INBOUND_CAPTURE_PORT}" + else + ip6tables -t nat -A ISTIO_IN_REDIRECT -p tcp -j REDIRECT --to-port "${PROXY_PORT}" + fi + + # Handling of inbound ports. Traffic will be redirected to Envoy, which will process and forward + # to the local service. If not set, no inbound port will be intercepted by istio iptables. + if [ -n "${INBOUND_PORTS_INCLUDE}" ]; then + table=nat + ip6tables -t ${table} -N ISTIO_INBOUND + ip6tables -t ${table} -A PREROUTING -p tcp -j ISTIO_INBOUND + + if [ "${INBOUND_PORTS_INCLUDE}" == "*" ]; then + # Makes sure SSH is not redirected + ip6tables -t ${table} -A ISTIO_INBOUND -p tcp --dport 22 -j RETURN + # Apply any user-specified port exclusions. + if [ -n "${INBOUND_PORTS_EXCLUDE}" ]; then + for port in ${INBOUND_PORTS_EXCLUDE}; do + ip6tables -t ${table} -A ISTIO_INBOUND -p tcp --dport "${port}" -j RETURN + done + fi + else + # User has specified a non-empty list of ports to be redirected to Envoy. + for port in ${INBOUND_PORTS_INCLUDE}; do + ip6tables -t nat -A ISTIO_INBOUND -p tcp --dport "${port}" -j ISTIO_IN_REDIRECT + done + fi + fi + + # Create a new chain for selectively redirecting outbound packets to Envoy. + ip6tables -t nat -N ISTIO_OUTPUT + + # Jump to the ISTIO_OUTPUT chain from OUTPUT chain for all tcp traffic. + ip6tables -t nat -A OUTPUT -p tcp -j ISTIO_OUTPUT + + # Apply port based exclusions. Must be applied before connections back to self + # are redirected. + if [ -n "${OUTBOUND_PORTS_EXCLUDE}" ]; then + for port in ${OUTBOUND_PORTS_EXCLUDE}; do + ip6tables -t nat -A ISTIO_OUTPUT -p tcp --dport "${port}" -j RETURN + done + fi + + # ::6 is bind when connect from inbound passthrough cluster + ip6tables -t nat -A ISTIO_OUTPUT -o lo -s ::6/128 -j RETURN + + # Redirect app calls to back itself via Envoy when using the service VIP or endpoint + # address, e.g. appN => Envoy (client) => Envoy (server) => appN. + ip6tables -t nat -A ISTIO_OUTPUT -o lo ! -d ::1/128 -j ISTIO_IN_REDIRECT + + for uid in ${PROXY_UID}; do + # Avoid infinite loops. Don't redirect Envoy traffic directly back to + # Envoy for non-loopback traffic. + ip6tables -t nat -A ISTIO_OUTPUT -m owner --uid-owner "${uid}" -j RETURN + done + + for gid in ${PROXY_GID}; do + # Avoid infinite loops. Don't redirect Envoy traffic directly back to + # Envoy for non-loopback traffic. + ip6tables -t nat -A ISTIO_OUTPUT -m owner --gid-owner "${gid}" -j RETURN + done + + # Skip redirection for Envoy-aware applications and + # container-to-container traffic both of which explicitly use + # localhost. + ip6tables -t nat -A ISTIO_OUTPUT -d ::1/128 -j RETURN + + # Apply outbound IPv6 exclusions. Must be applied before inclusions. + if [ ${#ipv6_ranges_exclude[@]} -gt 0 ]; then + for cidr in "${ipv6_ranges_exclude[@]}"; do + ip6tables -t nat -A ISTIO_OUTPUT -d "${cidr}" -j RETURN + done + fi + # Apply outbound IPv6 inclusions. + if [ ${#ipv6_ranges_include[@]} -gt 0 ]; then + if [ "${ipv6_ranges_include[0]}" == "*" ]; then + # Wildcard specified. Redirect all remaining outbound traffic to Envoy. + ip6tables -t nat -A ISTIO_OUTPUT -j ISTIO_REDIRECT + for internalInterface in ${KUBEVIRT_INTERFACES}; do + ip6tables -t nat -I PREROUTING 1 -i "${internalInterface}" -j RETURN + done + else + # User has specified a non-empty list of cidrs to be redirected to Envoy. + for cidr in "${ipv6_ranges_include[@]}"; do + for internalInterface in ${KUBEVIRT_INTERFACES}; do + ip6tables -t nat -I PREROUTING 1 -i "${internalInterface}" -d "${cidr}" -j ISTIO_REDIRECT + done + ip6tables -t nat -A ISTIO_OUTPUT -d "${cidr}" -j ISTIO_REDIRECT + done + # All other traffic is not redirected. + ip6tables -t nat -A ISTIO_OUTPUT -j RETURN + fi + fi +else + # Drop all inbound traffic except established connections. + ip6tables -F INPUT || true + ip6tables -A INPUT -m state --state ESTABLISHED -j ACCEPT || true + ip6tables -A INPUT -i lo -d ::1 -j ACCEPT || true + ip6tables -A INPUT -j REJECT || true +fi diff --git a/istio-1.3.5/tools/packaging/common/istio-node-agent-start.sh b/istio-1.3.5/tools/packaging/common/istio-node-agent-start.sh new file mode 100755 index 0000000..845c040 --- /dev/null +++ b/istio-1.3.5/tools/packaging/common/istio-node-agent-start.sh @@ -0,0 +1,66 @@ +#!/bin/bash +# +# Copyright 2017 Istio Authors. All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +################################################################################ +# +# Script to configure and start the Istio node agent. +# Will run the node_agent as istio-proxy instead of root - to allow interception +# of apps running as root (node_agent requires root to not be intercepted) and +# to reduce risks. + +set -e + +# Load optional config variables +ISTIO_SIDECAR_CONFIG=${ISTIO_SIDECAR_CONFIG:-/var/lib/istio/envoy/sidecar.env} +if [[ -r ${ISTIO_SIDECAR_CONFIG} ]]; then + # shellcheck disable=SC1090 + . "$ISTIO_SIDECAR_CONFIG" +fi + +# Load config variables ISTIO_SYSTEM_NAMESPACE, CONTROL_PLANE_AUTH_POLICY +ISTIO_CLUSTER_CONFIG=${ISTIO_CLUSTER_CONFIG:-/var/lib/istio/envoy/cluster.env} +if [[ -r ${ISTIO_CLUSTER_CONFIG} ]]; then + # shellcheck disable=SC1090 + . "$ISTIO_CLUSTER_CONFIG" +fi + +# Set defaults +ISTIO_BIN_BASE=${ISTIO_BIN_BASE:-/usr/local/bin} +ISTIO_LOG_DIR=${ISTIO_LOG_DIR:-/var/log/istio} +export NS=${ISTIO_NAMESPACE:-default} +export SVC=${ISTIO_SERVICE:-rawvm} +ISTIO_SYSTEM_NAMESPACE=${ISTIO_SYSTEM_NAMESPACE:-istio-system} + +EXEC_USER=${EXEC_USER:-istio-proxy} + +if [ -z "${CITADEL_ADDRESS:-}" ]; then + CITADEL_ADDRESS=istio-citadel:8060 +fi + +CERTS_DIR=${CERTS_DIR:-/etc/certs} + +CITADEL_ARGS=( + "--ca-address" "${CITADEL_ADDRESS}" + "--cert-chain" "${CERTS_DIR}/cert-chain.pem" + "--key" "${CERTS_DIR}/key.pem" + "--root-cert" "${CERTS_DIR}/root-cert.pem" +) + +if [ "${EXEC_USER}" == "${USER:-}" ] ; then + "${ISTIO_BIN_BASE}/node_agent" "${CITADEL_ARGS[@]}" +else + su -s /bin/sh -c "exec ${ISTIO_BIN_BASE}/node_agent ${CITADEL_ARGS[*]}" "${EXEC_USER}" +fi diff --git a/istio-1.3.5/tools/packaging/common/istio-start.sh b/istio-1.3.5/tools/packaging/common/istio-start.sh new file mode 100755 index 0000000..e1d5d40 --- /dev/null +++ b/istio-1.3.5/tools/packaging/common/istio-start.sh @@ -0,0 +1,113 @@ +#!/bin/bash +# +# Copyright 2017 Istio Authors. All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +################################################################################ +# +# Script to configure and start the Istio sidecar. + +set -e + +# Match pilot/docker/Dockerfile.proxyv2 +export ISTIO_META_ISTIO_VERSION="1.3.0" + +# Load optional config variables +ISTIO_SIDECAR_CONFIG=${ISTIO_SIDECAR_CONFIG:-/var/lib/istio/envoy/sidecar.env} +if [[ -r ${ISTIO_SIDECAR_CONFIG} ]]; then + # shellcheck disable=SC1090 + . "$ISTIO_SIDECAR_CONFIG" +fi + +# Load config variables ISTIO_SYSTEM_NAMESPACE, CONTROL_PLANE_AUTH_POLICY +ISTIO_CLUSTER_CONFIG=${ISTIO_CLUSTER_CONFIG:-/var/lib/istio/envoy/cluster.env} +if [[ -r ${ISTIO_CLUSTER_CONFIG} ]]; then + # shellcheck disable=SC1090 + . "$ISTIO_CLUSTER_CONFIG" + # Make sure the documented configuration variables are exported + export ISTIO_CP_AUTH ISTIO_SERVICE_CIDR ISTIO_INBOUND_PORTS +fi + +# Set defaults +ISTIO_BIN_BASE=${ISTIO_BIN_BASE:-/usr/local/bin} +ISTIO_LOG_DIR=${ISTIO_LOG_DIR:-/var/log/istio} +NS=${ISTIO_NAMESPACE:-default} +SVC=${ISTIO_SERVICE:-rawvm} +ISTIO_SYSTEM_NAMESPACE=${ISTIO_SYSTEM_NAMESPACE:-istio-system} + +# The default matches the default istio.yaml - use sidecar.env to override this if you +# enable auth. This requires node-agent to be running. +ISTIO_PILOT_PORT=${ISTIO_PILOT_PORT:-15011} + +# If set, override the default +CONTROL_PLANE_AUTH_POLICY=("--controlPlaneAuthPolicy" "MUTUAL_TLS") +if [ -n "${ISTIO_CP_AUTH:-}" ]; then + CONTROL_PLANE_AUTH_POLICY=("--controlPlaneAuthPolicy" "${ISTIO_CP_AUTH}") +fi + +if [ -z "${ISTIO_SVC_IP:-}" ]; then + ISTIO_SVC_IP=$(hostname --all-ip-addresses | cut -d ' ' -f 1) +fi + +if [ -z "${POD_NAME:-}" ]; then + POD_NAME=$(hostname -s) +fi + +# Init option will only initialize iptables. set ISTIO_CUSTOM_IP_TABLES to true if you would like to ignore this step +if [ "${ISTIO_CUSTOM_IP_TABLES}" != "true" ] ; then + if [[ ${1-} == "init" || ${1-} == "-p" ]] ; then + # Update iptables, based on current config. This is for backward compatibility with the init image mode. + # The sidecar image can replace the k8s init image, to avoid downloading 2 different images. + "${ISTIO_BIN_BASE}/istio-iptables.sh" "${@}" + exit 0 + fi + + if [[ ${1-} != "run" ]] ; then + # Update iptables, based on config file + "${ISTIO_BIN_BASE}/istio-iptables.sh" + fi +fi + +EXEC_USER=${EXEC_USER:-istio-proxy} +if [ "${ISTIO_INBOUND_INTERCEPTION_MODE}" = "TPROXY" ] ; then + # In order to allow redirect inbound traffic using TPROXY, run envoy with the CAP_NET_ADMIN capability. + # This allows configuring listeners with the "transparent" socket option set to true. + EXEC_USER=root +fi + +if [ -z "${PILOT_ADDRESS:-}" ]; then + PILOT_ADDRESS=istio-pilot.${ISTIO_SYSTEM_NAMESPACE}:${ISTIO_PILOT_PORT} +fi + +# If predefined ISTIO_AGENT_FLAGS is null, make it an empty string. +ISTIO_AGENT_FLAGS=${ISTIO_AGENT_FLAGS:-} +# Split ISTIO_AGENT_FLAGS by spaces. +IFS=' ' read -r -a ISTIO_AGENT_FLAGS_ARRAY <<< "$ISTIO_AGENT_FLAGS" + +if [ ${EXEC_USER} == "${USER:-}" ] ; then + # if started as istio-proxy (or current user), do a normal start, without + # redirecting stderr. + INSTANCE_IP=${ISTIO_SVC_IP} POD_NAME=${POD_NAME} POD_NAMESPACE=${NS} "${ISTIO_BIN_BASE}/pilot-agent" proxy "${ISTIO_AGENT_FLAGS_ARRAY[@]}" \ + --serviceCluster "$SVC" \ + --discoveryAddress "${PILOT_ADDRESS}" \ + "${CONTROL_PLANE_AUTH_POLICY[@]}" +else + +# Will run: ${ISTIO_BIN_BASE}/envoy -c $ENVOY_CFG --restart-epoch 0 --drain-time-s 2 --parent-shutdown-time-s 3 --service-cluster $SVC --service-node 'sidecar~${ISTIO_SVC_IP}~${POD_NAME}.${NS}.svc.cluster.local~${NS}.svc.cluster.local' --allow-unknown-fields $ISTIO_DEBUG >${ISTIO_LOG_DIR}/istio.log" istio-proxy +exec su -s /bin/bash -c "INSTANCE_IP=${ISTIO_SVC_IP} POD_NAME=${POD_NAME} POD_NAMESPACE=${NS} exec ${ISTIO_BIN_BASE}/pilot-agent proxy ${ISTIO_AGENT_FLAGS_ARRAY[*]} \ + --serviceCluster $SVC \ + --discoveryAddress ${PILOT_ADDRESS} \ + ${CONTROL_PLANE_AUTH_POLICY[*]} \ + 2> ${ISTIO_LOG_DIR}/istio.err.log > ${ISTIO_LOG_DIR}/istio.log" ${EXEC_USER} +fi diff --git a/istio-1.3.5/tools/packaging/common/istio.service b/istio-1.3.5/tools/packaging/common/istio.service new file mode 100644 index 0000000..fd4d29e --- /dev/null +++ b/istio-1.3.5/tools/packaging/common/istio.service @@ -0,0 +1,12 @@ +[Unit] +Description=istio-sidecar: The Istio sidecar +Documentation=http://istio.io/ + +[Service] +ExecStart=/usr/local/bin/istio-start.sh +Restart=always +StartLimitInterval=0 +RestartSec=10 + +[Install] +WantedBy=multi-user.target diff --git a/istio-1.3.5/tools/packaging/common/sidecar.env b/istio-1.3.5/tools/packaging/common/sidecar.env new file mode 100644 index 0000000..7b8c7cb --- /dev/null +++ b/istio-1.3.5/tools/packaging/common/sidecar.env @@ -0,0 +1,84 @@ +# Environment variables used to configure istio startup + +# Comma separated list of CIDRs used for services. If set, iptables will be run to allow istio +# sidecar to intercept outbound calls to configured addresses. If not set, outbound istio sidecar +# will not be used via iptables. +# ISTIO_SERVICE_CIDR= + +# Name of the service exposed by the machine. +# ISTIO_SERVICE=myservice + +# The mode used to redirect inbound connections to Envoy. This setting +# has no effect on outbound traffic: iptables REDIRECT is always used for +# outbound connections. +# If "REDIRECT", use iptables REDIRECT to NAT and redirect to Envoy. +# The "REDIRECT" mode loses source addresses during redirection. +# If "TPROXY", use iptables TPROXY to redirect to Envoy. +# The "TPROXY" mode preserves both the source and destination IP +# addresses and ports, so that they can be used for advanced filtering +# and manipulation. +# The "TPROXY" mode also configures the sidecar to run with the +# CAP_NET_ADMIN capability, which is required to use TPROXY. +# If not set, defaults to "REDIRECT". +# ISTIO_INBOUND_INTERCEPTION_MODE=REDIRECT + +# When the interception mode is "TPROXY", the iptables skb mark that is set on +# every inbound packet to be redirected to Envoy. +# If not set, defaults to "1337". +# ISTIO_INBOUND_TPROXY_MARK=1337 + +# When the interception mode is "TPROXY", the number of the routing table that +# is configured and used to route inbound connections to the loopback interface +# in order to be redirected to Envoy. +# If not set, defaults to "133". +# ISTIO_INBOUND_TPROXY_ROUTE_TABLE=133 + +# Comma separated list of local ports that will use Istio sidecar for inbound services. +# If set, iptables rules will be configured to intercept inbound traffic and redirect to sidecar. +# If not set, no rules will be enabled +# ISTIO_INBOUND_PORTS= + +# List of ports to exclude from inbound interception, if ISTIO_INBOUND_PORTS is set to * +# Port 22 is automatically excluded +# ISTIO_INBOUND_EXCLUDE_PORTS= + +# Namespace of the cluster. +# ISTIO_NAMESPACE=default + +# Specify the IP address used in endpoints. If not set, 'hostname --ip-address' will be used. +# Needed if the host has multiple IP. +# ISTIO_SVC_IP= + +# If istio-pilot is configured with mTLS authentication (--controlPlaneAuthPolicy MUTUAL_TLS ) you must +# also configure the mesh expansion machines: +# ISTIO_PILOT_PORT=15005 +# ISTIO_CP_AUTH=MUTUAL_TLS + +# Fine tunning - useful if installing/building binaries instead of using the .deb file, or running +# multiple instances. + +# Port used by Envoy. Defaults to 15001, used in the autogenerated config +# ENVOY_PORT=15001 + +# User running Envoy. For testing you can use a regular user ID - however running iptables requires +# root or netadmin capability. The debian file creates user istio. +# ENVOY_USER=istio-proxy + +# Uncomment to enable debugging +# ISTIO_AGENT_FLAGS="--proxyLogLevel debug" + +# Directory for stdout redirection. The redirection is required because envoy attempts to open +# /dev/stdout - must be a real file. Will be used for access logs. Additional config for logsaver +# needs to be made, envoy reopens the file on SIGUSR1 +# ISTIO_LOG_DIR=/var/log/istio + +# Installation directory for istio binaries, customize in case you're using a binary. +# This is likely to change - current path matches the docker layout in 0.1 +# ISTIO_BIN_BASE=/usr/local/bin + +# Location of istio configs. +# ISTIO_CFG=/var/lib/istio + +# Ignore Istio iptables custom rules +# Enable this flag if you would like to manage iptables yourself. Default to false (true/false) +# ISTIO_CUSTOM_IP_TABLES=false diff --git a/istio-1.3.5/tools/packaging/deb/Dockerfile b/istio-1.3.5/tools/packaging/deb/Dockerfile new file mode 100644 index 0000000..399887a --- /dev/null +++ b/istio-1.3.5/tools/packaging/deb/Dockerfile @@ -0,0 +1,28 @@ +# Base dockerfile containing ubuntu and istio debian. +# Can be used for testing +# ISTIO_VERSION is used to specify the version of the release +ARG BASE_VERSION=latest + +# The following section is used as base image if BASE_DISTRIBUTION=default +FROM docker.io/istio/base:${BASE_VERSION} + +# hadolint ignore=DL3006 +FROM istionightly/base_debug + +# Micro pilot+mock mixer+echo, local kube +COPY hyperistio kube-apiserver etcd kubectl /usr/local/bin/ +COPY *.yaml /var/lib/istio/config/ +COPY certs/ /var/lib/istio/ +COPY certs/default/* /etc/certs/ + +COPY istio.deb /tmp +COPY istio-sidecar.deb /tmp +COPY deb_test.sh /usr/local/bin/ + +# Root and istio are not intercepted +RUN adduser istio-test --system + +# Verify the debian files can be installed +RUN dpkg -i /tmp/istio-sidecar.deb && rm /tmp/istio-sidecar.deb +RUN dpkg -i /tmp/istio.deb && rm /tmp/istio.deb + diff --git a/istio-1.3.5/tools/packaging/deb/deb_test.sh b/istio-1.3.5/tools/packaging/deb/deb_test.sh new file mode 100755 index 0000000..e9ce7fb --- /dev/null +++ b/istio-1.3.5/tools/packaging/deb/deb_test.sh @@ -0,0 +1,49 @@ +#!/bin/bash +# +# Copyright 2017 Istio Authors. All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +################################################################################ +# +# Test for istio debian. Will run in a docker image where the .deb has been installed. + +function startIstio() { + /usr/local/bin/hyperistio --envoy=false & + sleep 1 + + bash -x /usr/local/bin/istio-start.sh & + sleep 1 +} + +function istioDebug() { + curl localhost:15000/logging?upstream=debug + curl localhost:15000/logging?client=debug + curl localhost:15000/logging?connection=debug + curl localhost:15000/logging?http2=debug + curl localhost:15000/logging?grpc=debug +} + +function istioStats() { + curl localhost:15000/stats + + # Try to get the endpoints over https + curl -k --key tests/testdata/certs/default/key.pem \ + --cert tests/testdata/certs/default/cert-chain.pem \ + -v https://istio-pilot.istio-system:15011/debug/endpointz +} + +function istioTest() { + # Will go to local machine + su -s /bin/bash -c "curl -v byon-docker.test.istio.io:7072" istio-test +} diff --git a/istio-1.3.5/tools/packaging/deb/istio.mk b/istio-1.3.5/tools/packaging/deb/istio.mk new file mode 100644 index 0000000..193852d --- /dev/null +++ b/istio-1.3.5/tools/packaging/deb/istio.mk @@ -0,0 +1,167 @@ +# Make the deb image using the CI/CD image and docker, for users who don't have 'fpm' installed. +# TODO: use 'which fpm' to detect if fpm is installed on host, consolidate under one target ('deb') +deb/build-in-docker: + (cd ${TOP}; docker run --rm -u $(shell id -u) -it \ + -v ${GO_TOP}:${GO_TOP} \ + -w ${PWD} \ + -e USER=${USER} \ + -e GOPATH=${GOPATH} \ + --entrypoint /bin/bash ${CI_HUB}/ci:${CI_VERSION} \ + -c "make deb/fpm") + +# Create the 'sidecar' deb, including envoy and istio agents and configs. +# This target uses a locally installed 'fpm' - use 'docker.sidecar.deb' to use +# the builder image. +# TODO: consistent layout, possibly /opt/istio-VER/... +sidecar.deb: ${ISTIO_OUT}/istio-sidecar.deb + +deb: ${ISTIO_OUT}/istio-sidecar.deb + +# Base directory for istio binaries. Likely to change ! +ISTIO_DEB_BIN=/usr/local/bin + +ISTIO_DEB_DEPS:=pilot-discovery istioctl mixs istio_ca +ISTIO_FILES:= +# subst is used to turn an absolute path into the relative path that fpm seems to expect +$(foreach DEP,$(ISTIO_DEB_DEPS),\ + $(eval ${ISTIO_OUT}/istio.deb: $(ISTIO_OUT)/$(DEP)) \ + $(eval ISTIO_FILES+=$(subst $(GO_TOP)/,,$(ISTIO_OUT))/$(DEP)=$(ISTIO_DEB_BIN)/$(DEP)) ) + +SIDECAR_DEB_DEPS:=envoy pilot-agent node_agent +SIDECAR_FILES:= +# subst is used to turn an absolute path into the relative path that fpm seems to expect +$(foreach DEP,$(SIDECAR_DEB_DEPS),\ + $(eval ${ISTIO_OUT}/istio-sidecar.deb: $(ISTIO_OUT)/$(DEP)) \ + $(eval SIDECAR_FILES+=$(subst $(GO_TOP)/,,$(ISTIO_OUT))/$(DEP)=$(ISTIO_DEB_BIN)/$(DEP)) ) + +ISTIO_DEB_DEST:=${ISTIO_DEB_BIN}/istio-start.sh \ + ${ISTIO_DEB_BIN}/istio-node-agent-start.sh \ + ${ISTIO_DEB_BIN}/istio-iptables.sh \ + /lib/systemd/system/istio.service \ + /lib/systemd/system/istio-auth-node-agent.service \ + /var/lib/istio/envoy/sidecar.env + +$(foreach DEST,$(ISTIO_DEB_DEST),\ + $(eval ${ISTIO_OUT}/istio-sidecar.deb: tools/packaging/common/$(notdir $(DEST))) \ + $(eval SIDECAR_FILES+=src/istio.io/istio/tools/packaging/common/$(notdir $(DEST))=$(DEST))) + +SIDECAR_FILES+=src/istio.io/istio/tools/packaging/common/envoy_bootstrap_v2.json=/var/lib/istio/envoy/envoy_bootstrap_tmpl.json +SIDECAR_FILES+=src/istio.io/istio/tools/packaging/common/envoy_bootstrap_drain.json=/var/lib/istio/envoy/envoy_bootstrap_drain.json + +# original name used in 0.2 - will be updated to 'istio.deb' since it now includes all istio binaries. +ISTIO_DEB_NAME ?= istio-sidecar + +# TODO: rename istio-sidecar.deb to istio.deb + +# Note: adding --deb-systemd ${GO_TOP}/src/istio.io/istio/tools/packaging/common/istio.service will result in +# a /etc/systemd/system/multi-user.target.wants/istio.service and auto-start. Currently not used +# since we need configuration. +# --iteration 1 adds a "-1" suffix to the version that didn't exist before +${ISTIO_OUT}/istio-sidecar.deb: | ${ISTIO_OUT} + $(MAKE) deb/fpm + +# Package the sidecar deb file. +deb/fpm: + rm -f ${ISTIO_OUT}/istio-sidecar.deb + fpm -s dir -t deb -n ${ISTIO_DEB_NAME} -p ${ISTIO_OUT}/istio-sidecar.deb --version $(PACKAGE_VERSION) -C ${GO_TOP} -f \ + --url http://istio.io \ + --license Apache \ + --vendor istio.io \ + --maintainer istio@istio.io \ + --after-install tools/packaging/deb/postinst.sh \ + --config-files /var/lib/istio/envoy/envoy_bootstrap_tmpl.json \ + --config-files /var/lib/istio/envoy/sidecar.env \ + --description "Istio Sidecar" \ + --depends iproute2 \ + --depends iptables \ + $(SIDECAR_FILES) + +${ISTIO_OUT}/istio.deb: + rm -f ${ISTIO_OUT}/istio.deb + fpm -s dir -t deb -n istio -p ${ISTIO_OUT}/istio.deb --version $(PACKAGE_VERSION) -C ${GO_TOP} -f \ + --url http://istio.io \ + --license Apache \ + --vendor istio.io \ + --maintainer istio@istio.io \ + --description "Istio" \ + $(ISTIO_FILES) + +# Install the deb in a docker image, for testing of the install process. +deb/docker: hyperistio build deb/fpm ${ISTIO_OUT}/istio.deb + mkdir -p ${OUT_DIR}/deb + cp tools/packaging/deb/Dockerfile tools/packaging/deb/deb_test.sh ${OUT_DIR}/deb + cp tests/testdata/config/*.yaml ${OUT_DIR}/deb + cp -a tests/testdata/certs ${OUT_DIR}/deb + cp ${ISTIO_OUT}/hyperistio ${OUT_DIR}/deb + cp ${GOPATH}/bin/{kube-apiserver,etcd,kubectl} ${OUT_DIR}/deb + cp ${ISTIO_OUT}/istio-sidecar.deb ${OUT_DIR}/deb/istio-sidecar.deb + cp ${ISTIO_OUT}/istio.deb ${OUT_DIR}/deb/istio.deb + docker build -t istio_deb -f ${OUT_DIR}/deb/Dockerfile ${OUT_DIR}/deb/ + +deb/test: + docker run --cap-add=NET_ADMIN --rm -v ${ISTIO_GO}/tools/packaging/deb/deb_test.sh:/tmp/deb_test.sh istio_deb /tmp/deb_test.sh + +# For the test, by default use a local pilot. +# Set it to 172.18.0.1 to run against a pilot or hyperistio running in IDE. +# You may need to enable 15007 in the local machine firewall for this to work. +DEB_PILOT_IP ?= 127.0.0.1 +DEB_CMD ?= /bin/bash +DEB_IP ?= 172.18.0.3 +DEB_PORT_PREFIX ?= 1600 + +# TODO: docker compose ? + +# Run the docker image including the installed debian, with access to all source +# code. Useful for debugging/experiments with iptables. +# +# Before running: +# docker network create --subnet=172.18.0.0/16 istiotest +# The IP of the docker matches the byon-docker service entry +deb/run/docker: + docker run --cap-add=NET_ADMIN --rm \ + -v ${GO_TOP}:${GO_TOP} \ + -w ${PWD} \ + --net istiotest --ip ${DEB_IP} \ + --add-host echo:10.1.1.1 \ + --add-host byon.test.istio.io:10.1.1.2 \ + --add-host byon-docker.test.istio.io:10.1.1.2 \ + --add-host istio-pilot.istio-system:${DEB_PILOT_IP} \ + ${DEB_ENV} -e ISTIO_SERVICE_CIDR=10.1.1.0/24 \ + -e ISTIO_INBOUND_PORTS=7070,7072,7073,7074,7075 \ + -e PILOT_CERT_DIR=/var/lib/istio/pilot \ + -p 127.0.0.1:${DEB_PORT_PREFIX}1:15007 \ + -p 127.0.0.1:${DEB_PORT_PREFIX}2:7070 \ + -p 127.0.0.1:${DEB_PORT_PREFIX}3:7072 \ + -p 127.0.0.1:${DEB_PORT_PREFIX}4:7073 \ + -p 127.0.0.1:${DEB_PORT_PREFIX}5:7074 \ + -p 127.0.0.1:${DEB_PORT_PREFIX}6:7075 \ + -p 127.0.0.1:${DEB_PORT_PREFIX}7:15011 \ + -p 127.0.0.1:${DEB_PORT_PREFIX}8:15010 \ + -e GOPATH=${GOPATH} \ + -it istio_deb ${DEB_CMD} + +deb/run/debug: + $(MAKE) deb/run/docker DEB_ENV="-e DEB_PILOT_IP=172.18.0.1" + +deb/run/tproxy: + $(MAKE) deb/run/docker DEB_PORT_PREFIX=1610 DEB_IP=172.18.0.4 DEB_ENV="-e ISTIO_INBOUND_INTERCEPTION_MODE=TPROXY" + +deb/run/mtls: + $(MAKE) deb/run/docker DEB_PORT_PREFIX=1620 -e DEB_PILOT_IP=172.18.0.1 DEB_IP=172.18.0.5 DEB_ENV="-e ISTIO_PILOT_PORT=15005 -e ISTIO_CP_AUTH=MUTUAL_TLS" + +# Similar with above, but using a pilot running on the local machine +deb/run/docker-debug: + $(MAKE) deb/run/docker PILOT_IP= + +# +deb/docker-run: deb/docker deb/run/docker + +.PHONY: \ + deb \ + deb/build-in-docker \ + deb/docker \ + deb/docker-run \ + deb/run/docker \ + deb/fpm \ + deb/test \ + sidecar.deb diff --git a/istio-1.3.5/tools/packaging/deb/postinst.sh b/istio-1.3.5/tools/packaging/deb/postinst.sh new file mode 100755 index 0000000..8b17dbb --- /dev/null +++ b/istio-1.3.5/tools/packaging/deb/postinst.sh @@ -0,0 +1,50 @@ +#!/bin/bash +# +# Copyright 2017, 2018 Istio Authors. All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +################################################################################ +set -e + +umask 022 + +if ! getent passwd istio-proxy >/dev/null; then + addgroup --system istio-proxy + adduser --system --group --home /var/lib/istio istio-proxy +fi + +if [ ! -e /etc/istio ]; then + # Backward compat. + ln -s /var/lib/istio /etc/istio +fi + +mkdir -p /var/lib/istio/envoy +mkdir -p /var/lib/istio/proxy +mkdir -p /var/lib/istio/config +mkdir -p /var/log/istio + +touch /var/lib/istio/config/mesh + +mkdir -p /etc/certs +chown istio-proxy.istio-proxy /etc/certs + +chown istio-proxy.istio-proxy /var/lib/istio/envoy /var/lib/istio/config /var/log/istio /var/lib/istio/config/mesh /var/lib/istio/proxy +chmod o+rx /usr/local/bin/{envoy,pilot-agent,node_agent} + +# pilot-agent and envoy may run with effective uid 0 in order to run envoy with +# CAP_NET_ADMIN, so any iptables rule matching on "-m owner --uid-owner +# istio-proxy" will not match connections from those processes anymore. +# Instead, rely on the process's effective gid being istio-proxy and create a +# "-m owner --gid-owner istio-proxy" iptables rule in istio-iptables.sh. +chmod 2755 /usr/local/bin/{envoy,pilot-agent} diff --git a/istio-1.3.5/tools/packaging/packaging.mk b/istio-1.3.5/tools/packaging/packaging.mk new file mode 100644 index 0000000..6540d3a --- /dev/null +++ b/istio-1.3.5/tools/packaging/packaging.mk @@ -0,0 +1,8 @@ +#remove leading characters since package version expects to start with digit +PACKAGE_VERSION ?= $(shell echo $(VERSION) | sed 's/^[a-z]*-//' | sed 's/-//') + +# Building the debian file, docker.istio.deb and istio.deb +include tools/packaging/deb/istio.mk + +# RPM/RHEL/CENTOS stuff +include tools/packaging/rpm/rpm.mk diff --git a/istio-1.3.5/tools/packaging/rpm/Dockerfile.build b/istio-1.3.5/tools/packaging/rpm/Dockerfile.build new file mode 100644 index 0000000..5ea5c7a --- /dev/null +++ b/istio-1.3.5/tools/packaging/rpm/Dockerfile.build @@ -0,0 +1,22 @@ +FROM centos:7 + +RUN yum upgrade -y && \ + yum install -y epel-release centos-release-scl && \ + yum install -y fedpkg sudo make which cmake3 rh-git218 \ + automake autoconf autogen libtool ninja-build \ + llvm-toolset-7 devtoolset-7-libatomic-devel && \ + yum clean all + +# Install go (go package in yum repositories is too old) +RUN curl -o /root/go.tar.gz https://dl.google.com/go/go1.12.7.linux-amd64.tar.gz && \ + tar zxf /root/go.tar.gz -C /usr/local +ENV GOROOT=/usr/local/go \ + PATH=/usr/local/go/bin:${PATH} + +# Install bazel +RUN curl -o /root/bazel-installer.sh -L http://github.com/bazelbuild/bazel/releases/download/0.27.1/bazel-0.27.1-installer-linux-x86_64.sh && \ + chmod +x /root/bazel-installer.sh && \ + /root/bazel-installer.sh + +RUN ln -s /usr/bin/cmake3 /usr/bin/cmake && \ + ln -s /usr/bin/ninja-build /usr/bin/ninja diff --git a/istio-1.3.5/tools/packaging/rpm/build-istio-rpm.sh b/istio-1.3.5/tools/packaging/rpm/build-istio-rpm.sh new file mode 100755 index 0000000..7256c43 --- /dev/null +++ b/istio-1.3.5/tools/packaging/rpm/build-istio-rpm.sh @@ -0,0 +1,33 @@ +#!/bin/bash + +#set -x + +# We rely on the following ENV variables: +# ISTIO_GO +# ISTIO_OUT +# USER_ID +# GROUP_ID + +PKG_DIR="${ISTIO_GO}/tools/packaging" +WORK_DIR="$(mktemp -d)" + +cp -r "${PKG_DIR}" "${WORK_DIR}" +mv "${WORK_DIR}"/packaging/common/* "${WORK_DIR}"/packaging/rpm/istio + +cd "${ISTIO_GO}/.." || exit 1 +tar cfz "${WORK_DIR}/packaging/rpm/istio/istio.tar.gz" --exclude=.git istio + +cd "${WORK_DIR}/packaging/rpm/istio" || exit 1 + +if [ -n "${PACKAGE_VERSION}" ]; then + sed -i "s/%global package_version .*/%global package_version ${PACKAGE_VERSION}/" istio.spec +fi +if [ -n "${PACKAGE_RELEASE}" ]; then + sed -i "s/%global package_release .*/%global package_release ${PACKAGE_RELEASE}/" istio.spec +fi + +fedpkg --release el7 local + +mkdir -p "${ISTIO_OUT}/rpm" +cp -r x86_64/* "${ISTIO_OUT}/rpm" +chown -R "${USER_ID}":"${GROUP_ID}" "${ISTIO_OUT}/rpm" diff --git a/istio-1.3.5/tools/packaging/rpm/build-proxy-rpm.sh b/istio-1.3.5/tools/packaging/rpm/build-proxy-rpm.sh new file mode 100755 index 0000000..b076cde --- /dev/null +++ b/istio-1.3.5/tools/packaging/rpm/build-proxy-rpm.sh @@ -0,0 +1,48 @@ +#!/bin/bash + +#set -x + +# We rely on the following ENV variables: +# ISTIO_ENVOY_VERSION +# ISTIO_OUT +# ISTIO_GO +# USER_ID +# GROUP_ID + +PKG_DIR="${ISTIO_GO}/tools/packaging" +WORK_DIR="$(mktemp -d)" +RPM_DIR="${WORK_DIR}/packaging/rpm/proxy" + +cp -r "${PKG_DIR}" "${WORK_DIR}" +mv "${WORK_DIR}"/packaging/common/* "${RPM_DIR}" + +# shellcheck disable=SC1091 +source /opt/rh/rh-git218/enable +# shellcheck disable=SC1091 +source /opt/rh/llvm-toolset-7/enable + +cd /builder || exit 1 +git clone https://github.com/istio/proxy.git istio-proxy +cd istio-proxy || exit 1 +git checkout "${ISTIO_ENVOY_VERSION}" + +cat "${RPM_DIR}/bazelrc" >> .bazelrc +BUILD_SCM_REVISION=$(date +%s) +sed -i "1i echo BUILD_SCM_REVISION ${BUILD_SCM_REVISION}\necho BUILD_SCM_STATUS Clean\nexit 0" tools/bazel_get_workspace_status + +cd .. +tar cfz "${RPM_DIR}/istio-proxy.tar.gz" --exclude=.git istio-proxy +cd "${RPM_DIR}" || exit 1 + +if [ -n "${PACKAGE_VERSION}" ]; then + sed -i "s/%global package_version .*/%global package_version ${PACKAGE_VERSION}/" istio-proxy.spec +fi +if [ -n "${PACKAGE_RELEASE}" ]; then + sed -i "s/%global package_release .*/%global package_release ${PACKAGE_RELEASE}/" istio-proxy.spec +fi + +fedpkg --release el7 local + +mkdir -p "${ISTIO_OUT}/rpm" +cp -r x86_64/* "${ISTIO_OUT}/rpm" +chown -R "${USER_ID}":"${GROUP_ID}" "${ISTIO_OUT}/rpm" diff --git a/istio-1.3.5/tools/packaging/rpm/istio/istio.spec b/istio-1.3.5/tools/packaging/rpm/istio/istio.spec new file mode 100644 index 0000000..c3a6eb5 --- /dev/null +++ b/istio-1.3.5/tools/packaging/rpm/istio/istio.spec @@ -0,0 +1,354 @@ +# Build with debug info rpm +%global with_debug 0 +# Run unit tests +%global with_tests 0 +# Build test binaries +%global with_test_binaries 0 + +%if 0%{?with_debug} +%global _dwz_low_mem_die_limit 0 +%else +%global debug_package %{nil} +%endif + +# Those can be overridden when invoking make, eg: `make VERSION=2.0.0 rpm` +%global package_version 0.0.1 +%global package_release 1 + +%global provider github +%global provider_tld com +%global project istio +%global repo istio +# https://github.com/istio/istio +%global provider_prefix %{provider}.%{provider_tld}/%{project}/%{repo} +%global import_path istio.io/istio + +# Use /usr/local as base dir, once upstream heavily depends on that +%global _prefix /usr/local + +Name: istio +Version: %{package_version} +Release: %{package_release}%{?dist} +Summary: An open platform to connect, manage, and secure microservices +License: ASL 2.0 +URL: https://%{provider_prefix} + +Source0: istio.tar.gz +#Source1: istiorc +#Source2: buildinfo +Source3: istio-start.sh +Source4: istio-node-agent-start.sh +Source5: istio-iptables.sh +Source6: istio.service +Source7: istio-auth-node-agent.service + +# e.g. el6 has ppc64 arch without gcc-go, so EA tag is required +ExclusiveArch: %{?go_arches:%{go_arches}}%{!?go_arches:%{ix86} x86_64 aarch64 %{arm}} + +%description +Istio is an open platform that provides a uniform way to connect, manage +and secure microservices. Istio supports managing traffic flows between +microservices, enforcing access policies, and aggregating telemetry data, +all without requiring changes to the microservice code. + +########### pilot-discovery ############### +%package pilot-discovery +Summary: The istio pilot discovery +Requires: istio = %{version}-%{release} + +%description pilot-discovery +Istio is an open platform that provides a uniform way to connect, manage +and secure microservices. Istio supports managing traffic flows between +microservices, enforcing access policies, and aggregating telemetry data, +all without requiring changes to the microservice code. + +This package contains the pilot-discovery program. + +pilot-discovery is the main pilot component and belongs to Control Plane. + +########### pilot-agent ############### +%package pilot-agent +Summary: The istio pilot agent +Requires: istio = %{version}-%{release} + +%description pilot-agent +Istio is an open platform that provides a uniform way to connect, manage +and secure microservices. Istio supports managing traffic flows between +microservices, enforcing access policies, and aggregating telemetry data, +all without requiring changes to the microservice code. + +This package contains the pilot-agent program. + +pilot-agent is agent that talks to Istio pilot. It belongs to Data Plane. +Along with Envoy, makes up the proxy that goes in the sidecar along with applications. + +########### istioctl ############### +%package istioctl +Summary: The istio command line tool +Requires: istio = %{version}-%{release} + +%description istioctl +Istio is an open platform that provides a uniform way to connect, manage +and secure microservices. Istio supports managing traffic flows between +microservices, enforcing access policies, and aggregating telemetry data, +all without requiring changes to the microservice code. + +This package contains the istioctl program. + +istioctl is the configuration command line utility. + +########### sidecar-injector ############### +%package sidecar-injector +Summary: The istio sidecar injector +Requires: istio = %{version}-%{release} + +%description sidecar-injector +Istio is an open platform that provides a uniform way to connect, manage +and secure microservices. Istio supports managing traffic flows between +microservices, enforcing access policies, and aggregating telemetry data, +all without requiring changes to the microservice code. + +This package contains the sidecar-injector program. + +sidecar-injector is the Kubernetes injector for Istio sidecar. +It belongs to Control Plane. + +########### mixs ############### +%package mixs +Summary: The istio mixs +Requires: istio = %{version}-%{release} + +%description mixs +Istio is an open platform that provides a uniform way to connect, manage +and secure microservices. Istio supports managing traffic flows between +microservices, enforcing access policies, and aggregating telemetry data, +all without requiring changes to the microservice code. + +This package contains the mixs program. + +mixs is the main mixer (server) component. Belongs to Control Plane. + +########### mixc ############### +%package mixc +Summary: The istio mixc +Requires: istio = %{version}-%{release} + +%description mixc +Istio is an open platform that provides a uniform way to connect, manage +and secure microservices. Istio supports managing traffic flows between +microservices, enforcing access policies, and aggregating telemetry data, +all without requiring changes to the microservice code. + +This package contains the mixc program. + +mixc is a debug/development CLI tool to interact with Mixer API. + +########### citadel ############### +%package citadel +Summary: Istio Security Component +Requires: istio = %{version}-%{release} + +%description citadel +Istio is an open platform that provides a uniform way to connect, manage +and secure microservices. Istio supports managing traffic flows between +microservices, enforcing access policies, and aggregating telemetry data, +all without requiring changes to the microservice code. + +This package contains the istio_ca program. + +This is the Istio Certificate Authority (CA) + security components. + +########### galley ############### +%package galley +Summary: Istio Galley Component +Requires: istio = %{version}-%{release} + +%description galley +Istio is an open platform that provides a uniform way to connect, manage +and secure microservices. Istio supports managing traffic flows between +microservices, enforcing access policies, and aggregating telemetry data, +all without requiring changes to the microservice code. + +This package contains the galley program. + +Galley is responsible for configuration management in Istio. + +########### node-agent ############### +%package node-agent +Summary: The Istio Node Agent +Requires: istio = %{version}-%{release} + +%description node-agent +Istio is an open platform that provides a uniform way to connect, manage +and secure microservices. Istio supports managing traffic flows between +microservices, enforcing access policies, and aggregating telemetry data, +all without requiring changes to the microservice code. + +This package contains the node agent. + + +%if 0%{?with_test_binaries} + +########### tests ############### +%package pilot-tests +Summary: Istio Pilot Test Binaries +Requires: istio = %{version}-%{release} + +%description pilot-tests +Istio is an open platform that provides a uniform way to connect, manage +and secure microservices. Istio supports managing traffic flows between +microservices, enforcing access policies, and aggregating telemetry data, +all without requiring changes to the microservice code. + +This package contains the binaries needed for pilot tests. + +%endif + +%prep + +rm -rf ISTIO +mkdir -p ISTIO/src/istio.io/istio +tar zxf %{SOURCE0} -C ISTIO/src/istio.io/istio --strip=1 + +#cp %{SOURCE1} ISTIO/src/istio.io/istio/.istiorc.mk +#cp %{SOURCE2} ISTIO/src/istio.io/istio/buildinfo + +%build +cd ISTIO +export GOPATH=$(pwd) + +pushd src/istio.io/istio +make pilot-discovery pilot-agent istioctl sidecar-injector mixc mixs citadel galley node_agent + +%if 0%{?with_test_binaries} +make test-bins +%endif + +popd + +%install +rm -rf $RPM_BUILD_ROOT +install -d -m755 $RPM_BUILD_ROOT/%{_bindir} +install -d -m755 $RPM_BUILD_ROOT/%{_unitdir} + +install -m755 %{SOURCE3} $RPM_BUILD_ROOT/%{_bindir}/istio-start.sh +install -m755 %{SOURCE4} $RPM_BUILD_ROOT/%{_bindir}/istio-node-agent-start.sh +install -m755 %{SOURCE5} $RPM_BUILD_ROOT/%{_bindir}/istio-iptables.sh + +install -m644 %{SOURCE6} $RPM_BUILD_ROOT/%{_unitdir}/istio.service +install -m644 %{SOURCE7} $RPM_BUILD_ROOT/%{_unitdir}/istio-auth-node-agent.service + +binaries=(pilot-discovery pilot-agent istioctl sidecar-injector mixs mixc istio_ca galley node_agent) +pushd . +cd ISTIO/out/linux_amd64/release +%if 0%{?with_debug} + for i in "${binaries[@]}"; do + cp -pav $i $RPM_BUILD_ROOT%{_bindir}/ +%else + mkdir stripped + for i in "${binaries[@]}"; do + echo stripping: $i + strip -o stripped/$i -s $i + cp -pav stripped/$i $RPM_BUILD_ROOT%{_bindir}/ + done +%endif +popd + +%if 0%{?with_test_binaries} +cp -pav ISTIO/out/linux_amd64/release/{pilot-test-server,pilot-test-client,pilot-test-eurekamirror} $RPM_BUILD_ROOT%{_bindir}/ +%endif + +%if 0%{?with_tests} + +%check +cd ISTIO +export GOPATH=$(pwd):%{gopath} +pushd src/istio.io/istio +make localTestEnv test +make localTestEnvCleanup +popd + +%endif + +%pre pilot-agent +getent group istio-proxy >/dev/null || groupadd --system istio-proxy || : +getent passwd istio-proxy >/dev/null || \ + useradd -c "Istio Proxy User" --system -g istio-proxy \ + -s /sbin/nologin -d /var/lib/istio istio-proxy 2> /dev/null || : + +mkdir -p /var/lib/istio/{envoy,proxy,config} /var/log/istio /etc/certs +touch /var/lib/istio/config/mesh +chown -R istio-proxy.istio-proxy /var/lib/istio/ /var/log/istio /etc/certs + +ln -s -T /var/lib/istio /etc/istio 2> /dev/null || : + +%post pilot-agent +%systemd_post istio.service + +%preun pilot-agent +%systemd_preun istio.service + +%postun pilot-agent +%systemd_postun_with_restart istio.service + +%pre node-agent +getent group istio-proxy >/dev/null || groupadd --system istio-proxy || : +getent passwd istio-proxy >/dev/null || \ + useradd -c "Istio Proxy User" --system -g istio-proxy \ + -s /sbin/nologin -d /var/lib/istio istio-proxy 2> /dev/null || : + +mkdir -p /var/lib/istio/{envoy,proxy,config} /var/log/istio /etc/certs +touch /var/lib/istio/config/mesh +chown -R istio-proxy.istio-proxy /var/lib/istio/ /var/log/istio /etc/certs + +ln -s -T /var/lib/istio /etc/istio 2> /dev/null || : + +#define license tag if not already defined +%{!?_licensedir:%global license %doc} + +%files +%license ISTIO/src/istio.io/istio/LICENSE +%doc ISTIO/src/istio.io/istio/README.md + +%files pilot-discovery +%{_bindir}/pilot-discovery + +%files pilot-agent +%attr(2755,root,root) %{_bindir}/pilot-agent +%attr(0755,root,root) %{_bindir}/istio-start.sh +%attr(0755,root,root) %{_bindir}/istio-iptables.sh +%attr(0644,root,root) %{_unitdir}/istio.service + +%files istioctl +%{_bindir}/istioctl + +%files sidecar-injector +%{_bindir}/sidecar-injector + +%files mixs +%{_bindir}/mixs + +%files mixc +%{_bindir}/mixc + +%files citadel +%{_bindir}/istio_ca + +%files galley +%{_bindir}/galley + +%files node-agent +%attr(0755,root,root) %{_bindir}/node_agent +%attr(0755,root,root) %{_bindir}/istio-node-agent-start.sh +%attr(0644,root,root) %{_unitdir}/istio-auth-node-agent.service + +%if 0%{?with_test_binaries} +%files pilot-tests +%{_bindir}/pilot-test-server +%{_bindir}/pilot-test-client +%{_bindir}/pilot-test-eurekamirror +%endif + +%changelog +* Thu Feb 7 2019 Jonh Wendell - 1.1.0-1 +- First package diff --git a/istio-1.3.5/tools/packaging/rpm/proxy/bazelrc b/istio-1.3.5/tools/packaging/rpm/proxy/bazelrc new file mode 100644 index 0000000..093acbf --- /dev/null +++ b/istio-1.3.5/tools/packaging/rpm/proxy/bazelrc @@ -0,0 +1,2 @@ +build --cxxopt -D_GLIBCXX_USE_CXX11_ABI=1 +build --cxxopt -DENVOY_IGNORE_GLIBCXX_USE_CXX11_ABI_ERROR=1 diff --git a/istio-1.3.5/tools/packaging/rpm/proxy/istio-proxy.spec b/istio-1.3.5/tools/packaging/rpm/proxy/istio-proxy.spec new file mode 100644 index 0000000..09bd023 --- /dev/null +++ b/istio-1.3.5/tools/packaging/rpm/proxy/istio-proxy.spec @@ -0,0 +1,74 @@ +# Those can be overridden when invoking make, eg: `make VERSION=2.0.0 rpm` +%global package_version 0.0.1 +%global package_release 1 + +# https://github.com/istio/proxy +%global provider github +%global provider_tld com +%global project istio +%global repo proxy +%global provider_prefix %{provider}.%{provider_tld}/%{project}/%{repo} + +# Use /usr/local as base dir, once upstream heavily depends on that +%global _prefix /usr/local +%global envoy_libdir /var/lib/istio/envoy + +Name: istio-proxy +Version: %{package_version} +Release: %{package_release}%{?dist} +Summary: The Istio Proxy is a microservice proxy that can be used on the client and server side, and forms a microservice mesh. The Proxy supports a large number of features. +License: ASL 2.0 +URL: https://%{provider_prefix} + +BuildRequires: ninja-build +BuildRequires: perl +BuildRequires: binutils +BuildRequires: cmake3 + +Source0: istio-proxy.tar.gz +Source1: sidecar.env +Source2: envoy_bootstrap_v2.json +Source3: envoy_bootstrap_drain.json + +%description +The Istio Proxy is a microservice proxy that can be used on the client and server side, and forms a microservice mesh. The Proxy supports a large number of features. + +########### istio-proxy ############### +%package istio-proxy +Summary: The istio envoy proxy + +%description istio-proxy +The Istio Proxy is a microservice proxy that can be used on the client and server side, and forms a microservice mesh. The Proxy supports a large number of features. + +This package contains the envoy program. + +istio-proxy is the proxy required by the Istio Pilot Agent that talks to Istio pilot + +%prep +%setup -q -n %{name} + +%build +export CC=clang +export CXX=clang++ +bazel --output_base=/builder/bazel_cache --output_user_root=/builder/bazel_cache/root build //... +bazel shutdown + +%install +rm -rf $RPM_BUILD_ROOT +install -d -m755 $RPM_BUILD_ROOT/%{_bindir} +install -d -m755 $RPM_BUILD_ROOT/%{envoy_libdir} + +install -m755 ${RPM_BUILD_DIR}/istio-proxy/bazel-bin/src/envoy/envoy ${RPM_BUILD_ROOT}%{_bindir} +install -m644 %{SOURCE1} $RPM_BUILD_ROOT%{envoy_libdir}/sidecar.env +install -m644 %{SOURCE2} $RPM_BUILD_ROOT%{envoy_libdir}/envoy_bootstrap_tmpl.json +install -m644 %{SOURCE3} $RPM_BUILD_ROOT%{envoy_libdir}/envoy_bootstrap_drain.json + +%files +%attr(0755,root,root) %{_bindir}/envoy +%attr(0644,root,root) %{envoy_libdir}/sidecar.env +%attr(0644,root,root) %{envoy_libdir}/envoy_bootstrap_tmpl.json +%attr(0644,root,root) %{envoy_libdir}/envoy_bootstrap_drain.json + +%changelog +* Fri Feb 15 2019 Jonh Wendell + First release diff --git a/istio-1.3.5/tools/packaging/rpm/rpm.mk b/istio-1.3.5/tools/packaging/rpm/rpm.mk new file mode 100644 index 0000000..b9a79ff --- /dev/null +++ b/istio-1.3.5/tools/packaging/rpm/rpm.mk @@ -0,0 +1,38 @@ +rpm: rpm/builder-image rpm/istio rpm/proxy + +rpm/istio: + docker run --rm -it \ + -v ${GO_TOP}:${GO_TOP} \ + -w ${PWD} \ + -e USER=${USER} \ + -e TAG=${TAG} \ + -e ISTIO_GO=${ISTIO_GO} \ + -e ISTIO_OUT=${ISTIO_OUT} \ + -e PACKAGE_VERSION=${PACKAGE_VERSION} \ + -e USER_ID=$(shell id -u) \ + -e GROUP_ID=$(shell id -g) \ + istio-rpm-builder \ + tools/packaging/rpm/build-istio-rpm.sh + +rpm/proxy: + docker run --rm -it \ + -v ${GO_TOP}:${GO_TOP} \ + -w /builder \ + -e USER=${USER} \ + -e ISTIO_ENVOY_VERSION=${ISTIO_ENVOY_VERSION} \ + -e ISTIO_GO=${ISTIO_GO} \ + -e ISTIO_OUT=${ISTIO_OUT} \ + -e PACKAGE_VERSION=${PACKAGE_VERSION} \ + -e USER_ID=$(shell id -u) \ + -e GROUP_ID=$(shell id -g) \ + istio-rpm-builder \ + ${PWD}/tools/packaging/rpm/build-proxy-rpm.sh + +rpm/builder-image: + docker build -t istio-rpm-builder -f ${PWD}/tools/packaging/rpm/Dockerfile.build ${PWD}/tools/packaging/rpm + +.PHONY: \ + rpm \ + rpm/istio \ + rpm/proxy \ + rpm/builder-image diff --git a/istio-1.3.5/tools/perf_istio_rules.yaml b/istio-1.3.5/tools/perf_istio_rules.yaml new file mode 100644 index 0000000..d0890b3 --- /dev/null +++ b/istio-1.3.5/tools/perf_istio_rules.yaml @@ -0,0 +1,45 @@ +apiVersion: networking.istio.io/v1alpha3 +kind: Gateway +metadata: + name: fortio-gateway +spec: + selector: + istio: ingressgateway # use istio default controller + servers: + - port: + number: 80 + name: http + protocol: HTTP + hosts: + - "*" +--- +apiVersion: networking.istio.io/v1alpha3 +kind: VirtualService +metadata: + name: fortio +spec: + hosts: + - "*" + gateways: + - fortio-gateway + http: + - match: + - uri: + prefix: /fortio1/ + route: + - destination: + host: echosrv1.istio.svc.cluster.local + port: + number: 8080 + rewrite: + uri: / # drop the /fortio1 prefix when talking to fortio such as /fortio1/fortio -> /fortio + - match: + - uri: + prefix: /fortio2/ + route: + - destination: + host: echosrv2.istio.svc.cluster.local + port: + number: 8080 + rewrite: + uri: / # drop the /fortio2 prefix when talking to fortio such as /fortio2/fortio -> /fortio diff --git a/istio-1.3.5/tools/perf_k8svcs.yaml b/istio-1.3.5/tools/perf_k8svcs.yaml new file mode 100644 index 0000000..e4067fc --- /dev/null +++ b/istio-1.3.5/tools/perf_k8svcs.yaml @@ -0,0 +1,72 @@ +# 2 services will get istio injected +--- +apiVersion: v1 +kind: Service +metadata: + name: echosrv1 +spec: + ports: + - port: 8080 + name: http-echo + - port: 8079 + name: grpc-ping + selector: + app: echosrv1 +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: echo-svc-deployment1 +spec: + replicas: 1 # tells deployment to run 1 pods matching the template + selector: + matchLabels: + app: echosrv1 + template: # create pods using pod definition in this template + metadata: + # a unique name is generated from the deployment name + labels: + app: echosrv1 + spec: + containers: + - name: echosrv + image: fortio/fortio:latest_release + imagePullPolicy: Always # needed despite what is documented to really get latest + ports: + - containerPort: 8080 +--- +apiVersion: v1 +kind: Service +metadata: + name: echosrv2 +spec: + ports: + - port: 8080 + name: http-echo + - port: 8079 + name: grpc-ping + selector: + app: echosrv2 +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: echo-svc-deployment2 +spec: + replicas: 1 # tells deployment to run 1 pods matching the template + selector: + matchLabels: + app: echosrv2 + template: # create pods using pod definition in this template + metadata: + # a unique name is generated from the deployment name + labels: + app: echosrv2 + spec: + containers: + - name: echosrv + image: fortio/fortio:latest_release + imagePullPolicy: Always # needed despite what is documented to really get latest + ports: + - containerPort: 8080 +--- diff --git a/istio-1.3.5/tools/perf_setup.svg b/istio-1.3.5/tools/perf_setup.svg new file mode 100644 index 0000000..0e4c0ce --- /dev/null +++ b/istio-1.3.5/tools/perf_setup.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/istio-1.3.5/tools/rules.yml b/istio-1.3.5/tools/rules.yml new file mode 100644 index 0000000..509f85d --- /dev/null +++ b/istio-1.3.5/tools/rules.yml @@ -0,0 +1,57 @@ +subject: namespace:ns +revision: "2022" +rules: +- selector: # must be empty for preprocessing adapters + aspects: + - kind: quotas + params: + quotas: + - descriptorName: RequestCount + maxAmount: 5000 + expiration: 1s + - kind: metrics + adapter: prometheus + params: + metrics: + - descriptor_name: request_count + # we want to increment this counter by 1 for each unique (source, target, service, method, response_code) tuple + value: "1" + labels: + source: source.labels["app"] | "unknown" + target: destination.service | "unknown" + service: destination.labels["app"] | "unknown" + method: request.path | "unknown" + version: destination.labels["version"] | "unknown" + response_code: response.code | 200 + - descriptor_name: request_duration + value: response.duration | "0ms" + labels: + source: source.labels["app"] | "unknown" + target: destination.service | "unknown" + service: destination.labels["app"] | "unknown" + method: request.path | "unknown" + version: destination.labels["version"] | "unknown" + response_code: response.code | 200 + - kind: access-logs + params: + logName: access_log + log: + descriptor_name: accesslog.common + template_expressions: + originIp: origin.ip + sourceUser: origin.user + timestamp: request.time + method: request.method + url: request.path + protocol: request.scheme + responseCode: response.code + responseSize: response.size + labels: + originIp: origin.ip + sourceUser: origin.user + timestamp: request.time + method: request.method + url: request.path + protocol: request.scheme + responseCode: response.code + responseSize: response.size diff --git a/istio-1.3.5/tools/run_canonical_perf_tests.sh b/istio-1.3.5/tools/run_canonical_perf_tests.sh new file mode 100755 index 0000000..42953b7 --- /dev/null +++ b/istio-1.3.5/tools/run_canonical_perf_tests.sh @@ -0,0 +1,52 @@ +#!/bin/bash + +DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" +# shellcheck source=tools/setup_perf_cluster.sh +source "${DIR}/setup_perf_cluster.sh" + +LABEL="${1}" +OUT_DIR="${2}" + +if [[ -z "${OUT_DIR// }" ]]; then + OUT_DIR=$(mktemp -d -t "istio_perf.XXXXXX") +fi + +DURATION="1m" + +run_canonical_perf_test "${LABEL}" "fortio2" "echo1" 100 "${DURATION}" 16 "${OUT_DIR}" +run_canonical_perf_test "${LABEL}" "fortio2" "echo1" 400 "${DURATION}" 16 "${OUT_DIR}" +run_canonical_perf_test "${LABEL}" "fortio2" "echo1" 1000 "${DURATION}" 16 "${OUT_DIR}" +run_canonical_perf_test "${LABEL}" "fortio2" "echo1" 1200 "${DURATION}" 16 "${OUT_DIR}" +run_canonical_perf_test "${LABEL}" "fortio2" "echo1" 1600 "${DURATION}" 16 "${OUT_DIR}" + +run_canonical_perf_test "${LABEL}" "fortio1" "echo2" 100 "${DURATION}" 16 "${OUT_DIR}" +run_canonical_perf_test "${LABEL}" "fortio1" "echo2" 400 "${DURATION}" 16 "${OUT_DIR}" +run_canonical_perf_test "${LABEL}" "fortio1" "echo2" 1000 "${DURATION}" 16 "${OUT_DIR}" +run_canonical_perf_test "${LABEL}" "fortio1" "echo2" 1200 "${DURATION}" 16 "${OUT_DIR}" +run_canonical_perf_test "${LABEL}" "fortio1" "echo2" 1600 "${DURATION}" 16 "${OUT_DIR}" + +run_canonical_perf_test "${LABEL}" "fortio2" "echo1" 100 "${DURATION}" 20 "${OUT_DIR}" +run_canonical_perf_test "${LABEL}" "fortio2" "echo1" 400 "${DURATION}" 20 "${OUT_DIR}" +run_canonical_perf_test "${LABEL}" "fortio2" "echo1" 1000 "${DURATION}" 20 "${OUT_DIR}" +run_canonical_perf_test "${LABEL}" "fortio2" "echo1" 1200 "${DURATION}" 20 "${OUT_DIR}" +run_canonical_perf_test "${LABEL}" "fortio2" "echo1" 1600 "${DURATION}" 20 "${OUT_DIR}" + +run_canonical_perf_test "${LABEL}" "fortio1" "echo2" 100 "${DURATION}" 20 "${OUT_DIR}" +run_canonical_perf_test "${LABEL}" "fortio1" "echo2" 400 "${DURATION}" 20 "${OUT_DIR}" +run_canonical_perf_test "${LABEL}" "fortio1" "echo2" 1000 "${DURATION}" 20 "${OUT_DIR}" +run_canonical_perf_test "${LABEL}" "fortio1" "echo2" 1200 "${DURATION}" 20 "${OUT_DIR}" +run_canonical_perf_test "${LABEL}" "fortio1" "echo2" 1600 "${DURATION}" 20 "${OUT_DIR}" + +run_canonical_perf_test "${LABEL}" "fortio2" "echo1" 100 "${DURATION}" 24 "${OUT_DIR}" +run_canonical_perf_test "${LABEL}" "fortio2" "echo1" 400 "${DURATION}" 24 "${OUT_DIR}" +run_canonical_perf_test "${LABEL}" "fortio2" "echo1" 1000 "${DURATION}" 24 "${OUT_DIR}" +run_canonical_perf_test "${LABEL}" "fortio2" "echo1" 1200 "${DURATION}" 24 "${OUT_DIR}" +run_canonical_perf_test "${LABEL}" "fortio2" "echo1" 1600 "${DURATION}" 24 "${OUT_DIR}" + +run_canonical_perf_test "${LABEL}" "fortio1" "echo2" 100 "${DURATION}" 24 "${OUT_DIR}" +run_canonical_perf_test "${LABEL}" "fortio1" "echo2" 400 "${DURATION}" 24 "${OUT_DIR}" +run_canonical_perf_test "${LABEL}" "fortio1" "echo2" 1000 "${DURATION}" 24 "${OUT_DIR}" +run_canonical_perf_test "${LABEL}" "fortio1" "echo2" 1200 "${DURATION}" 24 "${OUT_DIR}" +run_canonical_perf_test "${LABEL}" "fortio1" "echo2" 1600 "${DURATION}" 24 "${OUT_DIR}" + +python "${DIR}/convert_perf_results.py" "${OUT_DIR}" > "${OUT_DIR}/out.csv" diff --git a/istio-1.3.5/tools/setup_perf_cluster.sh b/istio-1.3.5/tools/setup_perf_cluster.sh new file mode 100644 index 0000000..36484a6 --- /dev/null +++ b/istio-1.3.5/tools/setup_perf_cluster.sh @@ -0,0 +1,540 @@ +#!/bin/bash +# +# Sets up a cluster for perf testing - GCP/GKE +# tools/setup_perf_cluster.sh +# Notes: +# * See README.md +# * Make sure istioctl in your path is the one matching your release/crd/... +# * You need to update istio-auth.yaml or run from a release directory: +# source tools/setup_perf_cluster.sh +# setup_all +# (inside google you may need to rerun setup_vm_firewall multiple times) +# +# This can be used as a script or sourced and functions called interactively +# +# The script must be run/sourced from the parent of the tools/ directory +# + +PROJECT=${PROJECT:-$(gcloud config list --format 'value(core.project)' 2>/dev/null)} +ZONE=${ZONE:-us-east4-b} +CLUSTER_NAME=${CLUSTER_NAME:-istio-perf} +MACHINE_TYPE=${MACHINE_TYPE:-n1-highcpu-2} +NUM_NODES=${NUM_NODES:-6} # SvcA<->SvcB + Ingress + Pilot + Mixer + 1 extra (kube-system) +VM_NAME=${VM_NAME:-fortio-vm} +ISTIOCTL=${ISTIOCTL:-istioctl} # to override istioctl from outside of the path +FORTIO_NAMESPACE=${FORTIO_NAMESPACE:-fortio} # Namespace for non istio app +ISTIO_NAMESPACE=${ISTIO_NAMESPACE:-istio} # Namespace for istio injected app + +function Usage() { + echo "usage: PROJECT=project ZONE=zone $0" + echo "also settable are NUM_NODES, MACHINE_TYPE, CLUSTER_NAME, VM_NAME, VM_IMAGE" + exit 1 +} + +function abspath() { +# Source https://stackoverflow.com/questions/3915040/bash-fish-command-to-print-absolute-path-to-a-file +# Thanks to Alexander Klimetschek + + # generate absolute path from relative path + # $1 : relative filename + # return : absolute path + if [ -d "$1" ]; then + # dir + (cd "$1"; pwd) + elif [ -f "$1" ]; then + # file + if [[ $1 = /* ]]; then + echo "$1" + elif [[ $1 == */* ]]; then + echo "$(cd "${1%/*}"; pwd)/${1##*/}" + else + echo "$(pwd)/$1" + fi + fi +} + +function List_functions() { + grep -E "^function [a-z]" "${BASH_SOURCE[0]}" | sed -e 's/function \([a-z_0-9]*\).*/\1/' +} + +if [[ "${BASH_SOURCE[0]}" != "${0}" ]]; then + TOOLS_ABSPATH=$(abspath "${BASH_SOURCE[0]}") + TOOLS_DIR=${TOOLS_DIR:-$(dirname "${TOOLS_ABSPATH}")} + echo "Script ${BASH_SOURCE[0]} is being sourced (Tools in $TOOLS_DIR)..." + List_functions + SOURCED=1 +else + TOOLS_ABSPATH=$(abspath "${0}") + TOOLS_DIR=${TOOLS_DIR:-$(dirname "${TOOLS_ABSPATH}")} + echo "$0 is Executed, (Tools in $TOOLS_DIR) (can also be sourced interactively)..." + echo "In case of errors, retry at the failed step (readyness checks missing)" + set -e + SOURCED=0 + if [[ -z "${PROJECT}" ]]; then + Usage + fi +fi + +function update_gcp_opts() { + export GCP_OPTS="--project=${PROJECT} --zone=${ZONE}" +} + +function Execute() { + echo "### Running:" "$@" 1>&2 + "$@" +} + +function ExecuteEval() { + echo "### Running:" "$@" 1>&2 + eval "$@" +} + + +function create_cluster() { + Execute gcloud container clusters create "$CLUSTER_NAME" "$GCP_OPTS" --machine-type="$MACHINE_TYPE" --num-nodes="$NUM_NODES" --no-enable-legacy-authorization +} + +function delete_cluster() { + echo "Deleting CLUSTER_NAME=$CLUSTER_NAME" + Execute gcloud container clusters delete "$CLUSTER_NAME" "$GCP_OPTS" -q +} + +function create_vm() { + echo "Obtaining latest ubuntu xenial image name... (takes a few seconds)..." + VM_IMAGE=${VM_IMAGE:-$(gcloud compute images list --standard-images --filter=name~ubuntu-1604-xenial --limit=1 --uri)} + echo "Creating VM_NAME=$VM_NAME using VM_IMAGE=$VM_IMAGE" + Execute gcloud compute instances create "$VM_NAME" "$GCP_OPTS" --machine-type "$MACHINE_TYPE" --image "$VM_IMAGE" + echo "Waiting a bit for the VM to come up..." + #TODO: 'wait for vm to be ready' + sleep 45 +} + +function delete_vm() { + echo "Deleting VM_NAME=$VM_NAME" + Execute gcloud compute instances delete "$VM_NAME" "$GCP_OPTS" -q +} + +function run_on_vm() { + echo "*** Remote run: \"$1\"" 1>&2 + Execute gcloud compute ssh "$VM_NAME" "$GCP_OPTS" --command "$1" +} + +function setup_vm() { + Execute gcloud compute instances add-tags "$VM_NAME" "$GCP_OPTS" --tags https-server + # shellcheck disable=SC2016 + run_on_vm '(sudo add-apt-repository ppa:gophers/archive > /dev/null && sudo apt-get update > /dev/null && sudo apt-get upgrade --no-install-recommends -y && sudo apt-get install --no-install-recommends -y golang-1.10-go make && mv .bashrc .bashrc.orig && (echo "export PATH=/usr/lib/go-1.10/bin:\$PATH:~/go/bin"; cat .bashrc.orig) > ~/.bashrc ) < /dev/null' +} + +function setup_vm_firewall() { + Execute gcloud compute --project="$PROJECT" firewall-rules create default-allow-https --network=default --action=ALLOW --rules=tcp:443 --source-ranges=0.0.0.0/0 --target-tags=https-server || true +} + +function delete_vm_firewall() { + Execute gcloud compute --project="$PROJECT" firewall-rules delete default-allow-https -q +} + +function update_fortio_on_vm() { + # shellcheck disable=SC2016 + run_on_vm 'go get fortio.org/fortio && cd go/src/fortio.org/fortio && git fetch --tags && git checkout latest_release && make submodule-sync && make official-build-version OFFICIAL_BIN=~/go/bin/fortio && sudo setcap 'cap_net_bind_service=+ep' `which fortio` && fortio version' +} + +function run_fortio_on_vm() { + run_on_vm 'pkill fortio; nohup fortio server -http-port 443 > ~/fortio.log 2>&1 &' +} + +function get_vm_ip() { + VM_IP=$(gcloud compute instances describe "$VM_NAME" "$GCP_OPTS" |grep natIP|awk -F": " '{print $2}') + VM_URL="http://$VM_IP:443/fortio/" + echo "+++ VM Ip is $VM_IP - visit (http on port 443 is not a typo:) $VM_URL" +} + +# assumes run from istio/ (or release) directory +function install_istio() { + # You need these permissions to create the necessary RBAC rules for Istio + # shellcheck disable=SC2016 + Execute sh -c 'kubectl create clusterrolebinding cluster-admin-binding --clusterrole=cluster-admin --user="$(gcloud config get-value core/account)"' + # Use the non debug ingress and remove the -v "2" + Execute sh -c 'sed -e "s/_debug//g" install/kubernetes/istio-auth.yaml | egrep -v -e "- (-v|\"2\")" | kubectl apply -f -' +} + +# assumes run from istio/ (or release) directory +function delete_istio() { + # Use the non debug ingress and remove the -v "2" + Execute sh -c 'kubectl delete -f install/kubernetes/istio-auth.yaml' +} + +function kubectl_setup() { + Execute gcloud container clusters get-credentials "$CLUSTER_NAME" "$GCP_OPTS" +} + +function install_non_istio_svc() { + Execute kubectl create namespace "$FORTIO_NAMESPACE" + Execute kubectl -n "$FORTIO_NAMESPACE" run fortio1 --image=fortio/fortio:latest_release --port=8080 + Execute kubectl -n "$FORTIO_NAMESPACE" expose deployment fortio1 --target-port=8080 --type=LoadBalancer + Execute kubectl -n "$FORTIO_NAMESPACE" run fortio2 --image=fortio/fortio:latest_release --port=8080 + Execute kubectl -n "$FORTIO_NAMESPACE" expose deployment fortio2 --target-port=8080 +} + +function install_istio_svc() { + Execute kubectl create namespace "$ISTIO_NAMESPACE" || echo "Error assumed to be ns $ISTIO_NAMESPACE already created" + FNAME=$TOOLS_DIR/perf_k8svcs + Execute sh -c "$ISTIOCTL kube-inject -n $ISTIO_NAMESPACE -f $FNAME.yaml > ${FNAME}_istio.yaml" + Execute kubectl apply -n "$ISTIO_NAMESPACE" -f "${FNAME}_istio.yaml" +} + +function install_istio_ingress_rules() { + # perf istio rules installs rules for both fortio and grafana + FNAME=$TOOLS_DIR/perf_istio_rules.yaml + Execute kubectl create -n "$ISTIO_NAMESPACE" -f "$FNAME" +} + +function install_istio_cache_busting_rule() { + FNAME=$TOOLS_DIR/cache_buster.yaml + Execute kubectl create -n "$ISTIO_NAMESPACE" -f "$FNAME" +} + +function get_fortio_k8s_ip() { + FORTIO_K8S_IP=$(kubectl -n "$FORTIO_NAMESPACE" get svc -o jsonpath='{.items[0].status.loadBalancer.ingress[0].ip}') + while [[ -z "${FORTIO_K8S_IP}" ]] + do + echo sleeping to get FORTIO_K8S_IP "$FORTIO_K8S_IP" + sleep 5 + FORTIO_K8S_IP=$(kubectl -n "$FORTIO_NAMESPACE" get svc -o jsonpath='{.items[0].status.loadBalancer.ingress[0].ip}') + done + echo "+++ In k8s fortio external ip: http://$FORTIO_K8S_IP:8080/fortio/" +} + +# Doesn't work somehow... +function setup_non_istio_ingress2() { + cat <<_EOF_ | kubectl apply -n fortio -f - +apiVersion: extensions/v1beta1 +kind: Ingress +metadata: + name: fortio-ingress2 +spec: + rules: + - http: + paths: + - path: /fortio1 + backend: + serviceName: fortio1 + servicePort: 8080 + - path: /fortio2 + backend: + serviceName: fortio2 + servicePort: 8080 +_EOF_ +} + +function setup_non_istio_ingress() { + cat <<_EOF_ | kubectl apply -n fortio -f - +apiVersion: extensions/v1beta1 +kind: Ingress +metadata: + name: fortio-ingress +spec: + backend: + serviceName: fortio1 + servicePort: 8080 +_EOF_ +} + + +function get_non_istio_ingress_ip() { + K8S_INGRESS_IP=$(kubectl -n "$FORTIO_NAMESPACE" get ingress -o jsonpath='{.items[0].status.loadBalancer.ingress[0].ip}') + while [[ -z "${K8S_INGRESS_IP}" ]] + do + echo sleeping to get K8S_INGRESS_IP "${K8S_INGRESS_IP}" + sleep 5 + K8S_INGRESS_IP=$(kubectl -n "$FORTIO_NAMESPACE" get ingress -o jsonpath='{.items[0].status.loadBalancer.ingress[0].ip}') + done + +# echo "+++ In k8s non istio ingress: http://$K8S_INGRESS_IP/fortio1/fortio/ and fortio2" + echo "+++ In k8s non istio ingress: http://$K8S_INGRESS_IP/fortio/" +} + +function get_istio_ingressgateway_ip() { + ISTIO_INGRESSGATEWAY_IP=$(kubectl -n istio-system get service istio-ingressgateway -o jsonpath='{.status.loadBalancer.ingress[0].ip}') + ISTIO_INGRESSGATEWAY_PORT=$(kubectl -n istio-system get service istio-ingressgateway -o jsonpath='{.spec.ports[?(@.name=="http")].port}') + while [[ -z "${ISTIO_INGRESSGATEWAY_IP}" ]] + do + echo sleeping to get ISTIO_INGRESSGATEWAY_IP "${ISTIO_INGRESSGATEWAY_IP}" + sleep 5 + ISTIO_INGRESSGATEWAY_IP=$(kubectl -n istio-system get service istio-ingressgateway -o jsonpath='{.status.loadBalancer.ingress[0].ip}') + done + + echo "+++ In k8s istio ingress: http://$ISTIO_INGRESSGATEWAY_IP:$ISTIO_INGRESSGATEWAY_PORT/fortio1/fortio/ and fortio2" + echo "+++ In k8s grafana: http://$ISTIO_INGRESSGATEWAY_IP:$ISTIO_INGRESSGATEWAY_PORT/d/1/" +} + +# Set default QPS to max qps +if [ -z "${QPS+x}" ] || [ "$QPS" == "" ]; then + echo "Setting default qps" + QPS=-1 +fi + +# Set default run duration to 30s +if [ -z "${DUR+x}" ] || [ "$DUR" == "" ]; then + DUR="30s" +fi + +function get_istio_version() { + kubectl describe pods -n istio|grep /proxyv2:|head -1 | awk -F: '{print $3}' +} + +function get_json_file_name() { + BASE="${1}" + if [[ $TS == "" ]]; then + TS=$(date +'%Y-%m-%d-%H-%M') + fi + if [[ $VERSION == "" ]]; then + VERSION=$(get_istio_version) + fi + QPSSTR="qps_${QPS}" + if [[ $QPSSTR == "qps_-1" ]]; then + QPSSTR="qps_max" + fi + LABELS="$BASE $QPSSTR $VERSION" + FNAME=$QPSSTR-$BASE-$VERSION-$TS + file_escape + label_escape + echo "$FNAME" +} + +function file_escape() { + FNAME=${FNAME// /_} +} + +function label_escape() { + LABELS=${LABELS// /+} +} + +function run_fortio_test1() { + echo "Using default loadbalancer, no istio:" + Execute curl "$VM_URL?json=on&save=on&qps=$QPS&t=$DUR&c=48&load=Start&url=http://$FORTIO_K8S_IP:8080/echo" +} +function run_fortio_test2() { + echo "Using default ingress, no istio:" + Execute curl "$VM_URL?json=on&save=on&qps=$QPS&t=$DUR&c=48&load=Start&url=http://$K8S_INGRESS_IP/echo" +} + +function run_fortio_test_istio_ingress1() { + get_json_file_name "ingress to s1" + echo "Using istio ingress to fortio1, saving to $FNAME" + ExecuteEval curl -s "$VM_URL?labels=$LABELS\\&json=on\\&save=on\\&qps=$QPS\\&t=$DUR\\&c=48\\&load=Start\\&url=http://$ISTIO_INGRESSGATEWAY_IP:$ISTIO_INGRESSGATEWAY_PORT/fortio1/echo" \| tee "$FNAME.json" \| grep ActualQPS +} +function run_fortio_test_istio_ingress2() { + get_json_file_name "ingress to s2" + echo "Using istio ingress to fortio2, saving to $FNAME" + ExecuteEval curl -s "$VM_URL?labels=$LABELS\\&json=on\\&save=on\\&qps=$QPS\\&t=$DUR\\&c=48\\&load=Start\\&url=http://$ISTIO_INGRESSGATEWAY_IP:$ISTIO_INGRESSGATEWAY_PORT/fortio2/echo" \| tee "$FNAME.json" \| grep ActualQPS +} +function run_fortio_test_istio_1_2() { + get_json_file_name "s1 to s2" + echo "Using istio f1 to f2, saving to $FNAME" + ExecuteEval curl -s "http://$ISTIO_INGRESSGATEWAY_IP:$ISTIO_INGRESSGATEWAY_PORT/fortio1/fortio/?labels=$LABELS\\&json=on\\&save=on\\&qps=$QPS\\&t=$DUR\\&c=48\\&load=Start\\&url=http://echosrv2:8080/echo" \| tee "$FNAME.json" \| grep ActualQPS +} +function run_fortio_test_istio_2_1() { + get_json_file_name "s2 to s1" + echo "Using istio f2 to f1, saving to $FNAME" + ExecuteEval curl -s "http://$ISTIO_INGRESSGATEWAY_IP:$ISTIO_INGRESSGATEWAY_PORT/fortio2/fortio/?labels=$LABELS\\&json=on\\&save=on\\&qps=$QPS\\&t=$DUR\\&c=48\\&load=Start\\&url=http://echosrv1:8080/echo" \| tee "$FNAME.json" \| grep ActualQPS +} + +# Run canonical perf tests. +# The following parameters can be supplied: +# 1) Label: +# A custom label to use. This is useful when running the same suite against two target binaries/configs. +# Defaults to "canonical" +# 2) Driver: +# The load driver to use. Currently "fortio1" and "fortio2" are supported. Defaults to "fortio1". +# 3) Target: +# The target service for the load. Currently "echo1" and "echo2" are supported. +# Defaults to "echo2" +# 4) QPS: +# The QPS to apply. Defaults to 400. +# 5) Duration: +# The duration of the test. Default is 5 minutes. +# 6) Clients: +# The number of clients to use. Defaults is 16. +# 7) Outdir: +# The output dir for collecting the Json results. If not specified, a temporary dir will be created. +function run_canonical_perf_test() { + LABEL="${1}" + DRIVER="${2}" + TARGET="${3}" + QPS="${4}" + DURATION="${5}" + CLIENTS="${6}" + OUT_DIR="${7}" + + # Set defaults + LABEL="${LABEL:-canonical}" + DRIVER="${DRIVER:-fortio1}" + TARGET="${TARGET:-echo2}" + QPS="${QPS:-400}" + DURATION="${DURATION:-5m}" + CLIENTS="${CLIENTS:-16}" + + get_istio_ingressgateway_ip + + FORTIO1_URL="http://${ISTIO_INGRESSGATEWAY_IP}:${ISTIO_INGRESSGATEWAY_PORT}/fortio1/fortio/" + FORTIO2_URL="http://${ISTIO_INGRESSGATEWAY_IP}:${ISTIO_INGRESSGATEWAY_PORT}/fortio2/fortio/" + case "${DRIVER}" in + "fortio1") + DRIVER_URL="${FORTIO1_URL}" + ;; + "fortio2") + DRIVER_URL="${FORTIO2_URL}" + ;; + *) + echo "unknown driver: ${DRIVER}" >&2 + exit 1 + ;; + esac + + # URL encoded URLs for echo1 and echo2. These get directly embedded as parameters into the main URL to invoke + # the test. + ECHO1_URL="echosrv1:8080/echo" + ECHO2_URL="echosrv2:8080/echo" + case "${TARGET}" in + "echo1") + TARGET_URL="${ECHO1_URL}" + ;; + "echo2") + TARGET_URL="${ECHO2_URL}" + ;; + *) + echo "unknown target: ${TARGET}" >&2 + exit 1 + ;; + esac + + GRANULARITY="0.001" + + LABELS="${LABEL}+${DRIVER}+${TARGET}+Q${QPS}+T${DURATION}+C${CLIENTS}" + + if [[ -z "${OUT_DIR// }" ]]; then + OUT_DIR=$(mktemp -d -t "istio_perf.XXXXXX") + fi + + FILE_NAME="${LABELS//\+/_}" + OUT_FILE="${OUT_DIR}/${FILE_NAME}.json" + + echo "Running '${LABELS}' and storing results in ${OUT_FILE}" + + URL="${DRIVER_URL}/?labels=${LABELS}&url=${TARGET_URL}&qps=${QPS}&t=${DURATION}&c=${CLIENTS}&r=${GRANULARITY}&json=on&save=on&load=Start" + #echo "URL: ${URL}" + + curl -s "${URL}" -o "${OUT_FILE}" +} + +function wait_istio_up() { + for namespace in $(kubectl get namespaces --no-headers -o name); do + for name in $(kubectl get deployment -o name -n "${namespace}"); do + kubectl -n "${namespace}" rollout status "${name}" -w; + done + done +} + +function setup_vm_all() { + update_gcp_opts + create_vm + setup_vm + setup_vm_firewall + update_fortio_on_vm + run_fortio_on_vm +} + +function setup_istio_all() { + update_gcp_opts + install_istio + install_istio_svc + wait_istio_up #wait + install_istio_ingress_rules + install_istio_cache_busting_rule + wait_istio_up #wait +} + +function setup_cluster_all() { + echo "Setting up CLUSTER_NAME=$CLUSTER_NAME for PROJECT=$PROJECT in ZONE=$ZONE, NUM_NODES=$NUM_NODES * MACHINE_TYPE=$MACHINE_TYPE" + create_cluster + kubectl_setup + install_non_istio_svc + setup_non_istio_ingress + setup_istio_all +} + +function setup_all() { + setup_vm_all + setup_cluster_all +} + +function delete_all() { + echo "Deleting Istio mesh, cluster $CLUSTER_NAME, Instance $VM_NAME and firewall rules for project $PROJECT in zone $ZONE" + echo "Interrupt now if you don't want to delete..." + sleep 5 + delete_istio + delete_cluster + delete_vm + delete_vm_firewall +} + +function get_ips() { + #TODO: wait for ingresses/svcs to be ready + get_vm_ip + get_fortio_k8s_ip + get_non_istio_ingress_ip + get_istio_ingressgateway_ip +} + +function run_4_tests() { + run_fortio_test_istio_ingress1 + run_fortio_test_istio_ingress2 + run_fortio_test_istio_1_2 + run_fortio_test_istio_2_1 +} + +function run_tests() { + update_gcp_opts + get_ips + VERSION="" # reset in case it changed + TS="" # reset once per set + QPS=-1 + run_4_tests + QPS=400 + TS="" # reset once per set + run_4_tests + echo "Graph the results:" + fortio report & +} + + +function check_image_versions() { + kubectl get pods --all-namespaces -o jsonpath="{..image}" | tr -s '[:space:]' '\n' | sort | uniq -c | grep -v -e google.containers +} + +if [[ $SOURCED == 0 ]]; then + # Normal mode: all at once: + update_gcp_opts + setup_all + +#update_fortio_on_vm +#run_fortio_on_vm +#setup_vm_all + +# test/retry one step at a time, eg. +#install_non_istio_svc +#setup_non_istio_ingress +#get_non_istio_ingress_ip +#setup_istio_all +#install_istio_svc +#install_istio_ingress_rules +#setup_non_istio_ingress +#install_istio +#setup_vm_firewall +#get_ips + run_tests +#setup_vm_firewall +#get_ips +#install_istio_svc +#delete_all +fi diff --git a/istio-1.3.5/tools/setup_run b/istio-1.3.5/tools/setup_run new file mode 100644 index 0000000..4b033a6 --- /dev/null +++ b/istio-1.3.5/tools/setup_run @@ -0,0 +1,19 @@ +# very basic local run, this is meant to be source'ed +set -x +ulimit -n 16384 +mkdir -p emptydir +mkdir -p mixerconfig +cp istio/mixer/testdata/config/* mixerconfig/ +rm mixerconfig/stackdriver.yaml +cd istio; set +x; source bin/use_bazel_go.sh ; set -x; cd .. +# Need to have go installed and GOPATH/bin in the path +fortio server & +( cd proxy/src/envoy/http/mixer; ./start_envoy > /tmp/envoy.log ) & +./istio/bazel-bin/mixer/cmd/mixs/mixs server --configStoreURL=fs://$(pwd)/mixerconfig --configStoreURL=fs://$(pwd)/emptydir 2> /tmp/mixs.2.log > /tmp/mixs.1.log & +echo "starting everything..." +sleep 3 +curl -v http://localhost:9090/debug +sleep 1 +curl -v http://localhost:42422/metrics +set +x +echo "you can now run: fortio load -qps 0 -c 16 http://localhost:9090/echo" diff --git a/istio-1.3.5/tools/update_all b/istio-1.3.5/tools/update_all new file mode 100755 index 0000000..f95ef4e --- /dev/null +++ b/istio-1.3.5/tools/update_all @@ -0,0 +1,13 @@ +#!/bin/bash +# update and rebuild from source +set -e +set -x +cd istio +git pull +bazel build -c opt mixer/cmd/mixs:mixs +cd ../proxy +git pull +bazel build -c opt src/envoy/mixer:envoy +go get -u fortio.org/fortio +set +x +echo "### All done... source istio/tools/setup_run now" diff --git a/istio-1.3.5/tools/vagrant/Vagrantfile b/istio-1.3.5/tools/vagrant/Vagrantfile new file mode 100644 index 0000000..d5a92b6 --- /dev/null +++ b/istio-1.3.5/tools/vagrant/Vagrantfile @@ -0,0 +1,23 @@ +# -*- mode: ruby -*- +# vi: set ft=ruby : + +# Vagrantfile API/syntax version. Don't touch unless you know what you're doing! +VAGRANTFILE_API_VERSION = "2" + +Vagrant.configure(VAGRANTFILE_API_VERSION) do |config| + # Every Vagrant virtual environment requires a box to build off of. + config.vm.box = "ubuntu/trusty64" + config.vm.network "forwarded_port", guest: 5000, host: 5000 + config.vm.network "private_network", ip: "192.168.33.100" + config.vm.provider "virtualbox" do |v| + v.memory = 2048 + v.cpus = 2 + end + # Share the home directory for access to host source code + config.vm.synced_folder "../../", "/home/vagrant/golang/src/istio.io/istio", owner: "vagrant", group: "vagrant" + + # Now run manual shell script for additional provisioning: + config.vm.provision "shell", path: "./provision-vagrant.sh" + +end + diff --git a/istio-1.3.5/tools/vagrant/provision-vagrant.sh b/istio-1.3.5/tools/vagrant/provision-vagrant.sh new file mode 100644 index 0000000..32c7ef0 --- /dev/null +++ b/istio-1.3.5/tools/vagrant/provision-vagrant.sh @@ -0,0 +1,79 @@ +#!/bin/bash +set -e +VERSION="1.12.5" + +# Update, get python-software-properties in order to get add-apt-repository, +# then update (for latest git version): +apt-get update +apt-get install -y python-software-properties +add-apt-repository -y ppa:git-core/ppa +apt-get update +apt-get install -y git +apt-get install -y make +apt-get install -y docker +# Vim & Curl: +apt-get install -y vim curl + +# Install golang +shell_profile="bashrc" +DFILE="go$VERSION.linux-amd64.tar.gz" +HOME="/home/vagrant" +echo "Downloading $DFILE ..." +if ! wget https://dl.google.com/go/$DFILE -O /tmp/go.tar.gz; then + echo "Download failed! Exiting." + exit 1 +fi + +echo "Extracting File..." +tar -C "$HOME" -xzf /tmp/go.tar.gz +mv "$HOME/go" "$HOME/.go" + +touch "$HOME/.${shell_profile}" +{ + echo '# GoLang' + # shellcheck disable=SC2016 + echo 'export GOROOT=$HOME/.go' + # shellcheck disable=SC2016 + echo 'export PATH=$PATH:$GOROOT/bin' + # shellcheck disable=SC2016 + echo 'export GOPATH=$HOME/golang' + # shellcheck disable=SC2016 + echo 'export PATH=$PATH:$GOPATH/bin' +} >> "$HOME/.${shell_profile}" + +mkdir -p $HOME/golang/{src,pkg,bin} +mkdir -p $HOME/golang/src/istio.io + +chown -R vagrant:vagrant /home/vagrant/golang +echo -e "\\nGo $VERSION was installed.\\nMake sure to relogin into your shell or run:" +echo -e "\\n\\tsource $HOME/.${shell_profile}\\n\\nto update your environment variables." +rm -f /tmp/go.tar.gz + +# install minikube +export K8S_VER=v1.7.4 +export MASTER_IP=127.0.0.1 +export MASTER_CLUSTER_IP=10.99.0.1 +mkdir -p /tmp/apiserver && \ +cd /tmp/apiserver && \ +wget https://storage.googleapis.com/kubernetes-release/release/v1.7.4/bin/linux/amd64/kube-apiserver && \ +chmod +x /tmp/apiserver/kube-apiserver + +cd /tmp && \ +curl -L -O https://storage.googleapis.com/kubernetes-release/easy-rsa/easy-rsa.tar.gz && \ +tar xzf easy-rsa.tar.gz && \ +cd easy-rsa-master/easyrsa3 && \ +./easyrsa init-pki && \ +./easyrsa --batch "--req-cn=${MASTER_IP}@$(date +%s)" build-ca nopass && \ +./easyrsa --subject-alt-name="IP:${MASTER_IP},""IP:${MASTER_CLUSTER_IP},""DNS:kubernetes,""DNS:kubernetes.default,""DNS:kubernetes.default.svc,""DNS:kubernetes.default.svc.cluster,""DNS:kubernetes.default.svc.cluster.local" --days=10000 build-server-full server nopass && \ +cp /tmp/easy-rsa-master/easyrsa3/pki/ca.crt /tmp/apiserver/ca.crt && \ +cp /tmp/easy-rsa-master/easyrsa3/pki/issued/server.crt /tmp/apiserver/server.crt && \ +cp /tmp/easy-rsa-master/easyrsa3/pki/private/server.key /tmp/apiserver/server.key && \ +cd /tmp && \ +rm -rf /tmp/easy-rsa-master/ + +# Include minikube and kubectl in the image +curl -Lo /tmp/kubectl https://storage.googleapis.com/kubernetes-release/release/v1.7.4/bin/linux/amd64/kubectl && \ +chmod +x /tmp/kubectl && sudo mv /tmp/kubectl /usr/local/bin/ + +curl -Lo /tmp/minikube https://storage.googleapis.com/minikube/releases/v0.22.3/minikube-linux-amd64 &&\ +chmod +x /tmp/minikube && sudo mv /tmp/minikube /usr/local/bin/ diff --git a/istio-1.5.0/LICENSE b/istio-1.5.0/LICENSE new file mode 100644 index 0000000..56e48aa --- /dev/null +++ b/istio-1.5.0/LICENSE @@ -0,0 +1,202 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "{}" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright 2016-2020 Istio Authors + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/istio-1.5.0/README.md b/istio-1.5.0/README.md new file mode 100644 index 0000000..eb74c07 --- /dev/null +++ b/istio-1.5.0/README.md @@ -0,0 +1,112 @@ +[![Go Report Card](https://goreportcard.com/badge/github.com/istio/istio)](https://goreportcard.com/report/github.com/istio/istio) +[![GoDoc](https://godoc.org/istio.io/istio?status.svg)](https://godoc.org/istio.io/istio) + +# Istio + +An open platform to connect, manage, and secure microservices. + +- For in-depth information about how to use Istio, visit [istio.io](https://istio.io) +- To ask questions and get assistance from our community, visit [discuss.istio.io](https://discuss.istio.io) +- To learn how to participate in our overall community, visit [our community page](https://istio.io/about/community) + +In this README: + +- [Introduction](#introduction) +- [Repositories](#repositories) +- [Issue management](#issue-management) + +In addition, here are some other documents you may wish to read: + +- [Istio Community](https://github.com/istio/community) - describes how to get involved and contribute to the Istio project +- [Istio Developer's Guide](https://github.com/istio/istio/wiki/Preparing-for-Development) - explains how to set up and use an Istio development environment +- [Project Conventions](https://github.com/istio/istio/wiki/Development-Conventions) - describes the conventions we use within the code base +- [Creating Fast and Lean Code](https://github.com/istio/istio/wiki/Writing-Fast-and-Lean-Code) - performance-oriented advice and guidelines for the code base + +You'll find many other useful documents on our [Wiki](https://github.com/istio/istio/wiki). + +## Introduction + +Istio is an open platform for providing a uniform way to integrate +microservices, manage traffic flow across microservices, enforce policies +and aggregate telemetry data. Istio's control plane provides an abstraction +layer over the underlying cluster management platform, such as Kubernetes. + +Istio is composed of these components: + +- **Envoy** - Sidecar proxies per microservice to handle ingress/egress traffic + between services in the cluster and from a service to external + services. The proxies form a _secure microservice mesh_ providing a rich + set of functions like discovery, rich layer-7 routing, circuit breakers, + policy enforcement and telemetry recording/reporting + functions. + + > Note: The service mesh is not an overlay network. It + > simplifies and enhances how microservices in an application talk to each + > other over the network provided by the underlying platform. + +- **Mixer** - Central component that is leveraged by the proxies and microservices + to enforce policies such as authorization, rate limits, quotas, authentication, request + tracing and telemetry collection. + +- **Pilot** - A component responsible for configuring the proxies at runtime. + +- **Citadel** - A centralized component responsible for certificate issuance and rotation. + +- **Citadel Agent** - A per-node component responsible for certificate issuance and rotation. + +- **Galley**- Central component for validating, ingesting, aggregating, transforming and distributing config within Istio. + +Istio currently supports Kubernetes and Consul-based environments. We plan support for additional platforms such as +Cloud Foundry, and Mesos in the near future. + +## Repositories + +The Istio project is divided across a few GitHub repositories. + +- [istio/istio](README.md). This is the main repository that you are +currently looking at. It hosts Istio's core components and also +the sample programs and the various documents that govern the Istio open source +project. It includes: + + - [security](security/). This directory contains security related code, +including Citadel (acting as Certificate Authority), citadel agent, etc. + + - [pilot](pilot/). This directory +contains platform-specific code to populate the +[abstract service model](https://istio.io/docs/concepts/traffic-management/#pilot), dynamically reconfigure the proxies +when the application topology changes, as well as translate +[routing rules](https://istio.io/docs/reference/config/networking/) into proxy specific configuration. + + - [istioctl](istioctl/). This directory contains code for the +[_istioctl_](https://istio.io/docs/reference/commands/istioctl.html) command line utility. + + - [mixer](mixer/). This directory +contains code to enforce various policies for traffic passing through the +proxies, and collect telemetry data from proxies and services. There +are plugins for interfacing with various cloud platforms, policy +management services, and monitoring services. + +- [istio/api](https://github.com/istio/api). This repository defines +component-level APIs and common configuration formats for the Istio platform. + +- [istio/proxy](https://github.com/istio/proxy). The Istio proxy contains +extensions to the [Envoy proxy](https://github.com/envoyproxy/envoy) (in the form of +Envoy filters), that allow the proxy to delegate policy enforcement +decisions to Mixer. + +## Issue management + +We use GitHub combined with ZenHub to track all of our bugs and feature requests. Each issue we track has a variety of metadata: + +- **Epic**. An epic represents a feature area for Istio as a whole. Epics are fairly broad in scope and are basically product-level things. +Each issue is ultimately part of an epic. + +- **Milestone**. Each issue is assigned a milestone. This is 0.1, 0.2, ..., or 'Nebulous Future'. The milestone indicates when we +think the issue should get addressed. + +- **Priority/Pipeline**. Each issue has a priority which is represented by the Pipeline field within GitHub. Priority can be one of +P0, P1, P2, or >P2. The priority indicates how important it is to address the issue within the milestone. P0 says that the +milestone cannot be considered achieved if the issue isn't resolved. + +We don't annotate issues with Releases; Milestones are used instead. We don't use GitHub projects at all, that +support is disabled for our organization. diff --git a/istio-1.5.0/install/README.md b/istio-1.5.0/install/README.md new file mode 100644 index 0000000..5a96245 --- /dev/null +++ b/istio-1.5.0/install/README.md @@ -0,0 +1,4 @@ +# Istio installation + +This directory contains the default Istio installation configuration in several +different flavors. Also contained is the script for updating it. diff --git a/istio-1.5.0/install/consul/README.md b/istio-1.5.0/install/consul/README.md new file mode 100644 index 0000000..50c74e0 --- /dev/null +++ b/istio-1.5.0/install/consul/README.md @@ -0,0 +1,4 @@ +# Install Istio with Consul in a simple Docker Compose setup + +The install file `istio.yaml` deploys Istio Pilot, Consul, Registrator, and +the Istio API server with etcd as Docker containers. diff --git a/istio-1.5.0/install/consul/consul_config/agent-loglevel.json b/istio-1.5.0/install/consul/consul_config/agent-loglevel.json new file mode 100644 index 0000000..c594477 --- /dev/null +++ b/istio-1.5.0/install/consul/consul_config/agent-loglevel.json @@ -0,0 +1,3 @@ +{ + "log_level": "INFO" +} \ No newline at end of file diff --git a/istio-1.5.0/install/consul/consul_config/agent.json b/istio-1.5.0/install/consul/consul_config/agent.json new file mode 100644 index 0000000..8048959 --- /dev/null +++ b/istio-1.5.0/install/consul/consul_config/agent.json @@ -0,0 +1,8 @@ +{ + "client_addr": "0.0.0.0", + "leave_on_terminate": true, + "dns_config": { + "allow_stale": true, + "max_stale": "1s" + } +} \ No newline at end of file diff --git a/istio-1.5.0/install/consul/consul_config/disable_update_check.json b/istio-1.5.0/install/consul/consul_config/disable_update_check.json new file mode 100644 index 0000000..f375d7a --- /dev/null +++ b/istio-1.5.0/install/consul/consul_config/disable_update_check.json @@ -0,0 +1,3 @@ +{ + "disable_update_check": true +} \ No newline at end of file diff --git a/istio-1.5.0/install/consul/consul_config/server.json b/istio-1.5.0/install/consul/consul_config/server.json new file mode 100644 index 0000000..3db174e --- /dev/null +++ b/istio-1.5.0/install/consul/consul_config/server.json @@ -0,0 +1,6 @@ +{ + "ui": true, + "dns_config": { + "allow_stale": false + } +} \ No newline at end of file diff --git a/istio-1.5.0/install/gcp/README.md b/istio-1.5.0/install/gcp/README.md new file mode 100644 index 0000000..ee4fb3d --- /dev/null +++ b/istio-1.5.0/install/gcp/README.md @@ -0,0 +1,4 @@ +# Google Cloud Platform Installation + +This directory contains contributed solutions for installing Istio that are +specific to Google Cloud Platform. diff --git a/istio-1.5.0/install/gcp/bootstrap/gcp_envoy_bootstrap.json b/istio-1.5.0/install/gcp/bootstrap/gcp_envoy_bootstrap.json new file mode 100644 index 0000000..4168d38 --- /dev/null +++ b/istio-1.5.0/install/gcp/bootstrap/gcp_envoy_bootstrap.json @@ -0,0 +1,125 @@ +{ + "node": { + "id": "{{ .nodeID }}", + "cluster": "{{ .cluster }}", + "locality": { + {{ if .region }} + "region": "{{ .region }}", + {{ end }} + {{ if .zone }} + "zone": "{{ .zone }}", + {{ end }} + {{ if .sub_zone }} + "sub_zone": "{{ .sub_zone }}", + {{ end }} + }, + "metadata": {{ .meta_json_str }} + }, + "dynamic_resources": { + "lds_config": { + "ads": {} + }, + "cds_config": { + "ads": {} + }, + "ads_config": { + "api_type": "GRPC", + "grpc_services": [ + { + "google_grpc": { + "target_uri": "{{ .discovery_address }}", + "stat_prefix": "googlegrpcxds", + "channel_credentials": { + "ssl_credentials": { + "root_certs": { + "filename": "/etc/ssl/certs/ca-certificates.crt" + } + } + }, + "call_credentials": { + "google_compute_engine": {} + } + } + } + ] + } + }, + "cluster_manager": { + "load_stats_config": { + "api_type": "GRPC", + "grpc_services": [ + { + "google_grpc": { + "target_uri": "{{ .discovery_address }}", + "stat_prefix": "googlegrpcxds", + "channel_credentials": { + "ssl_credentials": { + "root_certs": { + "filename": "/etc/ssl/certs/ca-certificates.crt" + } + } + }, + "call_credentials": { + {{ if .sts }} + "sts_service": { + "token_exchange_service_uri": "http://localhost:{{ .sts_port }}/token", + "subject_token_path": "/var/run/secrets/tokens/istio-token", + "subject_token_type": "urn:ietf:params:oauth:token-type:jwt", + "scope": "https://www.googleapis.com/auth/cloud-platform", + } + {{ else }} + "google_compute_engine": {} + {{ end }} + } + } + } + ] + } + }, + "admin": { + "access_log_path": "/dev/null", + "address": { + "socket_address": { + "address": "127.0.0.1", + "port_value": {{ .config.ProxyAdminPort }} + } + } + } + {{ if .stackdriver }} + , + "tracing": { + "http": { + "name": "envoy.tracers.opencensus", + "config": { + "stackdriver_exporter_enabled": true, + "stackdriver_project_id": "{{ .stackdriverProjectID }}", + "stdout_exporter_enabled": {{ .stackdriverDebug }}, + "incoming_trace_context": ["CLOUD_TRACE_CONTEXT", "TRACE_CONTEXT", "GRPC_TRACE_BIN", "B3"], + "outgoing_trace_context": ["CLOUD_TRACE_CONTEXT", "TRACE_CONTEXT", "GRPC_TRACE_BIN", "B3"], + "trace_config":{ + "constant_sampler":{ + "decision": "ALWAYS_PARENT" + }, + "max_number_of_annotations": {{ .stackdriverMaxAnnotations }}, + "max_number_of_attributes": {{ .stackdriverMaxAttributes }}, + "max_number_of_message_events": {{ .stackdriverMaxEvents }}, + "max_number_of_links": 200, + } + } + }} + {{ end }} + , + "layered_runtime": { + "layers": [ + { + "name": "rtds_layer", + "rtds_layer": { + "name": "traffic_director_runtime", + "rtds_config": { + "ads": {} + } + } + } + ] + } +} diff --git a/istio-1.5.0/install/kubernetes/README.md b/istio-1.5.0/install/kubernetes/README.md new file mode 100644 index 0000000..2a507a2 --- /dev/null +++ b/istio-1.5.0/install/kubernetes/README.md @@ -0,0 +1,6 @@ +# Install Istio on an existing Kubernetes cluster + +Please follow the installation instructions on [istio.io](https://istio.io/docs/setup/kubernetes/). + +If you want to install Istio using the istio/istio repository instead of downloading a release, +refer to the [developer wiki](https://github.com/istio/istio/wiki) for instructions. diff --git a/istio-1.5.0/install/kubernetes/global-default-sidecar-scope.yaml b/istio-1.5.0/install/kubernetes/global-default-sidecar-scope.yaml new file mode 100644 index 0000000..346c682 --- /dev/null +++ b/istio-1.5.0/install/kubernetes/global-default-sidecar-scope.yaml @@ -0,0 +1,20 @@ +apiVersion: v1 +kind: Namespace +metadata: + name: istio-config +--- +apiVersion: networking.istio.io/v1alpha3 +kind: Sidecar +metadata: + name: default-sidecar-scope + namespace: istio-config +spec: + egress: + # If this config is applied, sidecars will only be able to talk to + # other services in the same namespace, in addition to istio-telemetry + # and istio-policy + - hosts: + - "./*" + - "istio-system/istio-telemetry.istio-system.svc.cluster.local" + - "istio-system/istio-policy.istio-system.svc.cluster.local" +--- diff --git a/istio-1.5.0/install/kubernetes/helm/README.md b/istio-1.5.0/install/kubernetes/helm/README.md new file mode 100644 index 0000000..df4c700 --- /dev/null +++ b/istio-1.5.0/install/kubernetes/helm/README.md @@ -0,0 +1,7 @@ +# Installation using Helm + +Please follow the installation instructions from [istio.io](https://istio.io/docs/setup/kubernetes/install/helm/). + +## Development + +Future development for the installer is taking place on [istio/installer](https://github.com/istio/installer). Please add new features to that repository, as only bug fixes will be allowed here. \ No newline at end of file diff --git a/istio-1.5.0/install/kubernetes/helm/helm-service-account.yaml b/istio-1.5.0/install/kubernetes/helm/helm-service-account.yaml new file mode 100644 index 0000000..0e1b083 --- /dev/null +++ b/istio-1.5.0/install/kubernetes/helm/helm-service-account.yaml @@ -0,0 +1,21 @@ +# Create a service account for Helm and grant the cluster admin role. +# It is assumed that helm should be installed with this service account +# (tiller). +apiVersion: v1 +kind: ServiceAccount +metadata: + name: tiller + namespace: kube-system +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: tiller +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: cluster-admin +subjects: +- kind: ServiceAccount + name: tiller + namespace: kube-system diff --git a/istio-1.5.0/install/kubernetes/helm/istio-cni/Chart.yaml b/istio-1.5.0/install/kubernetes/helm/istio-cni/Chart.yaml new file mode 100644 index 0000000..ed908f5 --- /dev/null +++ b/istio-1.5.0/install/kubernetes/helm/istio-cni/Chart.yaml @@ -0,0 +1,13 @@ +apiVersion: v1 +name: istio-cni +version: 1.5.0 +appVersion: 1.5.0 +tillerVersion: ">=2.7.2" +description: Helm chart for istio-cni components +keywords: + - istio-cni + - istio +sources: + - http://github.com/istio/cni +engine: gotpl +icon: https://istio.io/favicons/android-192x192.png diff --git a/istio-1.5.0/install/kubernetes/helm/istio-cni/templates/_labels.tpl b/istio-1.5.0/install/kubernetes/helm/istio-cni/templates/_labels.tpl new file mode 100644 index 0000000..bc4a09f --- /dev/null +++ b/istio-1.5.0/install/kubernetes/helm/istio-cni/templates/_labels.tpl @@ -0,0 +1,10 @@ +{{- define "common_labels" }} + chart: {{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }} + release: {{ .Release.Name }} + version: {{ .Chart.Version }} + heritage: {{ .Release.Service }} +{{- end }} + +{{- define "common_template_labels" }} + version: {{ .Chart.Version }} +{{- end }} diff --git a/istio-1.5.0/install/kubernetes/helm/istio-cni/templates/istio-cni.yaml b/istio-1.5.0/install/kubernetes/helm/istio-cni/templates/istio-cni.yaml new file mode 100644 index 0000000..78738a7 --- /dev/null +++ b/istio-1.5.0/install/kubernetes/helm/istio-cni/templates/istio-cni.yaml @@ -0,0 +1,230 @@ +# Istio-CNI Version v0.1-dev +# +# This manifest installs the following component versions: +# istio-cni:v0.1 + +kind: ClusterRole +apiVersion: rbac.authorization.k8s.io/v1 +metadata: + name: istio-cni +rules: + - apiGroups: [""] + resources: + - pods + - nodes + verbs: + - get + +--- + +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: istio-cni +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: istio-cni +subjects: +- kind: ServiceAccount + name: istio-cni + namespace: {{ .Release.Namespace }} + +--- +# This ConfigMap is used to configure a self-hosted Istio CNI installation. +kind: ConfigMap +apiVersion: v1 +metadata: + name: istio-cni-config + namespace: {{ .Release.Namespace }} + labels: + {{- template "common_labels" . }} +data: + # The CNI network configuration to add to the plugin chain on each node. The special + # values in this config will be automatically populated. + cni_network_config: |- + { + "type": "istio-cni", + "log_level": {{ quote .Values.logLevel }}, + "kubernetes": { + "kubeconfig": "__KUBECONFIG_FILEPATH__", + "cni_bin_dir": {{ quote .Values.cniBinDir }}, + "exclude_namespaces": [ {{ range $idx, $ns := .Values.excludeNamespaces }}{{ if $idx }}, {{ end }}{{ quote $ns }}{{ end }} ] + } + } + +--- + +# This manifest installs the Istio install-cni container, as well +# as the Istio CNI plugin and config on +# each master and worker node in a Kubernetes cluster. +kind: DaemonSet +apiVersion: apps/v1 +metadata: + name: istio-cni-node + namespace: {{ .Release.Namespace }} + labels: + k8s-app: istio-cni-node + {{- template "common_labels" . }} +spec: + selector: + matchLabels: + k8s-app: istio-cni-node + updateStrategy: + type: RollingUpdate + rollingUpdate: + maxUnavailable: 1 + template: + metadata: + labels: + k8s-app: istio-cni-node + annotations: + # This, along with the CriticalAddonsOnly toleration below, + # marks the pod as a critical add-on, ensuring it gets + # priority scheduling and that its resources are reserved + # if it ever gets evicted. + scheduler.alpha.kubernetes.io/critical-pod: '' + {{- if .Values.podAnnotations }} +{{ toYaml .Values.podAnnotations | indent 8 }} + {{- end }} + spec: + nodeSelector: + beta.kubernetes.io/os: linux + hostNetwork: true + tolerations: + # Make sure istio-cni-node gets scheduled on all nodes. + - effect: NoSchedule + operator: Exists + # Mark the pod as a critical add-on for rescheduling. + - key: CriticalAddonsOnly + operator: Exists + - effect: NoExecute + operator: Exists + priorityClassName: system-cluster-critical + serviceAccountName: istio-cni + # Minimize downtime during a rolling upgrade or deletion; tell Kubernetes to do a "force + # deletion": https://kubernetes.io/docs/concepts/workloads/pods/pod/#termination-of-pods. + terminationGracePeriodSeconds: 5 + containers: + # This container installs the Istio CNI binaries + # and CNI network config file on each node. + - name: install-cni + image: {{ .Values.hub }}/install-cni:{{ .Values.tag }} + imagePullPolicy: {{ .Values.pullPolicy }} + command: ["/install-cni.sh"] + env: +{{- if .Values.cniConfFileName }} + # Name of the CNI config file to create. + - name: CNI_CONF_NAME + value: "{{ .Values.cniConfFileName }}" +{{- end }} + # The CNI network config to install on each node. + - name: CNI_NETWORK_CONFIG + valueFrom: + configMapKeyRef: + name: istio-cni-config + key: cni_network_config + - name: CNI_NET_DIR + value: {{ default "/etc/cni/net.d" .Values.cniConfDir }} + # Deploy as a standalone CNI plugin or as chained? + - name: CHAINED_CNI_PLUGIN + value: "{{ .Values.chained }}" + volumeMounts: + - mountPath: /host/opt/cni/bin + name: cni-bin-dir + - mountPath: /host/etc/cni/net.d + name: cni-net-dir +{{- if .Values.repair.enabled }} + # This container repairs broken CNI pods + - name: repair-cni + image: {{ default .Values.hub .Values.repair.hub }}/install-cni:{{ default .Values.tag .Values.repair.tag }} + imagePullPolicy: {{ .Values.pullPolicy }} + command: + - /opt/cni/bin/istio-cni-repair + env: + - name: "REPAIR_NODE-NAME" + valueFrom: + fieldRef: + fieldPath: spec.nodeName + - name: "REPAIR_LABEL-PODS" + value: "{{.Values.repair.labelPods}}" + # Set to true to enable pod deletion + - name: "REPAIR_DELETE-PODS" + value: "{{.Values.repair.deletePods}}" + - name: "REPAIR_RUN-AS-DAEMON" + value: "true" + - name: "REPAIR_SIDECAR-ANNOTATION" + value: "sidecar.istio.io/status" + - name: "REPAIR_INIT-CONTAINER-NAME" + value: "{{.Values.repair.initContainerName}}" + - name: "REPAIR_BROKEN-POD-LABEL-KEY" + value: "{{.Values.repair.brokenPodLabelKey}}" + - name: "REPAIR_BROKEN-POD-LABEL-VALUE" + value: "{{.Values.repair.brokenPodLabelValue}}" +{{- end }} + volumes: + # Used to install CNI. + - name: cni-bin-dir + hostPath: + path: {{ default "/opt/cni/bin" .Values.cniBinDir }} + - name: cni-net-dir + hostPath: + path: {{ default "/etc/cni/net.d" .Values.cniConfDir }} +--- + +apiVersion: v1 +kind: ServiceAccount +metadata: + name: istio-cni + namespace: {{ .Release.Namespace }} + +--- +{{- if ne .Values.psp_cluster_role "" }} +apiVersion: rbac.authorization.k8s.io/v1 +kind: RoleBinding +metadata: + name: istio-cni-psp + namespace: {{ .Release.Namespace }} +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: {{ .Values.psp_cluster_role }} +subjects: +- kind: ServiceAccount + name: istio-cni + namespace: {{ .Release.Namespace }} +{{- end }} + +{{- if .Values.repair.enabled }} +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: istio-cni-repair-role + namespace: {{ .Release.Namespace}} + labels: + k8s-app: istio-cni-repair +rules: +- apiGroups: [""] + resources: ["pods"] + verbs: ["get", "list", "watch", "delete", "patch", "update" ] +- apiGroups: [""] + resources: ["events"] + verbs: ["get", "list", "watch", "delete", "patch", "update", "create" ] +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: istio-cni-repair-rolebinding + namespace: {{ .Release.Namespace}} + labels: + k8s-app: istio-cni-repair +subjects: +- kind: ServiceAccount + name: istio-cni + namespace: {{ .Release.Namespace}} +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: istio-cni-repair-role +{{- end }} diff --git a/istio-1.5.0/install/kubernetes/helm/istio-cni/values.yaml b/istio-1.5.0/install/kubernetes/helm/istio-cni/values.yaml new file mode 100644 index 0000000..a19025a --- /dev/null +++ b/istio-1.5.0/install/kubernetes/helm/istio-cni/values.yaml @@ -0,0 +1,45 @@ +hub: docker.io/istio +tag: 1.5.0 +pullPolicy: Always + +logLevel: info + +# Configuration file to insert istio-cni plugin configuration +# by default this will be the first file found in the cni-conf-dir +# Example +# cniConfFileName: 10-calico.conflist + +# CNI bin and conf dir override settings +# defaults: +cniBinDir: /opt/cni/bin +cniConfDir: /etc/cni/net.d +cniConfFileName: "" + +excludeNamespaces: + - istio-system + +# Custom annotations on pod level, if you need them +podAnnotations: {} + +# If this value is set a RoleBinding will be created +# in the same namespace as the istio-cni DaemonSet is created. +# This can be used to bind a preexisting ClusterRole to the istio/cni ServiceAccount +# e.g. if you use PodSecurityPolicies +psp_cluster_role: "" + +# Deploy the config files as plugin chain (value "true") or as standalone files in the conf dir (value "false")? +# Some k8s flavors (e.g. OpenShift) do not support the chain approach, set to false if this is the case +chained: "true" + +repair: + enabled: true + hub: "" + tag: "" + + initContainerName: "istio-validation" + + labelPods: "true" + deletePods: "true" + + brokenPodLabelKey: "cni.istio.io/uninitialized" + brokenPodLabelValue: "true" diff --git a/istio-1.5.0/install/kubernetes/helm/istio-cni/values_gke.yaml b/istio-1.5.0/install/kubernetes/helm/istio-cni/values_gke.yaml new file mode 100644 index 0000000..d91fd3d --- /dev/null +++ b/istio-1.5.0/install/kubernetes/helm/istio-cni/values_gke.yaml @@ -0,0 +1,22 @@ +hub: docker.io/istio +tag: 1.5.0 +pullPolicy: Always + +logLevel: info + +# Configuration file to insert istio-cni plugin configuration +# by default this will be the first file found in the cni-conf-dir +# Example +# cniConfFileName: 10-calico.conflist + +# CNI bin and conf dir override settings +# defaults: +cniBinDir: /home/kubernetes/bin +cniConfDir: /etc/cni/net.d + +excludeNamespaces: + - istio-system + +# Custom annotations on pod level, if you need them +podAnnotations: {} + diff --git a/istio-1.5.0/install/kubernetes/helm/istio-init/Chart.yaml b/istio-1.5.0/install/kubernetes/helm/istio-init/Chart.yaml new file mode 100644 index 0000000..fddf710 --- /dev/null +++ b/istio-1.5.0/install/kubernetes/helm/istio-init/Chart.yaml @@ -0,0 +1,13 @@ +apiVersion: v1 +name: istio-init +version: 1.5.0 +appVersion: 1.5.0 +tillerVersion: ">=2.7.2-0" +description: Helm chart to initialize Istio CRDs +keywords: + - istio + - crd +sources: + - http://github.com/istio/istio +engine: gotpl +icon: https://istio.io/favicons/android-192x192.png diff --git a/istio-1.5.0/install/kubernetes/helm/istio-init/README.md b/istio-1.5.0/install/kubernetes/helm/istio-init/README.md new file mode 100644 index 0000000..f4da03d --- /dev/null +++ b/istio-1.5.0/install/kubernetes/helm/istio-init/README.md @@ -0,0 +1,82 @@ +# Istio + +[Istio](https://istio.io/) is an open platform for providing a uniform way to integrate microservices, manage traffic flow across microservices, enforce policies and aggregate telemetry data. + +## Introduction + +This chart bootstraps Istio's [CRDs](https://kubernetes.io/docs/concepts/extend-kubernetes/api-extension/custom-resources/#customresourcedefinitions) +which are an internal implementation detail of Istio. CRDs define data structures for storing runtime configuration +specified by a human operator. + +This chart must be run to completion prior to running other Istio charts, or other Istio charts will fail to initialize. + +## Prerequisites + +- Kubernetes 1.9 or newer cluster with RBAC (Role-Based Access Control) enabled is required +- Helm 2.7.2 or newer or alternately the ability to modify RBAC rules is also required + +## Resources Required + +The chart deploys pods that consume minimal resources. + +## Installing the Chart + +1. If a service account has not already been installed for Tiller, install one: + + ```bash + $ kubectl apply -f install/kubernetes/helm/helm-service-account.yaml + ``` + +1. If Tiller has not already been installed in your cluster, Install Tiller on your cluster with the service account: + + ```bash + $ helm init --service-account tiller + ``` + +1. Install the Istio initializer chart: + + ```bash + $ helm install install/kubernetes/helm/istio-init --name istio-init --namespace istio-system + ``` + + > Although you can install the `istio-init` chart to any namespace, it is recommended to install `istio-init` in the same namespace(`istio-system`) as other Istio charts. + +## Configuration + +The Helm chart ships with reasonable defaults. There may be circumstances in which defaults require overrides. +To override Helm values, use `--set key=value` argument during the `helm install` command. Multiple `--set` operations may be used in the same Helm operation. + +Helm charts expose configuration options which are currently in alpha. The currently exposed options are explained in the following table: + +| Parameter | Description | Values | Default | +| --- | --- | --- | --- | +| `global.hub` | Specifies the HUB for most images used by Istio | registry/namespace | `docker.io/istio` | +| `global.tag` | Specifies the TAG for most images used by Istio | valid image tag | `0.8.latest` | +| `global.imagePullPolicy` | Specifies the image pull policy | valid image pull policy | `IfNotPresent` | + +## Uninstalling the Chart + +> Uninstalling this chart does not delete Istio's registered CRDs. Istio by design expects +> CRDs to leak into the Kubernetes environment. As CRDs contain all runtime configuration +> data in CustomResources the Istio designers feel it is better to explicitly delete this +> configuration rather than unexpectedly lose it. + +To uninstall/delete the `istio-init` release but continue to track the release: + + ```bash + $ helm delete istio-init + ``` + +To uninstall/delete the `istio-init` release completely and make its name free for later use: + + ```bash + $ helm delete --purge istio-init + ``` + +> Warning: Deleting CRDs will delete any configuration that you have made to Istio. + +To delete all CRDs, run the following command + + ```bash + $ for i in istio-init/files/*crd*yaml; do kubectl delete -f $i; done + ``` diff --git a/istio-1.5.0/install/kubernetes/helm/istio-init/files/crd-all.gen.yaml b/istio-1.5.0/install/kubernetes/helm/istio-init/files/crd-all.gen.yaml new file mode 100644 index 0000000..431c993 --- /dev/null +++ b/istio-1.5.0/install/kubernetes/helm/istio-init/files/crd-all.gen.yaml @@ -0,0 +1,5603 @@ +# DO NOT EDIT - Generated by Cue OpenAPI generator based on Istio APIs. +apiVersion: apiextensions.k8s.io/v1beta1 +kind: CustomResourceDefinition +metadata: + annotations: + "helm.sh/resource-policy": keep + labels: + app: istio-citadel + chart: istio + heritage: Tiller + release: istio + name: meshpolicies.authentication.istio.io +spec: + group: authentication.istio.io + names: + categories: + - istio-io + - authentication-istio-io + kind: MeshPolicy + listKind: MeshPolicyList + plural: meshpolicies + singular: meshpolicy + scope: Cluster + subresources: + status: {} + validation: + openAPIV3Schema: + properties: + spec: + description: 'Authentication policy for Istio services. See more details + at: https://istio.io/docs/reference/config/security/istio.authentication.v1alpha1.html' + properties: + originIsOptional: + description: Deprecated. + type: boolean + origins: + description: Deprecated. + items: + properties: + jwt: + description: Jwt params for the method. + properties: + audiences: + items: + format: string + type: string + type: array + issuer: + description: Identifies the issuer that issued the JWT. + format: string + type: string + jwks: + description: JSON Web Key Set of public keys to validate signature + of the JWT. + format: string + type: string + jwks_uri: + format: string + type: string + jwksUri: + format: string + type: string + jwt_headers: + description: JWT is sent in a request header. + items: + format: string + type: string + type: array + jwtHeaders: + description: JWT is sent in a request header. + items: + format: string + type: string + type: array + jwtParams: + description: JWT is sent in a query parameter. + items: + format: string + type: string + type: array + trigger_rules: + items: + properties: + excluded_paths: + description: List of paths to be excluded from the request. + items: + oneOf: + - required: + - exact + - required: + - prefix + - required: + - suffix + - required: + - regex + properties: + exact: + description: exact string match. + format: string + type: string + prefix: + description: prefix-based match. + format: string + type: string + regex: + description: ECMAscript style regex-based match + as defined by [EDCA-262](http://en.cppreference.com/w/cpp/regex/ecmascript). + format: string + type: string + suffix: + description: suffix-based match. + format: string + type: string + type: object + type: array + excludedPaths: + description: List of paths to be excluded from the request. + items: + oneOf: + - required: + - exact + - required: + - prefix + - required: + - suffix + - required: + - regex + properties: + exact: + description: exact string match. + format: string + type: string + prefix: + description: prefix-based match. + format: string + type: string + regex: + description: ECMAscript style regex-based match + as defined by [EDCA-262](http://en.cppreference.com/w/cpp/regex/ecmascript). + format: string + type: string + suffix: + description: suffix-based match. + format: string + type: string + type: object + type: array + included_paths: + description: List of paths that the request must include. + items: + oneOf: + - required: + - exact + - required: + - prefix + - required: + - suffix + - required: + - regex + properties: + exact: + description: exact string match. + format: string + type: string + prefix: + description: prefix-based match. + format: string + type: string + regex: + description: ECMAscript style regex-based match + as defined by [EDCA-262](http://en.cppreference.com/w/cpp/regex/ecmascript). + format: string + type: string + suffix: + description: suffix-based match. + format: string + type: string + type: object + type: array + includedPaths: + description: List of paths that the request must include. + items: + oneOf: + - required: + - exact + - required: + - prefix + - required: + - suffix + - required: + - regex + properties: + exact: + description: exact string match. + format: string + type: string + prefix: + description: prefix-based match. + format: string + type: string + regex: + description: ECMAscript style regex-based match + as defined by [EDCA-262](http://en.cppreference.com/w/cpp/regex/ecmascript). + format: string + type: string + suffix: + description: suffix-based match. + format: string + type: string + type: object + type: array + type: object + type: array + triggerRules: + items: + properties: + excluded_paths: + description: List of paths to be excluded from the request. + items: + oneOf: + - required: + - exact + - required: + - prefix + - required: + - suffix + - required: + - regex + properties: + exact: + description: exact string match. + format: string + type: string + prefix: + description: prefix-based match. + format: string + type: string + regex: + description: ECMAscript style regex-based match + as defined by [EDCA-262](http://en.cppreference.com/w/cpp/regex/ecmascript). + format: string + type: string + suffix: + description: suffix-based match. + format: string + type: string + type: object + type: array + excludedPaths: + description: List of paths to be excluded from the request. + items: + oneOf: + - required: + - exact + - required: + - prefix + - required: + - suffix + - required: + - regex + properties: + exact: + description: exact string match. + format: string + type: string + prefix: + description: prefix-based match. + format: string + type: string + regex: + description: ECMAscript style regex-based match + as defined by [EDCA-262](http://en.cppreference.com/w/cpp/regex/ecmascript). + format: string + type: string + suffix: + description: suffix-based match. + format: string + type: string + type: object + type: array + included_paths: + description: List of paths that the request must include. + items: + oneOf: + - required: + - exact + - required: + - prefix + - required: + - suffix + - required: + - regex + properties: + exact: + description: exact string match. + format: string + type: string + prefix: + description: prefix-based match. + format: string + type: string + regex: + description: ECMAscript style regex-based match + as defined by [EDCA-262](http://en.cppreference.com/w/cpp/regex/ecmascript). + format: string + type: string + suffix: + description: suffix-based match. + format: string + type: string + type: object + type: array + includedPaths: + description: List of paths that the request must include. + items: + oneOf: + - required: + - exact + - required: + - prefix + - required: + - suffix + - required: + - regex + properties: + exact: + description: exact string match. + format: string + type: string + prefix: + description: prefix-based match. + format: string + type: string + regex: + description: ECMAscript style regex-based match + as defined by [EDCA-262](http://en.cppreference.com/w/cpp/regex/ecmascript). + format: string + type: string + suffix: + description: suffix-based match. + format: string + type: string + type: object + type: array + type: object + type: array + type: object + type: object + type: array + peerIsOptional: + description: Deprecated. + type: boolean + peers: + description: List of authentication methods that can be used for peer + authentication. + items: + oneOf: + - required: + - mtls + - properties: + jwt: {} + required: + - jwt + properties: + jwt: + properties: + audiences: + items: + format: string + type: string + type: array + issuer: + description: Identifies the issuer that issued the JWT. + format: string + type: string + jwks: + description: JSON Web Key Set of public keys to validate signature + of the JWT. + format: string + type: string + jwks_uri: + format: string + type: string + jwksUri: + format: string + type: string + jwt_headers: + description: JWT is sent in a request header. + items: + format: string + type: string + type: array + jwtHeaders: + description: JWT is sent in a request header. + items: + format: string + type: string + type: array + jwtParams: + description: JWT is sent in a query parameter. + items: + format: string + type: string + type: array + trigger_rules: + items: + properties: + excluded_paths: + description: List of paths to be excluded from the request. + items: + oneOf: + - required: + - exact + - required: + - prefix + - required: + - suffix + - required: + - regex + properties: + exact: + description: exact string match. + format: string + type: string + prefix: + description: prefix-based match. + format: string + type: string + regex: + description: ECMAscript style regex-based match + as defined by [EDCA-262](http://en.cppreference.com/w/cpp/regex/ecmascript). + format: string + type: string + suffix: + description: suffix-based match. + format: string + type: string + type: object + type: array + excludedPaths: + description: List of paths to be excluded from the request. + items: + oneOf: + - required: + - exact + - required: + - prefix + - required: + - suffix + - required: + - regex + properties: + exact: + description: exact string match. + format: string + type: string + prefix: + description: prefix-based match. + format: string + type: string + regex: + description: ECMAscript style regex-based match + as defined by [EDCA-262](http://en.cppreference.com/w/cpp/regex/ecmascript). + format: string + type: string + suffix: + description: suffix-based match. + format: string + type: string + type: object + type: array + included_paths: + description: List of paths that the request must include. + items: + oneOf: + - required: + - exact + - required: + - prefix + - required: + - suffix + - required: + - regex + properties: + exact: + description: exact string match. + format: string + type: string + prefix: + description: prefix-based match. + format: string + type: string + regex: + description: ECMAscript style regex-based match + as defined by [EDCA-262](http://en.cppreference.com/w/cpp/regex/ecmascript). + format: string + type: string + suffix: + description: suffix-based match. + format: string + type: string + type: object + type: array + includedPaths: + description: List of paths that the request must include. + items: + oneOf: + - required: + - exact + - required: + - prefix + - required: + - suffix + - required: + - regex + properties: + exact: + description: exact string match. + format: string + type: string + prefix: + description: prefix-based match. + format: string + type: string + regex: + description: ECMAscript style regex-based match + as defined by [EDCA-262](http://en.cppreference.com/w/cpp/regex/ecmascript). + format: string + type: string + suffix: + description: suffix-based match. + format: string + type: string + type: object + type: array + type: object + type: array + triggerRules: + items: + properties: + excluded_paths: + description: List of paths to be excluded from the request. + items: + oneOf: + - required: + - exact + - required: + - prefix + - required: + - suffix + - required: + - regex + properties: + exact: + description: exact string match. + format: string + type: string + prefix: + description: prefix-based match. + format: string + type: string + regex: + description: ECMAscript style regex-based match + as defined by [EDCA-262](http://en.cppreference.com/w/cpp/regex/ecmascript). + format: string + type: string + suffix: + description: suffix-based match. + format: string + type: string + type: object + type: array + excludedPaths: + description: List of paths to be excluded from the request. + items: + oneOf: + - required: + - exact + - required: + - prefix + - required: + - suffix + - required: + - regex + properties: + exact: + description: exact string match. + format: string + type: string + prefix: + description: prefix-based match. + format: string + type: string + regex: + description: ECMAscript style regex-based match + as defined by [EDCA-262](http://en.cppreference.com/w/cpp/regex/ecmascript). + format: string + type: string + suffix: + description: suffix-based match. + format: string + type: string + type: object + type: array + included_paths: + description: List of paths that the request must include. + items: + oneOf: + - required: + - exact + - required: + - prefix + - required: + - suffix + - required: + - regex + properties: + exact: + description: exact string match. + format: string + type: string + prefix: + description: prefix-based match. + format: string + type: string + regex: + description: ECMAscript style regex-based match + as defined by [EDCA-262](http://en.cppreference.com/w/cpp/regex/ecmascript). + format: string + type: string + suffix: + description: suffix-based match. + format: string + type: string + type: object + type: array + includedPaths: + description: List of paths that the request must include. + items: + oneOf: + - required: + - exact + - required: + - prefix + - required: + - suffix + - required: + - regex + properties: + exact: + description: exact string match. + format: string + type: string + prefix: + description: prefix-based match. + format: string + type: string + regex: + description: ECMAscript style regex-based match + as defined by [EDCA-262](http://en.cppreference.com/w/cpp/regex/ecmascript). + format: string + type: string + suffix: + description: suffix-based match. + format: string + type: string + type: object + type: array + type: object + type: array + type: object + mtls: + description: Set if mTLS is used. + properties: + allowTls: + description: Deprecated. + type: boolean + mode: + description: Defines the mode of mTLS authentication. + enum: + - STRICT + - PERMISSIVE + type: string + type: object + type: object + type: array + principalBinding: + description: Deprecated. + enum: + - USE_PEER + - USE_ORIGIN + type: string + targets: + description: Deprecated. + items: + properties: + name: + description: The name must be a short name from the service registry. + format: string + type: string + ports: + description: Specifies the ports. + items: + oneOf: + - required: + - number + - required: + - name + properties: + name: + format: string + type: string + number: + type: integer + type: object + type: array + type: object + type: array + type: object + type: object + versions: + - name: v1alpha1 + served: true + storage: true + +--- +apiVersion: apiextensions.k8s.io/v1beta1 +kind: CustomResourceDefinition +metadata: + annotations: + "helm.sh/resource-policy": keep + labels: + app: istio-citadel + chart: istio + heritage: Tiller + release: istio + name: policies.authentication.istio.io +spec: + group: authentication.istio.io + names: + categories: + - istio-io + - authentication-istio-io + kind: Policy + listKind: PolicyList + plural: policies + singular: policy + scope: Namespaced + subresources: + status: {} + validation: + openAPIV3Schema: + properties: + spec: + description: 'Authentication policy for Istio services. See more details + at: https://istio.io/docs/reference/config/security/istio.authentication.v1alpha1.html' + properties: + originIsOptional: + description: Deprecated. + type: boolean + origins: + description: Deprecated. + items: + properties: + jwt: + description: Jwt params for the method. + properties: + audiences: + items: + format: string + type: string + type: array + issuer: + description: Identifies the issuer that issued the JWT. + format: string + type: string + jwks: + description: JSON Web Key Set of public keys to validate signature + of the JWT. + format: string + type: string + jwks_uri: + format: string + type: string + jwksUri: + format: string + type: string + jwt_headers: + description: JWT is sent in a request header. + items: + format: string + type: string + type: array + jwtHeaders: + description: JWT is sent in a request header. + items: + format: string + type: string + type: array + jwtParams: + description: JWT is sent in a query parameter. + items: + format: string + type: string + type: array + trigger_rules: + items: + properties: + excluded_paths: + description: List of paths to be excluded from the request. + items: + oneOf: + - required: + - exact + - required: + - prefix + - required: + - suffix + - required: + - regex + properties: + exact: + description: exact string match. + format: string + type: string + prefix: + description: prefix-based match. + format: string + type: string + regex: + description: ECMAscript style regex-based match + as defined by [EDCA-262](http://en.cppreference.com/w/cpp/regex/ecmascript). + format: string + type: string + suffix: + description: suffix-based match. + format: string + type: string + type: object + type: array + excludedPaths: + description: List of paths to be excluded from the request. + items: + oneOf: + - required: + - exact + - required: + - prefix + - required: + - suffix + - required: + - regex + properties: + exact: + description: exact string match. + format: string + type: string + prefix: + description: prefix-based match. + format: string + type: string + regex: + description: ECMAscript style regex-based match + as defined by [EDCA-262](http://en.cppreference.com/w/cpp/regex/ecmascript). + format: string + type: string + suffix: + description: suffix-based match. + format: string + type: string + type: object + type: array + included_paths: + description: List of paths that the request must include. + items: + oneOf: + - required: + - exact + - required: + - prefix + - required: + - suffix + - required: + - regex + properties: + exact: + description: exact string match. + format: string + type: string + prefix: + description: prefix-based match. + format: string + type: string + regex: + description: ECMAscript style regex-based match + as defined by [EDCA-262](http://en.cppreference.com/w/cpp/regex/ecmascript). + format: string + type: string + suffix: + description: suffix-based match. + format: string + type: string + type: object + type: array + includedPaths: + description: List of paths that the request must include. + items: + oneOf: + - required: + - exact + - required: + - prefix + - required: + - suffix + - required: + - regex + properties: + exact: + description: exact string match. + format: string + type: string + prefix: + description: prefix-based match. + format: string + type: string + regex: + description: ECMAscript style regex-based match + as defined by [EDCA-262](http://en.cppreference.com/w/cpp/regex/ecmascript). + format: string + type: string + suffix: + description: suffix-based match. + format: string + type: string + type: object + type: array + type: object + type: array + triggerRules: + items: + properties: + excluded_paths: + description: List of paths to be excluded from the request. + items: + oneOf: + - required: + - exact + - required: + - prefix + - required: + - suffix + - required: + - regex + properties: + exact: + description: exact string match. + format: string + type: string + prefix: + description: prefix-based match. + format: string + type: string + regex: + description: ECMAscript style regex-based match + as defined by [EDCA-262](http://en.cppreference.com/w/cpp/regex/ecmascript). + format: string + type: string + suffix: + description: suffix-based match. + format: string + type: string + type: object + type: array + excludedPaths: + description: List of paths to be excluded from the request. + items: + oneOf: + - required: + - exact + - required: + - prefix + - required: + - suffix + - required: + - regex + properties: + exact: + description: exact string match. + format: string + type: string + prefix: + description: prefix-based match. + format: string + type: string + regex: + description: ECMAscript style regex-based match + as defined by [EDCA-262](http://en.cppreference.com/w/cpp/regex/ecmascript). + format: string + type: string + suffix: + description: suffix-based match. + format: string + type: string + type: object + type: array + included_paths: + description: List of paths that the request must include. + items: + oneOf: + - required: + - exact + - required: + - prefix + - required: + - suffix + - required: + - regex + properties: + exact: + description: exact string match. + format: string + type: string + prefix: + description: prefix-based match. + format: string + type: string + regex: + description: ECMAscript style regex-based match + as defined by [EDCA-262](http://en.cppreference.com/w/cpp/regex/ecmascript). + format: string + type: string + suffix: + description: suffix-based match. + format: string + type: string + type: object + type: array + includedPaths: + description: List of paths that the request must include. + items: + oneOf: + - required: + - exact + - required: + - prefix + - required: + - suffix + - required: + - regex + properties: + exact: + description: exact string match. + format: string + type: string + prefix: + description: prefix-based match. + format: string + type: string + regex: + description: ECMAscript style regex-based match + as defined by [EDCA-262](http://en.cppreference.com/w/cpp/regex/ecmascript). + format: string + type: string + suffix: + description: suffix-based match. + format: string + type: string + type: object + type: array + type: object + type: array + type: object + type: object + type: array + peerIsOptional: + description: Deprecated. + type: boolean + peers: + description: List of authentication methods that can be used for peer + authentication. + items: + oneOf: + - required: + - mtls + - properties: + jwt: {} + required: + - jwt + properties: + jwt: + properties: + audiences: + items: + format: string + type: string + type: array + issuer: + description: Identifies the issuer that issued the JWT. + format: string + type: string + jwks: + description: JSON Web Key Set of public keys to validate signature + of the JWT. + format: string + type: string + jwks_uri: + format: string + type: string + jwksUri: + format: string + type: string + jwt_headers: + description: JWT is sent in a request header. + items: + format: string + type: string + type: array + jwtHeaders: + description: JWT is sent in a request header. + items: + format: string + type: string + type: array + jwtParams: + description: JWT is sent in a query parameter. + items: + format: string + type: string + type: array + trigger_rules: + items: + properties: + excluded_paths: + description: List of paths to be excluded from the request. + items: + oneOf: + - required: + - exact + - required: + - prefix + - required: + - suffix + - required: + - regex + properties: + exact: + description: exact string match. + format: string + type: string + prefix: + description: prefix-based match. + format: string + type: string + regex: + description: ECMAscript style regex-based match + as defined by [EDCA-262](http://en.cppreference.com/w/cpp/regex/ecmascript). + format: string + type: string + suffix: + description: suffix-based match. + format: string + type: string + type: object + type: array + excludedPaths: + description: List of paths to be excluded from the request. + items: + oneOf: + - required: + - exact + - required: + - prefix + - required: + - suffix + - required: + - regex + properties: + exact: + description: exact string match. + format: string + type: string + prefix: + description: prefix-based match. + format: string + type: string + regex: + description: ECMAscript style regex-based match + as defined by [EDCA-262](http://en.cppreference.com/w/cpp/regex/ecmascript). + format: string + type: string + suffix: + description: suffix-based match. + format: string + type: string + type: object + type: array + included_paths: + description: List of paths that the request must include. + items: + oneOf: + - required: + - exact + - required: + - prefix + - required: + - suffix + - required: + - regex + properties: + exact: + description: exact string match. + format: string + type: string + prefix: + description: prefix-based match. + format: string + type: string + regex: + description: ECMAscript style regex-based match + as defined by [EDCA-262](http://en.cppreference.com/w/cpp/regex/ecmascript). + format: string + type: string + suffix: + description: suffix-based match. + format: string + type: string + type: object + type: array + includedPaths: + description: List of paths that the request must include. + items: + oneOf: + - required: + - exact + - required: + - prefix + - required: + - suffix + - required: + - regex + properties: + exact: + description: exact string match. + format: string + type: string + prefix: + description: prefix-based match. + format: string + type: string + regex: + description: ECMAscript style regex-based match + as defined by [EDCA-262](http://en.cppreference.com/w/cpp/regex/ecmascript). + format: string + type: string + suffix: + description: suffix-based match. + format: string + type: string + type: object + type: array + type: object + type: array + triggerRules: + items: + properties: + excluded_paths: + description: List of paths to be excluded from the request. + items: + oneOf: + - required: + - exact + - required: + - prefix + - required: + - suffix + - required: + - regex + properties: + exact: + description: exact string match. + format: string + type: string + prefix: + description: prefix-based match. + format: string + type: string + regex: + description: ECMAscript style regex-based match + as defined by [EDCA-262](http://en.cppreference.com/w/cpp/regex/ecmascript). + format: string + type: string + suffix: + description: suffix-based match. + format: string + type: string + type: object + type: array + excludedPaths: + description: List of paths to be excluded from the request. + items: + oneOf: + - required: + - exact + - required: + - prefix + - required: + - suffix + - required: + - regex + properties: + exact: + description: exact string match. + format: string + type: string + prefix: + description: prefix-based match. + format: string + type: string + regex: + description: ECMAscript style regex-based match + as defined by [EDCA-262](http://en.cppreference.com/w/cpp/regex/ecmascript). + format: string + type: string + suffix: + description: suffix-based match. + format: string + type: string + type: object + type: array + included_paths: + description: List of paths that the request must include. + items: + oneOf: + - required: + - exact + - required: + - prefix + - required: + - suffix + - required: + - regex + properties: + exact: + description: exact string match. + format: string + type: string + prefix: + description: prefix-based match. + format: string + type: string + regex: + description: ECMAscript style regex-based match + as defined by [EDCA-262](http://en.cppreference.com/w/cpp/regex/ecmascript). + format: string + type: string + suffix: + description: suffix-based match. + format: string + type: string + type: object + type: array + includedPaths: + description: List of paths that the request must include. + items: + oneOf: + - required: + - exact + - required: + - prefix + - required: + - suffix + - required: + - regex + properties: + exact: + description: exact string match. + format: string + type: string + prefix: + description: prefix-based match. + format: string + type: string + regex: + description: ECMAscript style regex-based match + as defined by [EDCA-262](http://en.cppreference.com/w/cpp/regex/ecmascript). + format: string + type: string + suffix: + description: suffix-based match. + format: string + type: string + type: object + type: array + type: object + type: array + type: object + mtls: + description: Set if mTLS is used. + properties: + allowTls: + description: Deprecated. + type: boolean + mode: + description: Defines the mode of mTLS authentication. + enum: + - STRICT + - PERMISSIVE + type: string + type: object + type: object + type: array + principalBinding: + description: Deprecated. + enum: + - USE_PEER + - USE_ORIGIN + type: string + targets: + description: Deprecated. + items: + properties: + name: + description: The name must be a short name from the service registry. + format: string + type: string + ports: + description: Specifies the ports. + items: + oneOf: + - required: + - number + - required: + - name + properties: + name: + format: string + type: string + number: + type: integer + type: object + type: array + type: object + type: array + type: object + type: object + versions: + - name: v1alpha1 + served: true + storage: true + +--- +apiVersion: apiextensions.k8s.io/v1beta1 +kind: CustomResourceDefinition +metadata: + annotations: + "helm.sh/resource-policy": keep + labels: + app: istio-mixer + chart: istio + heritage: Tiller + release: istio + name: httpapispecs.config.istio.io +spec: + group: config.istio.io + names: + categories: + - istio-io + - apim-istio-io + kind: HTTPAPISpec + listKind: HTTPAPISpecList + plural: httpapispecs + singular: httpapispec + scope: Namespaced + subresources: + status: {} + validation: + openAPIV3Schema: + properties: + spec: + properties: + api_keys: + items: + oneOf: + - required: + - query + - required: + - header + - required: + - cookie + properties: + cookie: + format: string + type: string + header: + description: API key is sent in a request header. + format: string + type: string + query: + description: API Key is sent as a query parameter. + format: string + type: string + type: object + type: array + apiKeys: + items: + oneOf: + - required: + - query + - required: + - header + - required: + - cookie + properties: + cookie: + format: string + type: string + header: + description: API key is sent in a request header. + format: string + type: string + query: + description: API Key is sent as a query parameter. + format: string + type: string + type: object + type: array + attributes: + properties: + attributes: + additionalProperties: + oneOf: + - required: + - stringValue + - required: + - int64Value + - required: + - doubleValue + - required: + - boolValue + - required: + - bytesValue + - required: + - timestampValue + - required: + - durationValue + - required: + - stringMapValue + properties: + boolValue: + type: boolean + bytesValue: + format: binary + type: string + doubleValue: + format: double + type: number + durationValue: + type: string + int64Value: + format: int64 + type: integer + stringMapValue: + properties: + entries: + additionalProperties: + format: string + type: string + description: Holds a set of name/value pairs. + type: object + type: object + stringValue: + format: string + type: string + timestampValue: + format: dateTime + type: string + type: object + description: A map of attribute name to its value. + type: object + type: object + patterns: + description: List of HTTP patterns to match. + items: + oneOf: + - required: + - uriTemplate + - required: + - regex + properties: + attributes: + properties: + attributes: + additionalProperties: + oneOf: + - required: + - stringValue + - required: + - int64Value + - required: + - doubleValue + - required: + - boolValue + - required: + - bytesValue + - required: + - timestampValue + - required: + - durationValue + - required: + - stringMapValue + properties: + boolValue: + type: boolean + bytesValue: + format: binary + type: string + doubleValue: + format: double + type: number + durationValue: + type: string + int64Value: + format: int64 + type: integer + stringMapValue: + properties: + entries: + additionalProperties: + format: string + type: string + description: Holds a set of name/value pairs. + type: object + type: object + stringValue: + format: string + type: string + timestampValue: + format: dateTime + type: string + type: object + description: A map of attribute name to its value. + type: object + type: object + httpMethod: + format: string + type: string + regex: + format: string + type: string + uriTemplate: + format: string + type: string + type: object + type: array + type: object + type: object + versions: + - name: v1alpha2 + served: true + storage: true + +--- +apiVersion: apiextensions.k8s.io/v1beta1 +kind: CustomResourceDefinition +metadata: + annotations: + "helm.sh/resource-policy": keep + labels: + app: istio-mixer + chart: istio + heritage: Tiller + release: istio + name: httpapispecbindings.config.istio.io +spec: + group: config.istio.io + names: + categories: + - istio-io + - apim-istio-io + kind: HTTPAPISpecBinding + listKind: HTTPAPISpecBindingList + plural: httpapispecbindings + singular: httpapispecbinding + scope: Namespaced + subresources: + status: {} + validation: + openAPIV3Schema: + properties: + spec: + properties: + api_specs: + items: + properties: + name: + description: The short name of the HTTPAPISpec. + format: string + type: string + namespace: + description: Optional namespace of the HTTPAPISpec. + format: string + type: string + type: object + type: array + apiSpecs: + items: + properties: + name: + description: The short name of the HTTPAPISpec. + format: string + type: string + namespace: + description: Optional namespace of the HTTPAPISpec. + format: string + type: string + type: object + type: array + services: + description: One or more services to map the listed HTTPAPISpec onto. + items: + properties: + domain: + description: Domain suffix used to construct the service FQDN + in implementations that support such specification. + format: string + type: string + labels: + additionalProperties: + format: string + type: string + description: Optional one or more labels that uniquely identify + the service version. + type: object + name: + description: The short name of the service such as "foo". + format: string + type: string + namespace: + description: Optional namespace of the service. + format: string + type: string + service: + description: The service FQDN. + format: string + type: string + type: object + type: array + type: object + type: object + versions: + - name: v1alpha2 + served: true + storage: true + +--- +apiVersion: apiextensions.k8s.io/v1beta1 +kind: CustomResourceDefinition +metadata: + annotations: + "helm.sh/resource-policy": keep + labels: + app: istio-mixer + chart: istio + heritage: Tiller + release: istio + name: quotaspecs.config.istio.io +spec: + group: config.istio.io + names: + categories: + - istio-io + - apim-istio-io + kind: QuotaSpec + listKind: QuotaSpecList + plural: quotaspecs + singular: quotaspec + scope: Namespaced + subresources: + status: {} + validation: + openAPIV3Schema: + properties: + spec: + description: Determines the quotas used for individual requests. + properties: + rules: + description: A list of Quota rules. + items: + properties: + match: + description: If empty, match all request. + items: + properties: + clause: + additionalProperties: + oneOf: + - required: + - exact + - required: + - prefix + - required: + - regex + properties: + exact: + format: string + type: string + prefix: + format: string + type: string + regex: + format: string + type: string + type: object + description: Map of attribute names to StringMatch type. + type: object + type: object + type: array + quotas: + description: The list of quotas to charge. + items: + properties: + charge: + format: int32 + type: integer + quota: + format: string + type: string + type: object + type: array + type: object + type: array + type: object + type: object + versions: + - name: v1alpha2 + served: true + storage: true + +--- +apiVersion: apiextensions.k8s.io/v1beta1 +kind: CustomResourceDefinition +metadata: + annotations: + "helm.sh/resource-policy": keep + labels: + app: istio-mixer + chart: istio + heritage: Tiller + release: istio + name: quotaspecbindings.config.istio.io +spec: + group: config.istio.io + names: + categories: + - istio-io + - apim-istio-io + kind: QuotaSpecBinding + listKind: QuotaSpecBindingList + plural: quotaspecbindings + singular: quotaspecbinding + scope: Namespaced + subresources: + status: {} + validation: + openAPIV3Schema: + properties: + spec: + properties: + quotaSpecs: + items: + properties: + name: + description: The short name of the QuotaSpec. + format: string + type: string + namespace: + description: Optional namespace of the QuotaSpec. + format: string + type: string + type: object + type: array + services: + description: One or more services to map the listed QuotaSpec onto. + items: + properties: + domain: + description: Domain suffix used to construct the service FQDN + in implementations that support such specification. + format: string + type: string + labels: + additionalProperties: + format: string + type: string + description: Optional one or more labels that uniquely identify + the service version. + type: object + name: + description: The short name of the service such as "foo". + format: string + type: string + namespace: + description: Optional namespace of the service. + format: string + type: string + service: + description: The service FQDN. + format: string + type: string + type: object + type: array + type: object + type: object + versions: + - name: v1alpha2 + served: true + storage: true + +--- +apiVersion: apiextensions.k8s.io/v1beta1 +kind: CustomResourceDefinition +metadata: + annotations: + "helm.sh/resource-policy": keep + labels: + app: istio-pilot + chart: istio + heritage: Tiller + release: istio + name: destinationrules.networking.istio.io +spec: + additionalPrinterColumns: + - JSONPath: .spec.host + description: The name of a service from the service registry + name: Host + type: string + - JSONPath: .metadata.creationTimestamp + description: 'CreationTimestamp is a timestamp representing the server time when + this object was created. It is not guaranteed to be set in happens-before order + across separate operations. Clients may not set this value. It is represented + in RFC3339 form and is in UTC. Populated by the system. Read-only. Null for + lists. More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#metadata' + name: Age + type: date + group: networking.istio.io + names: + categories: + - istio-io + - networking-istio-io + kind: DestinationRule + listKind: DestinationRuleList + plural: destinationrules + shortNames: + - dr + singular: destinationrule + scope: Namespaced + subresources: + status: {} + validation: + openAPIV3Schema: + properties: + spec: + description: 'Configuration affecting load balancing, outlier detection, + etc. See more details at: https://istio.io/docs/reference/config/networking/destination-rule.html' + properties: + exportTo: + description: A list of namespaces to which this destination rule is + exported. + items: + format: string + type: string + type: array + host: + description: The name of a service from the service registry. + format: string + type: string + subsets: + items: + properties: + labels: + additionalProperties: + format: string + type: string + type: object + name: + description: Name of the subset. + format: string + type: string + trafficPolicy: + description: Traffic policies that apply to this subset. + properties: + connectionPool: + properties: + http: + description: HTTP connection pool settings. + properties: + h2UpgradePolicy: + description: Specify if http1.1 connection should + be upgraded to http2 for the associated destination. + enum: + - DEFAULT + - DO_NOT_UPGRADE + - UPGRADE + type: string + http1MaxPendingRequests: + description: Maximum number of pending HTTP requests + to a destination. + format: int32 + type: integer + http2MaxRequests: + description: Maximum number of requests to a backend. + format: int32 + type: integer + idleTimeout: + description: The idle timeout for upstream connection + pool connections. + type: string + maxRequestsPerConnection: + description: Maximum number of requests per connection + to a backend. + format: int32 + type: integer + maxRetries: + format: int32 + type: integer + type: object + tcp: + description: Settings common to both HTTP and TCP upstream + connections. + properties: + connectTimeout: + description: TCP connection timeout. + type: string + maxConnections: + description: Maximum number of HTTP1 /TCP connections + to a destination host. + format: int32 + type: integer + tcpKeepalive: + description: If set then set SO_KEEPALIVE on the socket + to enable TCP Keepalives. + properties: + interval: + description: The time duration between keep-alive + probes. + type: string + probes: + type: integer + time: + type: string + type: object + type: object + type: object + loadBalancer: + description: Settings controlling the load balancer algorithms. + oneOf: + - required: + - simple + - properties: + consistentHash: + oneOf: + - required: + - httpHeaderName + - required: + - httpCookie + - required: + - useSourceIp + required: + - consistentHash + properties: + consistentHash: + properties: + httpCookie: + description: Hash based on HTTP cookie. + properties: + name: + description: Name of the cookie. + format: string + type: string + path: + description: Path to set for the cookie. + format: string + type: string + ttl: + description: Lifetime of the cookie. + type: string + type: object + httpHeaderName: + description: Hash based on a specific HTTP header. + format: string + type: string + minimumRingSize: + type: integer + useSourceIp: + description: Hash based on the source IP address. + type: boolean + type: object + localityLbSetting: + properties: + distribute: + description: 'Optional: only one of distribute or + failover can be set.' + items: + properties: + from: + description: Originating locality, '/' separated, + e.g. + format: string + type: string + to: + additionalProperties: + type: integer + description: Map of upstream localities to traffic + distribution weights. + type: object + type: object + type: array + enabled: + description: enable locality load balancing, this + is DestinationRule-level and will override mesh + wide settings in entirety. + type: boolean + failover: + description: 'Optional: only failover or distribute + can be set.' + items: + properties: + from: + description: Originating region. + format: string + type: string + to: + format: string + type: string + type: object + type: array + type: object + simple: + enum: + - ROUND_ROBIN + - LEAST_CONN + - RANDOM + - PASSTHROUGH + type: string + type: object + outlierDetection: + properties: + baseEjectionTime: + description: Minimum ejection duration. + type: string + consecutive5xxErrors: + description: Number of 5xx errors before a host is ejected + from the connection pool. + type: integer + consecutiveErrors: + format: int32 + type: integer + consecutiveGatewayErrors: + description: Number of gateway errors before a host is + ejected from the connection pool. + type: integer + interval: + description: Time interval between ejection sweep analysis. + type: string + maxEjectionPercent: + format: int32 + type: integer + minHealthPercent: + format: int32 + type: integer + type: object + portLevelSettings: + description: Traffic policies specific to individual ports. + items: + properties: + connectionPool: + properties: + http: + description: HTTP connection pool settings. + properties: + h2UpgradePolicy: + description: Specify if http1.1 connection should + be upgraded to http2 for the associated destination. + enum: + - DEFAULT + - DO_NOT_UPGRADE + - UPGRADE + type: string + http1MaxPendingRequests: + description: Maximum number of pending HTTP + requests to a destination. + format: int32 + type: integer + http2MaxRequests: + description: Maximum number of requests to a + backend. + format: int32 + type: integer + idleTimeout: + description: The idle timeout for upstream connection + pool connections. + type: string + maxRequestsPerConnection: + description: Maximum number of requests per + connection to a backend. + format: int32 + type: integer + maxRetries: + format: int32 + type: integer + type: object + tcp: + description: Settings common to both HTTP and TCP + upstream connections. + properties: + connectTimeout: + description: TCP connection timeout. + type: string + maxConnections: + description: Maximum number of HTTP1 /TCP connections + to a destination host. + format: int32 + type: integer + tcpKeepalive: + description: If set then set SO_KEEPALIVE on + the socket to enable TCP Keepalives. + properties: + interval: + description: The time duration between keep-alive + probes. + type: string + probes: + type: integer + time: + type: string + type: object + type: object + type: object + loadBalancer: + description: Settings controlling the load balancer + algorithms. + oneOf: + - required: + - simple + - properties: + consistentHash: + oneOf: + - required: + - httpHeaderName + - required: + - httpCookie + - required: + - useSourceIp + required: + - consistentHash + properties: + consistentHash: + properties: + httpCookie: + description: Hash based on HTTP cookie. + properties: + name: + description: Name of the cookie. + format: string + type: string + path: + description: Path to set for the cookie. + format: string + type: string + ttl: + description: Lifetime of the cookie. + type: string + type: object + httpHeaderName: + description: Hash based on a specific HTTP header. + format: string + type: string + minimumRingSize: + type: integer + useSourceIp: + description: Hash based on the source IP address. + type: boolean + type: object + localityLbSetting: + properties: + distribute: + description: 'Optional: only one of distribute + or failover can be set.' + items: + properties: + from: + description: Originating locality, '/' + separated, e.g. + format: string + type: string + to: + additionalProperties: + type: integer + description: Map of upstream localities + to traffic distribution weights. + type: object + type: object + type: array + enabled: + description: enable locality load balancing, + this is DestinationRule-level and will override + mesh wide settings in entirety. + type: boolean + failover: + description: 'Optional: only failover or distribute + can be set.' + items: + properties: + from: + description: Originating region. + format: string + type: string + to: + format: string + type: string + type: object + type: array + type: object + simple: + enum: + - ROUND_ROBIN + - LEAST_CONN + - RANDOM + - PASSTHROUGH + type: string + type: object + outlierDetection: + properties: + baseEjectionTime: + description: Minimum ejection duration. + type: string + consecutive5xxErrors: + description: Number of 5xx errors before a host + is ejected from the connection pool. + type: integer + consecutiveErrors: + format: int32 + type: integer + consecutiveGatewayErrors: + description: Number of gateway errors before a host + is ejected from the connection pool. + type: integer + interval: + description: Time interval between ejection sweep + analysis. + type: string + maxEjectionPercent: + format: int32 + type: integer + minHealthPercent: + format: int32 + type: integer + type: object + port: + properties: + number: + type: integer + type: object + tls: + description: TLS related settings for connections to + the upstream service. + properties: + caCertificates: + format: string + type: string + clientCertificate: + description: REQUIRED if mode is `MUTUAL`. + format: string + type: string + mode: + enum: + - DISABLE + - SIMPLE + - MUTUAL + - ISTIO_MUTUAL + type: string + privateKey: + description: REQUIRED if mode is `MUTUAL`. + format: string + type: string + sni: + description: SNI string to present to the server + during TLS handshake. + format: string + type: string + subjectAltNames: + items: + format: string + type: string + type: array + type: object + type: object + type: array + tls: + description: TLS related settings for connections to the upstream + service. + properties: + caCertificates: + format: string + type: string + clientCertificate: + description: REQUIRED if mode is `MUTUAL`. + format: string + type: string + mode: + enum: + - DISABLE + - SIMPLE + - MUTUAL + - ISTIO_MUTUAL + type: string + privateKey: + description: REQUIRED if mode is `MUTUAL`. + format: string + type: string + sni: + description: SNI string to present to the server during + TLS handshake. + format: string + type: string + subjectAltNames: + items: + format: string + type: string + type: array + type: object + type: object + type: object + type: array + trafficPolicy: + properties: + connectionPool: + properties: + http: + description: HTTP connection pool settings. + properties: + h2UpgradePolicy: + description: Specify if http1.1 connection should be upgraded + to http2 for the associated destination. + enum: + - DEFAULT + - DO_NOT_UPGRADE + - UPGRADE + type: string + http1MaxPendingRequests: + description: Maximum number of pending HTTP requests to + a destination. + format: int32 + type: integer + http2MaxRequests: + description: Maximum number of requests to a backend. + format: int32 + type: integer + idleTimeout: + description: The idle timeout for upstream connection pool + connections. + type: string + maxRequestsPerConnection: + description: Maximum number of requests per connection to + a backend. + format: int32 + type: integer + maxRetries: + format: int32 + type: integer + type: object + tcp: + description: Settings common to both HTTP and TCP upstream connections. + properties: + connectTimeout: + description: TCP connection timeout. + type: string + maxConnections: + description: Maximum number of HTTP1 /TCP connections to + a destination host. + format: int32 + type: integer + tcpKeepalive: + description: If set then set SO_KEEPALIVE on the socket + to enable TCP Keepalives. + properties: + interval: + description: The time duration between keep-alive probes. + type: string + probes: + type: integer + time: + type: string + type: object + type: object + type: object + loadBalancer: + description: Settings controlling the load balancer algorithms. + oneOf: + - required: + - simple + - properties: + consistentHash: + oneOf: + - required: + - httpHeaderName + - required: + - httpCookie + - required: + - useSourceIp + required: + - consistentHash + properties: + consistentHash: + properties: + httpCookie: + description: Hash based on HTTP cookie. + properties: + name: + description: Name of the cookie. + format: string + type: string + path: + description: Path to set for the cookie. + format: string + type: string + ttl: + description: Lifetime of the cookie. + type: string + type: object + httpHeaderName: + description: Hash based on a specific HTTP header. + format: string + type: string + minimumRingSize: + type: integer + useSourceIp: + description: Hash based on the source IP address. + type: boolean + type: object + localityLbSetting: + properties: + distribute: + description: 'Optional: only one of distribute or failover + can be set.' + items: + properties: + from: + description: Originating locality, '/' separated, + e.g. + format: string + type: string + to: + additionalProperties: + type: integer + description: Map of upstream localities to traffic + distribution weights. + type: object + type: object + type: array + enabled: + description: enable locality load balancing, this is DestinationRule-level + and will override mesh wide settings in entirety. + type: boolean + failover: + description: 'Optional: only failover or distribute can + be set.' + items: + properties: + from: + description: Originating region. + format: string + type: string + to: + format: string + type: string + type: object + type: array + type: object + simple: + enum: + - ROUND_ROBIN + - LEAST_CONN + - RANDOM + - PASSTHROUGH + type: string + type: object + outlierDetection: + properties: + baseEjectionTime: + description: Minimum ejection duration. + type: string + consecutive5xxErrors: + description: Number of 5xx errors before a host is ejected from + the connection pool. + type: integer + consecutiveErrors: + format: int32 + type: integer + consecutiveGatewayErrors: + description: Number of gateway errors before a host is ejected + from the connection pool. + type: integer + interval: + description: Time interval between ejection sweep analysis. + type: string + maxEjectionPercent: + format: int32 + type: integer + minHealthPercent: + format: int32 + type: integer + type: object + portLevelSettings: + description: Traffic policies specific to individual ports. + items: + properties: + connectionPool: + properties: + http: + description: HTTP connection pool settings. + properties: + h2UpgradePolicy: + description: Specify if http1.1 connection should + be upgraded to http2 for the associated destination. + enum: + - DEFAULT + - DO_NOT_UPGRADE + - UPGRADE + type: string + http1MaxPendingRequests: + description: Maximum number of pending HTTP requests + to a destination. + format: int32 + type: integer + http2MaxRequests: + description: Maximum number of requests to a backend. + format: int32 + type: integer + idleTimeout: + description: The idle timeout for upstream connection + pool connections. + type: string + maxRequestsPerConnection: + description: Maximum number of requests per connection + to a backend. + format: int32 + type: integer + maxRetries: + format: int32 + type: integer + type: object + tcp: + description: Settings common to both HTTP and TCP upstream + connections. + properties: + connectTimeout: + description: TCP connection timeout. + type: string + maxConnections: + description: Maximum number of HTTP1 /TCP connections + to a destination host. + format: int32 + type: integer + tcpKeepalive: + description: If set then set SO_KEEPALIVE on the socket + to enable TCP Keepalives. + properties: + interval: + description: The time duration between keep-alive + probes. + type: string + probes: + type: integer + time: + type: string + type: object + type: object + type: object + loadBalancer: + description: Settings controlling the load balancer algorithms. + oneOf: + - required: + - simple + - properties: + consistentHash: + oneOf: + - required: + - httpHeaderName + - required: + - httpCookie + - required: + - useSourceIp + required: + - consistentHash + properties: + consistentHash: + properties: + httpCookie: + description: Hash based on HTTP cookie. + properties: + name: + description: Name of the cookie. + format: string + type: string + path: + description: Path to set for the cookie. + format: string + type: string + ttl: + description: Lifetime of the cookie. + type: string + type: object + httpHeaderName: + description: Hash based on a specific HTTP header. + format: string + type: string + minimumRingSize: + type: integer + useSourceIp: + description: Hash based on the source IP address. + type: boolean + type: object + localityLbSetting: + properties: + distribute: + description: 'Optional: only one of distribute or + failover can be set.' + items: + properties: + from: + description: Originating locality, '/' separated, + e.g. + format: string + type: string + to: + additionalProperties: + type: integer + description: Map of upstream localities to traffic + distribution weights. + type: object + type: object + type: array + enabled: + description: enable locality load balancing, this + is DestinationRule-level and will override mesh + wide settings in entirety. + type: boolean + failover: + description: 'Optional: only failover or distribute + can be set.' + items: + properties: + from: + description: Originating region. + format: string + type: string + to: + format: string + type: string + type: object + type: array + type: object + simple: + enum: + - ROUND_ROBIN + - LEAST_CONN + - RANDOM + - PASSTHROUGH + type: string + type: object + outlierDetection: + properties: + baseEjectionTime: + description: Minimum ejection duration. + type: string + consecutive5xxErrors: + description: Number of 5xx errors before a host is ejected + from the connection pool. + type: integer + consecutiveErrors: + format: int32 + type: integer + consecutiveGatewayErrors: + description: Number of gateway errors before a host is + ejected from the connection pool. + type: integer + interval: + description: Time interval between ejection sweep analysis. + type: string + maxEjectionPercent: + format: int32 + type: integer + minHealthPercent: + format: int32 + type: integer + type: object + port: + properties: + number: + type: integer + type: object + tls: + description: TLS related settings for connections to the upstream + service. + properties: + caCertificates: + format: string + type: string + clientCertificate: + description: REQUIRED if mode is `MUTUAL`. + format: string + type: string + mode: + enum: + - DISABLE + - SIMPLE + - MUTUAL + - ISTIO_MUTUAL + type: string + privateKey: + description: REQUIRED if mode is `MUTUAL`. + format: string + type: string + sni: + description: SNI string to present to the server during + TLS handshake. + format: string + type: string + subjectAltNames: + items: + format: string + type: string + type: array + type: object + type: object + type: array + tls: + description: TLS related settings for connections to the upstream + service. + properties: + caCertificates: + format: string + type: string + clientCertificate: + description: REQUIRED if mode is `MUTUAL`. + format: string + type: string + mode: + enum: + - DISABLE + - SIMPLE + - MUTUAL + - ISTIO_MUTUAL + type: string + privateKey: + description: REQUIRED if mode is `MUTUAL`. + format: string + type: string + sni: + description: SNI string to present to the server during TLS + handshake. + format: string + type: string + subjectAltNames: + items: + format: string + type: string + type: array + type: object + type: object + type: object + type: object + versions: + - name: v1alpha3 + served: true + storage: true + - name: v1beta1 + served: true + storage: false + +--- +apiVersion: apiextensions.k8s.io/v1beta1 +kind: CustomResourceDefinition +metadata: + annotations: + "helm.sh/resource-policy": keep + labels: + app: istio-pilot + chart: istio + heritage: Tiller + release: istio + name: envoyfilters.networking.istio.io +spec: + group: networking.istio.io + names: + categories: + - istio-io + - networking-istio-io + kind: EnvoyFilter + listKind: EnvoyFilterList + plural: envoyfilters + singular: envoyfilter + scope: Namespaced + subresources: + status: {} + validation: + openAPIV3Schema: + properties: + spec: + description: 'Customizing Envoy configuration generated by Istio. See more + details at: https://istio.io/docs/reference/config/networking/envoy-filter.html' + properties: + configPatches: + description: One or more patches with match conditions. + items: + properties: + applyTo: + enum: + - INVALID + - LISTENER + - FILTER_CHAIN + - NETWORK_FILTER + - HTTP_FILTER + - ROUTE_CONFIGURATION + - VIRTUAL_HOST + - HTTP_ROUTE + - CLUSTER + type: string + match: + description: Match on listener/route configuration/cluster. + oneOf: + - required: + - listener + - required: + - routeConfiguration + - required: + - cluster + properties: + cluster: + description: Match on envoy cluster attributes. + properties: + name: + description: The exact name of the cluster to match. + format: string + type: string + portNumber: + description: The service port for which this cluster was + generated. + type: integer + service: + description: The fully qualified service name for this + cluster. + format: string + type: string + subset: + description: The subset associated with the service. + format: string + type: string + type: object + context: + description: The specific config generation context to match + on. + enum: + - ANY + - SIDECAR_INBOUND + - SIDECAR_OUTBOUND + - GATEWAY + type: string + listener: + description: Match on envoy listener attributes. + properties: + filterChain: + description: Match a specific filter chain in a listener. + properties: + applicationProtocols: + description: Applies only to sidecars. + format: string + type: string + filter: + description: The name of a specific filter to apply + the patch to. + properties: + name: + description: The filter name to match on. + format: string + type: string + subFilter: + properties: + name: + description: The filter name to match on. + format: string + type: string + type: object + type: object + name: + description: The name assigned to the filter chain. + format: string + type: string + sni: + description: The SNI value used by a filter chain's + match condition. + format: string + type: string + transportProtocol: + description: Applies only to SIDECAR_INBOUND context. + format: string + type: string + type: object + name: + description: Match a specific listener by its name. + format: string + type: string + portName: + format: string + type: string + portNumber: + type: integer + type: object + proxy: + description: Match on properties associated with a proxy. + properties: + metadata: + additionalProperties: + format: string + type: string + type: object + proxyVersion: + format: string + type: string + type: object + routeConfiguration: + description: Match on envoy HTTP route configuration attributes. + properties: + gateway: + format: string + type: string + name: + description: Route configuration name to match on. + format: string + type: string + portName: + description: Applicable only for GATEWAY context. + format: string + type: string + portNumber: + type: integer + vhost: + properties: + name: + format: string + type: string + route: + description: Match a specific route within the virtual + host. + properties: + action: + description: Match a route with specific action + type. + enum: + - ANY + - ROUTE + - REDIRECT + - DIRECT_RESPONSE + type: string + name: + format: string + type: string + type: object + type: object + type: object + type: object + patch: + description: The patch to apply along with the operation. + properties: + operation: + description: Determines how the patch should be applied. + enum: + - INVALID + - MERGE + - ADD + - REMOVE + - INSERT_BEFORE + - INSERT_AFTER + - INSERT_FIRST + type: string + value: + description: The JSON config of the object being patched. + type: object + type: object + type: object + type: array + filters: + items: + properties: + filterConfig: + type: object + filterName: + description: The name of the filter to instantiate. + format: string + type: string + filterType: + description: The type of filter to instantiate. + enum: + - INVALID + - HTTP + - NETWORK + type: string + insertPosition: + description: Insert position in the filter chain. + properties: + index: + description: Position of this filter in the filter chain. + enum: + - FIRST + - LAST + - BEFORE + - AFTER + type: string + relativeTo: + format: string + type: string + type: object + listenerMatch: + properties: + address: + description: One or more IP addresses to which the listener + is bound. + items: + format: string + type: string + type: array + listenerProtocol: + description: Selects a class of listeners for the same protocol. + enum: + - ALL + - HTTP + - TCP + type: string + listenerType: + description: Inbound vs outbound sidecar listener or gateway + listener. + enum: + - ANY + - SIDECAR_INBOUND + - SIDECAR_OUTBOUND + - GATEWAY + type: string + portNamePrefix: + format: string + type: string + portNumber: + type: integer + type: object + type: object + type: array + workloadLabels: + additionalProperties: + format: string + type: string + description: Deprecated. + type: object + workloadSelector: + properties: + labels: + additionalProperties: + format: string + type: string + type: object + type: object + type: object + type: object + versions: + - name: v1alpha3 + served: true + storage: true + +--- +apiVersion: apiextensions.k8s.io/v1beta1 +kind: CustomResourceDefinition +metadata: + annotations: + "helm.sh/resource-policy": keep + labels: + app: istio-pilot + chart: istio + heritage: Tiller + release: istio + name: gateways.networking.istio.io +spec: + group: networking.istio.io + names: + categories: + - istio-io + - networking-istio-io + kind: Gateway + listKind: GatewayList + plural: gateways + shortNames: + - gw + singular: gateway + scope: Namespaced + subresources: + status: {} + validation: + openAPIV3Schema: + properties: + spec: + description: 'Configuration affecting edge load balancer. See more details + at: https://istio.io/docs/reference/config/networking/gateway.html' + properties: + selector: + additionalProperties: + format: string + type: string + type: object + servers: + description: A list of server specifications. + items: + properties: + bind: + format: string + type: string + defaultEndpoint: + format: string + type: string + hosts: + description: One or more hosts exposed by this gateway. + items: + format: string + type: string + type: array + port: + properties: + name: + description: Label assigned to the port. + format: string + type: string + number: + description: A valid non-negative integer port number. + type: integer + protocol: + description: The protocol exposed on the port. + format: string + type: string + type: object + tls: + description: Set of TLS related options that govern the server's + behavior. + properties: + caCertificates: + description: REQUIRED if mode is `MUTUAL`. + format: string + type: string + cipherSuites: + description: 'Optional: If specified, only support the specified + cipher list.' + items: + format: string + type: string + type: array + credentialName: + format: string + type: string + httpsRedirect: + type: boolean + maxProtocolVersion: + description: 'Optional: Maximum TLS protocol version.' + enum: + - TLS_AUTO + - TLSV1_0 + - TLSV1_1 + - TLSV1_2 + - TLSV1_3 + type: string + minProtocolVersion: + description: 'Optional: Minimum TLS protocol version.' + enum: + - TLS_AUTO + - TLSV1_0 + - TLSV1_1 + - TLSV1_2 + - TLSV1_3 + type: string + mode: + enum: + - PASSTHROUGH + - SIMPLE + - MUTUAL + - AUTO_PASSTHROUGH + - ISTIO_MUTUAL + type: string + privateKey: + description: REQUIRED if mode is `SIMPLE` or `MUTUAL`. + format: string + type: string + serverCertificate: + description: REQUIRED if mode is `SIMPLE` or `MUTUAL`. + format: string + type: string + subjectAltNames: + items: + format: string + type: string + type: array + verifyCertificateHash: + items: + format: string + type: string + type: array + verifyCertificateSpki: + items: + format: string + type: string + type: array + type: object + type: object + type: array + type: object + type: object + versions: + - name: v1alpha3 + served: true + storage: true + - name: v1beta1 + served: true + storage: false + +--- +apiVersion: apiextensions.k8s.io/v1beta1 +kind: CustomResourceDefinition +metadata: + annotations: + "helm.sh/resource-policy": keep + labels: + app: istio-pilot + chart: istio + heritage: Tiller + release: istio + name: serviceentries.networking.istio.io +spec: + additionalPrinterColumns: + - JSONPath: .spec.hosts + description: The hosts associated with the ServiceEntry + name: Hosts + type: string + - JSONPath: .spec.location + description: Whether the service is external to the mesh or part of the mesh (MESH_EXTERNAL + or MESH_INTERNAL) + name: Location + type: string + - JSONPath: .spec.resolution + description: Service discovery mode for the hosts (NONE, STATIC, or DNS) + name: Resolution + type: string + - JSONPath: .metadata.creationTimestamp + description: 'CreationTimestamp is a timestamp representing the server time when + this object was created. It is not guaranteed to be set in happens-before order + across separate operations. Clients may not set this value. It is represented + in RFC3339 form and is in UTC. Populated by the system. Read-only. Null for + lists. More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#metadata' + name: Age + type: date + group: networking.istio.io + names: + categories: + - istio-io + - networking-istio-io + kind: ServiceEntry + listKind: ServiceEntryList + plural: serviceentries + shortNames: + - se + singular: serviceentry + scope: Namespaced + subresources: + status: {} + validation: + openAPIV3Schema: + properties: + spec: + description: 'Configuration affecting service registry. See more details + at: https://istio.io/docs/reference/config/networking/service-entry.html' + properties: + addresses: + description: The virtual IP addresses associated with the service. + items: + format: string + type: string + type: array + endpoints: + description: One or more endpoints associated with the service. + items: + properties: + address: + format: string + type: string + labels: + additionalProperties: + format: string + type: string + description: One or more labels associated with the endpoint. + type: object + locality: + description: The locality associated with the endpoint. + format: string + type: string + network: + format: string + type: string + ports: + additionalProperties: + type: integer + description: Set of ports associated with the endpoint. + type: object + weight: + description: The load balancing weight associated with the endpoint. + type: integer + type: object + type: array + exportTo: + description: A list of namespaces to which this service is exported. + items: + format: string + type: string + type: array + hosts: + description: The hosts associated with the ServiceEntry. + items: + format: string + type: string + type: array + location: + enum: + - MESH_EXTERNAL + - MESH_INTERNAL + type: string + ports: + description: The ports associated with the external service. + items: + properties: + name: + description: Label assigned to the port. + format: string + type: string + number: + description: A valid non-negative integer port number. + type: integer + protocol: + description: The protocol exposed on the port. + format: string + type: string + type: object + type: array + resolution: + description: Service discovery mode for the hosts. + enum: + - NONE + - STATIC + - DNS + type: string + subjectAltNames: + items: + format: string + type: string + type: array + type: object + type: object + versions: + - name: v1alpha3 + served: true + storage: true + - name: v1beta1 + served: true + storage: false + +--- +apiVersion: apiextensions.k8s.io/v1beta1 +kind: CustomResourceDefinition +metadata: + annotations: + "helm.sh/resource-policy": keep + labels: + app: istio-pilot + chart: istio + heritage: Tiller + release: istio + name: sidecars.networking.istio.io +spec: + group: networking.istio.io + names: + categories: + - istio-io + - networking-istio-io + kind: Sidecar + listKind: SidecarList + plural: sidecars + singular: sidecar + scope: Namespaced + subresources: + status: {} + validation: + openAPIV3Schema: + properties: + spec: + description: 'Configuration affecting network reachability of a sidecar. + See more details at: https://istio.io/docs/reference/config/networking/sidecar.html' + properties: + egress: + items: + properties: + bind: + format: string + type: string + captureMode: + enum: + - DEFAULT + - IPTABLES + - NONE + type: string + hosts: + items: + format: string + type: string + type: array + port: + description: The port associated with the listener. + properties: + name: + description: Label assigned to the port. + format: string + type: string + number: + description: A valid non-negative integer port number. + type: integer + protocol: + description: The protocol exposed on the port. + format: string + type: string + type: object + type: object + type: array + ingress: + items: + properties: + bind: + description: The IP to which the listener should be bound. + format: string + type: string + captureMode: + enum: + - DEFAULT + - IPTABLES + - NONE + type: string + defaultEndpoint: + format: string + type: string + port: + description: The port associated with the listener. + properties: + name: + description: Label assigned to the port. + format: string + type: string + number: + description: A valid non-negative integer port number. + type: integer + protocol: + description: The protocol exposed on the port. + format: string + type: string + type: object + type: object + type: array + outboundTrafficPolicy: + description: This allows to configure the outbound traffic policy. + properties: + mode: + enum: + - REGISTRY_ONLY + - ALLOW_ANY + type: string + type: object + workloadSelector: + properties: + labels: + additionalProperties: + format: string + type: string + type: object + type: object + type: object + type: object + versions: + - name: v1alpha3 + served: true + storage: true + - name: v1beta1 + served: true + storage: false + +--- +apiVersion: apiextensions.k8s.io/v1beta1 +kind: CustomResourceDefinition +metadata: + annotations: + "helm.sh/resource-policy": keep + labels: + app: istio-pilot + chart: istio + heritage: Tiller + release: istio + name: virtualservices.networking.istio.io +spec: + additionalPrinterColumns: + - JSONPath: .spec.gateways + description: The names of gateways and sidecars that should apply these routes + name: Gateways + type: string + - JSONPath: .spec.hosts + description: The destination hosts to which traffic is being sent + name: Hosts + type: string + - JSONPath: .metadata.creationTimestamp + description: 'CreationTimestamp is a timestamp representing the server time when + this object was created. It is not guaranteed to be set in happens-before order + across separate operations. Clients may not set this value. It is represented + in RFC3339 form and is in UTC. Populated by the system. Read-only. Null for + lists. More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#metadata' + name: Age + type: date + group: networking.istio.io + names: + categories: + - istio-io + - networking-istio-io + kind: VirtualService + listKind: VirtualServiceList + plural: virtualservices + shortNames: + - vs + singular: virtualservice + scope: Namespaced + subresources: + status: {} + validation: + openAPIV3Schema: + properties: + spec: + description: 'Configuration affecting label/content routing, sni routing, + etc. See more details at: https://istio.io/docs/reference/config/networking/virtual-service.html' + properties: + exportTo: + description: A list of namespaces to which this virtual service is exported. + items: + format: string + type: string + type: array + gateways: + description: The names of gateways and sidecars that should apply these + routes. + items: + format: string + type: string + type: array + hosts: + description: The destination hosts to which traffic is being sent. + items: + format: string + type: string + type: array + http: + description: An ordered list of route rules for HTTP traffic. + items: + properties: + corsPolicy: + description: Cross-Origin Resource Sharing policy (CORS). + properties: + allowCredentials: + type: boolean + allowHeaders: + items: + format: string + type: string + type: array + allowMethods: + description: List of HTTP methods allowed to access the resource. + items: + format: string + type: string + type: array + allowOrigin: + description: The list of origins that are allowed to perform + CORS requests. + items: + format: string + type: string + type: array + allowOrigins: + description: String patterns that match allowed origins. + items: + oneOf: + - required: + - exact + - required: + - prefix + - required: + - regex + properties: + exact: + format: string + type: string + prefix: + format: string + type: string + regex: + format: string + type: string + type: object + type: array + exposeHeaders: + items: + format: string + type: string + type: array + maxAge: + type: string + type: object + fault: + description: Fault injection policy to apply on HTTP traffic at + the client side. + properties: + abort: + oneOf: + - required: + - httpStatus + - required: + - grpcStatus + - required: + - http2Error + properties: + grpcStatus: + format: string + type: string + http2Error: + format: string + type: string + httpStatus: + description: HTTP status code to use to abort the Http + request. + format: int32 + type: integer + percentage: + description: Percentage of requests to be aborted with + the error code provided. + properties: + value: + format: double + type: number + type: object + type: object + delay: + oneOf: + - properties: + percent: {} + required: + - fixedDelay + - properties: + percent: {} + required: + - exponentialDelay + properties: + exponentialDelay: + type: string + fixedDelay: + description: Add a fixed delay before forwarding the request. + type: string + percent: + description: Percentage of requests on which the delay + will be injected (0-100). + format: int32 + type: integer + percentage: + description: Percentage of requests on which the delay + will be injected. + properties: + value: + format: double + type: number + type: object + type: object + type: object + headers: + properties: + request: + properties: + add: + additionalProperties: + format: string + type: string + type: object + remove: + items: + format: string + type: string + type: array + set: + additionalProperties: + format: string + type: string + type: object + type: object + response: + properties: + add: + additionalProperties: + format: string + type: string + type: object + remove: + items: + format: string + type: string + type: array + set: + additionalProperties: + format: string + type: string + type: object + type: object + type: object + match: + items: + properties: + authority: + oneOf: + - required: + - exact + - required: + - prefix + - required: + - regex + properties: + exact: + format: string + type: string + prefix: + format: string + type: string + regex: + format: string + type: string + type: object + gateways: + description: Names of gateways where the rule should be + applied. + items: + format: string + type: string + type: array + headers: + additionalProperties: + oneOf: + - required: + - exact + - required: + - prefix + - required: + - regex + properties: + exact: + format: string + type: string + prefix: + format: string + type: string + regex: + format: string + type: string + type: object + type: object + ignoreUriCase: + description: Flag to specify whether the URI matching should + be case-insensitive. + type: boolean + method: + oneOf: + - required: + - exact + - required: + - prefix + - required: + - regex + properties: + exact: + format: string + type: string + prefix: + format: string + type: string + regex: + format: string + type: string + type: object + name: + description: The name assigned to a match. + format: string + type: string + port: + description: Specifies the ports on the host that is being + addressed. + type: integer + queryParams: + additionalProperties: + oneOf: + - required: + - exact + - required: + - prefix + - required: + - regex + properties: + exact: + format: string + type: string + prefix: + format: string + type: string + regex: + format: string + type: string + type: object + description: Query parameters for matching. + type: object + scheme: + oneOf: + - required: + - exact + - required: + - prefix + - required: + - regex + properties: + exact: + format: string + type: string + prefix: + format: string + type: string + regex: + format: string + type: string + type: object + sourceLabels: + additionalProperties: + format: string + type: string + type: object + uri: + oneOf: + - required: + - exact + - required: + - prefix + - required: + - regex + properties: + exact: + format: string + type: string + prefix: + format: string + type: string + regex: + format: string + type: string + type: object + type: object + type: array + mirror: + properties: + host: + description: The name of a service from the service registry. + format: string + type: string + port: + description: Specifies the port on the host that is being + addressed. + properties: + number: + type: integer + type: object + subset: + description: The name of a subset within the service. + format: string + type: string + type: object + mirror_percent: + description: Percentage of the traffic to be mirrored by the `mirror` + field. + type: integer + mirrorPercent: + description: Percentage of the traffic to be mirrored by the `mirror` + field. + type: integer + mirrorPercentage: + description: Percentage of the traffic to be mirrored by the `mirror` + field. + properties: + value: + format: double + type: number + type: object + name: + description: The name assigned to the route for debugging purposes. + format: string + type: string + redirect: + description: A HTTP rule can either redirect or forward (default) + traffic. + properties: + authority: + format: string + type: string + redirectCode: + type: integer + uri: + format: string + type: string + type: object + retries: + description: Retry policy for HTTP requests. + properties: + attempts: + description: Number of retries for a given request. + format: int32 + type: integer + perTryTimeout: + description: Timeout per retry attempt for a given request. + type: string + retryOn: + description: Specifies the conditions under which retry takes + place. + format: string + type: string + type: object + rewrite: + description: Rewrite HTTP URIs and Authority headers. + properties: + authority: + description: rewrite the Authority/Host header with this value. + format: string + type: string + uri: + format: string + type: string + type: object + route: + description: A HTTP rule can either redirect or forward (default) + traffic. + items: + properties: + destination: + properties: + host: + description: The name of a service from the service + registry. + format: string + type: string + port: + description: Specifies the port on the host that is + being addressed. + properties: + number: + type: integer + type: object + subset: + description: The name of a subset within the service. + format: string + type: string + type: object + headers: + properties: + request: + properties: + add: + additionalProperties: + format: string + type: string + type: object + remove: + items: + format: string + type: string + type: array + set: + additionalProperties: + format: string + type: string + type: object + type: object + response: + properties: + add: + additionalProperties: + format: string + type: string + type: object + remove: + items: + format: string + type: string + type: array + set: + additionalProperties: + format: string + type: string + type: object + type: object + type: object + weight: + format: int32 + type: integer + type: object + type: array + timeout: + description: Timeout for HTTP requests. + type: string + type: object + type: array + tcp: + description: An ordered list of route rules for opaque TCP traffic. + items: + properties: + match: + items: + properties: + destinationSubnets: + description: IPv4 or IPv6 ip addresses of destination with + optional subnet. + items: + format: string + type: string + type: array + gateways: + description: Names of gateways where the rule should be + applied. + items: + format: string + type: string + type: array + port: + description: Specifies the port on the host that is being + addressed. + type: integer + sourceLabels: + additionalProperties: + format: string + type: string + type: object + sourceSubnet: + description: IPv4 or IPv6 ip address of source with optional + subnet. + format: string + type: string + type: object + type: array + route: + description: The destination to which the connection should be + forwarded to. + items: + properties: + destination: + properties: + host: + description: The name of a service from the service + registry. + format: string + type: string + port: + description: Specifies the port on the host that is + being addressed. + properties: + number: + type: integer + type: object + subset: + description: The name of a subset within the service. + format: string + type: string + type: object + weight: + format: int32 + type: integer + type: object + type: array + type: object + type: array + tls: + items: + properties: + match: + items: + properties: + destinationSubnets: + description: IPv4 or IPv6 ip addresses of destination with + optional subnet. + items: + format: string + type: string + type: array + gateways: + description: Names of gateways where the rule should be + applied. + items: + format: string + type: string + type: array + port: + description: Specifies the port on the host that is being + addressed. + type: integer + sniHosts: + description: SNI (server name indicator) to match on. + items: + format: string + type: string + type: array + sourceLabels: + additionalProperties: + format: string + type: string + type: object + type: object + type: array + route: + description: The destination to which the connection should be + forwarded to. + items: + properties: + destination: + properties: + host: + description: The name of a service from the service + registry. + format: string + type: string + port: + description: Specifies the port on the host that is + being addressed. + properties: + number: + type: integer + type: object + subset: + description: The name of a subset within the service. + format: string + type: string + type: object + weight: + format: int32 + type: integer + type: object + type: array + type: object + type: array + type: object + type: object + versions: + - name: v1alpha3 + served: true + storage: true + - name: v1beta1 + served: true + storage: false + +--- +apiVersion: apiextensions.k8s.io/v1beta1 +kind: CustomResourceDefinition +metadata: + annotations: + "helm.sh/resource-policy": keep + labels: + app: mixer + chart: istio + heritage: Tiller + istio: core + package: istio.io.mixer + release: istio + name: attributemanifests.config.istio.io +spec: + group: config.istio.io + names: + categories: + - istio-io + - policy-istio-io + kind: attributemanifest + listKind: attributemanifestList + plural: attributemanifests + singular: attributemanifest + scope: Namespaced + subresources: + status: {} + validation: + openAPIV3Schema: + properties: + spec: + description: 'Describes the rules used to configure Mixer''s policy and + telemetry features. See more details at: https://istio.io/docs/reference/config/policy-and-telemetry/istio.policy.v1beta1.html' + properties: + attributes: + additionalProperties: + properties: + description: + description: A human-readable description of the attribute's purpose. + format: string + type: string + valueType: + description: The type of data carried by this attribute. + enum: + - VALUE_TYPE_UNSPECIFIED + - STRING + - INT64 + - DOUBLE + - BOOL + - TIMESTAMP + - IP_ADDRESS + - EMAIL_ADDRESS + - URI + - DNS_NAME + - DURATION + - STRING_MAP + type: string + type: object + description: The set of attributes this Istio component will be responsible + for producing at runtime. + type: object + name: + description: Name of the component producing these attributes. + format: string + type: string + revision: + description: The revision of this document. + format: string + type: string + type: object + type: object + versions: + - name: v1alpha2 + served: true + storage: true + +--- +apiVersion: apiextensions.k8s.io/v1beta1 +kind: CustomResourceDefinition +metadata: + annotations: + "helm.sh/resource-policy": keep + labels: + app: mixer + chart: istio + heritage: Tiller + istio: mixer-handler + package: handler + release: istio + name: handlers.config.istio.io +spec: + group: config.istio.io + names: + categories: + - istio-io + - policy-istio-io + kind: handler + listKind: handlerList + plural: handlers + singular: handler + scope: Namespaced + subresources: + status: {} + validation: + openAPIV3Schema: + properties: + spec: + description: Handler allows the operator to configure a specific adapter + implementation. + properties: + adapter: + description: The name of a specific adapter implementation. + format: string + type: string + compiledAdapter: + description: The name of the compiled in adapter this handler instantiates. + format: string + type: string + connection: + description: Information on how to connect to the out-of-process adapter. + properties: + address: + description: The address of the backend. + format: string + type: string + authentication: + description: Auth config for the connection to the backend. + oneOf: + - properties: + tls: + allOf: + - oneOf: + - required: + - tokenPath + - required: + - oauth + - oneOf: + - required: + - authHeader + - required: + - customHeader + required: + - tls + - required: + - mutual + properties: + mutual: + properties: + caCertificates: + format: string + type: string + clientCertificate: + description: The path to the file holding client certificate + for mutual TLS. + format: string + type: string + privateKey: + description: The path to the file holding the private key + for mutual TLS. + format: string + type: string + serverName: + description: Used to configure mixer mutual TLS client to + supply server name for SNI. + format: string + type: string + type: object + tls: + properties: + authHeader: + description: Access token is passed as authorization header. + enum: + - PLAIN + - BEARER + type: string + caCertificates: + format: string + type: string + customHeader: + description: Customized header key to hold access token, + e.g. + format: string + type: string + oauth: + description: Oauth config to fetch access token from auth + provider. + properties: + clientId: + description: OAuth client id for mixer. + format: string + type: string + clientSecret: + description: The path to the file holding the client + secret for oauth. + format: string + type: string + endpointParams: + additionalProperties: + format: string + type: string + description: Additional parameters for requests to the + token endpoint. + type: object + scopes: + description: List of requested permissions. + items: + format: string + type: string + type: array + tokenUrl: + description: The Resource server's token endpoint URL. + format: string + type: string + type: object + serverName: + format: string + type: string + tokenPath: + format: string + type: string + type: object + type: object + timeout: + description: Timeout for remote calls to the backend. + type: string + type: object + name: + description: Must be unique in the entire Mixer configuration. + format: string + type: string + params: + description: Depends on adapter implementation. + type: object + type: object + type: object + versions: + - name: v1alpha2 + served: true + storage: true + +--- +apiVersion: apiextensions.k8s.io/v1beta1 +kind: CustomResourceDefinition +metadata: + annotations: + "helm.sh/resource-policy": keep + labels: + app: mixer + chart: istio + heritage: Tiller + istio: mixer-instance + package: instance + release: istio + name: instances.config.istio.io +spec: + group: config.istio.io + names: + categories: + - istio-io + - policy-istio-io + kind: instance + listKind: instanceList + plural: instances + singular: instance + scope: Namespaced + subresources: + status: {} + validation: + openAPIV3Schema: + properties: + spec: + description: An Instance tells Mixer how to create instances for particular + template. + properties: + attributeBindings: + additionalProperties: + format: string + type: string + type: object + compiledTemplate: + description: The name of the compiled in template this instance creates + instances for. + format: string + type: string + name: + format: string + type: string + params: + description: Depends on referenced template. + type: object + template: + description: The name of the template this instance creates instances + for. + format: string + type: string + type: object + type: object + versions: + - name: v1alpha2 + served: true + storage: true + +--- +apiVersion: apiextensions.k8s.io/v1beta1 +kind: CustomResourceDefinition +metadata: + annotations: + "helm.sh/resource-policy": keep + labels: + app: mixer + chart: istio + heritage: Tiller + istio: core + package: istio.io.mixer + release: istio + name: rules.config.istio.io +spec: + group: config.istio.io + names: + categories: + - istio-io + - policy-istio-io + kind: rule + listKind: ruleList + plural: rules + singular: rule + scope: Namespaced + subresources: + status: {} + validation: + openAPIV3Schema: + properties: + spec: + description: 'Describes the rules used to configure Mixer''s policy and + telemetry features. See more details at: https://istio.io/docs/reference/config/policy-and-telemetry/istio.policy.v1beta1.html' + properties: + actions: + description: The actions that will be executed when match evaluates + to `true`. + items: + properties: + handler: + description: Fully qualified name of the handler to invoke. + format: string + type: string + instances: + items: + format: string + type: string + type: array + name: + description: A handle to refer to the results of the action. + format: string + type: string + type: object + type: array + match: + description: Match is an attribute based predicate. + format: string + type: string + requestHeaderOperations: + items: + properties: + name: + description: Header name literal value. + format: string + type: string + operation: + description: Header operation type. + enum: + - REPLACE + - REMOVE + - APPEND + type: string + values: + description: Header value expressions. + items: + format: string + type: string + type: array + type: object + type: array + responseHeaderOperations: + items: + properties: + name: + description: Header name literal value. + format: string + type: string + operation: + description: Header operation type. + enum: + - REPLACE + - REMOVE + - APPEND + type: string + values: + description: Header value expressions. + items: + format: string + type: string + type: array + type: object + type: array + sampling: + properties: + random: + description: Provides filtering of actions based on random selection + per request. + properties: + attributeExpression: + description: Specifies an attribute expression to use to override + the numerator in the `percent_sampled` field. + format: string + type: string + percentSampled: + description: The default sampling rate, expressed as a percentage. + properties: + denominator: + description: Specifies the denominator. + enum: + - HUNDRED + - TEN_THOUSAND + type: string + numerator: + description: Specifies the numerator. + type: integer + type: object + useIndependentRandomness: + description: By default sampling will be based on the value + of the request header `x-request-id`. + type: boolean + type: object + rateLimit: + properties: + maxUnsampledEntries: + description: Number of entries to allow during the `sampling_duration` + before sampling is enforced. + format: int64 + type: integer + samplingDuration: + description: Window in which to enforce the sampling rate. + type: string + samplingRate: + description: The rate at which to sample entries once the unsampled + limit has been reached. + format: int64 + type: integer + type: object + type: object + type: object + type: object + versions: + - name: v1alpha2 + served: true + storage: true + +--- +apiVersion: apiextensions.k8s.io/v1beta1 +kind: CustomResourceDefinition +metadata: + annotations: + "helm.sh/resource-policy": keep + labels: + app: istio-pilot + chart: istio + heritage: Tiller + istio: rbac + release: istio + name: clusterrbacconfigs.rbac.istio.io +spec: + group: rbac.istio.io + names: + categories: + - istio-io + - rbac-istio-io + kind: ClusterRbacConfig + listKind: ClusterRbacConfigList + plural: clusterrbacconfigs + singular: clusterrbacconfig + scope: Cluster + subresources: + status: {} + validation: + openAPIV3Schema: + properties: + spec: + description: 'Configuration for Role Based Access Control. See more details + at: https://istio.io/docs/reference/config/security/istio.rbac.v1alpha1.html' + properties: + enforcementMode: + enum: + - ENFORCED + - PERMISSIVE + type: string + exclusion: + description: A list of services or namespaces that should not be enforced + by Istio RBAC policies. + properties: + namespaces: + description: A list of namespaces. + items: + format: string + type: string + type: array + services: + description: A list of services. + items: + format: string + type: string + type: array + type: object + inclusion: + description: A list of services or namespaces that should be enforced + by Istio RBAC policies. + properties: + namespaces: + description: A list of namespaces. + items: + format: string + type: string + type: array + services: + description: A list of services. + items: + format: string + type: string + type: array + type: object + mode: + description: Istio RBAC mode. + enum: + - "OFF" + - "ON" + - ON_WITH_INCLUSION + - ON_WITH_EXCLUSION + type: string + type: object + type: object + versions: + - name: v1alpha1 + served: true + storage: true + +--- +apiVersion: apiextensions.k8s.io/v1beta1 +kind: CustomResourceDefinition +metadata: + annotations: + "helm.sh/resource-policy": keep + labels: + app: mixer + chart: istio + heritage: Tiller + istio: rbac + package: istio.io.mixer + release: istio + name: rbacconfigs.rbac.istio.io +spec: + group: rbac.istio.io + names: + categories: + - istio-io + - rbac-istio-io + kind: RbacConfig + listKind: RbacConfigList + plural: rbacconfigs + singular: rbacconfig + scope: Namespaced + subresources: + status: {} + validation: + openAPIV3Schema: + properties: + spec: + description: 'Configuration for Role Based Access Control. See more details + at: https://istio.io/docs/reference/config/security/istio.rbac.v1alpha1.html' + properties: + enforcementMode: + enum: + - ENFORCED + - PERMISSIVE + type: string + exclusion: + description: A list of services or namespaces that should not be enforced + by Istio RBAC policies. + properties: + namespaces: + description: A list of namespaces. + items: + format: string + type: string + type: array + services: + description: A list of services. + items: + format: string + type: string + type: array + type: object + inclusion: + description: A list of services or namespaces that should be enforced + by Istio RBAC policies. + properties: + namespaces: + description: A list of namespaces. + items: + format: string + type: string + type: array + services: + description: A list of services. + items: + format: string + type: string + type: array + type: object + mode: + description: Istio RBAC mode. + enum: + - "OFF" + - "ON" + - ON_WITH_INCLUSION + - ON_WITH_EXCLUSION + type: string + type: object + type: object + versions: + - name: v1alpha1 + served: true + storage: true + +--- +apiVersion: apiextensions.k8s.io/v1beta1 +kind: CustomResourceDefinition +metadata: + annotations: + "helm.sh/resource-policy": keep + labels: + app: mixer + chart: istio + heritage: Tiller + istio: rbac + package: istio.io.mixer + release: istio + name: serviceroles.rbac.istio.io +spec: + group: rbac.istio.io + names: + categories: + - istio-io + - rbac-istio-io + kind: ServiceRole + listKind: ServiceRoleList + plural: serviceroles + singular: servicerole + scope: Namespaced + subresources: + status: {} + validation: + openAPIV3Schema: + properties: + spec: + description: 'Configuration for Role Based Access Control. See more details + at: https://istio.io/docs/reference/config/security/istio.rbac.v1alpha1.html' + properties: + rules: + description: The set of access rules (permissions) that the role has. + items: + properties: + constraints: + description: Optional. + items: + properties: + key: + description: Key of the constraint. + format: string + type: string + values: + description: List of valid values for the constraint. + items: + format: string + type: string + type: array + type: object + type: array + hosts: + items: + format: string + type: string + type: array + methods: + description: Optional. + items: + format: string + type: string + type: array + notHosts: + items: + format: string + type: string + type: array + notMethods: + items: + format: string + type: string + type: array + notPaths: + items: + format: string + type: string + type: array + notPorts: + items: + format: int32 + type: integer + type: array + paths: + description: Optional. + items: + format: string + type: string + type: array + ports: + items: + format: int32 + type: integer + type: array + services: + description: A list of service names. + items: + format: string + type: string + type: array + type: object + type: array + type: object + type: object + versions: + - name: v1alpha1 + served: true + storage: true + +--- +apiVersion: apiextensions.k8s.io/v1beta1 +kind: CustomResourceDefinition +metadata: + annotations: + "helm.sh/resource-policy": keep + labels: + app: mixer + chart: istio + heritage: Tiller + istio: rbac + package: istio.io.mixer + release: istio + name: servicerolebindings.rbac.istio.io +spec: + additionalPrinterColumns: + - JSONPath: .spec.roleRef.name + description: The name of the ServiceRole object being referenced + name: Reference + type: string + - JSONPath: .metadata.creationTimestamp + description: 'CreationTimestamp is a timestamp representing the server time when + this object was created. It is not guaranteed to be set in happens-before order + across separate operations. Clients may not set this value. It is represented + in RFC3339 form and is in UTC. Populated by the system. Read-only. Null for + lists. More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#metadata' + name: Age + type: date + group: rbac.istio.io + names: + categories: + - istio-io + - rbac-istio-io + kind: ServiceRoleBinding + listKind: ServiceRoleBindingList + plural: servicerolebindings + singular: servicerolebinding + scope: Namespaced + subresources: + status: {} + validation: + openAPIV3Schema: + properties: + spec: + description: 'Configuration for Role Based Access Control. See more details + at: https://istio.io/docs/reference/config/security/istio.rbac.v1alpha1.html' + properties: + actions: + items: + properties: + constraints: + description: Optional. + items: + properties: + key: + description: Key of the constraint. + format: string + type: string + values: + description: List of valid values for the constraint. + items: + format: string + type: string + type: array + type: object + type: array + hosts: + items: + format: string + type: string + type: array + methods: + description: Optional. + items: + format: string + type: string + type: array + notHosts: + items: + format: string + type: string + type: array + notMethods: + items: + format: string + type: string + type: array + notPaths: + items: + format: string + type: string + type: array + notPorts: + items: + format: int32 + type: integer + type: array + paths: + description: Optional. + items: + format: string + type: string + type: array + ports: + items: + format: int32 + type: integer + type: array + services: + description: A list of service names. + items: + format: string + type: string + type: array + type: object + type: array + mode: + enum: + - ENFORCED + - PERMISSIVE + type: string + role: + format: string + type: string + roleRef: + description: Reference to the ServiceRole object. + properties: + kind: + description: The type of the role being referenced. + format: string + type: string + name: + description: The name of the ServiceRole object being referenced. + format: string + type: string + type: object + subjects: + description: List of subjects that are assigned the ServiceRole object. + items: + properties: + group: + format: string + type: string + groups: + items: + format: string + type: string + type: array + ips: + items: + format: string + type: string + type: array + names: + items: + format: string + type: string + type: array + namespaces: + items: + format: string + type: string + type: array + notGroups: + items: + format: string + type: string + type: array + notIps: + items: + format: string + type: string + type: array + notNames: + items: + format: string + type: string + type: array + notNamespaces: + items: + format: string + type: string + type: array + properties: + additionalProperties: + format: string + type: string + description: Optional. + type: object + user: + description: Optional. + format: string + type: string + type: object + type: array + type: object + type: object + versions: + - name: v1alpha1 + served: true + storage: true + +--- +apiVersion: apiextensions.k8s.io/v1beta1 +kind: CustomResourceDefinition +metadata: + annotations: + "helm.sh/resource-policy": keep + labels: + app: istio-pilot + chart: istio + heritage: Tiller + istio: security + release: istio + name: authorizationpolicies.security.istio.io +spec: + group: security.istio.io + names: + categories: + - istio-io + - security-istio-io + kind: AuthorizationPolicy + listKind: AuthorizationPolicyList + plural: authorizationpolicies + singular: authorizationpolicy + scope: Namespaced + subresources: + status: {} + validation: + openAPIV3Schema: + properties: + spec: + description: 'Configuration for access control on workloads. See more details + at: https://istio.io/docs/reference/config/security/authorization-policy.html' + properties: + action: + description: Optional. + enum: + - ALLOW + - DENY + type: string + rules: + description: Optional. + items: + properties: + from: + description: Optional. + items: + properties: + source: + description: Source specifies the source of a request. + properties: + ipBlocks: + description: Optional. + items: + format: string + type: string + type: array + namespaces: + description: Optional. + items: + format: string + type: string + type: array + notIpBlocks: + description: Optional. + items: + format: string + type: string + type: array + notNamespaces: + description: Optional. + items: + format: string + type: string + type: array + notPrincipals: + description: Optional. + items: + format: string + type: string + type: array + notRequestPrincipals: + description: Optional. + items: + format: string + type: string + type: array + principals: + description: Optional. + items: + format: string + type: string + type: array + requestPrincipals: + description: Optional. + items: + format: string + type: string + type: array + type: object + type: object + type: array + to: + description: Optional. + items: + properties: + operation: + description: Operation specifies the operation of a request. + properties: + hosts: + description: Optional. + items: + format: string + type: string + type: array + methods: + description: Optional. + items: + format: string + type: string + type: array + notHosts: + description: Optional. + items: + format: string + type: string + type: array + notMethods: + description: Optional. + items: + format: string + type: string + type: array + notPaths: + description: Optional. + items: + format: string + type: string + type: array + notPorts: + description: Optional. + items: + format: string + type: string + type: array + paths: + description: Optional. + items: + format: string + type: string + type: array + ports: + description: Optional. + items: + format: string + type: string + type: array + type: object + type: object + type: array + when: + description: Optional. + items: + properties: + key: + description: The name of an Istio attribute. + format: string + type: string + notValues: + description: Optional. + items: + format: string + type: string + type: array + values: + description: Optional. + items: + format: string + type: string + type: array + type: object + type: array + type: object + type: array + selector: + description: Optional. + properties: + matchLabels: + additionalProperties: + format: string + type: string + type: object + type: object + type: object + type: object + versions: + - name: v1beta1 + served: true + storage: true + +--- +apiVersion: apiextensions.k8s.io/v1beta1 +kind: CustomResourceDefinition +metadata: + annotations: + "helm.sh/resource-policy": keep + labels: + app: istio-pilot + chart: istio + heritage: Tiller + istio: security + release: istio + name: peerauthentications.security.istio.io +spec: + group: security.istio.io + names: + categories: + - istio-io + - security-istio-io + kind: PeerAuthentication + listKind: PeerAuthenticationList + plural: peerauthentications + singular: peerauthentication + scope: Namespaced + subresources: + status: {} + validation: + openAPIV3Schema: + properties: + spec: + description: PeerAuthentication defines how traffic will be tunneled (or + not) to the sidecar. + properties: + mtls: + description: Mutual TLS settings for workload. + properties: + mode: + description: Defines the mTLS mode used for peer authentication. + enum: + - UNSET + - DISABLE + - PERMISSIVE + - STRICT + type: string + type: object + portLevelMtls: + additionalProperties: + properties: + mode: + description: Defines the mTLS mode used for peer authentication. + enum: + - UNSET + - DISABLE + - PERMISSIVE + - STRICT + type: string + type: object + description: Port specific mutual TLS settings. + type: object + selector: + description: The selector determines the workloads to apply the ChannelAuthentication + on. + properties: + matchLabels: + additionalProperties: + format: string + type: string + type: object + type: object + type: object + type: object + versions: + - name: v1beta1 + served: true + storage: true + +--- +apiVersion: apiextensions.k8s.io/v1beta1 +kind: CustomResourceDefinition +metadata: + annotations: + "helm.sh/resource-policy": keep + labels: + app: istio-pilot + chart: istio + heritage: Tiller + istio: security + release: istio + name: requestauthentications.security.istio.io +spec: + group: security.istio.io + names: + categories: + - istio-io + - security-istio-io + kind: RequestAuthentication + listKind: RequestAuthenticationList + plural: requestauthentications + singular: requestauthentication + scope: Namespaced + subresources: + status: {} + validation: + openAPIV3Schema: + properties: + spec: + description: RequestAuthentication defines what request authentication methods + are supported by a workload. + properties: + jwtRules: + description: Define the list of JWTs that can be validated at the selected + workloads' proxy. + items: + properties: + audiences: + items: + format: string + type: string + type: array + forwardOriginalToken: + description: If set to true, the orginal token will be kept for + the ustream request. + type: boolean + fromHeaders: + description: List of header locations from which JWT is expected. + items: + properties: + name: + description: The HTTP header name. + format: string + type: string + prefix: + description: The prefix that should be stripped before decoding + the token. + format: string + type: string + type: object + type: array + fromParams: + description: List of query parameters from which JWT is expected. + items: + format: string + type: string + type: array + issuer: + description: Identifies the issuer that issued the JWT. + format: string + type: string + jwks: + description: JSON Web Key Set of public keys to validate signature + of the JWT. + format: string + type: string + jwks_uri: + format: string + type: string + jwksUri: + format: string + type: string + outputPayloadToHeader: + format: string + type: string + type: object + type: array + selector: + description: The selector determines the workloads to apply the RequestAuthentication + on. + properties: + matchLabels: + additionalProperties: + format: string + type: string + type: object + type: object + type: object + type: object + versions: + - name: v1beta1 + served: true + storage: true + +--- diff --git a/istio-1.5.0/install/kubernetes/helm/istio-init/files/crd-certmanager-10.yaml b/istio-1.5.0/install/kubernetes/helm/istio-init/files/crd-certmanager-10.yaml new file mode 100644 index 0000000..d3a3069 --- /dev/null +++ b/istio-1.5.0/install/kubernetes/helm/istio-init/files/crd-certmanager-10.yaml @@ -0,0 +1,91 @@ +apiVersion: apiextensions.k8s.io/v1beta1 +kind: CustomResourceDefinition +metadata: + name: clusterissuers.certmanager.k8s.io + labels: + app: certmanager + chart: certmanager + heritage: Tiller + release: istio + annotations: + "helm.sh/resource-policy": keep +spec: + group: certmanager.k8s.io + versions: + - name: v1alpha1 + served: true + storage: true + names: + kind: ClusterIssuer + plural: clusterissuers + scope: Cluster +--- +apiVersion: apiextensions.k8s.io/v1beta1 +kind: CustomResourceDefinition +metadata: + name: issuers.certmanager.k8s.io + labels: + app: certmanager + chart: certmanager + heritage: Tiller + release: istio + annotations: + "helm.sh/resource-policy": keep +spec: + group: certmanager.k8s.io + versions: + - name: v1alpha1 + served: true + storage: true + names: + kind: Issuer + plural: issuers + scope: Namespaced +--- +apiVersion: apiextensions.k8s.io/v1beta1 +kind: CustomResourceDefinition +metadata: + name: certificates.certmanager.k8s.io + labels: + app: certmanager + chart: certmanager + heritage: Tiller + release: istio + annotations: + "helm.sh/resource-policy": keep +spec: + additionalPrinterColumns: + - JSONPath: .status.conditions[?(@.type=="Ready")].status + name: Ready + type: string + - JSONPath: .spec.secretName + name: Secret + type: string + - JSONPath: .spec.issuerRef.name + name: Issuer + type: string + priority: 1 + - JSONPath: .status.conditions[?(@.type=="Ready")].message + name: Status + type: string + priority: 1 + - JSONPath: .metadata.creationTimestamp + description: |- + CreationTimestamp is a timestamp representing the server time when this object was created. It is not guaranteed to be set in happens-before order across separate operations. Clients may not set this value. It is represented in RFC3339 form and is in UTC. + + Populated by the system. Read-only. Null for lists. More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#metadata + name: Age + type: date + group: certmanager.k8s.io + versions: + - name: v1alpha1 + served: true + storage: true + scope: Namespaced + names: + kind: Certificate + plural: certificates + shortNames: + - cert + - certs +--- diff --git a/istio-1.5.0/install/kubernetes/helm/istio-init/files/crd-certmanager-11.yaml b/istio-1.5.0/install/kubernetes/helm/istio-init/files/crd-certmanager-11.yaml new file mode 100644 index 0000000..f63787b --- /dev/null +++ b/istio-1.5.0/install/kubernetes/helm/istio-init/files/crd-certmanager-11.yaml @@ -0,0 +1,80 @@ +apiVersion: apiextensions.k8s.io/v1beta1 +kind: CustomResourceDefinition +metadata: + name: orders.certmanager.k8s.io + labels: + app: certmanager + chart: certmanager + heritage: Tiller + release: istio + annotations: + "helm.sh/resource-policy": keep +spec: + additionalPrinterColumns: + - JSONPath: .status.state + name: State + type: string + - JSONPath: .spec.issuerRef.name + name: Issuer + type: string + priority: 1 + - JSONPath: .status.reason + name: Reason + type: string + priority: 1 + - JSONPath: .metadata.creationTimestamp + description: |- + CreationTimestamp is a timestamp representing the server time when this object was created. It is not guaranteed to be set in happens-before order across separate operations. Clients may not set this value. It is represented in RFC3339 form and is in UTC. + + Populated by the system. Read-only. Null for lists. More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#metadata + name: Age + type: date + group: certmanager.k8s.io + versions: + - name: v1alpha1 + served: true + storage: true + names: + kind: Order + plural: orders + scope: Namespaced +--- +apiVersion: apiextensions.k8s.io/v1beta1 +kind: CustomResourceDefinition +metadata: + name: challenges.certmanager.k8s.io + labels: + app: certmanager + chart: certmanager + heritage: Tiller + release: istio + annotations: + "helm.sh/resource-policy": keep +spec: + additionalPrinterColumns: + - JSONPath: .status.state + name: State + type: string + - JSONPath: .spec.dnsName + name: Domain + type: string + - JSONPath: .status.reason + name: Reason + type: string + - JSONPath: .metadata.creationTimestamp + description: |- + CreationTimestamp is a timestamp representing the server time when this object was created. It is not guaranteed to be set in happens-before order across separate operations. Clients may not set this value. It is represented in RFC3339 form and is in UTC. + + Populated by the system. Read-only. Null for lists. More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#metadata + name: Age + type: date + group: certmanager.k8s.io + versions: + - name: v1alpha1 + served: true + storage: true + names: + kind: Challenge + plural: challenges + scope: Namespaced +--- diff --git a/istio-1.5.0/install/kubernetes/helm/istio-init/files/crd-mixer.yaml b/istio-1.5.0/install/kubernetes/helm/istio-init/files/crd-mixer.yaml new file mode 100644 index 0000000..021382b --- /dev/null +++ b/istio-1.5.0/install/kubernetes/helm/istio-init/files/crd-mixer.yaml @@ -0,0 +1,59 @@ +kind: CustomResourceDefinition +apiVersion: apiextensions.k8s.io/v1beta1 +metadata: + name: adapters.config.istio.io + labels: + app: mixer + package: adapter + istio: mixer-adapter + chart: istio + heritage: Tiller + release: istio + annotations: + "helm.sh/resource-policy": keep +spec: + group: config.istio.io + names: + kind: adapter + plural: adapters + singular: adapter + categories: + - istio-io + - policy-istio-io + scope: Namespaced + subresources: + status: {} + versions: + - name: v1alpha2 + served: true + storage: true +--- +kind: CustomResourceDefinition +apiVersion: apiextensions.k8s.io/v1beta1 +metadata: + name: templates.config.istio.io + labels: + app: mixer + package: template + istio: mixer-template + chart: istio + heritage: Tiller + release: istio + annotations: + "helm.sh/resource-policy": keep +spec: + group: config.istio.io + names: + kind: template + plural: templates + singular: template + categories: + - istio-io + - policy-istio-io + scope: Namespaced + subresources: + status: {} + versions: + - name: v1alpha2 + served: true + storage: true diff --git a/istio-1.5.0/install/kubernetes/helm/istio-init/templates/clusterrole.yaml b/istio-1.5.0/install/kubernetes/helm/istio-init/templates/clusterrole.yaml new file mode 100644 index 0000000..0b7c50f --- /dev/null +++ b/istio-1.5.0/install/kubernetes/helm/istio-init/templates/clusterrole.yaml @@ -0,0 +1,11 @@ +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: istio-init-{{ .Release.Namespace }} + labels: + app: istio-init + istio: init +rules: +- apiGroups: ["apiextensions.k8s.io"] + resources: ["customresourcedefinitions"] + verbs: ["create", "get", "list", "watch", "patch"] diff --git a/istio-1.5.0/install/kubernetes/helm/istio-init/templates/clusterrolebinding.yaml b/istio-1.5.0/install/kubernetes/helm/istio-init/templates/clusterrolebinding.yaml new file mode 100644 index 0000000..481674c --- /dev/null +++ b/istio-1.5.0/install/kubernetes/helm/istio-init/templates/clusterrolebinding.yaml @@ -0,0 +1,15 @@ +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: istio-init-admin-role-binding-{{ .Release.Namespace }} + labels: + app: istio-init + istio: init +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: istio-init-{{ .Release.Namespace }} +subjects: + - kind: ServiceAccount + name: istio-init-service-account + namespace: {{ .Release.Namespace }} diff --git a/istio-1.5.0/install/kubernetes/helm/istio-init/templates/configmap-crd-all.yaml b/istio-1.5.0/install/kubernetes/helm/istio-init/templates/configmap-crd-all.yaml new file mode 100644 index 0000000..7ab00d8 --- /dev/null +++ b/istio-1.5.0/install/kubernetes/helm/istio-init/templates/configmap-crd-all.yaml @@ -0,0 +1,8 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + namespace: {{ .Release.Namespace }} + name: istio-crd-all +data: + crd-all.gen.yaml: |- +{{.Files.Get "files/crd-all.gen.yaml" | printf "%s" | indent 4}} diff --git a/istio-1.5.0/install/kubernetes/helm/istio-init/templates/configmap-crd-certmanager-10.yaml b/istio-1.5.0/install/kubernetes/helm/istio-init/templates/configmap-crd-certmanager-10.yaml new file mode 100644 index 0000000..8ab3e83 --- /dev/null +++ b/istio-1.5.0/install/kubernetes/helm/istio-init/templates/configmap-crd-certmanager-10.yaml @@ -0,0 +1,10 @@ +{{- if .Values.certmanager.enabled }} +apiVersion: v1 +kind: ConfigMap +metadata: + namespace: {{ .Release.Namespace }} + name: istio-crd-certmanager-10 +data: + crd-certmanager-10.yaml: |- +{{.Files.Get "files/crd-certmanager-10.yaml" | printf "%s" | indent 4}} +{{- end }} diff --git a/istio-1.5.0/install/kubernetes/helm/istio-init/templates/configmap-crd-certmanager-11.yaml b/istio-1.5.0/install/kubernetes/helm/istio-init/templates/configmap-crd-certmanager-11.yaml new file mode 100644 index 0000000..beef304 --- /dev/null +++ b/istio-1.5.0/install/kubernetes/helm/istio-init/templates/configmap-crd-certmanager-11.yaml @@ -0,0 +1,10 @@ +{{- if .Values.certmanager.enabled }} +apiVersion: v1 +kind: ConfigMap +metadata: + namespace: {{ .Release.Namespace }} + name: istio-crd-certmanager-11 +data: + crd-certmanager-11.yaml: |- +{{.Files.Get "files/crd-certmanager-11.yaml" | printf "%s" | indent 4}} +{{- end }} diff --git a/istio-1.5.0/install/kubernetes/helm/istio-init/templates/configmap-crd-mixer.yaml b/istio-1.5.0/install/kubernetes/helm/istio-init/templates/configmap-crd-mixer.yaml new file mode 100644 index 0000000..651aec3 --- /dev/null +++ b/istio-1.5.0/install/kubernetes/helm/istio-init/templates/configmap-crd-mixer.yaml @@ -0,0 +1,8 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + namespace: {{ .Release.Namespace }} + name: istio-crd-mixer +data: + crd-mixer.yaml: |- +{{.Files.Get "files/crd-mixer.yaml" | printf "%s" | indent 4}} diff --git a/istio-1.5.0/install/kubernetes/helm/istio-init/templates/job-crd-all.yaml b/istio-1.5.0/install/kubernetes/helm/istio-init/templates/job-crd-all.yaml new file mode 100644 index 0000000..209ff40 --- /dev/null +++ b/istio-1.5.0/install/kubernetes/helm/istio-init/templates/job-crd-all.yaml @@ -0,0 +1,30 @@ +apiVersion: batch/v1 +kind: Job +metadata: + namespace: {{ .Release.Namespace }} + name: istio-init-crd-all-{{ .Values.global.tag | printf "%v" | trunc 32 | trimSuffix "-" }} +spec: + template: + metadata: + annotations: + sidecar.istio.io/inject: "false" + spec: + serviceAccountName: istio-init-service-account + containers: + - name: istio-init-crd-all + image: "{{ .Values.global.hub }}/kubectl:{{ .Values.global.tag }}" + imagePullPolicy: {{ .Values.global.imagePullPolicy }} +{{- if .Values.job.resources }} + resources: +{{ toYaml .Values.job.resources | indent 10 }} +{{- end }} + volumeMounts: + - name: crd-all + mountPath: /etc/istio/crd-all + readOnly: true + command: ["kubectl", "apply", "-f", "/etc/istio/crd-all/crd-all.gen.yaml"] + volumes: + - name: crd-all + configMap: + name: istio-crd-all + restartPolicy: OnFailure diff --git a/istio-1.5.0/install/kubernetes/helm/istio-init/templates/job-crd-certmanager-10.yaml b/istio-1.5.0/install/kubernetes/helm/istio-init/templates/job-crd-certmanager-10.yaml new file mode 100644 index 0000000..61e4cce --- /dev/null +++ b/istio-1.5.0/install/kubernetes/helm/istio-init/templates/job-crd-certmanager-10.yaml @@ -0,0 +1,32 @@ +{{- if .Values.certmanager.enabled }} +apiVersion: batch/v1 +kind: Job +metadata: + namespace: {{ .Release.Namespace }} + name: istio-init-crd-certmanager-10-{{ .Values.global.tag | printf "%v" | trunc 32 | trimSuffix "-" }} +spec: + template: + metadata: + annotations: + sidecar.istio.io/inject: "false" + spec: + serviceAccountName: istio-init-service-account + containers: + - name: istio-init-crd-certmanager-10 + image: "{{ .Values.global.hub }}/kubectl:{{ .Values.global.tag }}" + imagePullPolicy: {{ .Values.global.imagePullPolicy }} +{{- if .Values.job.resources }} + resources: +{{ toYaml .Values.job.resources | indent 10 }} +{{- end }} + volumeMounts: + - name: crd-certmanager-10 + mountPath: /etc/istio/crd-certmanager-10 + readOnly: true + command: ["kubectl", "apply", "-f", "/etc/istio/crd-certmanager-10/crd-certmanager-10.yaml"] + volumes: + - name: crd-certmanager-10 + configMap: + name: istio-crd-certmanager-10 + restartPolicy: OnFailure +{{- end }} diff --git a/istio-1.5.0/install/kubernetes/helm/istio-init/templates/job-crd-certmanager-11.yaml b/istio-1.5.0/install/kubernetes/helm/istio-init/templates/job-crd-certmanager-11.yaml new file mode 100644 index 0000000..5c80271 --- /dev/null +++ b/istio-1.5.0/install/kubernetes/helm/istio-init/templates/job-crd-certmanager-11.yaml @@ -0,0 +1,32 @@ +{{- if .Values.certmanager.enabled }} +apiVersion: batch/v1 +kind: Job +metadata: + namespace: {{ .Release.Namespace }} + name: istio-init-crd-certmanager-11-{{ .Values.global.tag | printf "%v" | trunc 32 | trimSuffix "-" }} +spec: + template: + metadata: + annotations: + sidecar.istio.io/inject: "false" + spec: + serviceAccountName: istio-init-service-account + containers: + - name: istio-init-crd-certmanager-11 + image: "{{ .Values.global.hub }}/kubectl:{{ .Values.global.tag }}" + imagePullPolicy: {{ .Values.global.imagePullPolicy }} +{{- if .Values.job.resources }} + resources: +{{ toYaml .Values.job.resources | indent 10 }} +{{- end }} + volumeMounts: + - name: crd-certmanager-11 + mountPath: /etc/istio/crd-certmanager-11 + readOnly: true + command: ["kubectl", "apply", "-f", "/etc/istio/crd-certmanager-11/crd-certmanager-11.yaml"] + volumes: + - name: crd-certmanager-11 + configMap: + name: istio-crd-certmanager-11 + restartPolicy: OnFailure +{{- end }} diff --git a/istio-1.5.0/install/kubernetes/helm/istio-init/templates/job-crd-mixer.yaml b/istio-1.5.0/install/kubernetes/helm/istio-init/templates/job-crd-mixer.yaml new file mode 100644 index 0000000..d1e9e6d --- /dev/null +++ b/istio-1.5.0/install/kubernetes/helm/istio-init/templates/job-crd-mixer.yaml @@ -0,0 +1,30 @@ +apiVersion: batch/v1 +kind: Job +metadata: + namespace: {{ .Release.Namespace }} + name: istio-init-crd-mixer-{{ .Values.global.tag | printf "%v" | trunc 32 | trimSuffix "-" }} +spec: + template: + metadata: + annotations: + sidecar.istio.io/inject: "false" + spec: + serviceAccountName: istio-init-service-account + containers: + - name: istio-init-crd-mixer + image: "{{ .Values.global.hub }}/kubectl:{{ .Values.global.tag }}" + imagePullPolicy: {{ .Values.global.imagePullPolicy }} +{{- if .Values.job.resources }} + resources: +{{ toYaml .Values.job.resources | indent 10 }} +{{- end }} + volumeMounts: + - name: crd-mixer + mountPath: /etc/istio/crd-mixer + readOnly: true + command: ["kubectl", "apply", "-f", "/etc/istio/crd-mixer/crd-mixer.yaml"] + volumes: + - name: crd-mixer + configMap: + name: istio-crd-mixer + restartPolicy: OnFailure diff --git a/istio-1.5.0/install/kubernetes/helm/istio-init/templates/serviceaccount.yaml b/istio-1.5.0/install/kubernetes/helm/istio-init/templates/serviceaccount.yaml new file mode 100644 index 0000000..3146662 --- /dev/null +++ b/istio-1.5.0/install/kubernetes/helm/istio-init/templates/serviceaccount.yaml @@ -0,0 +1,15 @@ +apiVersion: v1 +kind: ServiceAccount +{{- if .Values.global.imagePullSecrets }} +imagePullSecrets: +{{- range .Values.global.imagePullSecrets }} + - name: {{ . }} +{{- end }} +{{- end }} +metadata: + name: istio-init-service-account + namespace: {{ .Release.Namespace }} + labels: + app: istio-init + istio: init + diff --git a/istio-1.5.0/install/kubernetes/helm/istio-init/values.yaml b/istio-1.5.0/install/kubernetes/helm/istio-init/values.yaml new file mode 100644 index 0000000..5300109 --- /dev/null +++ b/istio-1.5.0/install/kubernetes/helm/istio-init/values.yaml @@ -0,0 +1,25 @@ +global: + # Default hub for Istio images. + # Releases are published to docker hub under 'istio' project. + # Dev builds from prow are on gcr.io + hub: docker.io/istio + + # Default tag for Istio images. + tag: 1.5.0 + + # imagePullPolicy is applied to istio control plane components. + # local tests require IfNotPresent, to avoid uploading to dockerhub. + # TODO: Switch to Always as default, and override in the local tests. + imagePullPolicy: IfNotPresent + +certmanager: + enabled: false + +job: + resources: + requests: + cpu: 10m + memory: 50Mi + limits: + cpu: 100m + memory: 200Mi diff --git a/istio-1.5.0/install/kubernetes/helm/istio/Chart.yaml b/istio-1.5.0/install/kubernetes/helm/istio/Chart.yaml new file mode 100644 index 0000000..26fc020 --- /dev/null +++ b/istio-1.5.0/install/kubernetes/helm/istio/Chart.yaml @@ -0,0 +1,17 @@ +apiVersion: v1 +name: istio +version: 1.5.0 +appVersion: 1.5.0 +tillerVersion: ">=2.7.2-0" +description: Helm chart for all istio components +keywords: + - istio + - security + - sidecarInjectorWebhook + - mixer + - pilot + - galley +sources: + - http://github.com/istio/istio +engine: gotpl +icon: https://istio.io/favicons/android-192x192.png diff --git a/istio-1.5.0/install/kubernetes/helm/istio/README.md b/istio-1.5.0/install/kubernetes/helm/istio/README.md new file mode 100644 index 0000000..f7f35cc --- /dev/null +++ b/istio-1.5.0/install/kubernetes/helm/istio/README.md @@ -0,0 +1,149 @@ +# Istio + +[Istio](https://istio.io/) is an open platform for providing a uniform way to integrate microservices, manage traffic flow across microservices, enforce policies and aggregate telemetry data. + +The documentation here is for developers only, please follow the installation instructions from [istio.io](https://istio.io/docs/setup/kubernetes/install/helm/) for all other uses. + +## Introduction + +This chart bootstraps all Istio [components](https://istio.io/docs/concepts/what-is-istio/) deployment on a [Kubernetes](http://kubernetes.io) cluster using the [Helm](https://helm.sh) package manager. + +## Chart Details + +This chart can install multiple Istio components as subcharts: +- ingressgateway +- egressgateway +- sidecarInjectorWebhook +- galley +- mixer +- pilot +- security(citadel) +- grafana +- prometheus +- tracing(jaeger) +- kiali + +To enable or disable each component, change the corresponding `enabled` flag. + +## Prerequisites + +- Kubernetes 1.9 or newer cluster with RBAC (Role-Based Access Control) enabled is required +- Helm 2.7.2 or newer or alternately the ability to modify RBAC rules is also required +- If you want to enable automatic sidecar injection, Kubernetes 1.9+ with `admissionregistration` API is required, and `kube-apiserver` process must have the `admission-control` flag set with the `MutatingAdmissionWebhook` and `ValidatingAdmissionWebhook` admission controllers added and listed in the correct order. +- The `istio-init` chart must be run to completion prior to install the `istio` chart. + +## Resources Required + +The chart deploys pods that consume minimum resources as specified in the resources configuration parameter. + +## Installing the Chart + +1. If a service account has not already been installed for Tiller, install one: + + ```bash + $ kubectl apply -f install/kubernetes/helm/helm-service-account.yaml + ``` + +1. Install Tiller on your cluster with the service account: + + ```bash + $ helm init --service-account tiller + ``` + +1. Set and create the namespace where Istio was installed: + + ```bash + $ NAMESPACE=istio-system + $ kubectl create ns $NAMESPACE + ``` + +1. If you are enabling `kiali`, you need to create the secret that contains the username and passphrase for `kiali` dashboard: + + ```bash + $ echo -n 'admin' | base64 + YWRtaW4= + $ echo -n '1f2d1e2e67df' | base64 + MWYyZDFlMmU2N2Rm + $ cat <=1.9.0): + + ```bash + $ helm install istio --name istio --namespace $NAMESPACE + ``` + + - Without the sidecar injection webhook: + + ```bash + $ helm install istio --name istio --namespace $NAMESPACE --set sidecarInjectorWebhook.enabled=false + ``` + +## Configuration + +The Helm chart ships with reasonable defaults. There may be circumstances in which defaults require overrides. +To override Helm values, use `--set key=value` argument during the `helm install` command. Multiple `--set` operations may be used in the same Helm operation. + +Helm charts expose configuration options which are currently in alpha. The currently exposed options can be found [here](https://istio.io/docs/reference/config/installation-options/). + +## Uninstalling the Chart + +To uninstall/delete the `istio` release but continue to track the release: + +```bash +$ helm delete istio +``` + +To uninstall/delete the `istio` release completely and make its name free for later use: + +```bash +$ helm delete --purge istio +``` diff --git a/istio-1.5.0/install/kubernetes/helm/istio/charts/certmanager/Chart.yaml b/istio-1.5.0/install/kubernetes/helm/istio/charts/certmanager/Chart.yaml new file mode 100644 index 0000000..e7dadd9 --- /dev/null +++ b/istio-1.5.0/install/kubernetes/helm/istio/charts/certmanager/Chart.yaml @@ -0,0 +1,6 @@ +apiVersion: v1 +description: A Helm chart for Kubernetes +name: certmanager +version: 1.5.0 +appVersion: 0.6.2 +tillerVersion: ">=2.7.2" diff --git a/istio-1.5.0/install/kubernetes/helm/istio/charts/certmanager/templates/NOTES.txt b/istio-1.5.0/install/kubernetes/helm/istio/charts/certmanager/templates/NOTES.txt new file mode 100644 index 0000000..0307ede --- /dev/null +++ b/istio-1.5.0/install/kubernetes/helm/istio/charts/certmanager/templates/NOTES.txt @@ -0,0 +1,6 @@ +certmanager has been deployed successfully! + +More information on the different types of issuers and how to configure them +can be found in our documentation: + +https://cert-manager.readthedocs.io/en/latest/reference/issuers.html \ No newline at end of file diff --git a/istio-1.5.0/install/kubernetes/helm/istio/charts/certmanager/templates/_helpers.tpl b/istio-1.5.0/install/kubernetes/helm/istio/charts/certmanager/templates/_helpers.tpl new file mode 100644 index 0000000..331a91d --- /dev/null +++ b/istio-1.5.0/install/kubernetes/helm/istio/charts/certmanager/templates/_helpers.tpl @@ -0,0 +1,32 @@ +{{/* vim: set filetype=mustache: */}} +{{/* +Expand the name of the chart. +*/}} +{{- define "certmanager.name" -}} +{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" -}} +{{- end -}} + +{{/* +Create a default fully qualified app name. +We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). +If release name contains chart name it will be used as a full name. +*/}} +{{- define "certmanager.fullname" -}} +{{- if .Values.fullnameOverride -}} +{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" -}} +{{- else -}} +{{- $name := default .Chart.Name .Values.nameOverride -}} +{{- if contains $name .Release.Name -}} +{{- .Release.Name | trunc 63 | trimSuffix "-" -}} +{{- else -}} +{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" -}} +{{- end -}} +{{- end -}} +{{- end -}} + +{{/* +Create chart name and version as used by the chart label. +*/}} +{{- define "certmanager.chart" -}} +{{- .Chart.Name | trunc 63 | trimSuffix "-" -}} +{{- end -}} diff --git a/istio-1.5.0/install/kubernetes/helm/istio/charts/certmanager/templates/deployment.yaml b/istio-1.5.0/install/kubernetes/helm/istio/charts/certmanager/templates/deployment.yaml new file mode 100644 index 0000000..48e4731 --- /dev/null +++ b/istio-1.5.0/install/kubernetes/helm/istio/charts/certmanager/templates/deployment.yaml @@ -0,0 +1,69 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: certmanager + namespace: {{ .Release.Namespace }} + labels: + app: certmanager + chart: {{ template "certmanager.chart" . }} + heritage: {{ .Release.Service }} + release: {{ .Release.Name }} +spec: + replicas: {{ .Values.replicaCount }} + selector: + matchLabels: + app: certmanager + template: + metadata: + labels: + app: certmanager + chart: {{ template "certmanager.chart" . }} + heritage: {{ .Release.Service }} + release: {{ .Release.Name }} + {{- if .Values.podLabels }} +{{ toYaml .Values.podLabels | indent 8 }} + {{- end }} + annotations: + sidecar.istio.io/inject: "false" + {{- if .Values.podAnnotations }} +{{ toYaml .Values.podAnnotations | indent 8 }} + {{- end }} + spec: + serviceAccountName: certmanager +{{- if .Values.global.priorityClassName }} + priorityClassName: "{{ .Values.global.priorityClassName }}" +{{- end }} + containers: + - name: certmanager + image: "{{ .Values.hub }}/{{ .Values.image }}:{{ .Values.tag }}" + imagePullPolicy: {{ .Values.global.imagePullPolicy }} + args: + - --cluster-resource-namespace=$(POD_NAMESPACE) + - --leader-election-namespace=$(POD_NAMESPACE) + {{- if .Values.extraArgs }} +{{ toYaml .Values.extraArgs | indent 8 }} + {{- end }} + env: + - name: POD_NAMESPACE + valueFrom: + fieldRef: + fieldPath: metadata.namespace + resources: +{{ toYaml .Values.resources | indent 10 }} + {{- if .Values.podDnsPolicy }} + dnsPolicy: {{ .Values.podDnsPolicy }} + {{- end }} + {{- if .Values.podDnsConfig }} + dnsConfig: +{{ toYaml .Values.podDnsConfig | indent 8 }} + {{- end }} + affinity: + {{- include "nodeaffinity" . | indent 6 }} + {{- include "podAntiAffinity" . | indent 6 }} +{{- if .Values.tolerations }} + tolerations: +{{ toYaml .Values.tolerations | indent 6 }} + {{- else if .Values.global.defaultTolerations }} + tolerations: +{{ toYaml .Values.global.defaultTolerations | indent 6 }} + {{- end }} diff --git a/istio-1.5.0/install/kubernetes/helm/istio/charts/certmanager/templates/issuer.yaml b/istio-1.5.0/install/kubernetes/helm/istio/charts/certmanager/templates/issuer.yaml new file mode 100644 index 0000000..59402da --- /dev/null +++ b/istio-1.5.0/install/kubernetes/helm/istio/charts/certmanager/templates/issuer.yaml @@ -0,0 +1,37 @@ +--- +apiVersion: certmanager.k8s.io/v1alpha1 +kind: ClusterIssuer +metadata: + name: letsencrypt-staging + namespace: {{ .Release.Namespace }} + labels: + app: certmanager + chart: {{ template "certmanager.chart" . }} + heritage: {{ .Release.Service }} + release: {{ .Release.Name }} +spec: + acme: + server: https://acme-staging-v02.api.letsencrypt.org/directory + email: {{ .Values.email }} + # Name of a secret used to store the ACME account private key + privateKeySecretRef: + name: letsencrypt-staging + http01: {} +--- +apiVersion: certmanager.k8s.io/v1alpha1 +kind: ClusterIssuer +metadata: + name: letsencrypt + namespace: {{ .Release.Namespace }} + labels: + app: certmanager + chart: {{ template "certmanager.chart" . }} + heritage: {{ .Release.Service }} + release: {{ .Release.Name }} +spec: + acme: + server: https://acme-v02.api.letsencrypt.org/directory + email: {{ .Values.email }} + privateKeySecretRef: + name: letsencrypt + http01: {} diff --git a/istio-1.5.0/install/kubernetes/helm/istio/charts/certmanager/templates/poddisruptionbudget.yaml b/istio-1.5.0/install/kubernetes/helm/istio/charts/certmanager/templates/poddisruptionbudget.yaml new file mode 100644 index 0000000..bb3c95c --- /dev/null +++ b/istio-1.5.0/install/kubernetes/helm/istio/charts/certmanager/templates/poddisruptionbudget.yaml @@ -0,0 +1,22 @@ +{{- if .Values.global.defaultPodDisruptionBudget.enabled }} +apiVersion: policy/v1beta1 +kind: PodDisruptionBudget +metadata: + name: certmanager + namespace: {{ .Release.Namespace }} + labels: + app: certmanager + chart: {{ template "certmanager.chart" . }} + heritage: {{ .Release.Service }} + release: {{ .Release.Name }} + version: {{ .Chart.Version }} + {{- if .Values.podLabels }} +{{ toYaml .Values.podLabels | indent 4 }} + {{- end }} +spec: +{{ include "podDisruptionBudget.spec" .Values.global.defaultPodDisruptionBudget }} + selector: + matchLabels: + app: certmanager + release: {{ .Release.Name }} +{{- end }} diff --git a/istio-1.5.0/install/kubernetes/helm/istio/charts/certmanager/templates/rbac.yaml b/istio-1.5.0/install/kubernetes/helm/istio/charts/certmanager/templates/rbac.yaml new file mode 100644 index 0000000..b3a4ef3 --- /dev/null +++ b/istio-1.5.0/install/kubernetes/helm/istio/charts/certmanager/templates/rbac.yaml @@ -0,0 +1,37 @@ +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: certmanager + labels: + app: certmanager + chart: {{ template "certmanager.chart" . }} + heritage: {{ .Release.Service }} + release: {{ .Release.Name }} +rules: + - apiGroups: ["certmanager.k8s.io"] + resources: ["certificates", "certificates/finalizers", "issuers", "clusterissuers", "orders", "orders/finalizers", "challenges"] + verbs: ["*"] + - apiGroups: [""] + resources: ["configmaps", "secrets", "events", "services", "pods"] + verbs: ["*"] + - apiGroups: ["extensions"] + resources: ["ingresses"] + verbs: ["*"] +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: certmanager + labels: + app: certmanager + chart: {{ template "certmanager.chart" . }} + heritage: {{ .Release.Service }} + release: {{ .Release.Name }} +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: certmanager +subjects: + - name: certmanager + namespace: {{ .Release.Namespace }} + kind: ServiceAccount diff --git a/istio-1.5.0/install/kubernetes/helm/istio/charts/certmanager/templates/serviceaccount.yaml b/istio-1.5.0/install/kubernetes/helm/istio/charts/certmanager/templates/serviceaccount.yaml new file mode 100644 index 0000000..f875435 --- /dev/null +++ b/istio-1.5.0/install/kubernetes/helm/istio/charts/certmanager/templates/serviceaccount.yaml @@ -0,0 +1,16 @@ +apiVersion: v1 +kind: ServiceAccount +{{- if .Values.global.imagePullSecrets }} +imagePullSecrets: +{{- range .Values.global.imagePullSecrets }} + - name: {{ . }} +{{- end }} +{{- end }} +metadata: + name: certmanager + namespace: {{ .Release.Namespace }} + labels: + app: certmanager + chart: {{ template "certmanager.chart" . }} + heritage: {{ .Release.Service }} + release: {{ .Release.Name }} diff --git a/istio-1.5.0/install/kubernetes/helm/istio/charts/certmanager/values.yaml b/istio-1.5.0/install/kubernetes/helm/istio/charts/certmanager/values.yaml new file mode 100644 index 0000000..01e565c --- /dev/null +++ b/istio-1.5.0/install/kubernetes/helm/istio/charts/certmanager/values.yaml @@ -0,0 +1,35 @@ +# Certmanager uses ACME to sign certificates. Since Istio gateways are +# mounting the TLS secrets the Certificate CRDs must be created in the +# istio-system namespace. Once the certificate has been created, the +# gateway must be updated by adding 'secretVolumes'. After the gateway +# restart, DestinationRules can be created using the ACME-signed certificates. +enabled: false +replicaCount: 1 +hub: quay.io/jetstack +image: cert-manager-controller +tag: v0.8.1 +resources: {} +nodeSelector: {} +tolerations: [] +podAnnotations: {} + +# Specify the pod anti-affinity that allows you to constrain which nodes +# your pod is eligible to be scheduled based on labels on pods that are +# already running on the node rather than based on labels on nodes. +# There are currently two types of anti-affinity: +# "requiredDuringSchedulingIgnoredDuringExecution" +# "preferredDuringSchedulingIgnoredDuringExecution" +# which denote "hard" vs. "soft" requirements, you can define your values +# in "podAntiAffinityLabelSelector" and "podAntiAffinityTermLabelSelector" +# correspondingly. +# For example: +# podAntiAffinityLabelSelector: +# - key: security +# operator: In +# values: S1,S2 +# topologyKey: "kubernetes.io/hostname" +# This pod anti-affinity rule says that the pod requires not to be scheduled +# onto a node if that node is already running a pod with label having key +# "security" and value "S1". +podAntiAffinityLabelSelector: [] +podAntiAffinityTermLabelSelector: [] diff --git a/istio-1.5.0/install/kubernetes/helm/istio/charts/galley/Chart.yaml b/istio-1.5.0/install/kubernetes/helm/istio/charts/galley/Chart.yaml new file mode 100644 index 0000000..981ed57 --- /dev/null +++ b/istio-1.5.0/install/kubernetes/helm/istio/charts/galley/Chart.yaml @@ -0,0 +1,13 @@ +apiVersion: v1 +name: galley +version: 1.5.0 +appVersion: 1.5.0 +tillerVersion: ">=2.7.2" +description: Helm chart for galley deployment +keywords: + - istio + - galley +sources: + - http://github.com/istio/istio +engine: gotpl +icon: https://istio.io/favicons/android-192x192.png diff --git a/istio-1.5.0/install/kubernetes/helm/istio/charts/galley/templates/_helpers.tpl b/istio-1.5.0/install/kubernetes/helm/istio/charts/galley/templates/_helpers.tpl new file mode 100644 index 0000000..5d42f4a --- /dev/null +++ b/istio-1.5.0/install/kubernetes/helm/istio/charts/galley/templates/_helpers.tpl @@ -0,0 +1,32 @@ +{{/* vim: set filetype=mustache: */}} +{{/* +Expand the name of the chart. +*/}} +{{- define "galley.name" -}} +{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" -}} +{{- end -}} + +{{/* +Create a default fully qualified app name. +We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). +If release name contains chart name it will be used as a full name. +*/}} +{{- define "galley.fullname" -}} +{{- if .Values.fullnameOverride -}} +{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" -}} +{{- else -}} +{{- $name := default .Chart.Name .Values.nameOverride -}} +{{- if contains $name .Release.Name -}} +{{- .Release.Name | trunc 63 | trimSuffix "-" -}} +{{- else -}} +{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" -}} +{{- end -}} +{{- end -}} +{{- end -}} + +{{/* +Create chart name and version as used by the chart label. +*/}} +{{- define "galley.chart" -}} +{{- .Chart.Name | trunc 63 | trimSuffix "-" -}} +{{- end -}} diff --git a/istio-1.5.0/install/kubernetes/helm/istio/charts/galley/templates/clusterrole.yaml b/istio-1.5.0/install/kubernetes/helm/istio/charts/galley/templates/clusterrole.yaml new file mode 100644 index 0000000..504abc0 --- /dev/null +++ b/istio-1.5.0/install/kubernetes/helm/istio/charts/galley/templates/clusterrole.yaml @@ -0,0 +1,53 @@ +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: istio-galley-{{ .Release.Namespace }} + labels: + app: {{ template "galley.name" . }} + chart: {{ template "galley.chart" . }} + heritage: {{ .Release.Service }} + release: {{ .Release.Name }} +rules: + # For reading Istio resources +- apiGroups: [ + "authentication.istio.io", + "config.istio.io", + "networking.istio.io", + "rbac.istio.io", + "security.istio.io"] + resources: ["*"] + verbs: ["get", "list", "watch"] + # For updating Istio resource statuses +- apiGroups: [ + "authentication.istio.io", + "config.istio.io", + "networking.istio.io", + "rbac.istio.io", + "security.istio.io"] + resources: ["*/status"] + verbs: ["update"] +{{- if not .Values.global.operatorManageWebhooks }} +- apiGroups: ["admissionregistration.k8s.io"] + resources: ["validatingwebhookconfigurations"] + verbs: ["get", "list", "watch", "update"] +# permissions to verify the webhook is ready and rejecting +# invalid config. We use --server-dry-run so no config is persisted. +- apiGroups: ["networking.istio.io"] + verbs: ["create"] + resources: ["gateways"] +{{- end }} +- apiGroups: ["extensions","apps"] + resources: ["deployments"] + verbs: ["get", "list", "watch"] +- apiGroups: [""] + resources: ["pods", "nodes", "services", "endpoints", "namespaces"] + verbs: ["get", "list", "watch"] +- apiGroups: ["extensions"] + resources: ["ingresses"] + verbs: ["get", "list", "watch"] +- apiGroups: ["apiextensions.k8s.io"] + resources: ["customresourcedefinitions"] + verbs: ["get", "list", "watch"] +- apiGroups: ["rbac.authorization.k8s.io"] + resources: ["clusterroles"] + verbs: ["get", "list", "watch"] diff --git a/istio-1.5.0/install/kubernetes/helm/istio/charts/galley/templates/clusterrolebinding.yaml b/istio-1.5.0/install/kubernetes/helm/istio/charts/galley/templates/clusterrolebinding.yaml new file mode 100644 index 0000000..88cde25 --- /dev/null +++ b/istio-1.5.0/install/kubernetes/helm/istio/charts/galley/templates/clusterrolebinding.yaml @@ -0,0 +1,17 @@ +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: istio-galley-admin-role-binding-{{ .Release.Namespace }} + labels: + app: {{ template "galley.name" . }} + chart: {{ template "galley.chart" . }} + heritage: {{ .Release.Service }} + release: {{ .Release.Name }} +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: istio-galley-{{ .Release.Namespace }} +subjects: + - kind: ServiceAccount + name: istio-galley-service-account + namespace: {{ .Release.Namespace }} diff --git a/istio-1.5.0/install/kubernetes/helm/istio/charts/galley/templates/configmap.yaml b/istio-1.5.0/install/kubernetes/helm/istio/charts/galley/templates/configmap.yaml new file mode 100644 index 0000000..662c960 --- /dev/null +++ b/istio-1.5.0/install/kubernetes/helm/istio/charts/galley/templates/configmap.yaml @@ -0,0 +1,16 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: istio-galley-configuration + namespace: {{ .Release.Namespace }} + labels: + app: {{ template "galley.name" . }} + chart: {{ template "galley.chart" . }} + heritage: {{ .Release.Service }} + release: {{ .Release.Name }} + istio: galley +data: +{{- if .Values.global.configValidation }} + validatingwebhookconfiguration.yaml: |- + {{- include "validatingwebhookconfiguration.yaml.tpl" . | indent 4}} +{{- end}} diff --git a/istio-1.5.0/install/kubernetes/helm/istio/charts/galley/templates/deployment.yaml b/istio-1.5.0/install/kubernetes/helm/istio/charts/galley/templates/deployment.yaml new file mode 100644 index 0000000..ca54a6c --- /dev/null +++ b/istio-1.5.0/install/kubernetes/helm/istio/charts/galley/templates/deployment.yaml @@ -0,0 +1,155 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: istio-galley + namespace: {{ .Release.Namespace }} + labels: + app: {{ template "galley.name" . }} + chart: {{ template "galley.chart" . }} + heritage: {{ .Release.Service }} + release: {{ .Release.Name }} + istio: galley +spec: + replicas: {{ .Values.replicaCount }} + selector: + matchLabels: + istio: galley + strategy: + rollingUpdate: + maxSurge: {{ .Values.rollingMaxSurge }} + maxUnavailable: {{ .Values.rollingMaxUnavailable }} + template: + metadata: + labels: + app: {{ template "galley.name" . }} + chart: {{ template "galley.chart" . }} + heritage: {{ .Release.Service }} + release: {{ .Release.Name }} + istio: galley + annotations: + sidecar.istio.io/inject: "false" + {{- if .Values.podAnnotations }} +{{ toYaml .Values.podAnnotations | indent 8 }} + {{- end }} + spec: + serviceAccountName: istio-galley-service-account +{{- if .Values.global.priorityClassName }} + priorityClassName: "{{ .Values.global.priorityClassName }}" +{{- end }} + containers: + - name: galley +{{- if contains "/" .Values.image }} + image: "{{ .Values.image }}" +{{- else }} + image: "{{ .Values.global.hub }}/{{ .Values.image }}:{{ .Values.global.tag }}" +{{- end }} + imagePullPolicy: {{ .Values.global.imagePullPolicy }} + ports: + - containerPort: 9443 + - containerPort: {{ .Values.global.monitoringPort }} + - containerPort: 9901 + command: + - /usr/local/bin/galley + - server + - --meshConfigFile=/etc/mesh-config/mesh + - --livenessProbeInterval=1s + - --livenessProbePath=/tmp/healthliveness + - --readinessProbePath=/tmp/healthready + - --readinessProbeInterval=1s + - --deployment-namespace={{ .Release.Namespace }} +{{- if $.Values.global.controlPlaneSecurityEnabled}} + - --insecure=false +{{- else }} + - --insecure=true +{{- end }} +{{- if .Values.enableServiceDiscovery }} + - --enableServiceDiscovery=true +{{- end }} +{{- if not $.Values.global.useMCP }} + - --enable-server=false +{{- end }} +{{- if not $.Values.global.configValidation }} + - --enable-validation=false +{{- end }} +{{- if .Values.global.operatorManageWebhooks }} + - --enable-reconcileWebhookConfiguration=false +{{- else }} + - --enable-reconcileWebhookConfiguration=true +{{- end }} + - --monitoringPort={{ .Values.global.monitoringPort }} +{{- if $.Values.global.logging.level }} + - --log_output_level={{ $.Values.global.logging.level }} +{{- end}} +{{- if .Values.enableAnalysis }} + - --enableAnalysis=true +{{- end }} +{{- if .Values.global.certificates }} + - --validation.tls.clientCertificate=/etc/dnscerts/cert-chain.pem + - --validation.tls.privateKey=/etc/dnscerts/key.pem + - --validation.tls.caCertificates=/etc/dnscerts/root-cert.pem +{{- end }} + volumeMounts: + - name: certs + mountPath: /etc/certs + readOnly: true +{{- if .Values.global.certificates }} + - name: dnscerts + mountPath: /etc/dnscerts + readOnly: true +{{- end }} + - name: config + mountPath: /etc/config + readOnly: true + - name: mesh-config + mountPath: /etc/mesh-config + readOnly: true + livenessProbe: + exec: + command: + - /usr/local/bin/galley + - probe + - --probe-path=/tmp/healthliveness + - --interval=10s + initialDelaySeconds: 5 + periodSeconds: 5 + readinessProbe: + exec: + command: + - /usr/local/bin/galley + - probe + - --probe-path=/tmp/healthready + - --interval=10s + initialDelaySeconds: 5 + periodSeconds: 5 + resources: +{{- if .Values.resources }} +{{ toYaml .Values.resources | indent 12 }} +{{- else }} +{{ toYaml .Values.global.defaultResources | indent 12 }} +{{- end }} + volumes: + - name: certs + secret: + secretName: istio.istio-galley-service-account +{{- if .Values.global.certificates }} + - name: dnscerts + secret: + secretName: dns.istio-galley-service-account +{{- end }} + # galley expects /etc/config to exist even though it doesn't include any files. + - name: config + emptyDir: + medium: Memory + - name: mesh-config + configMap: + name: istio + affinity: + {{- include "nodeaffinity" . | indent 6 }} + {{- include "podAntiAffinity" . | indent 6 }} + {{- if .Values.tolerations }} + tolerations: +{{ toYaml .Values.tolerations | indent 6 }} + {{- else if .Values.global.defaultTolerations }} + tolerations: +{{ toYaml .Values.global.defaultTolerations | indent 6 }} + {{- end }} \ No newline at end of file diff --git a/istio-1.5.0/install/kubernetes/helm/istio/charts/galley/templates/poddisruptionbudget.yaml b/istio-1.5.0/install/kubernetes/helm/istio/charts/galley/templates/poddisruptionbudget.yaml new file mode 100644 index 0000000..1bf374e --- /dev/null +++ b/istio-1.5.0/install/kubernetes/helm/istio/charts/galley/templates/poddisruptionbudget.yaml @@ -0,0 +1,20 @@ +{{- if .Values.global.defaultPodDisruptionBudget.enabled }} +apiVersion: policy/v1beta1 +kind: PodDisruptionBudget +metadata: + name: istio-galley + namespace: {{ .Release.Namespace }} + labels: + app: {{ template "galley.name" . }} + chart: {{ template "galley.chart" . }} + heritage: {{ .Release.Service }} + release: {{ .Release.Name }} + istio: galley +spec: +{{ include "podDisruptionBudget.spec" .Values.global.defaultPodDisruptionBudget }} + selector: + matchLabels: + app: {{ template "galley.name" . }} + release: {{ .Release.Name }} + istio: galley +{{- end }} diff --git a/istio-1.5.0/install/kubernetes/helm/istio/charts/galley/templates/service.yaml b/istio-1.5.0/install/kubernetes/helm/istio/charts/galley/templates/service.yaml new file mode 100644 index 0000000..35e2581 --- /dev/null +++ b/istio-1.5.0/install/kubernetes/helm/istio/charts/galley/templates/service.yaml @@ -0,0 +1,22 @@ +apiVersion: v1 +kind: Service +metadata: + name: istio-galley + namespace: {{ .Release.Namespace }} + labels: + app: {{ template "galley.name" . }} + chart: {{ template "galley.chart" . }} + heritage: {{ .Release.Service }} + release: {{ .Release.Name }} + istio: galley +spec: + ports: + - port: 443 + targetPort: 9443 + name: https-validation + - port: {{ .Values.global.monitoringPort }} + name: http-monitoring + - port: 9901 + name: grpc-mcp + selector: + istio: galley diff --git a/istio-1.5.0/install/kubernetes/helm/istio/charts/galley/templates/serviceaccount.yaml b/istio-1.5.0/install/kubernetes/helm/istio/charts/galley/templates/serviceaccount.yaml new file mode 100644 index 0000000..1ff54c4 --- /dev/null +++ b/istio-1.5.0/install/kubernetes/helm/istio/charts/galley/templates/serviceaccount.yaml @@ -0,0 +1,16 @@ +apiVersion: v1 +kind: ServiceAccount +{{- if .Values.global.imagePullSecrets }} +imagePullSecrets: +{{- range .Values.global.imagePullSecrets }} + - name: {{ . }} +{{- end }} +{{- end }} +metadata: + name: istio-galley-service-account + namespace: {{ .Release.Namespace }} + labels: + app: {{ template "galley.name" . }} + chart: {{ template "galley.chart" . }} + heritage: {{ .Release.Service }} + release: {{ .Release.Name }} diff --git a/istio-1.5.0/install/kubernetes/helm/istio/charts/galley/templates/validatingwebhookconfiguration.yaml b/istio-1.5.0/install/kubernetes/helm/istio/charts/galley/templates/validatingwebhookconfiguration.yaml new file mode 100644 index 0000000..4e1f50f --- /dev/null +++ b/istio-1.5.0/install/kubernetes/helm/istio/charts/galley/templates/validatingwebhookconfiguration.yaml @@ -0,0 +1,108 @@ +{{/* + This version of the validatingwebhookconfiguration is applied directly by + helm. Galley only patches the caBundle and failurePolicy. +*/}} +apiVersion: admissionregistration.k8s.io/v1beta1 +kind: ValidatingWebhookConfiguration +metadata: + name: istio-galley + labels: + app: {{ template "galley.name" . }} + chart: {{ template "galley.chart" . }} + heritage: {{ .Release.Service }} + release: {{ .Release.Name }} + istio: galley +webhooks: + - name: pilot.validation.istio.io + clientConfig: + service: + name: istio-galley + namespace: {{ .Release.Namespace }} + path: "/admitpilot" + caBundle: "" + rules: + - operations: + - CREATE + - UPDATE + apiGroups: + - config.istio.io + apiVersions: + - v1alpha2 + resources: + - httpapispecs + - httpapispecbindings + - quotaspecs + - quotaspecbindings + - operations: + - CREATE + - UPDATE + apiGroups: + - rbac.istio.io + apiVersions: + - "*" + resources: + - "*" + - operations: + - CREATE + - UPDATE + apiGroups: + - security.istio.io + apiVersions: + - "*" + resources: + - "*" + - operations: + - CREATE + - UPDATE + apiGroups: + - authentication.istio.io + apiVersions: + - "*" + resources: + - "*" + - operations: + - CREATE + - UPDATE + apiGroups: + - networking.istio.io + apiVersions: + - "*" + resources: + - destinationrules + - envoyfilters + - gateways + - serviceentries + - sidecars + - virtualservices + # Fail open until the validation webhook is ready. The webhook controller + # will update this to `Fail` and patch in the `caBundle` when the webhook + # endpoint is ready. + failurePolicy: Ignore + sideEffects: None + - name: mixer.validation.istio.io + clientConfig: + service: + name: istio-galley + namespace: {{ .Release.Namespace }} + path: "/admitmixer" + caBundle: "" + rules: + - operations: + - CREATE + - UPDATE + apiGroups: + - config.istio.io + apiVersions: + - v1alpha2 + resources: + - rules + - attributemanifests + - adapters + - handlers + - instances + - templates + # Fail open until the validation webhook is ready. The webhook controller + # will update this to `Fail` and patch in the `caBundle` when the webhook + # endpoint is ready. + failurePolicy: Ignore + sideEffects: None \ No newline at end of file diff --git a/istio-1.5.0/install/kubernetes/helm/istio/charts/galley/templates/validatingwebhookconfiguration.yaml.tpl b/istio-1.5.0/install/kubernetes/helm/istio/charts/galley/templates/validatingwebhookconfiguration.yaml.tpl new file mode 100644 index 0000000..8df00f7 --- /dev/null +++ b/istio-1.5.0/install/kubernetes/helm/istio/charts/galley/templates/validatingwebhookconfiguration.yaml.tpl @@ -0,0 +1,111 @@ +{{/* + This version of the validatingwebhookconfiguration is applied indirectly + by galley. This exists to support a smoother upgrade path from istio + Rversions < 1.4 +*/}} +{{ define "validatingwebhookconfiguration.yaml.tpl" }} +apiVersion: admissionregistration.k8s.io/v1beta1 +kind: ValidatingWebhookConfiguration +metadata: + name: istio-galley + labels: + app: {{ template "galley.name" . }} + chart: {{ template "galley.chart" . }} + heritage: {{ .Release.Service }} + release: {{ .Release.Name }} + istio: galley +webhooks: + - name: pilot.validation.istio.io + clientConfig: + service: + name: istio-galley + namespace: {{ .Release.Namespace }} + path: "/admitpilot" + caBundle: "" + rules: + - operations: + - CREATE + - UPDATE + apiGroups: + - config.istio.io + apiVersions: + - v1alpha2 + resources: + - httpapispecs + - httpapispecbindings + - quotaspecs + - quotaspecbindings + - operations: + - CREATE + - UPDATE + apiGroups: + - rbac.istio.io + apiVersions: + - "*" + resources: + - "*" + - operations: + - CREATE + - UPDATE + apiGroups: + - security.istio.io + apiVersions: + - "*" + resources: + - "*" + - operations: + - CREATE + - UPDATE + apiGroups: + - authentication.istio.io + apiVersions: + - "*" + resources: + - "*" + - operations: + - CREATE + - UPDATE + apiGroups: + - networking.istio.io + apiVersions: + - "*" + resources: + - destinationrules + - envoyfilters + - gateways + - serviceentries + - sidecars + - virtualservices + # Fail open until the validation webhook is ready. The webhook controller + # will update this to `Fail` and patch in the `caBundle` when the webhook + # endpoint is ready. + failurePolicy: Ignore + sideEffects: None + - name: mixer.validation.istio.io + clientConfig: + service: + name: istio-galley + namespace: {{ .Release.Namespace }} + path: "/admitmixer" + caBundle: "" + rules: + - operations: + - CREATE + - UPDATE + apiGroups: + - config.istio.io + apiVersions: + - v1alpha2 + resources: + - rules + - attributemanifests + - adapters + - handlers + - instances + - templates + # Fail open until the validation webhook is ready. The webhook controller + # will update this to `Fail` and patch in the `caBundle` when the webhook + # endpoint is ready. + failurePolicy: Ignore + sideEffects: None +{{- end }} diff --git a/istio-1.5.0/install/kubernetes/helm/istio/charts/galley/values.yaml b/istio-1.5.0/install/kubernetes/helm/istio/charts/galley/values.yaml new file mode 100644 index 0000000..1dc415a --- /dev/null +++ b/istio-1.5.0/install/kubernetes/helm/istio/charts/galley/values.yaml @@ -0,0 +1,38 @@ +# +# galley configuration +# +enabled: true +replicaCount: 1 +rollingMaxSurge: 100% +rollingMaxUnavailable: 25% +image: galley +nodeSelector: {} +tolerations: [] +podAnnotations: {} + +# Specify the pod anti-affinity that allows you to constrain which nodes +# your pod is eligible to be scheduled based on labels on pods that are +# already running on the node rather than based on labels on nodes. +# There are currently two types of anti-affinity: +# "requiredDuringSchedulingIgnoredDuringExecution" +# "preferredDuringSchedulingIgnoredDuringExecution" +# which denote "hard" vs. "soft" requirements, you can define your values +# in "podAntiAffinityLabelSelector" and "podAntiAffinityTermLabelSelector" +# correspondingly. +# For example: +# podAntiAffinityLabelSelector: +# - key: security +# operator: In +# values: S1,S2 +# topologyKey: "kubernetes.io/hostname" +# This pod anti-affinity rule says that the pod requires not to be scheduled +# onto a node if that node is already running a pod with label having key +# "security" and value "S1". +podAntiAffinityLabelSelector: [] +podAntiAffinityTermLabelSelector: [] + +# Enable service discovery processing in Galley +enableServiceDiscovery: false + +# Enable analysis and status update in Galley +enableAnalysis: false diff --git a/istio-1.5.0/install/kubernetes/helm/istio/charts/gateways/Chart.yaml b/istio-1.5.0/install/kubernetes/helm/istio/charts/gateways/Chart.yaml new file mode 100644 index 0000000..5491bbe --- /dev/null +++ b/istio-1.5.0/install/kubernetes/helm/istio/charts/gateways/Chart.yaml @@ -0,0 +1,15 @@ +apiVersion: v1 +name: gateways +version: 1.5.0 +appVersion: 1.5.0 +tillerVersion: ">=2.7.2" +description: Helm chart for deploying Istio gateways +keywords: + - istio + - ingressgateway + - egressgateway + - gateways +sources: + - http://github.com/istio/istio +engine: gotpl +icon: https://istio.io/favicons/android-192x192.png diff --git a/istio-1.5.0/install/kubernetes/helm/istio/charts/gateways/templates/_affinity.tpl b/istio-1.5.0/install/kubernetes/helm/istio/charts/gateways/templates/_affinity.tpl new file mode 100644 index 0000000..fbd0e9a --- /dev/null +++ b/istio-1.5.0/install/kubernetes/helm/istio/charts/gateways/templates/_affinity.tpl @@ -0,0 +1,93 @@ +{{/* affinity - https://kubernetes.io/docs/concepts/configuration/assign-pod-node/ */}} + +{{- define "gatewaynodeaffinity" }} + nodeAffinity: + requiredDuringSchedulingIgnoredDuringExecution: + {{- include "gatewayNodeAffinityRequiredDuringScheduling" . }} + preferredDuringSchedulingIgnoredDuringExecution: + {{- include "gatewayNodeAffinityPreferredDuringScheduling" . }} +{{- end }} + +{{- define "gatewayNodeAffinityRequiredDuringScheduling" }} + nodeSelectorTerms: + - matchExpressions: + - key: beta.kubernetes.io/arch + operator: In + values: + {{- range $key, $val := .root.Values.global.arch }} + {{- if gt ($val | int) 0 }} + - {{ $key | quote }} + {{- end }} + {{- end }} + {{- $nodeSelector := default .root.Values.global.defaultNodeSelector .nodeSelector -}} + {{- range $key, $val := $nodeSelector }} + - key: {{ $key }} + operator: In + values: + - {{ $val | quote }} + {{- end }} +{{- end }} + +{{- define "gatewayNodeAffinityPreferredDuringScheduling" }} + {{- range $key, $val := .root.Values.global.arch }} + {{- if gt ($val | int) 0 }} + - weight: {{ $val | int }} + preference: + matchExpressions: + - key: beta.kubernetes.io/arch + operator: In + values: + - {{ $key | quote }} + {{- end }} + {{- end }} +{{- end }} + +{{- define "gatewaypodAntiAffinity" }} +{{- if or .podAntiAffinityLabelSelector .podAntiAffinityTermLabelSelector}} + podAntiAffinity: + {{- if .podAntiAffinityLabelSelector }} + requiredDuringSchedulingIgnoredDuringExecution: + {{- include "gatewaypodAntiAffinityRequiredDuringScheduling" . }} + {{- end }} + {{- if .podAntiAffinityTermLabelSelector }} + preferredDuringSchedulingIgnoredDuringExecution: + {{- include "gatewaypodAntiAffinityPreferredDuringScheduling" . }} + {{- end }} +{{- end }} +{{- end }} + +{{- define "gatewaypodAntiAffinityRequiredDuringScheduling" }} + {{- range $index, $item := .podAntiAffinityLabelSelector }} + - labelSelector: + matchExpressions: + - key: {{ $item.key }} + operator: {{ $item.operator }} + {{- if $item.values }} + values: + {{- $vals := split "," $item.values }} + {{- range $i, $v := $vals }} + - {{ $v | quote }} + {{- end }} + {{- end }} + topologyKey: {{ $item.topologyKey }} + {{- end }} +{{- end }} + +{{- define "gatewaypodAntiAffinityPreferredDuringScheduling" }} + {{- range $index, $item := .podAntiAffinityTermLabelSelector }} + - podAffinityTerm: + labelSelector: + matchExpressions: + - key: {{ $item.key }} + operator: {{ $item.operator }} + {{- if $item.values }} + values: + {{- $vals := split "," $item.values }} + {{- range $i, $v := $vals }} + - {{ $v | quote }} + {{- end }} + {{- end }} + topologyKey: {{ $item.topologyKey }} + weight: 100 + {{- end }} +{{- end }} diff --git a/istio-1.5.0/install/kubernetes/helm/istio/charts/gateways/templates/_helpers.tpl b/istio-1.5.0/install/kubernetes/helm/istio/charts/gateways/templates/_helpers.tpl new file mode 100644 index 0000000..bfc8bc4 --- /dev/null +++ b/istio-1.5.0/install/kubernetes/helm/istio/charts/gateways/templates/_helpers.tpl @@ -0,0 +1,32 @@ +{{/* vim: set filetype=mustache: */}} +{{/* +Expand the name of the chart. +*/}} +{{- define "gateway.name" -}} +{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" -}} +{{- end -}} + +{{/* +Create a default fully qualified app name. +We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). +If release name contains chart name it will be used as a full name. +*/}} +{{- define "gateway.fullname" -}} +{{- if .Values.fullnameOverride -}} +{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" -}} +{{- else -}} +{{- $name := default .Chart.Name .Values.nameOverride -}} +{{- if contains $name .Release.Name -}} +{{- .Release.Name | trunc 63 | trimSuffix "-" -}} +{{- else -}} +{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" -}} +{{- end -}} +{{- end -}} +{{- end -}} + +{{/* +Create chart name and version as used by the chart label. +*/}} +{{- define "gateway.chart" -}} +{{- .Chart.Name | trunc 63 | trimSuffix "-" -}} +{{- end -}} diff --git a/istio-1.5.0/install/kubernetes/helm/istio/charts/gateways/templates/autoscale.yaml b/istio-1.5.0/install/kubernetes/helm/istio/charts/gateways/templates/autoscale.yaml new file mode 100644 index 0000000..2455ac3 --- /dev/null +++ b/istio-1.5.0/install/kubernetes/helm/istio/charts/gateways/templates/autoscale.yaml @@ -0,0 +1,31 @@ +{{- range $key, $spec := .Values }} +{{- if ne $key "enabled" }} +{{- if and $spec.enabled $spec.autoscaleEnabled $spec.autoscaleMin $spec.autoscaleMax }} +apiVersion: autoscaling/v2beta1 +kind: HorizontalPodAutoscaler +metadata: + name: {{ $key }} + namespace: {{ $spec.namespace | default $.Release.Namespace }} + labels: + chart: {{ template "gateway.chart" $ }} + heritage: {{ $.Release.Service }} + release: {{ $.Release.Name }} + {{- range $key, $val := $spec.labels }} + {{ $key }}: {{ $val }} + {{- end }} +spec: + maxReplicas: {{ $spec.autoscaleMax }} + minReplicas: {{ $spec.autoscaleMin }} + scaleTargetRef: + apiVersion: apps/v1 + kind: Deployment + name: {{ $key }} + metrics: + - type: Resource + resource: + name: cpu + targetAverageUtilization: {{ $spec.cpu.targetAverageUtilization }} +--- +{{- end }} +{{- end }} +{{- end }} diff --git a/istio-1.5.0/install/kubernetes/helm/istio/charts/gateways/templates/deployment.yaml b/istio-1.5.0/install/kubernetes/helm/istio/charts/gateways/templates/deployment.yaml new file mode 100644 index 0000000..7f93494 --- /dev/null +++ b/istio-1.5.0/install/kubernetes/helm/istio/charts/gateways/templates/deployment.yaml @@ -0,0 +1,393 @@ +{{- range $key, $spec := .Values }} +{{- if ne $key "enabled" }} +{{- if $spec.enabled }} + +{{- $labels := merge (dict "release" $.Release.Name "chart" (include "gateway.chart" $) "heritage" $.Release.Service) $spec.labels }} +apiVersion: apps/v1 +kind: Deployment +metadata: + name: {{ $key }} + namespace: {{ $spec.namespace | default $.Release.Namespace }} + labels: +{{ $labels | toYaml | indent 4 }} +spec: +{{- if not $spec.autoscaleEnabled }} +{{- if $spec.replicaCount }} + replicas: {{ $spec.replicaCount }} +{{- else }} + replicas: 1 +{{- end }} +{{- end }} + selector: + matchLabels: + {{- range $key, $val := $spec.labels }} + {{ $key }}: {{ $val }} + {{- end }} + strategy: + rollingUpdate: + maxSurge: {{ $spec.rollingMaxSurge }} + maxUnavailable: {{ $spec.rollingMaxUnavailable }} + template: + metadata: + labels: +{{ $labels | toYaml | indent 8 }} + annotations: + sidecar.istio.io/inject: "false" +{{- if $spec.podAnnotations }} +{{ toYaml $spec.podAnnotations | indent 8 }} +{{ end }} + spec: + serviceAccountName: {{ $key }}-service-account +{{- if $.Values.global.priorityClassName }} + priorityClassName: "{{ $.Values.global.priorityClassName }}" +{{- end }} +{{- if $.Values.global.proxy.enableCoreDump }} + initContainers: + - name: enable-core-dump + image: {{ $.Values.global.proxy.enableCoreDumpImage }} + imagePullPolicy: {{ $.Values.global.imagePullPolicy }} + command: + - /bin/sh + args: + - -c + - sysctl -w kernel.core_pattern=/var/lib/istio/core.proxy && ulimit -c unlimited + securityContext: + privileged: true +{{- end }} + containers: +{{- if $spec.sds }} +{{- if $spec.sds.enabled }} + - name: ingress-sds +{{- if contains "/" $spec.sds.image }} + image: "{{ $spec.sds.image }}" +{{- else }} + image: "{{ $.Values.global.hub }}/{{ $spec.sds.image }}:{{ $.Values.global.tag }}" +{{- end }} + imagePullPolicy: {{ $.Values.global.imagePullPolicy }} + resources: +{{- if $spec.sds.resources }} +{{ toYaml $spec.sds.resources | indent 12 }} +{{- else }} +{{ toYaml $.Values.global.defaultResources | indent 12 }} +{{- end }} + env: + - name: "ENABLE_WORKLOAD_SDS" + value: "false" + - name: "ENABLE_INGRESS_GATEWAY_SDS" + value: "true" + - name: "INGRESS_GATEWAY_NAMESPACE" + valueFrom: + fieldRef: + apiVersion: v1 + fieldPath: metadata.namespace + volumeMounts: + - name: ingressgatewaysdsudspath + mountPath: /var/run/ingress_gateway +{{- end }} +{{- end }} + - name: istio-proxy +{{- if contains "/" $.Values.global.proxy.image }} + image: "{{ $.Values.global.proxy.image }}" +{{- else }} + image: "{{ $.Values.global.hub }}/{{ $.Values.global.proxy.image }}:{{ $.Values.global.tag }}" +{{- end }} + imagePullPolicy: {{ $.Values.global.imagePullPolicy }} + ports: + {{- range $key, $val := $spec.ports }} + - containerPort: {{ $val.port }} + {{- end }} + - containerPort: 15090 + protocol: TCP + name: http-envoy-prom + args: + - proxy + - router + - --domain + - $(POD_NAMESPACE).svc.{{ $.Values.global.proxy.clusterDomain }} + {{- if $.Values.global.proxy.logLevel }} + - --proxyLogLevel={{ $.Values.global.proxy.logLevel }} + {{- end}} + {{- if $.Values.global.proxy.componentLogLevel }} + - --proxyComponentLogLevel={{ $.Values.global.proxy.componentLogLevel }} + {{- end}} + {{- if $.Values.global.logging.level }} + - --log_output_level={{ $.Values.global.logging.level }} + {{- end}} + - --drainDuration + - '45s' #drainDuration + - --parentShutdownDuration + - '1m0s' #parentShutdownDuration + - --connectTimeout + - '10s' #connectTimeout + - --serviceCluster + - {{ $key }} + {{- if eq $.Values.global.proxy.tracer "lightstep" }} + - --lightstepAddress + - {{ $.Values.global.tracer.lightstep.address }} + - --lightstepAccessToken + - {{ $.Values.global.tracer.lightstep.accessToken }} + - --lightstepSecure={{ $.Values.global.tracer.lightstep.secure }} + {{- if $.Values.global.tracer.lightstep.secure }} + - --lightstepCacertPath + - {{ $.Values.global.tracer.lightstep.cacertPath }} + {{- end }} + {{- else if eq $.Values.global.proxy.tracer "zipkin" }} + - --zipkinAddress + {{- if $.Values.global.tracer.zipkin.address }} + - {{ $.Values.global.tracer.zipkin.address }} + {{- else if $.Values.global.istioNamespace }} + - zipkin.{{ $.Values.global.istioNamespace }}:9411 + {{- else }} + - zipkin:9411 + {{- end }} + {{- else if eq $.Values.global.proxy.tracer "datadog" }} + - --datadogAgentAddress + - {{ $.Values.global.tracer.datadog.address }} + {{- end }} + {{- if $.Values.global.proxy.envoyStatsd.enabled }} + - --statsdUdpAddress + - {{ $.Values.global.proxy.envoyStatsd.host }}:{{ $.Values.global.proxy.envoyStatsd.port }} + {{- end }} + {{- if $.Values.global.proxy.envoyMetricsService.enabled }} + - --envoyMetricsService + {{- with $.Values.global.proxy.envoyMetricsService }} + - '{"address":"{{ .host }}:{{.port }}"{{ if .tlsSettings }},"tlsSettings":{{ .tlsSettings | toJson }}{{- end }}{{ if .tcpKeepalive }},"tcpKeepalive":{{ .tcpKeepalive | toJson }}{{- end }}}' + {{- end }} + {{- end}} + {{- if $.Values.global.proxy.envoyAccessLogService.enabled }} + - --envoyAccessLogService + {{- with $.Values.global.proxy.envoyAccessLogService }} + - '{"address":"{{ .host }}:{{.port }}"{{ if .tlsSettings }},"tlsSettings":{{ .tlsSettings | toJson }}{{- end }}{{ if .tcpKeepalive }},"tcpKeepalive":{{ .tcpKeepalive | toJson }}{{- end }}}' + {{- end }} + {{- end }} + - --proxyAdminPort + - "15000" + - --statusPort + - "15020" + {{- if $.Values.global.controlPlaneSecurityEnabled }} + - --controlPlaneAuthPolicy + - MUTUAL_TLS + - --discoveryAddress + {{- if $.Values.global.istioNamespace }} + - istio-pilot.{{ $.Values.global.istioNamespace }}:15011 + {{- else }} + - istio-pilot:15011 + {{- end }} + {{- else }} + - --controlPlaneAuthPolicy + - NONE + - --discoveryAddress + {{- if $.Values.global.istioNamespace }} + - istio-pilot.{{ $.Values.global.istioNamespace }}:15010 + {{- else }} + - istio-pilot:15010 + {{- end }} + {{- end }} + {{- if $.Values.global.trustDomain }} + - --trust-domain={{ $.Values.global.trustDomain }} + {{- end }} + readinessProbe: + failureThreshold: 30 + httpGet: + path: /healthz/ready + port: 15020 + scheme: HTTP + initialDelaySeconds: 1 + periodSeconds: 2 + successThreshold: 1 + timeoutSeconds: 1 + resources: +{{- if $spec.resources }} +{{ toYaml $spec.resources | indent 12 }} +{{- else }} +{{ toYaml $.Values.global.defaultResources | indent 12 }} +{{- end }} + env: + - name: NODE_NAME + valueFrom: + fieldRef: + apiVersion: v1 + fieldPath: spec.nodeName + - name: POD_NAME + valueFrom: + fieldRef: + apiVersion: v1 + fieldPath: metadata.name + - name: POD_NAMESPACE + valueFrom: + fieldRef: + apiVersion: v1 + fieldPath: metadata.namespace + - name: INSTANCE_IP + valueFrom: + fieldRef: + apiVersion: v1 + fieldPath: status.podIP + - name: HOST_IP + valueFrom: + fieldRef: + apiVersion: v1 + fieldPath: status.hostIP + - name: SERVICE_ACCOUNT + valueFrom: + fieldRef: + fieldPath: spec.serviceAccountName + {{- if $.Values.global.mtls.auto }} + - name: ISTIO_AUTO_MTLS_ENABLED + value: "true" + {{- end }} + - name: ISTIO_META_POD_NAME + valueFrom: + fieldRef: + apiVersion: v1 + fieldPath: metadata.name + - name: ISTIO_META_CONFIG_NAMESPACE + valueFrom: + fieldRef: + fieldPath: metadata.namespace + - name: ISTIO_METAJSON_LABELS + value: | + {{ $labels | toJson}} + - name: ISTIO_META_CLUSTER_ID + value: "{{ $.Values.global.multiCluster.clusterName | default `Kubernetes` }}" + - name: SDS_ENABLED + value: "{{ $.Values.global.sds.enabled }}" + - name: ISTIO_META_WORKLOAD_NAME + value: {{ $key }} + - name: ISTIO_META_OWNER + value: kubernetes://apis/apps/v1/namespaces/{{ $spec.namespace | default $.Release.Namespace }}/deployments/{{ $key }} + {{- if $.Values.global.meshID }} + - name: ISTIO_META_MESH_ID + value: "{{ $.Values.global.meshID }}" + {{- else if $.Values.global.trustDomain }} + - name: ISTIO_META_MESH_ID + value: "{{ $.Values.global.trustDomain }}" + {{- end }} + {{- if eq $.Values.global.proxy.tracer "datadog" }} + - name: HOST_IP + valueFrom: + fieldRef: + fieldPath: status.hostIP + {{- end }} + {{- if eq $.Values.global.proxy.tracer "stackdriver" }} + - name: STACKDRIVER_TRACING_ENABLED + value: "true" + - name: STACKDRIVER_TRACING_DEBUG + value: "{{ $.Values.global.tracer.stackdriver.debug }}" + {{- if $.Values.global.tracer.stackdriver.maxNumberOfAnnotations }} + - name: STACKDRIVER_TRACING_MAX_NUMBER_OF_ANNOTATIONS + value: "{{ $.Values.global.tracer.stackdriver.maxNumberOfAnnotations }}" + {{- end }} + {{- if $.Values.global.tracer.stackdriver.maxNumberOfAttributes }} + - name: STACKDRIVER_TRACING_MAX_NUMBER_OF_ATTRIBUTES + value: "{{ $.Values.global.tracer.stackdriver.maxNumberOfAttributes }}" + {{- end }} + {{- if $.Values.global.tracer.stackdriver.maxNumberOfMessageEvents }} + - name: STACKDRIVER_TRACING_MAX_NUMBER_OF_MESSAGE_EVENTS + value: "{{ $.Values.global.tracer.stackdriver.maxNumberOfMessageEvents }}" + {{- end }} + {{- end }} + {{- if $spec.sds }} + {{- if $spec.sds.enabled }} + - name: ISTIO_META_USER_SDS + value: "true" + {{- end }} + {{- end }} + {{- if $spec.env }} + {{- range $key, $val := $spec.env }} + - name: {{ $key }} + value: {{ $val }} + {{- end }} + {{- end }} + {{ if eq $key "istio-ingressgateway" }} + {{ $network_set := index $spec.env "ISTIO_META_NETWORK" }} + {{- if and (not $network_set) $.Values.global.network }} + - name: ISTIO_META_NETWORK + value: {{ $.Values.global.network }} + {{- end }} + {{- end }} + volumeMounts: + {{- if $.Values.global.sds.enabled }} + - name: sdsudspath + mountPath: /var/run/sds + readOnly: true + - name: istio-token + mountPath: /var/run/secrets/tokens + {{- end }} + {{- if $spec.sds }} + {{- if $spec.sds.enabled }} + - name: ingressgatewaysdsudspath + mountPath: /var/run/ingress_gateway + {{- end }} + {{- end }} + - name: istio-certs + mountPath: /etc/certs + readOnly: true + {{- range $spec.secretVolumes }} + - name: {{ .name }} + mountPath: {{ .mountPath | quote }} + readOnly: true + {{- end }} + {{- if and (eq $.Values.global.proxy.tracer "lightstep") $.Values.global.tracer.lightstep.cacertPath }} + - mountPath: {{ dir $.Values.global.tracer.lightstep.cacertPath }} + name: lightstep-certs + readOnly: true + {{- end }} +{{- if $spec.additionalContainers }} +{{ toYaml $spec.additionalContainers | indent 8 }} +{{- end }} + volumes: + {{- if $spec.sds }} + {{- if $spec.sds.enabled }} + - name: ingressgatewaysdsudspath + emptyDir: {} + {{- end }} + {{- end }} + {{- if $.Values.global.sds.enabled }} + - name: sdsudspath + hostPath: + path: /var/run/sds + - name: istio-token + projected: + sources: + - serviceAccountToken: + path: istio-token + expirationSeconds: 43200 + audience: {{ $.Values.global.sds.token.aud }} + {{- end }} + - name: istio-certs + secret: + secretName: istio.{{ $key }}-service-account + optional: true + {{- range $spec.secretVolumes }} + - name: {{ .name }} + secret: + secretName: {{ .secretName | quote }} + optional: true + {{- end }} + {{- range $spec.configVolumes }} + - name: {{ .name }} + configMap: + name: {{ .configMapName | quote }} + optional: true + {{- end }} + {{- if and (eq $.Values.global.proxy.tracer "lightstep") $.Values.global.tracer.lightstep.cacertPath }} + - name: lightstep-certs + secret: + optional: true + secretName: lightstep.cacert + {{- end }} + affinity: + {{- include "gatewaynodeaffinity" (dict "root" $ "nodeSelector" $spec.nodeSelector) | indent 6 }} + {{- include "gatewaypodAntiAffinity" (dict "podAntiAffinityLabelSelector" $spec.podAntiAffinityLabelSelector "podAntiAffinityTermLabelSelector" $spec.podAntiAffinityTermLabelSelector) | indent 6 }} + {{- if $spec.tolerations }} + tolerations: +{{ toYaml $spec.tolerations | indent 6 }} + {{- else if $.Values.global.defaultTolerations }} + tolerations: +{{ toYaml $.Values.global.defaultTolerations | indent 6 }} + {{- end }} +--- +{{- end }} +{{- end }} +{{- end }} diff --git a/istio-1.5.0/install/kubernetes/helm/istio/charts/gateways/templates/poddisruptionbudget.yaml b/istio-1.5.0/install/kubernetes/helm/istio/charts/gateways/templates/poddisruptionbudget.yaml new file mode 100644 index 0000000..865921e --- /dev/null +++ b/istio-1.5.0/install/kubernetes/helm/istio/charts/gateways/templates/poddisruptionbudget.yaml @@ -0,0 +1,29 @@ +{{- range $key, $spec := .Values }} +{{- if and (ne $key "enabled") }} +{{- if $spec.enabled }} +{{- if $.Values.global.defaultPodDisruptionBudget.enabled }} +apiVersion: policy/v1beta1 +kind: PodDisruptionBudget +metadata: + name: {{ $key }} + namespace: {{ $spec.namespace | default $.Release.Namespace }} + labels: + chart: {{ template "gateway.chart" $ }} + heritage: {{ $.Release.Service }} + release: {{ $.Release.Name }} + {{- range $key, $val := $spec.labels }} + {{ $key }}: {{ $val }} + {{- end }} +spec: +{{ include "podDisruptionBudget.spec" $.Values.global.defaultPodDisruptionBudget }} + selector: + matchLabels: + release: {{ $.Release.Name }} + {{- range $key, $val := $spec.labels }} + {{ $key }}: {{ $val }} + {{- end }} +--- +{{- end }} +{{- end }} +{{- end }} +{{- end }} diff --git a/istio-1.5.0/install/kubernetes/helm/istio/charts/gateways/templates/preconfigured.yaml b/istio-1.5.0/install/kubernetes/helm/istio/charts/gateways/templates/preconfigured.yaml new file mode 100644 index 0000000..6ef10a6 --- /dev/null +++ b/istio-1.5.0/install/kubernetes/helm/istio/charts/gateways/templates/preconfigured.yaml @@ -0,0 +1,246 @@ +{{- if .Values.global.k8sIngress.enabled }} +apiVersion: networking.istio.io/v1alpha3 +kind: Gateway +metadata: + name: istio-autogenerated-k8s-ingress + namespace: {{ .Release.Namespace }} + labels: + app: {{ template "gateway.name" . }} + chart: {{ template "gateway.chart" . }} + heritage: {{ .Release.Service }} + release: {{ .Release.Name }} +spec: + selector: + istio: {{ .Values.global.k8sIngress.gatewayName }} + servers: + - port: + number: 80 + protocol: HTTP2 + name: http + hosts: + - "*" +{{ if .Values.global.k8sIngress.enableHttps }} + - port: + number: 443 + protocol: HTTPS + name: https-default + tls: + mode: SIMPLE + serverCertificate: /etc/istio/ingressgateway-certs/tls.crt + privateKey: /etc/istio/ingressgateway-certs/tls.key + hosts: + - "*" +{{ end }} +--- +{{ end }} + +{{- if .Values.global.meshExpansion.enabled }} +{{- if .Values.global.meshExpansion.useILB }} +apiVersion: networking.istio.io/v1alpha3 +kind: Gateway +metadata: + name: meshexpansion-ilb-gateway + namespace: {{ .Release.Namespace }} + labels: + app: {{ template "gateway.name" . }} + chart: {{ template "gateway.chart" . }} + heritage: {{ .Release.Service }} + release: {{ .Release.Name }} +spec: + selector: + istio: ilbgateway + servers: + - port: + number: 15011 + protocol: TCP + name: tcp-pilot + hosts: + - "*" + - port: + number: 8060 + protocol: TCP + name: tcp-citadel + hosts: + - "*" + - port: + number: 15004 + name: tls-mixer + protocol: TLS + tls: + mode: AUTO_PASSTHROUGH + hosts: + - "*" +--- +{{- else }} +apiVersion: networking.istio.io/v1alpha3 +kind: Gateway +metadata: + name: meshexpansion-gateway + namespace: {{ .Release.Namespace }} + labels: + app: {{ template "gateway.name" . }} + chart: {{ template "gateway.chart" . }} + heritage: {{ .Release.Service }} + release: {{ .Release.Name }} +spec: + selector: + {{- range $key, $spec := .Values }} + {{- if eq $key "istio-ingressgateway" }} + {{- if $spec.enabled }} + {{- range $key, $val := $spec.labels }} + {{ $key }}: {{ $val }} + {{- end }} + {{- end }} + {{- end }} + {{- end }} + servers: + - port: + number: 15011 + protocol: TCP + name: tcp-pilot + hosts: + - "*" + - port: + number: 8060 + protocol: TCP + name: tcp-citadel + hosts: + - "*" + - port: + number: 15004 + name: tls-mixer + protocol: TLS + tls: + mode: AUTO_PASSTHROUGH + hosts: + - "*" +--- +{{- end }} +{{- end }} + +{{- if .Values.global.multiCluster.enabled }} +{{- if (index .Values "istio-egressgateway" "enabled") }} +apiVersion: networking.istio.io/v1alpha3 +kind: Gateway +metadata: + name: istio-multicluster-egressgateway + namespace: {{ .Release.Namespace }} + labels: + app: {{ template "gateway.name" . }} + chart: {{ template "gateway.chart" . }} + heritage: {{ .Release.Service }} + release: {{ .Release.Name }} +spec: + selector: + {{- range $key, $spec := .Values }} + {{- if eq $key "istio-egressgateway" }} + {{- if $spec.enabled }} + {{- range $key, $val := $spec.labels }} + {{ $key }}: {{ $val }} + {{- end }} + {{- end }} + {{- end }} + {{- end }} + servers: + - hosts: + - "*.global" + port: + name: tls + number: 15443 + protocol: TLS + tls: + mode: AUTO_PASSTHROUGH +{{- end }} +--- +apiVersion: networking.istio.io/v1alpha3 +kind: Gateway +metadata: + name: istio-multicluster-ingressgateway + namespace: {{ .Release.Namespace }} + labels: + app: {{ template "gateway.name" . }} + chart: {{ template "gateway.chart" . }} + heritage: {{ .Release.Service }} + release: {{ .Release.Name }} +spec: + selector: + {{- range $key, $spec := .Values }} + {{- if eq $key "istio-ingressgateway" }} + {{- if $spec.enabled }} + {{- range $key, $val := $spec.labels }} + {{ $key }}: {{ $val }} + {{- end }} + {{- end }} + {{- end }} + {{- end }} + servers: + - hosts: + - "*.global" + port: + name: tls + number: 15443 + protocol: TLS + tls: + mode: AUTO_PASSTHROUGH +--- +apiVersion: networking.istio.io/v1alpha3 +kind: EnvoyFilter +metadata: + name: istio-multicluster-ingressgateway + namespace: {{ .Release.Namespace }} + labels: + app: {{ template "gateway.name" . }} + chart: {{ template "gateway.chart" . }} + heritage: {{ .Release.Service }} + release: {{ .Release.Name }} +spec: + workloadSelector: + labels: + {{- range $key, $spec := .Values }} + {{- if eq $key "istio-ingressgateway" }} + {{- if $spec.enabled }} + {{- range $key, $val := $spec.labels }} + {{ $key }}: {{ $val }} + {{- end }} + {{- end }} + {{- end }} + {{- end }} + configPatches: + - applyTo: NETWORK_FILTER + match: + context: GATEWAY + listener: + portNumber: 15443 + filterChain: + filter: + name: "envoy.filters.network.sni_cluster" + patch: + operation: INSERT_AFTER + value: + name: "envoy.filters.network.tcp_cluster_rewrite" + config: + cluster_pattern: "\\.global$" + cluster_replacement: ".svc.{{ .Values.global.proxy.clusterDomain }}" +--- +## To ensure all traffic to *.global is using mTLS +apiVersion: networking.istio.io/v1alpha3 +kind: DestinationRule +metadata: + name: istio-multicluster-destinationrule + namespace: {{ .Release.Namespace }} + labels: + app: {{ template "gateway.name" . }} + chart: {{ template "gateway.chart" . }} + heritage: {{ .Release.Service }} + release: {{ .Release.Name }} +spec: + host: "*.global" + {{- if .Values.global.defaultConfigVisibilitySettings }} + exportTo: + - '*' + {{- end }} + trafficPolicy: + tls: + mode: ISTIO_MUTUAL +--- +{{- end }} diff --git a/istio-1.5.0/install/kubernetes/helm/istio/charts/gateways/templates/role.yaml b/istio-1.5.0/install/kubernetes/helm/istio/charts/gateways/templates/role.yaml new file mode 100644 index 0000000..37bdf3e --- /dev/null +++ b/istio-1.5.0/install/kubernetes/helm/istio/charts/gateways/templates/role.yaml @@ -0,0 +1,18 @@ +{{- range $key, $spec := .Values }} +{{- if ne $key "enabled" }} +{{- if $spec.enabled }} +{{- if ($spec.sds) and (eq $spec.sds.enabled true) }} +apiVersion: rbac.authorization.k8s.io/v1 +kind: Role +metadata: + name: {{ $key }}-sds + namespace: {{ $spec.namespace | default $.Release.Namespace }} +rules: +- apiGroups: [""] + resources: ["secrets"] + verbs: ["get", "watch", "list"] +--- +{{- end }} +{{- end }} +{{- end }} +{{- end }} diff --git a/istio-1.5.0/install/kubernetes/helm/istio/charts/gateways/templates/rolebindings.yaml b/istio-1.5.0/install/kubernetes/helm/istio/charts/gateways/templates/rolebindings.yaml new file mode 100644 index 0000000..cd3245b --- /dev/null +++ b/istio-1.5.0/install/kubernetes/helm/istio/charts/gateways/templates/rolebindings.yaml @@ -0,0 +1,21 @@ +{{- range $key, $spec := .Values }} +{{- if ne $key "enabled" }} +{{- if $spec.enabled }} +{{- if ($spec.sds) and (eq $spec.sds.enabled true) }} +apiVersion: rbac.authorization.k8s.io/v1 +kind: RoleBinding +metadata: + name: {{ $key }}-sds + namespace: {{ $spec.namespace | default $.Release.Namespace }} +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: Role + name: {{ $key }}-sds +subjects: +- kind: ServiceAccount + name: {{ $key }}-service-account +--- +{{- end }} +{{- end }} +{{- end }} +{{- end }} diff --git a/istio-1.5.0/install/kubernetes/helm/istio/charts/gateways/templates/service.yaml b/istio-1.5.0/install/kubernetes/helm/istio/charts/gateways/templates/service.yaml new file mode 100644 index 0000000..9474f04 --- /dev/null +++ b/istio-1.5.0/install/kubernetes/helm/istio/charts/gateways/templates/service.yaml @@ -0,0 +1,59 @@ +{{- range $key, $spec := .Values }} +{{- if ne $key "enabled" }} +{{- if $spec.enabled }} +apiVersion: v1 +kind: Service +metadata: + name: {{ $key }} + namespace: {{ $spec.namespace | default $.Release.Namespace }} + annotations: + {{- range $key, $val := $spec.serviceAnnotations }} + {{ $key }}: {{ $val | quote }} + {{- end }} + labels: + chart: {{ template "gateway.chart" $ }} + heritage: {{ $.Release.Service }} + release: {{ $.Release.Name }} + {{- range $key, $val := $spec.labels }} + {{ $key }}: {{ $val }} + {{- end }} +spec: +{{- if $spec.loadBalancerIP }} + loadBalancerIP: "{{ $spec.loadBalancerIP }}" +{{- end }} +{{- if $spec.loadBalancerSourceRanges }} + loadBalancerSourceRanges: +{{ toYaml $spec.loadBalancerSourceRanges | indent 4 }} +{{- end }} +{{- if $spec.externalTrafficPolicy }} + externalTrafficPolicy: {{$spec.externalTrafficPolicy }} +{{- end }} +{{- if $spec.externalIPs }} + externalIPs: +{{ toYaml $spec.externalIPs | indent 4 }} +{{- end }} + type: {{ .type }} + selector: + release: {{ $.Release.Name }} + {{- range $key, $val := $spec.labels }} + {{ $key }}: {{ $val }} + {{- end }} + ports: + {{- range $key, $val := $spec.ports }} + - + {{- range $pkey, $pval := $val }} + {{ $pkey}}: {{ $pval }} + {{- end }} + {{- end }} + {{- if $.Values.global.meshExpansion.enabled }} + {{- range $key, $val := $spec.meshExpansionPorts }} + - + {{- range $pkey, $pval := $val }} + {{ $pkey}}: {{ $pval }} + {{- end }} + {{- end }} + {{- end }} +--- +{{- end }} +{{- end }} +{{- end }} diff --git a/istio-1.5.0/install/kubernetes/helm/istio/charts/gateways/templates/serviceaccount.yaml b/istio-1.5.0/install/kubernetes/helm/istio/charts/gateways/templates/serviceaccount.yaml new file mode 100644 index 0000000..d4f6938 --- /dev/null +++ b/istio-1.5.0/install/kubernetes/helm/istio/charts/gateways/templates/serviceaccount.yaml @@ -0,0 +1,24 @@ +{{- range $key, $spec := .Values }} +{{- if ne $key "enabled" }} +{{- if $spec.enabled }} +apiVersion: v1 +kind: ServiceAccount +{{- if $.Values.global.imagePullSecrets }} +imagePullSecrets: +{{- range $.Values.global.imagePullSecrets }} + - name: {{ . }} +{{- end }} +{{- end }} +metadata: + name: {{ $key }}-service-account + namespace: {{ $spec.namespace | default $.Release.Namespace }} + labels: + app: {{ $spec.labels.app }} + chart: {{ template "gateway.chart" $ }} + heritage: {{ $.Release.Service }} + release: {{ $.Release.Name }} +--- +{{- end }} +{{- end }} +{{- end }} + diff --git a/istio-1.5.0/install/kubernetes/helm/istio/charts/gateways/values.yaml b/istio-1.5.0/install/kubernetes/helm/istio/charts/gateways/values.yaml new file mode 100644 index 0000000..69815e4 --- /dev/null +++ b/istio-1.5.0/install/kubernetes/helm/istio/charts/gateways/values.yaml @@ -0,0 +1,282 @@ +# +# Gateways Configuration +# By default (if enabled) a pair of Ingress and Egress Gateways will be created for the mesh. +# You can add more gateways in addition to the defaults but make sure those are uniquely named +# and that NodePorts are not conflicting. +# Disable specifc gateway by setting the `enabled` to false. +# +enabled: true + +istio-ingressgateway: + enabled: true + # + # Secret Discovery Service (SDS) configuration for ingress gateway. + # + sds: + # If true, ingress gateway fetches credentials from SDS server to handle TLS connections. + enabled: false + # SDS server that watches kubernetes secrets and provisions credentials to ingress gateway. + # This server runs in the same pod as ingress gateway. + image: node-agent-k8s + resources: + requests: + cpu: 100m + memory: 128Mi + limits: + cpu: 2000m + memory: 1024Mi + + labels: + app: istio-ingressgateway + istio: ingressgateway + autoscaleEnabled: true + autoscaleMin: 1 + autoscaleMax: 5 + # specify replicaCount when autoscaleEnabled: false + # replicaCount: 1 + rollingMaxSurge: 100% + rollingMaxUnavailable: 25% + resources: + requests: + cpu: 100m + memory: 128Mi + limits: + cpu: 2000m + memory: 1024Mi + cpu: + targetAverageUtilization: 80 + loadBalancerIP: "" + loadBalancerSourceRanges: [] + externalIPs: [] + serviceAnnotations: {} + podAnnotations: {} + type: LoadBalancer #change to NodePort, ClusterIP or LoadBalancer if need be + #externalTrafficPolicy: Local #change to Local to preserve source IP or Cluster for default behaviour or leave commented out + ports: + ## You can add custom gateway ports + # Note that AWS ELB will by default perform health checks on the first port + # on this list. Setting this to the health check port will ensure that health + # checks always work. https://github.com/istio/istio/issues/12503 + - port: 15020 + targetPort: 15020 + name: status-port + - port: 80 + targetPort: 80 + name: http2 + nodePort: 31380 + - port: 443 + name: https + nodePort: 31390 + # Example of a port to add. Remove if not needed + - port: 31400 + name: tcp + nodePort: 31400 + ### PORTS FOR UI/metrics ##### + ## Disable if not needed + - port: 15029 + targetPort: 15029 + name: https-kiali + - port: 15030 + targetPort: 15030 + name: https-prometheus + - port: 15031 + targetPort: 15031 + name: https-grafana + - port: 15032 + targetPort: 15032 + name: https-tracing + # This is the port where sni routing happens + - port: 15443 + targetPort: 15443 + name: tls + #### MESH EXPANSION PORTS ######## + # Pilot and Citadel MTLS ports are enabled in gateway - but will only redirect + # to pilot/citadel if global.meshExpansion settings are enabled. + # Delete these ports if mesh expansion is not enabled, to avoid + # exposing unnecessary ports on the web. + # You can remove these ports if you are not using mesh expansion + meshExpansionPorts: + - port: 15011 + targetPort: 15011 + name: tcp-pilot-grpc-tls + - port: 15004 + targetPort: 15004 + name: tcp-mixer-grpc-tls + - port: 8060 + targetPort: 8060 + name: tcp-citadel-grpc-tls + - port: 853 + targetPort: 853 + name: tcp-dns-tls + ####### end MESH EXPANSION PORTS ###### + ############## + secretVolumes: + - name: ingressgateway-certs + secretName: istio-ingressgateway-certs + mountPath: /etc/istio/ingressgateway-certs + - name: ingressgateway-ca-certs + secretName: istio-ingressgateway-ca-certs + mountPath: /etc/istio/ingressgateway-ca-certs + ### Advanced options ############ + + env: + # By default, a gateway is in "standard" mode. If the mode is set to "sni-dnat", + # pilot generates an additional + # set of clusters for internal services without Istio mTLS, to + # enable cross cluster routing. Enable when using multi-cluster routing. + ISTIO_META_ROUTER_MODE: "standard" + nodeSelector: {} + tolerations: [] + + # Specify the pod anti-affinity that allows you to constrain which nodes + # your pod is eligible to be scheduled based on labels on pods that are + # already running on the node rather than based on labels on nodes. + # There are currently two types of anti-affinity: + # "requiredDuringSchedulingIgnoredDuringExecution" + # "preferredDuringSchedulingIgnoredDuringExecution" + # which denote "hard" vs. "soft" requirements, you can define your values + # in "podAntiAffinityLabelSelector" and "podAntiAffinityTermLabelSelector" + # correspondingly. + # For example: + # podAntiAffinityLabelSelector: + # - key: security + # operator: In + # values: S1,S2 + # topologyKey: "kubernetes.io/hostname" + # This pod anti-affinity rule says that the pod requires not to be scheduled + # onto a node if that node is already running a pod with label having key + # "security" and value "S1". + podAntiAffinityLabelSelector: [] + podAntiAffinityTermLabelSelector: [] + +istio-egressgateway: + enabled: false + labels: + app: istio-egressgateway + istio: egressgateway + autoscaleEnabled: true + autoscaleMin: 1 + autoscaleMax: 5 + # specify replicaCount when autoscaleEnabled: false + # replicaCount: 1 + rollingMaxSurge: 100% + rollingMaxUnavailable: 25% + resources: + requests: + cpu: 100m + memory: 128Mi + limits: + cpu: 2000m + memory: 1024Mi + cpu: + targetAverageUtilization: 80 + serviceAnnotations: {} + podAnnotations: {} + type: ClusterIP #change to NodePort or LoadBalancer if need be + ports: + - port: 80 + name: http2 + - port: 443 + name: https + # This is the port where sni routing happens + - port: 15443 + targetPort: 15443 + name: tls + secretVolumes: + - name: egressgateway-certs + secretName: istio-egressgateway-certs + mountPath: /etc/istio/egressgateway-certs + - name: egressgateway-ca-certs + secretName: istio-egressgateway-ca-certs + mountPath: /etc/istio/egressgateway-ca-certs + #### Advanced options ######## + env: + # Set this to "external" if and only if you want the egress gateway to + # act as a transparent SNI gateway that routes mTLS/TLS traffic to + # external services defined using service entries, where the service + # entry has resolution set to DNS, has one or more endpoints with + # network field set to "external". By default its set to "" so that + # the egress gateway sees the same set of endpoints as the sidecars + # preserving backward compatibility + # ISTIO_META_REQUESTED_NETWORK_VIEW: "" + + # By default, a gateway is in "standard" mode. If the mode is set to "sni-dnat", + # pilot generates an additional + # set of clusters for internal services but without Istio mTLS, to + # enable cross cluster routing. + ISTIO_META_ROUTER_MODE: "standard" + nodeSelector: {} + tolerations: [] + + # Specify the pod anti-affinity that allows you to constrain which nodes + # your pod is eligible to be scheduled based on labels on pods that are + # already running on the node rather than based on labels on nodes. + # There are currently two types of anti-affinity: + # "requiredDuringSchedulingIgnoredDuringExecution" + # "preferredDuringSchedulingIgnoredDuringExecution" + # which denote "hard" vs. "soft" requirements, you can define your values + # in "podAntiAffinityLabelSelector" and "podAntiAffinityTermLabelSelector" + # correspondingly. + # For example: + # podAntiAffinityLabelSelector: + # - key: security + # operator: In + # values: S1,S2 + # topologyKey: "kubernetes.io/hostname" + # This pod anti-affinity rule says that the pod requires not to be scheduled + # onto a node if that node is already running a pod with label having key + # "security" and value "S1". + podAntiAffinityLabelSelector: [] + podAntiAffinityTermLabelSelector: [] + +# Mesh ILB gateway creates a gateway of type InternalLoadBalancer, +# for mesh expansion. It exposes the mtls ports for Pilot,CA as well +# as non-mtls ports to support upgrades and gradual transition. +istio-ilbgateway: + enabled: false + labels: + app: istio-ilbgateway + istio: ilbgateway + autoscaleEnabled: true + autoscaleMin: 1 + autoscaleMax: 5 + # specify replicaCount when autoscaleEnabled: false + # replicaCount: 1 + rollingMaxSurge: 100% + rollingMaxUnavailable: 25% + cpu: + targetAverageUtilization: 80 + resources: + requests: + cpu: 800m + memory: 512Mi + #limits: + # cpu: 1800m + # memory: 256Mi + loadBalancerIP: "" + serviceAnnotations: + cloud.google.com/load-balancer-type: "internal" + podAnnotations: {} + type: LoadBalancer + ports: + ## You can add custom gateway ports - google ILB default quota is 5 ports, + - port: 15011 + name: grpc-pilot-mtls + # Insecure port - only for migration from 0.8. Will be removed in 1.1 + - port: 15010 + name: grpc-pilot + - port: 8060 + targetPort: 8060 + name: tcp-citadel-grpc-tls + # Port 5353 is forwarded to kube-dns + - port: 5353 + name: tcp-dns + secretVolumes: + - name: ilbgateway-certs + secretName: istio-ilbgateway-certs + mountPath: /etc/istio/ilbgateway-certs + - name: ilbgateway-ca-certs + secretName: istio-ilbgateway-ca-certs + mountPath: /etc/istio/ilbgateway-ca-certs + nodeSelector: {} + tolerations: [] diff --git a/istio-1.5.0/install/kubernetes/helm/istio/charts/grafana/Chart.yaml b/istio-1.5.0/install/kubernetes/helm/istio/charts/grafana/Chart.yaml new file mode 100644 index 0000000..005ca5d --- /dev/null +++ b/istio-1.5.0/install/kubernetes/helm/istio/charts/grafana/Chart.yaml @@ -0,0 +1,6 @@ +apiVersion: v1 +description: A Helm chart for Kubernetes +name: grafana +version: 1.5.0 +appVersion: 1.5.0 +tillerVersion: ">=2.7.2" diff --git a/istio-1.5.0/install/kubernetes/helm/istio/charts/grafana/dashboards/citadel-dashboard.json b/istio-1.5.0/install/kubernetes/helm/istio/charts/grafana/dashboards/citadel-dashboard.json new file mode 100644 index 0000000..7cb8e5b --- /dev/null +++ b/istio-1.5.0/install/kubernetes/helm/istio/charts/grafana/dashboards/citadel-dashboard.json @@ -0,0 +1,1089 @@ +{ + "annotations": { + "list": [ + { + "builtIn": 1, + "datasource": "-- Grafana --", + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations & Alerts", + "type": "dashboard" + } + ] + }, + "description": "", + "editable": true, + "gnetId": null, + "graphTooltip": 0, + "links": [], + "panels": [ + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 0 + }, + "id": 8, + "panels": [], + "title": "Performance", + "type": "row" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "description": "CPU usage across Citadel instances.", + "fill": 1, + "gridPos": { + "h": 6, + "w": 8, + "x": 0, + "y": 1 + }, + "id": 10, + "legend": { + "alignAsTable": false, + "avg": false, + "current": false, + "max": false, + "min": false, + "rightSide": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(rate(container_cpu_usage_seconds_total{job=\"kubernetes-cadvisor\",container=~\"citadel\", pod=~\"istio-citadel-.*\"}[1m]))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Citadel CPU usage rate", + "refId": "A" + }, + { + "expr": "irate(process_cpu_seconds_total{job=\"citadel\"}[1m])", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Citadel CPU usage irate", + "refId": "C" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "CPU", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": "", + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "description": "Citadel process memory statistics.", + "fill": 1, + "gridPos": { + "h": 6, + "w": 8, + "x": 8, + "y": 1 + }, + "id": 12, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "process_virtual_memory_bytes{job=\"citadel\"}", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Virtual Memory", + "refId": "A" + }, + { + "expr": "process_resident_memory_bytes{job=\"citadel\"}", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Resident Memory", + "refId": "B" + }, + { + "expr": "go_memstats_heap_sys_bytes{job=\"citadel\"}", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Heap Memory Total", + "refId": "C" + }, + { + "expr": "go_memstats_alloc_bytes{job=\"citadel\"}", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Heap Memory Allocated", + "refId": "E" + }, + { + "expr": "go_memstats_heap_inuse_bytes{job=\"citadel\"}", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Heap Inuse", + "refId": "F" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Memory", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "fill": 1, + "gridPos": { + "h": 6, + "w": 8, + "x": 16, + "y": 1 + }, + "id": 14, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "go_goroutines{job=\"citadel\"}", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Goroutines", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Goroutines", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 7 + }, + "id": 28, + "panels": [], + "title": "General", + "type": "row" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "description": "Total number of CSR requests made to Citadel.", + "fill": 1, + "gridPos": { + "h": 5, + "w": 12, + "x": 0, + "y": 8 + }, + "id": 30, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "citadel_server_csr_count{job=\"citadel\"}", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "CSR Request Count", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "CSR Requests", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "description": "The number of certificates issuances that have succeeded.", + "fill": 1, + "gridPos": { + "h": 5, + "w": 12, + "x": 12, + "y": 8 + }, + "id": 32, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "citadel_server_success_cert_issuance_count{job=\"citadel\"}", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Certificates Issued", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Certificates Issued", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 13 + }, + "id": 23, + "panels": [], + "title": "Errors", + "type": "row" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "description": "The number of errors occurred when creating the CSR.", + "fill": 1, + "gridPos": { + "h": 5, + "w": 8, + "x": 0, + "y": 14 + }, + "id": 20, + "legend": { + "alignAsTable": false, + "avg": false, + "current": false, + "max": false, + "min": false, + "rightSide": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "citadel_secret_controller_csr_err_count{job=\"citadel\"}", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "CSR Creation Error Count", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "CSR Creation Errors", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": "", + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "fill": 1, + "gridPos": { + "h": 5, + "w": 8, + "x": 8, + "y": 14 + }, + "id": 24, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "citadel_server_csr_parsing_err_count{job=\"citadel\"}", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "CSR Parse Error Count", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "CSR Parse Errors", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "description": "The number of authentication failures.", + "fill": 1, + "gridPos": { + "h": 5, + "w": 8, + "x": 16, + "y": 14 + }, + "id": 26, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "citadel_server_authentication_failure_count{job=\"citadel\"}", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Authentication Failure Count", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Authentication Failures", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 19 + }, + "id": 4, + "panels": [], + "title": "Secret Controller", + "type": "row" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "description": "The number of certificates created due to service account creation.", + "fill": 1, + "gridPos": { + "h": 5, + "w": 8, + "x": 0, + "y": 20 + }, + "id": 2, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": true, + "targets": [ + { + "expr": "citadel_secret_controller_svc_acc_created_cert_count{job=\"citadel\"}", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "SA Secrets Created", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Service Account Secrets Created (due to SA creation)", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "decimals": null, + "format": "short", + "label": "Certs Created", + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "description": "The number of certificates deleted due to service account deletion.", + "fill": 1, + "gridPos": { + "h": 5, + "w": 8, + "x": 8, + "y": 20 + }, + "id": 16, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": true, + "targets": [ + { + "expr": "citadel_secret_controller_svc_acc_deleted_cert_count{job=\"citadel\"}", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "SA Secrets Deleted", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Service Account Secrets Deleted (due to SA deletion)", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "decimals": null, + "format": "short", + "label": "Certs Created", + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "description": "The number of certificates recreated due to secret deletion (service account still exists).", + "fill": 1, + "gridPos": { + "h": 5, + "w": 8, + "x": 16, + "y": 20 + }, + "id": 6, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": true, + "targets": [ + { + "expr": "citadel_secret_controller_secret_deleted_cert_count{job=\"citadel\"}", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "SA Secrets Recreated", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Service Account Secrets Recreated (due to errant deletion)", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "decimals": null, + "format": "short", + "label": "Certs Created", + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + } + ], + "refresh": "5s", + "schemaVersion": 18, + "style": "dark", + "tags": [], + "templating": { + "list": [] + }, + "time": { + "from": "now-5m", + "to": "now" + }, + "timepicker": { + "refresh_intervals": [ + "5s", + "10s", + "30s", + "1m", + "5m", + "15m", + "30m", + "1h", + "2h", + "1d" + ], + "time_options": [ + "5m", + "15m", + "1h", + "6h", + "12h", + "24h", + "2d", + "7d", + "30d" + ] + }, + "timezone": "", + "title": "Istio Citadel Dashboard", + "uid": "OOyOqb4Wz", + "version": 1 +} \ No newline at end of file diff --git a/istio-1.5.0/install/kubernetes/helm/istio/charts/grafana/dashboards/galley-dashboard.json b/istio-1.5.0/install/kubernetes/helm/istio/charts/grafana/dashboards/galley-dashboard.json new file mode 100644 index 0000000..1cdb6a5 --- /dev/null +++ b/istio-1.5.0/install/kubernetes/helm/istio/charts/grafana/dashboards/galley-dashboard.json @@ -0,0 +1,1734 @@ +{ + "__inputs": [ + { + "name": "DS_PROMETHEUS", + "label": "Prometheus", + "description": "", + "type": "datasource", + "pluginId": "prometheus", + "pluginName": "Prometheus" + } + ], + "annotations": { + "list": [ + { + "builtIn": 1, + "datasource": "-- Grafana --", + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations & Alerts", + "type": "dashboard" + } + ] + }, + "editable": false, + "gnetId": null, + "graphTooltip": 0, + "links": [], + "panels": [ + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 5, + "w": 24, + "x": 0, + "y": 0 + }, + "id": 46, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(istio_build{component=\"galley\"}) by (tag)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{ tag }}", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Galley Versions", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 5 + }, + "id": 40, + "panels": [], + "title": "Resource Usage", + "type": "row" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 8, + "w": 6, + "x": 0, + "y": 6 + }, + "id": 36, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "process_virtual_memory_bytes{job=\"galley\"}", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "Virtual Memory", + "refId": "A" + }, + { + "expr": "process_resident_memory_bytes{job=\"galley\"}", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "Resident Memory", + "refId": "B" + }, + { + "expr": "go_memstats_heap_sys_bytes{job=\"galley\"}", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "heap sys", + "refId": "C" + }, + { + "expr": "go_memstats_heap_alloc_bytes{job=\"galley\"}", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "heap alloc", + "refId": "D" + }, + { + "expr": "go_memstats_alloc_bytes{job=\"galley\"}", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "Alloc", + "refId": "F" + }, + { + "expr": "go_memstats_heap_inuse_bytes{job=\"galley\"}", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "Heap in-use", + "refId": "G" + }, + { + "expr": "go_memstats_stack_inuse_bytes{job=\"galley\"}", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "Stack in-use", + "refId": "H" + }, + { + "expr": "sum(container_memory_usage_bytes{job=\"kubernetes-cadvisor\",container=~\"galley\", pod=~\"istio-galley-.*\"})", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Total (kis)", + "refId": "E" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Memory", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 8, + "w": 6, + "x": 6, + "y": 6 + }, + "id": 38, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(rate(container_cpu_usage_seconds_total{job=\"kubernetes-cadvisor\",container=~\"galley\", pod=~\"istio-galley-.*\"}[1m]))", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "Total (k8s)", + "refId": "A" + }, + { + "expr": "sum(rate(container_cpu_usage_seconds_total{job=\"kubernetes-cadvisor\",container=~\"galley\", pod=~\"istio-galley-.*\"}[1m])) by (container)", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "{{ container }} (k8s)", + "refId": "B" + }, + { + "expr": "irate(process_cpu_seconds_total{job=\"galley\"}[1m])", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "galley (self-reported)", + "refId": "C" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "CPU", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 8, + "w": 6, + "x": 12, + "y": 6 + }, + "id": 42, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "process_open_fds{job=\"galley\"}", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "Open FDs (galley)", + "refId": "A" + }, + { + "expr": "container_fs_usage_bytes{job=\"kubernetes-cadvisor\",container=~\"galley\", pod=~\"istio-galley-.*\"}", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "{{ container }} ", + "refId": "B" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Disk", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 8, + "w": 6, + "x": 18, + "y": 6 + }, + "id": 44, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "go_goroutines{job=\"galley\"}", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "goroutines_total", + "refId": "A" + }, + { + "expr": "istio_mcp_clients_total{component=\"galley\"}", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "clients_total", + "refId": "B" + }, + { + "expr": "go_goroutines{job=\"galley\"}/sum(istio_mcp_clients_total{component=\"galley\"}) without (component)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "avg_goroutines_per_client", + "refId": "C" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Goroutines", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 14 + }, + "id": 10, + "panels": [], + "title": "Runtime", + "type": "row" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 6, + "w": 8, + "x": 0, + "y": 15 + }, + "id": 2, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(rate(galley_runtime_strategy_on_change_total[1m])) * 60", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Strategy Change Events", + "refId": "A" + }, + { + "expr": "sum(rate(galley_runtime_processor_events_processed_total[1m])) * 60", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Processed Events", + "refId": "B" + }, + { + "expr": "sum(rate(galley_runtime_processor_snapshots_published_total[1m])) * 60", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Snapshot Published", + "refId": "C" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Event Rates", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": "Events/min", + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": "", + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 6, + "w": 8, + "x": 8, + "y": 15 + }, + "id": 4, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(rate(galley_runtime_strategy_timer_max_time_reached_total[1m])) * 60", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Max Time Reached", + "refId": "A" + }, + { + "expr": "sum(rate(galley_runtime_strategy_timer_quiesce_reached_total[1m])) * 60", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Quiesce Reached", + "refId": "B" + }, + { + "expr": "sum(rate(galley_runtime_strategy_timer_resets_total[1m])) * 60", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Timer Resets", + "refId": "C" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Timer Rates", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": "Events/min", + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 6, + "w": 8, + "x": 16, + "y": 15 + }, + "id": 8, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 3, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": true, + "steppedLine": false, + "targets": [ + { + "expr": "histogram_quantile(0.50, sum by (le) (galley_runtime_processor_snapshot_events_total_bucket))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "P50", + "refId": "A" + }, + { + "expr": "histogram_quantile(0.90, sum by (le) (galley_runtime_processor_snapshot_events_total_bucket))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "P90", + "refId": "B" + }, + { + "expr": "histogram_quantile(0.95, sum by (le) (galley_runtime_processor_snapshot_events_total_bucket))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "P95", + "refId": "C" + }, + { + "expr": "histogram_quantile(0.99, sum by (le) (galley_runtime_processor_snapshot_events_total_bucket))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "P99", + "refId": "D" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Events Per Snapshot", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 6, + "w": 8, + "x": 8, + "y": 21 + }, + "id": 6, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum by (collection) (galley_runtime_state_type_instances_total)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{ collection }}", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "State Type Instances", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": "Count", + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 27 + }, + "id": 34, + "panels": [], + "title": "Validation", + "type": "row" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 6, + "w": 8, + "x": 0, + "y": 28 + }, + "id": 28, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "galley_validation_cert_key_updates{job=\"galley\"}", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Key Updates", + "refId": "A" + }, + { + "expr": "galley_validation_cert_key_update_errors{job=\"galley\"}", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Key Update Errors: {{ error }}", + "refId": "B" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Validation Webhook Certificate", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 6, + "w": 8, + "x": 8, + "y": 28 + }, + "id": 30, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(galley_validation_passed{job=\"galley\"}) by (group, version, resource)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Passed: {{ group }}/{{ version }}/{{resource}}", + "refId": "A" + }, + { + "expr": "sum(galley_validation_failed{job=\"galley\"}) by (group, version, resource, reason)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Failed: {{ group }}/{{ version }}/{{resource}} ({{ reason}})", + "refId": "B" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Resource Validation", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 6, + "w": 8, + "x": 16, + "y": 28 + }, + "id": 32, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(galley_validation_http_error{job=\"galley\"}) by (status)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{ status }}", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Validation HTTP Errors", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 34 + }, + "id": 12, + "panels": [], + "title": "Kubernetes Source", + "type": "row" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 6, + "w": 8, + "x": 0, + "y": 35 + }, + "id": 14, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "rate(galley_source_kube_event_success_total[1m]) * 60", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Success", + "refId": "A" + }, + { + "expr": "rate(galley_source_kube_event_error_total[1m]) * 60", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Error", + "refId": "B" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Source Event Rate", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": "Events/min", + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 6, + "w": 8, + "x": 16, + "y": 35 + }, + "id": 24, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "rate(galley_source_kube_dynamic_converter_failure_total[1m]) * 60", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Error", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Kubernetes Object Conversion Failures", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": "Failures/min", + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 41 + }, + "id": 18, + "panels": [], + "title": "Mesh Configuration Protocol", + "type": "row" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 6, + "w": 8, + "x": 0, + "y": 42 + }, + "id": 20, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(istio_mcp_clients_total{component=\"galley\"})", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Clients", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Connected Clients", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 6, + "w": 8, + "x": 8, + "y": 42 + }, + "id": 22, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum by(collection)(irate(istio_mcp_request_acks_total{component=\"galley\"}[1m]) * 60)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Request ACKs", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": "ACKs/min", + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 6, + "w": 8, + "x": 16, + "y": 42 + }, + "id": 26, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "rate(istio_mcp_request_nacks_total{component=\"galley\"}[1m]) * 60", + "format": "time_series", + "intervalFactor": 1, + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Request NACKs", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": "NACKs/min", + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + } + ], + "refresh": "5s", + "schemaVersion": 16, + "style": "dark", + "tags": [], + "templating": { + "list": [] + }, + "time": { + "from": "now-5m", + "to": "now" + }, + "timepicker": { + "refresh_intervals": [ + "5s", + "10s", + "30s", + "1m", + "5m", + "15m", + "30m", + "1h", + "2h", + "1d" + ], + "time_options": [ + "5m", + "15m", + "1h", + "6h", + "12h", + "24h", + "2d", + "7d", + "30d" + ] + }, + "timezone": "", + "title": "Istio Galley Dashboard", + "uid": "TSEY6jLmk", + "version": 1 +} diff --git a/istio-1.5.0/install/kubernetes/helm/istio/charts/grafana/dashboards/istio-mesh-dashboard.json b/istio-1.5.0/install/kubernetes/helm/istio/charts/grafana/dashboards/istio-mesh-dashboard.json new file mode 100644 index 0000000..1662e1f --- /dev/null +++ b/istio-1.5.0/install/kubernetes/helm/istio/charts/grafana/dashboards/istio-mesh-dashboard.json @@ -0,0 +1,1225 @@ +{ + "annotations": { + "list": [ + { + "builtIn": 1, + "datasource": "-- Grafana --", + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations & Alerts", + "type": "dashboard" + } + ] + }, + "editable": false, + "gnetId": null, + "graphTooltip": 0, + "id": null, + "links": [], + "panels": [ + { + "content": "
\n
\n Istio\n
\n
\n Istio is an open platform that provides a uniform way to connect,\n manage, and \n secure microservices.\n
\n Need help? Join the Istio community.\n
\n
", + "gridPos": { + "h": 3, + "w": 24, + "x": 0, + "y": 0 + }, + "height": "50px", + "id": 13, + "links": [], + "mode": "html", + "style": { + "font-size": "18pt" + }, + "title": "", + "transparent": true, + "type": "text" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "datasource": "Prometheus", + "format": "ops", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "gridPos": { + "h": 3, + "w": 6, + "x": 0, + "y": 3 + }, + "id": 20, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": true, + "lineColor": "rgb(31, 120, 193)", + "show": true + }, + "tableColumn": "", + "targets": [ + { + "expr": "round(sum(irate(istio_requests_total{reporter=\"destination\"}[1m])), 0.001)", + "intervalFactor": 1, + "refId": "A", + "step": 4 + } + ], + "thresholds": "", + "title": "Global Request Volume", + "type": "singlestat", + "valueFontSize": "80%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "avg" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "datasource": "Prometheus", + "format": "percentunit", + "gauge": { + "maxValue": 100, + "minValue": 80, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": false + }, + "gridPos": { + "h": 3, + "w": 6, + "x": 6, + "y": 3 + }, + "id": 21, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": true, + "lineColor": "rgb(31, 120, 193)", + "show": true + }, + "tableColumn": "", + "targets": [ + { + "expr": "sum(rate(istio_requests_total{reporter=\"destination\", response_code!~\"5.*\"}[1m])) / sum(rate(istio_requests_total{reporter=\"destination\"}[1m]))", + "format": "time_series", + "intervalFactor": 1, + "refId": "A", + "step": 4 + } + ], + "thresholds": "95, 99, 99.5", + "title": "Global Success Rate (non-5xx responses)", + "type": "singlestat", + "valueFontSize": "80%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "avg" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "datasource": "Prometheus", + "format": "ops", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "gridPos": { + "h": 3, + "w": 6, + "x": 12, + "y": 3 + }, + "id": 22, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": true, + "lineColor": "rgb(31, 120, 193)", + "show": true + }, + "tableColumn": "", + "targets": [ + { + "expr": "sum(irate(istio_requests_total{reporter=\"destination\", response_code=~\"4.*\"}[1m])) ", + "format": "time_series", + "intervalFactor": 1, + "refId": "A", + "step": 4 + } + ], + "thresholds": "", + "title": "4xxs", + "type": "singlestat", + "valueFontSize": "80%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "avg" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "datasource": "Prometheus", + "format": "ops", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "gridPos": { + "h": 3, + "w": 6, + "x": 18, + "y": 3 + }, + "id": 23, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": true, + "lineColor": "rgb(31, 120, 193)", + "show": true + }, + "tableColumn": "", + "targets": [ + { + "expr": "sum(irate(istio_requests_total{reporter=\"destination\", response_code=~\"5.*\"}[1m])) ", + "format": "time_series", + "intervalFactor": 1, + "refId": "A", + "step": 4 + } + ], + "thresholds": "", + "title": "5xxs", + "type": "singlestat", + "valueFontSize": "80%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "avg" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "#299c46", + "rgba(237, 129, 40, 0.89)", + "#d44a3a" + ], + "format": "none", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "gridPos": { + "h": 3, + "w": 6, + "x": 0, + "y": 6 + }, + "id": 113, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": false, + "lineColor": "rgb(31, 120, 193)", + "show": true + }, + "tableColumn": "", + "targets": [ + { + "expr": "sum(galley_istio_networking_virtualservices) / count(up{job=\"galley\"})", + "format": "time_series", + "intervalFactor": 1, + "refId": "A" + } + ], + "thresholds": "", + "timeFrom": null, + "timeShift": null, + "title": "Virtual Services", + "type": "singlestat", + "valueFontSize": "80%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "current" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "#299c46", + "rgba(237, 129, 40, 0.89)", + "#d44a3a" + ], + "format": "none", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "gridPos": { + "h": 3, + "w": 6, + "x": 6, + "y": 6 + }, + "id": 114, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": false, + "lineColor": "rgb(31, 120, 193)", + "show": true + }, + "tableColumn": "", + "targets": [ + { + "expr": "sum(galley_istio_networking_destinationrules) / count(up{job=\"galley\"})", + "format": "time_series", + "intervalFactor": 1, + "refId": "A" + } + ], + "thresholds": "", + "timeFrom": null, + "timeShift": null, + "title": "Destination Rules", + "type": "singlestat", + "valueFontSize": "80%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "current" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "#299c46", + "rgba(237, 129, 40, 0.89)", + "#d44a3a" + ], + "format": "none", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "gridPos": { + "h": 3, + "w": 6, + "x": 12, + "y": 6 + }, + "id": 115, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": false, + "lineColor": "rgb(31, 120, 193)", + "show": true + }, + "tableColumn": "", + "targets": [ + { + "expr": "sum(galley_istio_networking_gateways) / count(up{job=\"galley\"})", + "format": "time_series", + "intervalFactor": 1, + "refId": "A" + } + ], + "thresholds": "", + "timeFrom": null, + "timeShift": null, + "title": "Gateways", + "type": "singlestat", + "valueFontSize": "80%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "current" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "#299c46", + "rgba(237, 129, 40, 0.89)", + "#d44a3a" + ], + "format": "none", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "gridPos": { + "h": 3, + "w": 6, + "x": 18, + "y": 6 + }, + "id": 116, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": false, + "lineColor": "rgb(31, 120, 193)", + "show": true + }, + "tableColumn": "", + "targets": [ + { + "expr": "sum(galley_istio_authentication_meshpolicies) / count(up{job=\"galley\"})", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "refId": "A" + } + ], + "thresholds": "", + "timeFrom": null, + "timeShift": null, + "title": "Authentication Mesh Policies", + "type": "singlestat", + "valueFontSize": "80%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "current" + }, + { + "columns": [], + "datasource": "Prometheus", + "fontSize": "100%", + "gridPos": { + "h": 21, + "w": 24, + "x": 0, + "y": 9 + }, + "hideTimeOverride": false, + "id": 73, + "links": [], + "pageSize": null, + "repeat": null, + "repeatDirection": "v", + "scroll": true, + "showHeader": true, + "sort": { + "col": 4, + "desc": true + }, + "styles": [ + { + "alias": "Workload", + "colorMode": null, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "link": false, + "linkTargetBlank": false, + "linkTooltip": "Workload dashboard", + "linkUrl": "/dashboard/db/istio-workload-dashboard?var-namespace=$__cell_2&var-workload=$__cell_", + "pattern": "destination_workload", + "preserveFormat": false, + "sanitize": false, + "thresholds": [], + "type": "hidden", + "unit": "short" + }, + { + "alias": "", + "colorMode": null, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "pattern": "Time", + "thresholds": [], + "type": "hidden", + "unit": "short" + }, + { + "alias": "Requests", + "colorMode": null, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "pattern": "Value #A", + "thresholds": [], + "type": "number", + "unit": "ops" + }, + { + "alias": "P50 Latency", + "colorMode": null, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "pattern": "Value #B", + "thresholds": [], + "type": "number", + "unit": "s" + }, + { + "alias": "P90 Latency", + "colorMode": null, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "pattern": "Value #D", + "thresholds": [], + "type": "number", + "unit": "s" + }, + { + "alias": "P99 Latency", + "colorMode": null, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "pattern": "Value #E", + "thresholds": [], + "type": "number", + "unit": "s" + }, + { + "alias": "Success Rate", + "colorMode": "cell", + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "pattern": "Value #F", + "thresholds": [ + ".95", + " 1.00" + ], + "type": "number", + "unit": "percentunit" + }, + { + "alias": "Workload", + "colorMode": null, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "link": true, + "linkTooltip": "$__cell dashboard", + "linkUrl": "/dashboard/db/istio-workload-dashboard?var-workload=$__cell_2&var-namespace=$__cell_3", + "pattern": "destination_workload_var", + "thresholds": [], + "type": "number", + "unit": "short" + }, + { + "alias": "Service", + "colorMode": null, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "link": true, + "linkTooltip": "$__cell dashboard", + "linkUrl": "/dashboard/db/istio-service-dashboard?var-service=$__cell", + "pattern": "destination_service", + "thresholds": [], + "type": "string", + "unit": "short" + }, + { + "alias": "", + "colorMode": null, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "pattern": "destination_workload_namespace", + "thresholds": [], + "type": "hidden", + "unit": "short" + } + ], + "targets": [ + { + "expr": "label_join(sum(rate(istio_requests_total{reporter=\"destination\", response_code=\"200\"}[1m])) by (destination_workload, destination_workload_namespace, destination_service), \"destination_workload_var\", \".\", \"destination_workload\", \"destination_workload_namespace\")", + "format": "table", + "hide": false, + "instant": true, + "intervalFactor": 1, + "legendFormat": "{{ destination_workload}}.{{ destination_workload_namespace }}", + "refId": "A" + }, + { + "expr": "label_join((histogram_quantile(0.50, sum(rate(istio_request_duration_milliseconds_bucket{reporter=\"destination\"}[1m])) by (le, destination_workload, destination_workload_namespace)) / 1000) or histogram_quantile(0.50, sum(rate(istio_request_duration_seconds_bucket{reporter=\"destination\"}[1m])) by (le, destination_workload, destination_workload_namespace)), \"destination_workload_var\", \".\", \"destination_workload\", \"destination_workload_namespace\")", + "format": "table", + "hide": false, + "instant": true, + "intervalFactor": 1, + "legendFormat": "{{ destination_workload}}.{{ destination_workload_namespace }}", + "refId": "B" + }, + { + "expr": "label_join((histogram_quantile(0.90, sum(rate(istio_request_duration_milliseconds_bucket{reporter=\"destination\"}[1m])) by (le, destination_workload, destination_workload_namespace)) / 1000) or histogram_quantile(0.90, sum(rate(istio_request_duration_seconds_bucket{reporter=\"destination\"}[1m])) by (le, destination_workload, destination_workload_namespace)), \"destination_workload_var\", \".\", \"destination_workload\", \"destination_workload_namespace\")", + "format": "table", + "hide": false, + "instant": true, + "intervalFactor": 1, + "legendFormat": "{{ destination_workload }}.{{ destination_workload_namespace }}", + "refId": "D" + }, + { + "expr": "label_join((histogram_quantile(0.99, sum(rate(istio_request_duration_milliseconds_bucket{reporter=\"destination\"}[1m])) by (le, destination_workload, destination_workload_namespace)) / 1000) or histogram_quantile(0.99, sum(rate(istio_request_duration_seconds_bucket{reporter=\"destination\"}[1m])) by (le, destination_workload, destination_workload_namespace)), \"destination_workload_var\", \".\", \"destination_workload\", \"destination_workload_namespace\")", + "format": "table", + "hide": false, + "instant": true, + "intervalFactor": 1, + "legendFormat": "{{ destination_workload }}.{{ destination_workload_namespace }}", + "refId": "E" + }, + { + "expr": "label_join((sum(rate(istio_requests_total{reporter=\"destination\", response_code!~\"5.*\"}[1m])) by (destination_workload, destination_workload_namespace) / sum(rate(istio_requests_total{reporter=\"destination\"}[1m])) by (destination_workload, destination_workload_namespace)), \"destination_workload_var\", \".\", \"destination_workload\", \"destination_workload_namespace\")", + "format": "table", + "hide": false, + "instant": true, + "interval": "", + "intervalFactor": 1, + "legendFormat": "{{ destination_workload }}.{{ destination_workload_namespace }}", + "refId": "F" + } + ], + "timeFrom": null, + "title": "HTTP/GRPC Workloads", + "transform": "table", + "type": "table" + }, + { + "columns": [], + "datasource": "Prometheus", + "fontSize": "100%", + "gridPos": { + "h": 18, + "w": 24, + "x": 0, + "y": 30 + }, + "hideTimeOverride": false, + "id": 109, + "links": [], + "pageSize": null, + "repeatDirection": "v", + "scroll": true, + "showHeader": true, + "sort": { + "col": 2, + "desc": true + }, + "styles": [ + { + "alias": "Workload", + "colorMode": null, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "link": false, + "linkTargetBlank": false, + "linkTooltip": "$__cell dashboard", + "linkUrl": "/dashboard/db/istio-tcp-workload-dashboard?var-namespace=$__cell_2&&var-workload=$__cell", + "pattern": "destination_workload", + "preserveFormat": false, + "sanitize": false, + "thresholds": [], + "type": "hidden", + "unit": "short" + }, + { + "alias": "Bytes Sent", + "colorMode": null, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "pattern": "Value #A", + "thresholds": [ + "" + ], + "type": "number", + "unit": "Bps" + }, + { + "alias": "Bytes Received", + "colorMode": null, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "pattern": "Value #C", + "thresholds": [], + "type": "number", + "unit": "Bps" + }, + { + "alias": "", + "colorMode": null, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "pattern": "Time", + "thresholds": [], + "type": "hidden", + "unit": "short" + }, + { + "alias": "Workload", + "colorMode": null, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "link": true, + "linkTooltip": "$__cell dashboard", + "linkUrl": "/dashboard/db/istio-workload-dashboard?var-namespace=$__cell_3&var-workload=$__cell_2", + "pattern": "destination_workload_var", + "thresholds": [], + "type": "string", + "unit": "short" + }, + { + "alias": "", + "colorMode": null, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "pattern": "destination_workload_namespace", + "thresholds": [], + "type": "hidden", + "unit": "short" + }, + { + "alias": "Service", + "colorMode": null, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "link": true, + "linkTooltip": "$__cell dashboard", + "linkUrl": "/dashboard/db/istio-service-dashboard?var-service=$__cell", + "pattern": "destination_service", + "thresholds": [], + "type": "number", + "unit": "short" + } + ], + "targets": [ + { + "expr": "label_join(sum(rate(istio_tcp_received_bytes_total{reporter=\"source\"}[1m])) by (destination_workload, destination_workload_namespace, destination_service), \"destination_workload_var\", \".\", \"destination_workload\", \"destination_workload_namespace\")", + "format": "table", + "hide": false, + "instant": true, + "intervalFactor": 1, + "legendFormat": "{{ destination_workload }}", + "refId": "C" + }, + { + "expr": "label_join(sum(rate(istio_tcp_sent_bytes_total{reporter=\"source\"}[1m])) by (destination_workload, destination_workload_namespace, destination_service), \"destination_workload_var\", \".\", \"destination_workload\", \"destination_workload_namespace\")", + "format": "table", + "hide": false, + "instant": true, + "intervalFactor": 1, + "legendFormat": "{{ destination_workload }}", + "refId": "A" + } + ], + "timeFrom": null, + "title": "TCP Workloads", + "transform": "table", + "type": "table" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 9, + "w": 24, + "x": 0, + "y": 48 + }, + "id": 111, + "legend": { + "alignAsTable": false, + "avg": false, + "current": false, + "max": false, + "min": false, + "rightSide": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(istio_build) by (component, tag)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{ component }}: {{ tag }}", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Istio Components by Version", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + } + ], + "refresh": "5s", + "schemaVersion": 18, + "style": "dark", + "tags": [], + "templating": { + "list": [] + }, + "time": { + "from": "now-5m", + "to": "now" + }, + "timepicker": { + "refresh_intervals": [ + "5s", + "10s", + "30s", + "1m", + "5m", + "15m", + "30m", + "1h", + "2h", + "1d" + ], + "time_options": [ + "5m", + "15m", + "1h", + "6h", + "12h", + "24h", + "2d", + "7d", + "30d" + ] + }, + "timezone": "browser", + "title": "Istio Mesh Dashboard", + "uid": "G8wLrJIZk", + "version": 5 +} diff --git a/istio-1.5.0/install/kubernetes/helm/istio/charts/grafana/dashboards/istio-performance-dashboard.json b/istio-1.5.0/install/kubernetes/helm/istio/charts/grafana/dashboards/istio-performance-dashboard.json new file mode 100644 index 0000000..505043e --- /dev/null +++ b/istio-1.5.0/install/kubernetes/helm/istio/charts/grafana/dashboards/istio-performance-dashboard.json @@ -0,0 +1,1822 @@ +{ + "annotations": { + "list": [ + { + "builtIn": 1, + "datasource": "-- Grafana --", + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations & Alerts", + "type": "dashboard" + } + ] + }, + "editable": false, + "gnetId": null, + "graphTooltip": 0, + "id": 9, + "links": [], + "panels": [ + { + "collapsed": true, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 0 + }, + "id": 21, + "panels": [ + { + "content": "The charts on this dashboard are intended to show Istio main components cost in terms resources utilization under steady load.\n\n- **vCPU/1k rps:** shows vCPU utilization by the main Istio components normalized by 1000 requests/second. When idle or low traffic, this chart will be blank. The curve for istio-proxy refers to the services sidecars only.\n- **vCPU:** vCPU utilization by Istio components, not normalized.\n- **Memory:** memory footprint for the components. Telemetry and policy are normalized by 1k rps, and no data is shown when there is no traffic. For ingress and istio-proxy, the data is per instance.\n- **Bytes transferred/ sec:** shows the number of bytes flowing through each Istio component.\n\n\n", + "gridPos": { + "h": 6, + "w": 24, + "x": 0, + "y": 1 + }, + "id": 19, + "links": [], + "mode": "markdown", + "timeFrom": null, + "timeShift": null, + "title": "Performance Dashboard README", + "transparent": true, + "type": "text" + } + ], + "title": "Performance Dashboard Notes", + "type": "row" + }, + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 1 + }, + "id": 6, + "panels": [], + "title": "vCPU Usage", + "type": "row" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "fill": 1, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 2 + }, + "id": 4, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "(sum(irate(container_cpu_usage_seconds_total{job=\"kubernetes-cadvisor\",pod=~\"istio-telemetry-.*\",container=~\"mixer|istio-proxy\"}[1m]))/ (round(sum(irate(istio_requests_total[1m])), 0.001)/1000))/ (sum(irate(istio_requests_total{source_workload=\"istio-ingressgateway\"}[1m])) >bool 10)", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "istio-telemetry", + "refId": "A" + }, + { + "expr": "(sum(irate(container_cpu_usage_seconds_total{job=\"kubernetes-cadvisor\",pod=~\"istio-ingressgateway-.*\",container=\"istio-proxy\"}[1m])) / (round(sum(irate(istio_requests_total{source_workload=\"istio-ingressgateway\", reporter=\"source\"}[1m])), 0.001)/1000))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "istio-ingressgateway", + "refId": "B" + }, + { + "expr": "(sum(irate(container_cpu_usage_seconds_total{job=\"kubernetes-cadvisor\",namespace!=\"istio-system\",container=\"istio-proxy\"}[1m]))/ (round(sum(irate(istio_requests_total[1m])), 0.001)/1000))/ (sum(irate(istio_requests_total{source_workload=\"istio-ingressgateway\"}[1m])) >bool 10)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "istio-proxy", + "refId": "C" + }, + { + "expr": "(sum(irate(container_cpu_usage_seconds_total{job=\"kubernetes-cadvisor\",pod=~\"istio-policy-.*\",container=~\"mixer|istio-proxy\"}[1m]))/ (round(sum(irate(istio_requests_total[1m])), 0.001)/1000))/ (sum(irate(istio_requests_total{source_workload=\"istio-ingressgateway\"}[1m])) >bool 10)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "istio-policy", + "refId": "D" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "vCPU / 1k rps", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "fill": 1, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 2 + }, + "id": 7, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(rate(container_cpu_usage_seconds_total{job=\"kubernetes-cadvisor\",pod=~\"istio-telemetry-.*\",container=~\"mixer|istio-proxy\"}[1m]))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "istio-telemetry", + "refId": "A" + }, + { + "expr": "sum(rate(container_cpu_usage_seconds_total{job=\"kubernetes-cadvisor\",pod=~\"istio-ingressgateway-.*\",container=\"istio-proxy\"}[1m]))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "istio-ingressgateway", + "refId": "B" + }, + { + "expr": "sum(rate(container_cpu_usage_seconds_total{job=\"kubernetes-cadvisor\",namespace!=\"istio-system\",container=\"istio-proxy\"}[1m]))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "istio-proxy", + "refId": "C" + }, + { + "expr": "sum(rate(container_cpu_usage_seconds_total{job=\"kubernetes-cadvisor\",pod=~\"istio-policy-.*\",container=~\"mixer|istio-proxy\"}[1m]))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "istio-policy", + "refId": "D" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "vCPU", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 10 + }, + "id": 13, + "panels": [], + "title": "Memory and Data Rates", + "type": "row" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "fill": 1, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 11 + }, + "id": 902, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "(sum(container_memory_usage_bytes{job=\"kubernetes-cadvisor\",pod=~\"istio-telemetry-.*\"}) / (sum(irate(istio_requests_total[1m])) / 1000)) / (sum(irate(istio_requests_total{source_workload=\"istio-ingressgateway\"}[1m])) >bool 10)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "istio-telemetry / 1k rps", + "refId": "A" + }, + { + "expr": "sum(container_memory_usage_bytes{job=\"kubernetes-cadvisor\",pod=~\"istio-ingressgateway-.*\"}) / count(container_memory_usage_bytes{job=\"kubernetes-cadvisor\",pod=~\"istio-ingressgateway-.*\",container!=\"POD\"})", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "per istio-ingressgateway", + "refId": "B" + }, + { + "expr": "sum(container_memory_usage_bytes{job=\"kubernetes-cadvisor\",namespace!=\"istio-system\",container=\"istio-proxy\"}) / count(container_memory_usage_bytes{job=\"kubernetes-cadvisor\",namespace!=\"istio-system\",container=\"istio-proxy\"})", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "per istio proxy", + "refId": "C" + }, + { + "expr": "(sum(container_memory_usage_bytes{job=\"kubernetes-cadvisor\",pod=~\"istio-policy-.*\"}) / (sum(irate(istio_requests_total[1m])) / 1000))/ (sum(irate(istio_requests_total{source_workload=\"istio-ingressgateway\"}[1m])) >bool 10)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "istio-policy / 1k rps", + "refId": "D" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Memory Usage", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "bytes", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "fill": 1, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 11 + }, + "id": 11, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(irate(istio_response_bytes_sum{destination_workload=\"istio-telemetry\"}[1m])) + sum(irate(istio_request_bytes_sum{destination_workload=\"istio-telemetry\"}[1m]))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "istio-telemetry", + "refId": "A" + }, + { + "expr": "sum(irate(istio_response_bytes_sum{source_workload=\"istio-ingressgateway\", reporter=\"source\"}[1m]))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "istio-ingressgateway", + "refId": "B" + }, + { + "expr": "sum(irate(istio_response_bytes_sum{source_workload_namespace!=\"istio-system\", reporter=\"source\"}[1m])) + sum(irate(istio_response_bytes_sum{destination_workload_namespace!=\"istio-system\", reporter=\"destination\"}[1m])) + sum(irate(istio_request_bytes_sum{source_workload_namespace!=\"istio-system\", reporter=\"source\"}[1m])) + sum(irate(istio_request_bytes_sum{destination_workload_namespace!=\"istio-system\", reporter=\"destination\"}[1m]))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "istio-proxy", + "refId": "C" + }, + { + "expr": "sum(irate(istio_response_bytes_sum{destination_workload=\"istio-policy\"}[1m])) + sum(irate(istio_request_bytes_sum{destination_workload=\"istio-policy\"}[1m]))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "istio_policy", + "refId": "D" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Bytes transferred / sec", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "Bps", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 19 + }, + "id": 17, + "panels": [], + "title": "Istio Component Versions", + "type": "row" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "fill": 1, + "gridPos": { + "h": 8, + "w": 24, + "x": 0, + "y": 20 + }, + "id": 15, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(istio_build) by (component, tag)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{ component }}: {{ tag }}", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Istio Components by Version", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 31 + }, + "id": 71, + "panels": [], + "title": "Proxy Resource Usage", + "type": "row" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 7, + "w": 6, + "x": 0, + "y": 32 + }, + "id": 72, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(container_memory_usage_bytes{job=\"kubernetes-cadvisor\",container=\"istio-proxy\"})", + "format": "time_series", + "hide": false, + "intervalFactor": 2, + "legendFormat": "{{ container }} (k8s)", + "refId": "B", + "step": 2 + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Memory", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "bytes", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 7, + "w": 6, + "x": 6, + "y": 32 + }, + "id": 73, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(rate(container_cpu_usage_seconds_total{job=\"kubernetes-cadvisor\",container=\"istio-proxy\"}[1m]))", + "format": "time_series", + "hide": false, + "intervalFactor": 2, + "legendFormat": "Total (k8s)", + "refId": "A", + "step": 2 + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "vCPU", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 7, + "w": 6, + "x": 12, + "y": 32 + }, + "id": 702, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(container_fs_usage_bytes{job=\"kubernetes-cadvisor\", container=\"istio-proxy\"})", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "{{ container }}", + "refId": "B", + "step": 2 + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Disk", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "bytes", + "label": "", + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "decimals": null, + "format": "none", + "label": "", + "logBase": 1024, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 39 + }, + "id": 69, + "panels": [], + "title": "Pilot Resource Usage", + "type": "row" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 7, + "w": 6, + "x": 0, + "y": 40 + }, + "id": 5, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "process_virtual_memory_bytes{job=\"pilot\"}", + "format": "time_series", + "instant": false, + "intervalFactor": 2, + "legendFormat": "Virtual Memory", + "refId": "I", + "step": 2 + }, + { + "expr": "process_resident_memory_bytes{job=\"pilot\"}", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "Resident Memory", + "refId": "H", + "step": 2 + }, + { + "expr": "go_memstats_heap_sys_bytes{job=\"pilot\"}", + "format": "time_series", + "hide": true, + "intervalFactor": 2, + "legendFormat": "heap sys", + "refId": "A" + }, + { + "expr": "go_memstats_heap_alloc_bytes{job=\"pilot\"}", + "format": "time_series", + "hide": true, + "intervalFactor": 2, + "legendFormat": "heap alloc", + "refId": "D" + }, + { + "expr": "go_memstats_alloc_bytes{job=\"pilot\"}", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "Alloc", + "refId": "F", + "step": 2 + }, + { + "expr": "go_memstats_heap_inuse_bytes{job=\"pilot\"}", + "format": "time_series", + "hide": false, + "intervalFactor": 2, + "legendFormat": "Heap in-use", + "refId": "E", + "step": 2 + }, + { + "expr": "go_memstats_stack_inuse_bytes{job=\"pilot\"}", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "Stack in-use", + "refId": "G", + "step": 2 + }, + { + "expr": "sum(container_memory_usage_bytes{job=\"kubernetes-cadvisor\",container=~\"discovery|istio-proxy\", pod=~\"istio-pilot-.*\"})", + "format": "time_series", + "hide": false, + "intervalFactor": 2, + "legendFormat": "Total (k8s)", + "refId": "C", + "step": 2 + }, + { + "expr": "container_memory_usage_bytes{job=\"kubernetes-cadvisor\",container=~\"discovery|istio-proxy\", pod=~\"istio-pilot-.*\"}", + "format": "time_series", + "hide": false, + "intervalFactor": 2, + "legendFormat": "{{ container }} (k8s)", + "refId": "B", + "step": 2 + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Memory", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "bytes", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 7, + "w": 6, + "x": 6, + "y": 40 + }, + "id": 602, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(rate(container_cpu_usage_seconds_total{job=\"kubernetes-cadvisor\",container=~\"discovery|istio-proxy\", pod=~\"istio-pilot-.*\"}[1m]))", + "format": "time_series", + "hide": false, + "intervalFactor": 2, + "legendFormat": "Total (k8s)", + "refId": "A", + "step": 2 + }, + { + "expr": "sum(rate(container_cpu_usage_seconds_total{job=\"kubernetes-cadvisor\",container=~\"discovery|istio-proxy\", pod=~\"istio-pilot-.*\"}[1m])) by (container)", + "format": "time_series", + "hide": false, + "intervalFactor": 2, + "legendFormat": "{{ container }} (k8s)", + "refId": "B", + "step": 2 + }, + { + "expr": "irate(process_cpu_seconds_total{job=\"pilot\"}[1m])", + "format": "time_series", + "hide": false, + "intervalFactor": 2, + "legendFormat": "pilot (self-reported)", + "refId": "C", + "step": 2 + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "vCPU", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 7, + "w": 6, + "x": 12, + "y": 40 + }, + "id": 74, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "process_open_fds{job=\"pilot\"}", + "format": "time_series", + "hide": true, + "instant": false, + "interval": "", + "intervalFactor": 2, + "legendFormat": "Open FDs (pilot)", + "refId": "A" + }, + { + "expr": "container_fs_usage_bytes{job=\"kubernetes-cadvisor\", container=~\"discovery|istio-proxy\", pod=~\"istio-pilot-.*\"}", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "{{ container }}", + "refId": "B", + "step": 2 + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Disk", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "bytes", + "label": "", + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "decimals": null, + "format": "none", + "label": "", + "logBase": 1024, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 7, + "w": 6, + "x": 18, + "y": 40 + }, + "id": 402, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": false, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "go_goroutines{job=\"pilot\"}", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "Number of Goroutines", + "refId": "A", + "step": 2 + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Goroutines", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": "", + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 47 + }, + "id": 93, + "panels": [], + "title": "Mixer Resource Usage", + "type": "row" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 7, + "w": 6, + "x": 0, + "y": 48 + }, + "id": 94, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "process_virtual_memory_bytes{job=~\"istio-telemetry|istio-policy\"}", + "format": "time_series", + "instant": false, + "intervalFactor": 2, + "legendFormat": "Virtual Memory", + "refId": "I", + "step": 2 + }, + { + "expr": "process_resident_memory_bytes{job=~\"istio-telemetry|istio-policy\"}", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "Resident Memory", + "refId": "H", + "step": 2 + }, + { + "expr": "go_memstats_heap_sys_bytes{job=~\"istio-telemetry|istio-policy\"}", + "format": "time_series", + "hide": true, + "intervalFactor": 2, + "legendFormat": "heap sys", + "refId": "A" + }, + { + "expr": "go_memstats_heap_alloc_bytes{job=~\"istio-telemetry|istio-policy\"}", + "format": "time_series", + "hide": true, + "intervalFactor": 2, + "legendFormat": "heap alloc", + "refId": "D" + }, + { + "expr": "go_memstats_alloc_bytes{job=~\"istio-telemetry|istio-policy\"}", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "Alloc", + "refId": "F", + "step": 2 + }, + { + "expr": "go_memstats_heap_inuse_bytes{job=~\"istio-telemetry|istio-policy\"}", + "format": "time_series", + "hide": false, + "intervalFactor": 2, + "legendFormat": "Heap in-use", + "refId": "E", + "step": 2 + }, + { + "expr": "go_memstats_stack_inuse_bytes{job=~\"istio-policy|istio-telemetry\"}", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "Stack in-use", + "refId": "G", + "step": 2 + }, + { + "expr": "sum(container_memory_usage_bytes{job=\"kubernetes-cadvisor\",container=~\"mixer|istio-proxy\", pod=~\"istio-telemetry-.*\"})", + "format": "time_series", + "hide": false, + "intervalFactor": 2, + "legendFormat": "Total (k8s)", + "refId": "C", + "step": 2 + }, + { + "expr": "container_memory_usage_bytes{job=\"kubernetes-cadvisor\",container=~\"mixer|istio-proxy\", pod=~\"istio-telemetry-.*\"}", + "format": "time_series", + "hide": false, + "intervalFactor": 2, + "legendFormat": "{{ container }} (k8s)", + "refId": "B", + "step": 2 + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Memory", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "bytes", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 7, + "w": 6, + "x": 6, + "y": 48 + }, + "id": 95, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(rate(container_cpu_usage_seconds_total{job=\"kubernetes-cadvisor\",container=~\"mixer|istio-proxy\", pod=~\"istio-telemetry-.*\"}[1m]))", + "format": "time_series", + "hide": false, + "intervalFactor": 2, + "legendFormat": "Total (k8s)", + "refId": "A", + "step": 2 + }, + { + "expr": "sum(rate(container_cpu_usage_seconds_total{job=\"kubernetes-cadvisor\",container=~\"mixer|istio-proxy\", pod=~\"istio-telemetry-.*\"}[1m])) by (container)", + "format": "time_series", + "hide": false, + "intervalFactor": 2, + "legendFormat": "{{ container }} (k8s)", + "refId": "B", + "step": 2 + }, + { + "expr": "irate(process_cpu_seconds_total{job=~\"istio-policy|istio-telemetry\"}[1m])", + "format": "time_series", + "hide": false, + "intervalFactor": 2, + "legendFormat": "mixer (self-reported)", + "refId": "C", + "step": 2 + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "vCPU", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 7, + "w": 6, + "x": 12, + "y": 48 + }, + "id": 96, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "process_open_fds{job=~\"istio-policy|istio-telemetry\"}", + "format": "time_series", + "hide": true, + "instant": false, + "interval": "", + "intervalFactor": 2, + "legendFormat": "Open FDs (pilot)", + "refId": "A" + }, + { + "expr": "container_fs_usage_bytes{job=\"kubernetes-cadvisor\", container=~\"mixer|istio-proxy\", pod=~\"istio-telemetry-.*\"}", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "{{ container }}", + "refId": "B", + "step": 2 + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Disk", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "bytes", + "label": "", + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "decimals": null, + "format": "none", + "label": "", + "logBase": 1024, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 7, + "w": 6, + "x": 18, + "y": 48 + }, + "id": 97, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": false, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "go_goroutines{job=\"istio-telemetry\"}", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "Number of Goroutines", + "refId": "A", + "step": 2 + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Goroutines", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": "", + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + } + ], + "refresh": "10s", + "schemaVersion": 18, + "style": "dark", + "tags": [], + "templating": { + "list": [] + }, + "time": { + "from": "now-5m", + "to": "now" + }, + "timepicker": { + "refresh_intervals": [ + "5s", + "10s", + "30s", + "1m", + "5m", + "15m", + "30m", + "1h", + "2h", + "1d" + ], + "time_options": [ + "5m", + "15m", + "1h", + "6h", + "12h", + "24h", + "2d", + "7d", + "30d" + ] + }, + "timezone": "", + "title": "Istio Performance Dashboard", + "uid": "vu8e0VWZk", + "version": 22 +} diff --git a/istio-1.5.0/install/kubernetes/helm/istio/charts/grafana/dashboards/istio-service-dashboard.json b/istio-1.5.0/install/kubernetes/helm/istio/charts/grafana/dashboards/istio-service-dashboard.json new file mode 100644 index 0000000..f4d58a2 --- /dev/null +++ b/istio-1.5.0/install/kubernetes/helm/istio/charts/grafana/dashboards/istio-service-dashboard.json @@ -0,0 +1,2601 @@ +{ + "annotations": { + "list": [ + { + "builtIn": 1, + "datasource": "-- Grafana --", + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations & Alerts", + "type": "dashboard" + } + ] + }, + "editable": false, + "gnetId": null, + "graphTooltip": 0, + "iteration": 1536442501501, + "links": [], + "panels": [ + { + "content": "
\nSERVICE: $service\n
", + "gridPos": { + "h": 3, + "w": 24, + "x": 0, + "y": 0 + }, + "id": 89, + "links": [], + "mode": "html", + "title": "", + "transparent": true, + "type": "text" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "datasource": "Prometheus", + "format": "ops", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "gridPos": { + "h": 4, + "w": 6, + "x": 0, + "y": 3 + }, + "id": 12, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": true, + "lineColor": "rgb(31, 120, 193)", + "show": true + }, + "tableColumn": "", + "targets": [ + { + "expr": "round(sum(irate(istio_requests_total{reporter=\"source\",destination_service=~\"$service\"}[5m])), 0.001)", + "format": "time_series", + "intervalFactor": 1, + "refId": "A", + "step": 4 + } + ], + "thresholds": "", + "title": "Client Request Volume", + "transparent": false, + "type": "singlestat", + "valueFontSize": "80%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "current" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "rgba(50, 172, 45, 0.97)", + "rgba(237, 129, 40, 0.89)", + "rgba(245, 54, 54, 0.9)" + ], + "datasource": "Prometheus", + "decimals": null, + "format": "percentunit", + "gauge": { + "maxValue": 100, + "minValue": 80, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": false + }, + "gridPos": { + "h": 4, + "w": 6, + "x": 6, + "y": 3 + }, + "id": 14, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": true, + "lineColor": "rgb(31, 120, 193)", + "show": true + }, + "tableColumn": "", + "targets": [ + { + "expr": "sum(irate(istio_requests_total{reporter=\"source\",destination_service=~\"$service\",response_code!~\"5.*\"}[5m])) / sum(irate(istio_requests_total{reporter=\"source\",destination_service=~\"$service\"}[5m]))", + "format": "time_series", + "intervalFactor": 1, + "refId": "B" + } + ], + "thresholds": "95, 99, 99.5", + "title": "Client Success Rate (non-5xx responses)", + "transparent": false, + "type": "singlestat", + "valueFontSize": "80%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "avg" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 4, + "w": 6, + "x": 12, + "y": 3 + }, + "id": 87, + "legend": { + "alignAsTable": false, + "avg": false, + "current": false, + "hideEmpty": false, + "hideZero": false, + "max": false, + "min": false, + "rightSide": true, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "(histogram_quantile(0.50, sum(irate(istio_request_duration_milliseconds_bucket{reporter=\"source\",destination_service=~\"$service\"}[1m])) by (le)) / 1000) or histogram_quantile(0.50, sum(irate(istio_request_duration_seconds_bucket{reporter=\"source\",destination_service=~\"$service\"}[1m])) by (le))", + "format": "time_series", + "interval": "", + "intervalFactor": 1, + "legendFormat": "P50", + "refId": "A" + }, + { + "expr": "(histogram_quantile(0.90, sum(irate(istio_request_duration_milliseconds_bucket{reporter=\"source\",destination_service=~\"$service\"}[1m])) by (le)) / 1000) or histogram_quantile(0.90, sum(irate(istio_request_duration_seconds_bucket{reporter=\"source\",destination_service=~\"$service\"}[1m])) by (le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "P90", + "refId": "B" + }, + { + "expr": "(histogram_quantile(0.99, sum(irate(istio_request_duration_milliseconds_bucket{reporter=\"source\",destination_service=~\"$service\"}[1m])) by (le)) / 1000) or histogram_quantile(0.99, sum(irate(istio_request_duration_seconds_bucket{reporter=\"source\",destination_service=~\"$service\"}[1m])) by (le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "P99", + "refId": "C" + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Client Request Duration", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "s", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "#299c46", + "rgba(237, 129, 40, 0.89)", + "#d44a3a" + ], + "datasource": "Prometheus", + "format": "Bps", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "gridPos": { + "h": 4, + "w": 6, + "x": 18, + "y": 3 + }, + "id": 84, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": true, + "lineColor": "rgb(31, 120, 193)", + "show": true + }, + "tableColumn": "", + "targets": [ + { + "expr": "sum(irate(istio_tcp_received_bytes_total{reporter=\"source\", destination_service=~\"$service\"}[1m]))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "", + "refId": "A" + } + ], + "thresholds": "", + "title": "TCP Received Bytes", + "transparent": false, + "type": "singlestat", + "valueFontSize": "80%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "avg" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "datasource": "Prometheus", + "format": "ops", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "gridPos": { + "h": 4, + "w": 6, + "x": 0, + "y": 7 + }, + "id": 97, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": true, + "lineColor": "rgb(31, 120, 193)", + "show": true + }, + "tableColumn": "", + "targets": [ + { + "expr": "round(sum(irate(istio_requests_total{reporter=\"destination\",destination_service=~\"$service\"}[5m])), 0.001)", + "format": "time_series", + "intervalFactor": 1, + "refId": "A", + "step": 4 + } + ], + "thresholds": "", + "title": "Server Request Volume", + "transparent": false, + "type": "singlestat", + "valueFontSize": "80%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "current" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "rgba(50, 172, 45, 0.97)", + "rgba(237, 129, 40, 0.89)", + "rgba(245, 54, 54, 0.9)" + ], + "datasource": "Prometheus", + "decimals": null, + "format": "percentunit", + "gauge": { + "maxValue": 100, + "minValue": 80, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": false + }, + "gridPos": { + "h": 4, + "w": 6, + "x": 6, + "y": 7 + }, + "id": 98, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": true, + "lineColor": "rgb(31, 120, 193)", + "show": true + }, + "tableColumn": "", + "targets": [ + { + "expr": "sum(irate(istio_requests_total{reporter=\"destination\",destination_service=~\"$service\",response_code!~\"5.*\"}[5m])) / sum(irate(istio_requests_total{reporter=\"destination\",destination_service=~\"$service\"}[5m]))", + "format": "time_series", + "intervalFactor": 1, + "refId": "B" + } + ], + "thresholds": "95, 99, 99.5", + "title": "Server Success Rate (non-5xx responses)", + "transparent": false, + "type": "singlestat", + "valueFontSize": "80%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "avg" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 4, + "w": 6, + "x": 12, + "y": 7 + }, + "id": 99, + "legend": { + "alignAsTable": false, + "avg": false, + "current": false, + "hideEmpty": false, + "hideZero": false, + "max": false, + "min": false, + "rightSide": true, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "(histogram_quantile(0.50, sum(irate(istio_request_duration_milliseconds_bucket{reporter=\"destination\",destination_service=~\"$service\"}[1m])) by (le)) / 1000) or histogram_quantile(0.50, sum(irate(istio_request_duration_seconds_bucket{reporter=\"destination\",destination_service=~\"$service\"}[1m])) by (le))", + "format": "time_series", + "interval": "", + "intervalFactor": 1, + "legendFormat": "P50", + "refId": "A" + }, + { + "expr": "(histogram_quantile(0.90, sum(irate(istio_request_duration_milliseconds_bucket{reporter=\"destination\",destination_service=~\"$service\"}[1m])) by (le)) / 1000) or histogram_quantile(0.90, sum(irate(istio_request_duration_seconds_bucket{reporter=\"destination\",destination_service=~\"$service\"}[1m])) by (le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "P90", + "refId": "B" + }, + { + "expr": "(histogram_quantile(0.99, sum(irate(istio_request_duration_milliseconds_bucket{reporter=\"destination\",destination_service=~\"$service\"}[1m])) by (le)) / 1000) or histogram_quantile(0.99, sum(irate(istio_request_duration_seconds_bucket{reporter=\"destination\",destination_service=~\"$service\"}[1m])) by (le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "P99", + "refId": "C" + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Server Request Duration", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "s", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "#299c46", + "rgba(237, 129, 40, 0.89)", + "#d44a3a" + ], + "datasource": "Prometheus", + "format": "Bps", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "gridPos": { + "h": 4, + "w": 6, + "x": 18, + "y": 7 + }, + "id": 100, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": true, + "lineColor": "rgb(31, 120, 193)", + "show": true + }, + "tableColumn": "", + "targets": [ + { + "expr": "sum(irate(istio_tcp_sent_bytes_total{reporter=\"source\", destination_service=~\"$service\"}[1m])) ", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "", + "refId": "A" + } + ], + "thresholds": "", + "title": "TCP Sent Bytes", + "transparent": false, + "type": "singlestat", + "valueFontSize": "80%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "avg" + }, + { + "content": "
\nCLIENT WORKLOADS\n
", + "gridPos": { + "h": 3, + "w": 24, + "x": 0, + "y": 11 + }, + "id": 45, + "links": [], + "mode": "html", + "title": "", + "transparent": true, + "type": "text" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 0, + "gridPos": { + "h": 6, + "w": 12, + "x": 0, + "y": 14 + }, + "id": 25, + "legend": { + "avg": false, + "current": false, + "hideEmpty": true, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null as zero", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "round(sum(irate(istio_requests_total{connection_security_policy=\"mutual_tls\",destination_service=~\"$service\",reporter=\"source\",source_workload=~\"$srcwl\",source_workload_namespace=~\"$srcns\"}[5m])) by (source_workload, source_workload_namespace, response_code), 0.001)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{ source_workload }}.{{ source_workload_namespace }} : {{ response_code }} (🔐mTLS)", + "refId": "B", + "step": 2 + }, + { + "expr": "round(sum(irate(istio_requests_total{connection_security_policy!=\"mutual_tls\", destination_service=~\"$service\", reporter=\"source\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[5m])) by (source_workload, source_workload_namespace, response_code), 0.001)", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ source_workload }}.{{ source_workload_namespace }} : {{ response_code }}", + "refId": "A", + "step": 2 + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Incoming Requests by Source And Response Code", + "tooltip": { + "shared": false, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [ + "total" + ] + }, + "yaxes": [ + { + "format": "ops", + "label": null, + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 6, + "w": 12, + "x": 12, + "y": 14 + }, + "id": 26, + "legend": { + "avg": false, + "current": false, + "hideEmpty": true, + "hideZero": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(irate(istio_requests_total{reporter=\"source\", connection_security_policy=\"mutual_tls\", destination_service=~\"$service\",response_code!~\"5.*\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[5m])) by (source_workload, source_workload_namespace) / sum(irate(istio_requests_total{reporter=\"source\", connection_security_policy=\"mutual_tls\", destination_service=~\"$service\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[5m])) by (source_workload, source_workload_namespace)", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ source_workload }}.{{ source_workload_namespace }} (🔐mTLS)", + "refId": "A", + "step": 2 + }, + { + "expr": "sum(irate(istio_requests_total{reporter=\"source\", connection_security_policy!=\"mutual_tls\", destination_service=~\"$service\",response_code!~\"5.*\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[5m])) by (source_workload, source_workload_namespace) / sum(irate(istio_requests_total{reporter=\"source\", connection_security_policy!=\"mutual_tls\", destination_service=~\"$service\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[5m])) by (source_workload, source_workload_namespace)", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ source_workload }}.{{ source_workload_namespace }}", + "refId": "B", + "step": 2 + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Incoming Success Rate (non-5xx responses) By Source", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "percentunit", + "label": null, + "logBase": 1, + "max": "1.01", + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "description": "", + "fill": 1, + "gridPos": { + "h": 6, + "w": 8, + "x": 0, + "y": 20 + }, + "id": 27, + "legend": { + "alignAsTable": false, + "avg": false, + "current": false, + "hideEmpty": true, + "hideZero": false, + "max": false, + "min": false, + "rightSide": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "(histogram_quantile(0.50, sum(irate(istio_request_duration_milliseconds_bucket{reporter=\"source\", connection_security_policy=\"mutual_tls\", destination_service=~\"$service\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le)) / 1000) or histogram_quantile(0.50, sum(irate(istio_request_duration_seconds_bucket{reporter=\"source\", connection_security_policy=\"mutual_tls\", destination_service=~\"$service\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{source_workload}}.{{source_workload_namespace}} P50 (🔐mTLS)", + "refId": "D", + "step": 2 + }, + { + "expr": "(histogram_quantile(0.90, sum(irate(istio_request_duration_milliseconds_bucket{reporter=\"source\", connection_security_policy=\"mutual_tls\", destination_service=~\"$service\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le)) / 1000) or histogram_quantile(0.90, sum(irate(istio_request_duration_seconds_bucket{reporter=\"source\", connection_security_policy=\"mutual_tls\", destination_service=~\"$service\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{source_workload}}.{{source_workload_namespace}} P90 (🔐mTLS)", + "refId": "A", + "step": 2 + }, + { + "expr": "(histogram_quantile(0.95, sum(irate(istio_request_duration_milliseconds_bucket{reporter=\"source\", connection_security_policy=\"mutual_tls\", destination_service=~\"$service\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le)) / 1000) or histogram_quantile(0.95, sum(irate(istio_request_duration_seconds_bucket{reporter=\"source\", connection_security_policy=\"mutual_tls\", destination_service=~\"$service\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{source_workload}}.{{source_workload_namespace}} P95 (🔐mTLS)", + "refId": "B", + "step": 2 + }, + { + "expr": "(histogram_quantile(0.99, sum(irate(istio_request_duration_milliseconds_bucket{reporter=\"source\", connection_security_policy=\"mutual_tls\", destination_service=~\"$service\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le)) / 1000) or histogram_quantile(0.99, sum(irate(istio_request_duration_seconds_bucket{reporter=\"source\", connection_security_policy=\"mutual_tls\", destination_service=~\"$service\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{source_workload}}.{{source_workload_namespace}} P99 (🔐mTLS)", + "refId": "C", + "step": 2 + }, + { + "expr": "(histogram_quantile(0.50, sum(irate(istio_request_duration_milliseconds_bucket{reporter=\"source\", connection_security_policy!=\"mutual_tls\", destination_service=~\"$service\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le)) / 1000) or histogram_quantile(0.50, sum(irate(istio_request_duration_seconds_bucket{reporter=\"source\", connection_security_policy!=\"mutual_tls\", destination_service=~\"$service\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{source_workload}}.{{source_workload_namespace}} P50", + "refId": "E", + "step": 2 + }, + { + "expr": "(histogram_quantile(0.90, sum(irate(istio_request_duration_milliseconds_bucket{reporter=\"source\", connection_security_policy!=\"mutual_tls\", destination_service=~\"$service\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le)) / 1000) or histogram_quantile(0.90, sum(irate(istio_request_duration_seconds_bucket{reporter=\"source\", connection_security_policy!=\"mutual_tls\", destination_service=~\"$service\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{source_workload}}.{{source_workload_namespace}} P90", + "refId": "F", + "step": 2 + }, + { + "expr": "(histogram_quantile(0.95, sum(irate(istio_request_duration_milliseconds_bucket{reporter=\"source\", connection_security_policy!=\"mutual_tls\", destination_service=~\"$service\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le)) / 1000) or histogram_quantile(0.95, sum(irate(istio_request_duration_seconds_bucket{reporter=\"source\", connection_security_policy!=\"mutual_tls\", destination_service=~\"$service\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{source_workload}}.{{source_workload_namespace}} P95", + "refId": "G", + "step": 2 + }, + { + "expr": "(histogram_quantile(0.99, sum(irate(istio_request_duration_milliseconds_bucket{reporter=\"source\", connection_security_policy!=\"mutual_tls\", destination_service=~\"$service\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le)) / 1000) or histogram_quantile(0.99, sum(irate(istio_request_duration_seconds_bucket{reporter=\"source\", connection_security_policy!=\"mutual_tls\", destination_service=~\"$service\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{source_workload}}.{{source_workload_namespace}} P99", + "refId": "H", + "step": 2 + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Incoming Request Duration by Source", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "s", + "label": null, + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 6, + "w": 8, + "x": 8, + "y": 20 + }, + "id": 28, + "legend": { + "alignAsTable": false, + "avg": false, + "current": false, + "hideEmpty": true, + "max": false, + "min": false, + "rightSide": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "histogram_quantile(0.50, sum(irate(istio_request_bytes_bucket{reporter=\"source\", connection_security_policy=\"mutual_tls\", destination_service=~\"$service\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{source_workload}}.{{source_workload_namespace}} P50 (🔐mTLS)", + "refId": "D", + "step": 2 + }, + { + "expr": "histogram_quantile(0.90, sum(irate(istio_request_bytes_bucket{reporter=\"source\", connection_security_policy=\"mutual_tls\", destination_service=~\"$service\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{source_workload}}.{{source_workload_namespace}} P90 (🔐mTLS)", + "refId": "A", + "step": 2 + }, + { + "expr": "histogram_quantile(0.95, sum(irate(istio_request_bytes_bucket{reporter=\"source\", connection_security_policy=\"mutual_tls\", destination_service=~\"$service\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{source_workload}}.{{source_workload_namespace}} P95 (🔐mTLS)", + "refId": "B", + "step": 2 + }, + { + "expr": "histogram_quantile(0.99, sum(irate(istio_request_bytes_bucket{reporter=\"source\", connection_security_policy=\"mutual_tls\", destination_service=~\"$service\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{source_workload}}.{{source_workload_namespace}} P99 (🔐mTLS)", + "refId": "C", + "step": 2 + }, + { + "expr": "histogram_quantile(0.50, sum(irate(istio_request_bytes_bucket{reporter=\"source\", connection_security_policy!=\"mutual_tls\", destination_service=~\"$service\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{source_workload}}.{{source_workload_namespace}} P50", + "refId": "E", + "step": 2 + }, + { + "expr": "histogram_quantile(0.90, sum(irate(istio_request_bytes_bucket{reporter=\"source\", connection_security_policy!=\"mutual_tls\", destination_service=~\"$service\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{source_workload}}.{{source_workload_namespace}} P90", + "refId": "F", + "step": 2 + }, + { + "expr": "histogram_quantile(0.95, sum(irate(istio_request_bytes_bucket{reporter=\"source\", connection_security_policy!=\"mutual_tls\", destination_service=~\"$service\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{source_workload}}.{{source_workload_namespace}} P95", + "refId": "G", + "step": 2 + }, + { + "expr": "histogram_quantile(0.99, sum(irate(istio_request_bytes_bucket{reporter=\"source\", connection_security_policy!=\"mutual_tls\", destination_service=~\"$service\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{source_workload}}.{{source_workload_namespace}} P99", + "refId": "H", + "step": 2 + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Incoming Request Size By Source", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "decbytes", + "label": null, + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 6, + "w": 8, + "x": 16, + "y": 20 + }, + "id": 68, + "legend": { + "alignAsTable": false, + "avg": false, + "current": false, + "hideEmpty": true, + "max": false, + "min": false, + "rightSide": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "histogram_quantile(0.50, sum(irate(istio_response_bytes_bucket{reporter=\"source\", connection_security_policy=\"mutual_tls\", destination_service=~\"$service\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{source_workload}}.{{source_workload_namespace}} P50 (🔐mTLS)", + "refId": "D", + "step": 2 + }, + { + "expr": "histogram_quantile(0.90, sum(irate(istio_response_bytes_bucket{reporter=\"source\", connection_security_policy=\"mutual_tls\", destination_service=~\"$service\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{source_workload}}.{{source_workload_namespace}} P90 (🔐mTLS)", + "refId": "A", + "step": 2 + }, + { + "expr": "histogram_quantile(0.95, sum(irate(istio_response_bytes_bucket{reporter=\"source\", connection_security_policy=\"mutual_tls\", destination_service=~\"$service\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{source_workload}}.{{source_workload_namespace}} P95 (🔐mTLS)", + "refId": "B", + "step": 2 + }, + { + "expr": "histogram_quantile(0.99, sum(irate(istio_response_bytes_bucket{reporter=\"source\", connection_security_policy=\"mutual_tls\", destination_service=~\"$service\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{source_workload}}.{{source_workload_namespace}} P99 (🔐mTLS)", + "refId": "C", + "step": 2 + }, + { + "expr": "histogram_quantile(0.50, sum(irate(istio_response_bytes_bucket{reporter=\"source\", connection_security_policy!=\"mutual_tls\", destination_service=~\"$service\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{source_workload}}.{{source_workload_namespace}} P50", + "refId": "E", + "step": 2 + }, + { + "expr": "histogram_quantile(0.90, sum(irate(istio_response_bytes_bucket{reporter=\"source\", connection_security_policy!=\"mutual_tls\", destination_service=~\"$service\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{source_workload}}.{{source_workload_namespace}} P90", + "refId": "F", + "step": 2 + }, + { + "expr": "histogram_quantile(0.95, sum(irate(istio_response_bytes_bucket{reporter=\"source\", connection_security_policy!=\"mutual_tls\", destination_service=~\"$service\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{source_workload}}.{{source_workload_namespace}} P95", + "refId": "G", + "step": 2 + }, + { + "expr": "histogram_quantile(0.99, sum(irate(istio_response_bytes_bucket{reporter=\"source\", connection_security_policy!=\"mutual_tls\", destination_service=~\"$service\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{source_workload}}.{{source_workload_namespace}} P99", + "refId": "H", + "step": 2 + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Response Size By Source", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "decbytes", + "label": null, + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 6, + "w": 12, + "x": 0, + "y": 26 + }, + "id": 80, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "round(sum(irate(istio_tcp_received_bytes_total{reporter=\"source\", connection_security_policy=\"mutual_tls\", destination_service=~\"$service\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace), 0.001)", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ source_workload }}.{{ source_workload_namespace}} (🔐mTLS)", + "refId": "A", + "step": 2 + }, + { + "expr": "round(sum(irate(istio_tcp_received_bytes_total{reporter=\"source\", connection_security_policy!=\"mutual_tls\", destination_service=~\"$service\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace), 0.001)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{ source_workload }}.{{ source_workload_namespace}}", + "refId": "B", + "step": 2 + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Bytes Received from Incoming TCP Connection", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "Bps", + "label": null, + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 6, + "w": 12, + "x": 12, + "y": 26 + }, + "id": 82, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "round(sum(irate(istio_tcp_sent_bytes_total{connection_security_policy=\"mutual_tls\", reporter=\"source\", destination_service=~\"$service\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace), 0.001)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{ source_workload }}.{{ source_workload_namespace}} (🔐mTLS)", + "refId": "A", + "step": 2 + }, + { + "expr": "round(sum(irate(istio_tcp_sent_bytes_total{connection_security_policy!=\"mutual_tls\", reporter=\"source\", destination_service=~\"$service\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace), 0.001)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{ source_workload }}.{{ source_workload_namespace}}", + "refId": "B", + "step": 2 + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Bytes Sent to Incoming TCP Connection", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "Bps", + "label": null, + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "content": "
\nSERVICE WORKLOADS\n
", + "gridPos": { + "h": 3, + "w": 24, + "x": 0, + "y": 32 + }, + "id": 69, + "links": [], + "mode": "html", + "title": "", + "transparent": true, + "type": "text" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 0, + "gridPos": { + "h": 6, + "w": 12, + "x": 0, + "y": 35 + }, + "id": 90, + "legend": { + "avg": false, + "current": false, + "hideEmpty": true, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null as zero", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "round(sum(irate(istio_requests_total{connection_security_policy=\"mutual_tls\",destination_service=~\"$service\",reporter=\"destination\",destination_workload=~\"$dstwl\",destination_workload_namespace=~\"$dstns\"}[5m])) by (destination_workload, destination_workload_namespace, response_code), 0.001)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{ destination_workload }}.{{ destination_workload_namespace }} : {{ response_code }} (🔐mTLS)", + "refId": "B", + "step": 2 + }, + { + "expr": "round(sum(irate(istio_requests_total{connection_security_policy!=\"mutual_tls\", destination_service=~\"$service\", reporter=\"destination\", destination_workload=~\"$dstwl\", destination_workload_namespace=~\"$dstns\"}[5m])) by (destination_workload, destination_workload_namespace, response_code), 0.001)", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_workload }}.{{ destination_workload_namespace }} : {{ response_code }}", + "refId": "A", + "step": 2 + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Incoming Requests by Destination And Response Code", + "tooltip": { + "shared": false, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [ + "total" + ] + }, + "yaxes": [ + { + "format": "ops", + "label": null, + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 6, + "w": 12, + "x": 12, + "y": 35 + }, + "id": 91, + "legend": { + "avg": false, + "current": false, + "hideEmpty": true, + "hideZero": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(irate(istio_requests_total{reporter=\"destination\", connection_security_policy=\"mutual_tls\", destination_service=~\"$service\",response_code!~\"5.*\", destination_workload=~\"$dstwl\", destination_workload_namespace=~\"$dstns\"}[5m])) by (destination_workload, destination_workload_namespace) / sum(irate(istio_requests_total{reporter=\"destination\", connection_security_policy=\"mutual_tls\", destination_service=~\"$service\", destination_workload=~\"$dstwl\", destination_workload_namespace=~\"$dstns\"}[5m])) by (destination_workload, destination_workload_namespace)", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_workload }}.{{ destination_workload_namespace }} (🔐mTLS)", + "refId": "A", + "step": 2 + }, + { + "expr": "sum(irate(istio_requests_total{reporter=\"destination\", connection_security_policy!=\"mutual_tls\", destination_service=~\"$service\",response_code!~\"5.*\", destination_workload=~\"$dstwl\", destination_workload_namespace=~\"$dstns\"}[5m])) by (destination_workload, destination_workload_namespace) / sum(irate(istio_requests_total{reporter=\"destination\", connection_security_policy!=\"mutual_tls\", destination_service=~\"$service\", destination_workload=~\"$dstwl\", destination_workload_namespace=~\"$dstns\"}[5m])) by (destination_workload, destination_workload_namespace)", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_workload }}.{{ destination_workload_namespace }}", + "refId": "B", + "step": 2 + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Incoming Success Rate (non-5xx responses) By Source", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "percentunit", + "label": null, + "logBase": 1, + "max": "1.01", + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "description": "", + "fill": 1, + "gridPos": { + "h": 6, + "w": 8, + "x": 0, + "y": 41 + }, + "id": 94, + "legend": { + "alignAsTable": false, + "avg": false, + "current": false, + "hideEmpty": true, + "hideZero": false, + "max": false, + "min": false, + "rightSide": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "(histogram_quantile(0.50, sum(irate(istio_request_duration_milliseconds_bucket{reporter=\"destination\", connection_security_policy=\"mutual_tls\", destination_service=~\"$service\", destination_workload=~\"$dstwl\", destination_workload_namespace=~\"$dstns\"}[1m])) by (destination_workload, destination_workload_namespace, le)) / 1000) or histogram_quantile(0.50, sum(irate(istio_request_duration_seconds_bucket{reporter=\"destination\", connection_security_policy=\"mutual_tls\", destination_service=~\"$service\", destination_workload=~\"$dstwl\", destination_workload_namespace=~\"$dstns\"}[1m])) by (destination_workload, destination_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_workload }}.{{ destination_workload_namespace }} P50 (🔐mTLS)", + "refId": "D", + "step": 2 + }, + { + "expr": "(histogram_quantile(0.90, sum(irate(istio_request_duration_milliseconds_bucket{reporter=\"destination\", connection_security_policy=\"mutual_tls\", destination_service=~\"$service\", destination_workload=~\"$dstwl\", destination_workload_namespace=~\"$dstns\"}[1m])) by (destination_workload, destination_workload_namespace, le)) / 1000) or histogram_quantile(0.90, sum(irate(istio_request_duration_seconds_bucket{reporter=\"destination\", connection_security_policy=\"mutual_tls\", destination_service=~\"$service\", destination_workload=~\"$dstwl\", destination_workload_namespace=~\"$dstns\"}[1m])) by (destination_workload, destination_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_workload }}.{{ destination_workload_namespace }} P90 (🔐mTLS)", + "refId": "A", + "step": 2 + }, + { + "expr": "(histogram_quantile(0.95, sum(irate(istio_request_duration_milliseconds_bucket{reporter=\"destination\", connection_security_policy=\"mutual_tls\", destination_service=~\"$service\", destination_workload=~\"$dstwl\", destination_workload_namespace=~\"$dstns\"}[1m])) by (destination_workload, destination_workload_namespace, le)) / 1000) or histogram_quantile(0.95, sum(irate(istio_request_duration_seconds_bucket{reporter=\"destination\", connection_security_policy=\"mutual_tls\", destination_service=~\"$service\", destination_workload=~\"$dstwl\", destination_workload_namespace=~\"$dstns\"}[1m])) by (destination_workload, destination_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_workload }}.{{ destination_workload_namespace }} P95 (🔐mTLS)", + "refId": "B", + "step": 2 + }, + { + "expr": "(histogram_quantile(0.99, sum(irate(istio_request_duration_milliseconds_bucket{reporter=\"destination\", connection_security_policy=\"mutual_tls\", destination_service=~\"$service\", destination_workload=~\"$dstwl\", destination_workload_namespace=~\"$dstns\"}[1m])) by (destination_workload, destination_workload_namespace, le)) / 1000) or histogram_quantile(0.99, sum(irate(istio_request_duration_seconds_bucket{reporter=\"destination\", connection_security_policy=\"mutual_tls\", destination_service=~\"$service\", destination_workload=~\"$dstwl\", destination_workload_namespace=~\"$dstns\"}[1m])) by (destination_workload, destination_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_workload }}.{{ destination_workload_namespace }} P99 (🔐mTLS)", + "refId": "C", + "step": 2 + }, + { + "expr": "(histogram_quantile(0.50, sum(irate(istio_request_duration_milliseconds_bucket{reporter=\"destination\", connection_security_policy!=\"mutual_tls\", destination_service=~\"$service\", destination_workload=~\"$dstwl\", destination_workload_namespace=~\"$dstns\"}[1m])) by (destination_workload, destination_workload_namespace, le)) / 1000) or histogram_quantile(0.50, sum(irate(istio_request_duration_seconds_bucket{reporter=\"destination\", connection_security_policy!=\"mutual_tls\", destination_service=~\"$service\", destination_workload=~\"$dstwl\", destination_workload_namespace=~\"$dstns\"}[1m])) by (destination_workload, destination_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_workload }}.{{ destination_workload_namespace }} P50", + "refId": "E", + "step": 2 + }, + { + "expr": "(histogram_quantile(0.90, sum(irate(istio_request_duration_milliseconds_bucket{reporter=\"destination\", connection_security_policy!=\"mutual_tls\", destination_service=~\"$service\", destination_workload=~\"$dstwl\", destination_workload_namespace=~\"$dstns\"}[1m])) by (destination_workload, destination_workload_namespace, le)) / 1000) or histogram_quantile(0.90, sum(irate(istio_request_duration_seconds_bucket{reporter=\"destination\", connection_security_policy!=\"mutual_tls\", destination_service=~\"$service\", destination_workload=~\"$dstwl\", destination_workload_namespace=~\"$dstns\"}[1m])) by (destination_workload, destination_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_workload }}.{{ destination_workload_namespace }} P90", + "refId": "F", + "step": 2 + }, + { + "expr": "(histogram_quantile(0.95, sum(irate(istio_request_duration_milliseconds_bucket{reporter=\"destination\", connection_security_policy!=\"mutual_tls\", destination_service=~\"$service\", destination_workload=~\"$dstwl\", destination_workload_namespace=~\"$dstns\"}[1m])) by (destination_workload, destination_workload_namespace, le)) / 1000) or histogram_quantile(0.95, sum(irate(istio_request_duration_seconds_bucket{reporter=\"destination\", connection_security_policy!=\"mutual_tls\", destination_service=~\"$service\", destination_workload=~\"$dstwl\", destination_workload_namespace=~\"$dstns\"}[1m])) by (destination_workload, destination_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_workload }}.{{ destination_workload_namespace }} P95", + "refId": "G", + "step": 2 + }, + { + "expr": "(histogram_quantile(0.99, sum(irate(istio_request_duration_milliseconds_bucket{reporter=\"destination\", connection_security_policy!=\"mutual_tls\", destination_service=~\"$service\", destination_workload=~\"$dstwl\", destination_workload_namespace=~\"$dstns\"}[1m])) by (destination_workload, destination_workload_namespace, le)) / 1000) or histogram_quantile(0.99, sum(irate(istio_request_duration_seconds_bucket{reporter=\"destination\", connection_security_policy!=\"mutual_tls\", destination_service=~\"$service\", destination_workload=~\"$dstwl\", destination_workload_namespace=~\"$dstns\"}[1m])) by (destination_workload, destination_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_workload }}.{{ destination_workload_namespace }} P99", + "refId": "H", + "step": 2 + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Incoming Request Duration by Source", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "s", + "label": null, + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 6, + "w": 8, + "x": 8, + "y": 41 + }, + "id": 95, + "legend": { + "alignAsTable": false, + "avg": false, + "current": false, + "hideEmpty": true, + "max": false, + "min": false, + "rightSide": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "histogram_quantile(0.50, sum(irate(istio_request_bytes_bucket{reporter=\"destination\", connection_security_policy=\"mutual_tls\", destination_service=~\"$service\", destination_workload=~\"$dstwl\", destination_workload_namespace=~\"$dstns\"}[1m])) by (destination_workload, destination_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_workload }}.{{ destination_workload_namespace }} P50 (🔐mTLS)", + "refId": "D", + "step": 2 + }, + { + "expr": "histogram_quantile(0.90, sum(irate(istio_request_bytes_bucket{reporter=\"destination\", connection_security_policy=\"mutual_tls\", destination_service=~\"$service\", destination_workload=~\"$dstwl\", destination_workload_namespace=~\"$dstns\"}[1m])) by (destination_workload, destination_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_workload }}.{{ destination_workload_namespace }} P90 (🔐mTLS)", + "refId": "A", + "step": 2 + }, + { + "expr": "histogram_quantile(0.95, sum(irate(istio_request_bytes_bucket{reporter=\"destination\", connection_security_policy=\"mutual_tls\", destination_service=~\"$service\", destination_workload=~\"$dstwl\", destination_workload_namespace=~\"$dstns\"}[1m])) by (destination_workload, destination_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_workload }}.{{ destination_workload_namespace }} P95 (🔐mTLS)", + "refId": "B", + "step": 2 + }, + { + "expr": "histogram_quantile(0.99, sum(irate(istio_request_bytes_bucket{reporter=\"destination\", connection_security_policy=\"mutual_tls\", destination_service=~\"$service\", destination_workload=~\"$dstwl\", destination_workload_namespace=~\"$dstns\"}[1m])) by (destination_workload, destination_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_workload }}.{{ destination_workload_namespace }} P99 (🔐mTLS)", + "refId": "C", + "step": 2 + }, + { + "expr": "histogram_quantile(0.50, sum(irate(istio_request_bytes_bucket{reporter=\"destination\", connection_security_policy!=\"mutual_tls\", destination_service=~\"$service\", destination_workload=~\"$dstwl\", destination_workload_namespace=~\"$dstns\"}[1m])) by (destination_workload, destination_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_workload }}.{{ destination_workload_namespace }} P50", + "refId": "E", + "step": 2 + }, + { + "expr": "histogram_quantile(0.90, sum(irate(istio_request_bytes_bucket{reporter=\"destination\", connection_security_policy!=\"mutual_tls\", destination_service=~\"$service\", destination_workload=~\"$dstwl\", destination_workload_namespace=~\"$dstns\"}[1m])) by (destination_workload, destination_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_workload }}.{{ destination_workload_namespace }} P90", + "refId": "F", + "step": 2 + }, + { + "expr": "histogram_quantile(0.95, sum(irate(istio_request_bytes_bucket{reporter=\"destination\", connection_security_policy!=\"mutual_tls\", destination_service=~\"$service\", destination_workload=~\"$dstwl\", destination_workload_namespace=~\"$dstns\"}[1m])) by (destination_workload, destination_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_workload }}.{{ destination_workload_namespace }} P95", + "refId": "G", + "step": 2 + }, + { + "expr": "histogram_quantile(0.99, sum(irate(istio_request_bytes_bucket{reporter=\"destination\", connection_security_policy!=\"mutual_tls\", destination_service=~\"$service\", destination_workload=~\"$dstwl\", destination_workload_namespace=~\"$dstns\"}[1m])) by (destination_workload, destination_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_workload }}.{{ destination_workload_namespace }} P99", + "refId": "H", + "step": 2 + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Incoming Request Size By Source", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "decbytes", + "label": null, + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 6, + "w": 8, + "x": 16, + "y": 41 + }, + "id": 96, + "legend": { + "alignAsTable": false, + "avg": false, + "current": false, + "hideEmpty": true, + "max": false, + "min": false, + "rightSide": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "histogram_quantile(0.50, sum(irate(istio_response_bytes_bucket{reporter=\"destination\", connection_security_policy=\"mutual_tls\", destination_service=~\"$service\", destination_workload=~\"$dstwl\", destination_workload_namespace=~\"$dstns\"}[1m])) by (destination_workload, destination_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_workload }}.{{ destination_workload_namespace }} P50 (🔐mTLS)", + "refId": "D", + "step": 2 + }, + { + "expr": "histogram_quantile(0.90, sum(irate(istio_response_bytes_bucket{reporter=\"destination\", connection_security_policy=\"mutual_tls\", destination_service=~\"$service\", destination_workload=~\"$dstwl\", destination_workload_namespace=~\"$dstns\"}[1m])) by (destination_workload, destination_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_workload }}.{{ destination_workload_namespace }} P90 (🔐mTLS)", + "refId": "A", + "step": 2 + }, + { + "expr": "histogram_quantile(0.95, sum(irate(istio_response_bytes_bucket{reporter=\"destination\", connection_security_policy=\"mutual_tls\", destination_service=~\"$service\", destination_workload=~\"$dstwl\", destination_workload_namespace=~\"$dstns\"}[1m])) by (destination_workload, destination_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_workload }}.{{ destination_workload_namespace }} P95 (🔐mTLS)", + "refId": "B", + "step": 2 + }, + { + "expr": "histogram_quantile(0.99, sum(irate(istio_response_bytes_bucket{reporter=\"destination\", connection_security_policy=\"mutual_tls\", destination_service=~\"$service\", destination_workload=~\"$dstwl\", destination_workload_namespace=~\"$dstns\"}[1m])) by (destination_workload, destination_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_workload }}.{{ destination_workload_namespace }} P99 (🔐mTLS)", + "refId": "C", + "step": 2 + }, + { + "expr": "histogram_quantile(0.50, sum(irate(istio_response_bytes_bucket{reporter=\"destination\", connection_security_policy!=\"mutual_tls\", destination_service=~\"$service\", destination_workload=~\"$dstwl\", destination_workload_namespace=~\"$dstns\"}[1m])) by (destination_workload, destination_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_workload }}.{{ destination_workload_namespace }} P50", + "refId": "E", + "step": 2 + }, + { + "expr": "histogram_quantile(0.90, sum(irate(istio_response_bytes_bucket{reporter=\"destination\", connection_security_policy!=\"mutual_tls\", destination_service=~\"$service\", destination_workload=~\"$dstwl\", destination_workload_namespace=~\"$dstns\"}[1m])) by (destination_workload, destination_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_workload }}.{{ destination_workload_namespace }} P90", + "refId": "F", + "step": 2 + }, + { + "expr": "histogram_quantile(0.95, sum(irate(istio_response_bytes_bucket{reporter=\"destination\", connection_security_policy!=\"mutual_tls\", destination_service=~\"$service\", destination_workload=~\"$dstwl\", destination_workload_namespace=~\"$dstns\"}[1m])) by (destination_workload, destination_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_workload }}.{{ destination_workload_namespace }} P95", + "refId": "G", + "step": 2 + }, + { + "expr": "histogram_quantile(0.99, sum(irate(istio_response_bytes_bucket{reporter=\"destination\", connection_security_policy!=\"mutual_tls\", destination_service=~\"$service\", destination_workload=~\"$dstwl\", destination_workload_namespace=~\"$dstns\"}[1m])) by (destination_workload, destination_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_workload }}.{{ destination_workload_namespace }} P99", + "refId": "H", + "step": 2 + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Response Size By Source", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "decbytes", + "label": null, + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 6, + "w": 12, + "x": 0, + "y": 47 + }, + "id": 92, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "round(sum(irate(istio_tcp_received_bytes_total{reporter=\"source\", connection_security_policy=\"mutual_tls\", destination_service=~\"$service\", destination_workload=~\"$dstwl\", destination_workload_namespace=~\"$dstns\"}[1m])) by (destination_workload, destination_workload_namespace), 0.001)", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_workload }}.{{ destination_workload_namespace}} (🔐mTLS)", + "refId": "A", + "step": 2 + }, + { + "expr": "round(sum(irate(istio_tcp_received_bytes_total{reporter=\"source\", connection_security_policy!=\"mutual_tls\", destination_service=~\"$service\", destination_workload=~\"$dstwl\", destination_workload_namespace=~\"$dstns\"}[1m])) by (destination_workload, destination_workload_namespace), 0.001)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{ destination_workload }}.{{ destination_workload_namespace}}", + "refId": "B", + "step": 2 + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Bytes Received from Incoming TCP Connection", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "Bps", + "label": null, + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 6, + "w": 12, + "x": 12, + "y": 47 + }, + "id": 93, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "round(sum(irate(istio_tcp_sent_bytes_total{connection_security_policy=\"mutual_tls\", reporter=\"source\", destination_service=~\"$service\", destination_workload=~\"$dstwl\", destination_workload_namespace=~\"$dstns\"}[1m])) by (destination_workload, destination_workload_namespace), 0.001)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{ destination_workload }}.{{destination_workload_namespace }} (🔐mTLS)", + "refId": "A", + "step": 2 + }, + { + "expr": "round(sum(irate(istio_tcp_sent_bytes_total{connection_security_policy!=\"mutual_tls\", reporter=\"source\", destination_service=~\"$service\", destination_workload=~\"$dstwl\", destination_workload_namespace=~\"$dstns\"}[1m])) by (destination_workload, destination_workload_namespace), 0.001)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{ destination_workload }}.{{destination_workload_namespace }}", + "refId": "B", + "step": 2 + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Bytes Sent to Incoming TCP Connection", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "Bps", + "label": null, + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + } + ], + "refresh": "10s", + "schemaVersion": 16, + "style": "dark", + "tags": [], + "templating": { + "list": [ + { + "allValue": null, + "datasource": "Prometheus", + "hide": 0, + "includeAll": false, + "label": "Service", + "multi": false, + "name": "service", + "options": [], + "query": "label_values(destination_service)", + "refresh": 1, + "regex": "", + "sort": 0, + "tagValuesQuery": "", + "tags": [], + "tagsQuery": "", + "type": "query", + "useTags": false + }, + { + "allValue": null, + "current": { + "text": "All", + "value": "$__all" + }, + "datasource": "Prometheus", + "hide": 0, + "includeAll": true, + "label": "Client Workload Namespace", + "multi": true, + "name": "srcns", + "options": [], + "query": "query_result( sum(istio_requests_total{reporter=\"destination\", destination_service=\"$service\"}) by (source_workload_namespace) or sum(istio_tcp_sent_bytes_total{reporter=\"destination\", destination_service=~\"$service\"}) by (source_workload_namespace))", + "refresh": 1, + "regex": "/.*namespace=\"([^\"]*).*/", + "sort": 2, + "tagValuesQuery": "", + "tags": [], + "tagsQuery": "", + "type": "query", + "useTags": false + }, + { + "allValue": null, + "current": { + "text": "All", + "value": "$__all" + }, + "datasource": "Prometheus", + "hide": 0, + "includeAll": true, + "label": "Client Workload", + "multi": true, + "name": "srcwl", + "options": [], + "query": "query_result( sum(istio_requests_total{reporter=\"destination\", destination_service=~\"$service\", source_workload_namespace=~\"$srcns\"}) by (source_workload) or sum(istio_tcp_sent_bytes_total{reporter=\"destination\", destination_service=~\"$service\", source_workload_namespace=~\"$srcns\"}) by (source_workload))", + "refresh": 1, + "regex": "/.*workload=\"([^\"]*).*/", + "sort": 3, + "tagValuesQuery": "", + "tags": [], + "tagsQuery": "", + "type": "query", + "useTags": false + }, + { + "allValue": null, + "current": { + "text": "All", + "value": "$__all" + }, + "datasource": "Prometheus", + "hide": 0, + "includeAll": true, + "label": "Service Workload Namespace", + "multi": true, + "name": "dstns", + "options": [], + "query": "query_result( sum(istio_requests_total{reporter=\"destination\", destination_service=\"$service\"}) by (destination_workload_namespace) or sum(istio_tcp_sent_bytes_total{reporter=\"destination\", destination_service=~\"$service\"}) by (destination_workload_namespace))", + "refresh": 1, + "regex": "/.*namespace=\"([^\"]*).*/", + "sort": 2, + "tagValuesQuery": "", + "tags": [], + "tagsQuery": "", + "type": "query", + "useTags": false + }, + { + "allValue": null, + "current": { + "text": "All", + "value": "$__all" + }, + "datasource": "Prometheus", + "hide": 0, + "includeAll": true, + "label": "Service Workload", + "multi": true, + "name": "dstwl", + "options": [], + "query": "query_result( sum(istio_requests_total{reporter=\"destination\", destination_service=~\"$service\", destination_workload_namespace=~\"$dstns\"}) by (destination_workload) or sum(istio_tcp_sent_bytes_total{reporter=\"destination\", destination_service=~\"$service\", destination_workload_namespace=~\"$dstns\"}) by (destination_workload))", + "refresh": 1, + "regex": "/.*workload=\"([^\"]*).*/", + "sort": 3, + "tagValuesQuery": "", + "tags": [], + "tagsQuery": "", + "type": "query", + "useTags": false + } + ] + }, + "time": { + "from": "now-5m", + "to": "now" + }, + "timepicker": { + "refresh_intervals": [ + "5s", + "10s", + "30s", + "1m", + "5m", + "15m", + "30m", + "1h", + "2h", + "1d" + ], + "time_options": [ + "5m", + "15m", + "1h", + "6h", + "12h", + "24h", + "2d", + "7d", + "30d" + ] + }, + "timezone": "", + "title": "Istio Service Dashboard", + "uid": "LJ_uJAvmk", + "version": 1 +} diff --git a/istio-1.5.0/install/kubernetes/helm/istio/charts/grafana/dashboards/istio-workload-dashboard.json b/istio-1.5.0/install/kubernetes/helm/istio/charts/grafana/dashboards/istio-workload-dashboard.json new file mode 100644 index 0000000..62ad1b5 --- /dev/null +++ b/istio-1.5.0/install/kubernetes/helm/istio/charts/grafana/dashboards/istio-workload-dashboard.json @@ -0,0 +1,2303 @@ +{ + "__inputs": [ + { + "name": "DS_PROMETHEUS", + "label": "Prometheus", + "description": "", + "type": "datasource", + "pluginId": "prometheus", + "pluginName": "Prometheus" + } + ], + "__requires": [ + { + "type": "grafana", + "id": "grafana", + "name": "Grafana", + "version": "5.0.4" + }, + { + "type": "panel", + "id": "graph", + "name": "Graph", + "version": "5.0.0" + }, + { + "type": "datasource", + "id": "prometheus", + "name": "Prometheus", + "version": "5.0.0" + }, + { + "type": "panel", + "id": "singlestat", + "name": "Singlestat", + "version": "5.0.0" + }, + { + "type": "panel", + "id": "text", + "name": "Text", + "version": "5.0.0" + } + ], + "annotations": { + "list": [ + { + "builtIn": 1, + "datasource": "-- Grafana --", + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations & Alerts", + "type": "dashboard" + } + ] + }, + "editable": false, + "gnetId": null, + "graphTooltip": 0, + "id": null, + "iteration": 1531345461465, + "links": [], + "panels": [ + { + "content": "
\nWORKLOAD: $workload.$namespace\n
", + "gridPos": { + "h": 3, + "w": 24, + "x": 0, + "y": 0 + }, + "id": 89, + "links": [], + "mode": "html", + "title": "", + "transparent": true, + "type": "text" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "datasource": "Prometheus", + "format": "ops", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "gridPos": { + "h": 4, + "w": 8, + "x": 0, + "y": 3 + }, + "id": 12, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": true, + "lineColor": "rgb(31, 120, 193)", + "show": true + }, + "tableColumn": "", + "targets": [ + { + "expr": "round(sum(irate(istio_requests_total{reporter=\"destination\",destination_workload_namespace=~\"$namespace\",destination_workload=~\"$workload\"}[5m])), 0.001)", + "format": "time_series", + "intervalFactor": 1, + "refId": "A", + "step": 4 + } + ], + "thresholds": "", + "title": "Incoming Request Volume", + "transparent": false, + "type": "singlestat", + "valueFontSize": "80%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "current" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "rgba(50, 172, 45, 0.97)", + "rgba(237, 129, 40, 0.89)", + "rgba(245, 54, 54, 0.9)" + ], + "datasource": "Prometheus", + "decimals": null, + "format": "percentunit", + "gauge": { + "maxValue": 100, + "minValue": 80, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": false + }, + "gridPos": { + "h": 4, + "w": 8, + "x": 8, + "y": 3 + }, + "id": 14, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": true, + "lineColor": "rgb(31, 120, 193)", + "show": true + }, + "tableColumn": "", + "targets": [ + { + "expr": "sum(irate(istio_requests_total{reporter=\"destination\",destination_workload_namespace=~\"$namespace\",destination_workload=~\"$workload\",response_code!~\"5.*\"}[5m])) / sum(irate(istio_requests_total{reporter=\"destination\",destination_workload_namespace=~\"$namespace\",destination_workload=~\"$workload\"}[5m]))", + "format": "time_series", + "intervalFactor": 1, + "refId": "B" + } + ], + "thresholds": "95, 99, 99.5", + "title": "Incoming Success Rate (non-5xx responses)", + "transparent": false, + "type": "singlestat", + "valueFontSize": "80%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "avg" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 4, + "w": 8, + "x": 16, + "y": 3 + }, + "id": 87, + "legend": { + "alignAsTable": false, + "avg": false, + "current": false, + "hideEmpty": false, + "hideZero": false, + "max": false, + "min": false, + "rightSide": true, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "(histogram_quantile(0.50, sum(irate(istio_request_duration_milliseconds_bucket{reporter=\"destination\",destination_workload=~\"$workload\", destination_workload_namespace=~\"$namespace\"}[1m])) by (le)) / 1000) or histogram_quantile(0.50, sum(irate(istio_request_duration_seconds_bucket{reporter=\"destination\",destination_workload=~\"$workload\", destination_workload_namespace=~\"$namespace\"}[1m])) by (le))", + "format": "time_series", + "interval": "", + "intervalFactor": 1, + "legendFormat": "P50", + "refId": "A" + }, + { + "expr": "(histogram_quantile(0.50, sum(irate(istio_request_duration_milliseconds_bucket{reporter=\"destination\",destination_workload=~\"$workload\", destination_workload_namespace=~\"$namespace\"}[1m])) by (le)) / 1000) or histogram_quantile(0.90, sum(irate(istio_request_duration_seconds_bucket{reporter=\"destination\",destination_workload=~\"$workload\", destination_workload_namespace=~\"$namespace\"}[1m])) by (le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "P90", + "refId": "B" + }, + { + "expr": "(histogram_quantile(0.50, sum(irate(istio_request_duration_milliseconds_bucket{reporter=\"destination\",destination_workload=~\"$workload\", destination_workload_namespace=~\"$namespace\"}[1m])) by (le)) / 1000) or histogram_quantile(0.99, sum(irate(istio_request_duration_seconds_bucket{reporter=\"destination\",destination_workload=~\"$workload\", destination_workload_namespace=~\"$namespace\"}[1m])) by (le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "P99", + "refId": "C" + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Request Duration", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "s", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ] + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "#299c46", + "rgba(237, 129, 40, 0.89)", + "#d44a3a" + ], + "datasource": "Prometheus", + "format": "Bps", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "gridPos": { + "h": 4, + "w": 12, + "x": 0, + "y": 7 + }, + "id": 84, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": true, + "lineColor": "rgb(31, 120, 193)", + "show": true + }, + "tableColumn": "", + "targets": [ + { + "expr": "sum(irate(istio_tcp_sent_bytes_total{reporter=\"destination\", destination_workload_namespace=~\"$namespace\", destination_workload=~\"$workload\"}[1m])) + sum(irate(istio_tcp_received_bytes_total{reporter=\"destination\", destination_workload_namespace=~\"$namespace\", destination_workload=~\"$workload\"}[1m]))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "", + "refId": "A" + } + ], + "thresholds": "", + "title": "TCP Server Traffic", + "transparent": false, + "type": "singlestat", + "valueFontSize": "80%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "avg" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "#299c46", + "rgba(237, 129, 40, 0.89)", + "#d44a3a" + ], + "datasource": "Prometheus", + "format": "Bps", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "gridPos": { + "h": 4, + "w": 12, + "x": 12, + "y": 7 + }, + "id": 85, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": true, + "lineColor": "rgb(31, 120, 193)", + "show": true + }, + "tableColumn": "", + "targets": [ + { + "expr": "sum(irate(istio_tcp_sent_bytes_total{reporter=\"source\", source_workload_namespace=~\"$namespace\", source_workload=~\"$workload\"}[1m])) + sum(irate(istio_tcp_received_bytes_total{reporter=\"source\", source_workload_namespace=~\"$namespace\", source_workload=~\"$workload\"}[1m]))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "", + "refId": "A" + } + ], + "thresholds": "", + "title": "TCP Client Traffic", + "transparent": false, + "type": "singlestat", + "valueFontSize": "80%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "avg" + }, + { + "content": "
\nINBOUND WORKLOADS\n
", + "gridPos": { + "h": 3, + "w": 24, + "x": 0, + "y": 11 + }, + "id": 45, + "links": [], + "mode": "html", + "title": "", + "transparent": true, + "type": "text" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 0, + "gridPos": { + "h": 6, + "w": 12, + "x": 0, + "y": 14 + }, + "id": 25, + "legend": { + "avg": false, + "current": false, + "hideEmpty": true, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null as zero", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "round(sum(irate(istio_requests_total{connection_security_policy=\"mutual_tls\", destination_workload_namespace=~\"$namespace\", destination_workload=~\"$workload\", reporter=\"destination\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[5m])) by (source_workload, source_workload_namespace, response_code), 0.001)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{ source_workload }}.{{ source_workload_namespace }} : {{ response_code }} (🔐mTLS)", + "refId": "B", + "step": 2 + }, + { + "expr": "round(sum(irate(istio_requests_total{connection_security_policy!=\"mutual_tls\", destination_workload_namespace=~\"$namespace\", destination_workload=~\"$workload\", reporter=\"destination\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[5m])) by (source_workload, source_workload_namespace, response_code), 0.001)", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ source_workload }}.{{ source_workload_namespace }} : {{ response_code }}", + "refId": "A", + "step": 2 + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Incoming Requests by Source And Response Code", + "tooltip": { + "shared": false, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [ + "total" + ] + }, + "yaxes": [ + { + "format": "ops", + "label": null, + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ] + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 6, + "w": 12, + "x": 12, + "y": 14 + }, + "id": 26, + "legend": { + "avg": false, + "current": false, + "hideEmpty": true, + "hideZero": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(irate(istio_requests_total{reporter=\"destination\", connection_security_policy=\"mutual_tls\", destination_workload_namespace=~\"$namespace\", destination_workload=~\"$workload\",response_code!~\"5.*\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[5m])) by (source_workload, source_workload_namespace) / sum(irate(istio_requests_total{reporter=\"destination\", connection_security_policy=\"mutual_tls\", destination_workload_namespace=~\"$namespace\", destination_workload=~\"$workload\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[5m])) by (source_workload, source_workload_namespace)", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ source_workload }}.{{ source_workload_namespace }} (🔐mTLS)", + "refId": "A", + "step": 2 + }, + { + "expr": "sum(irate(istio_requests_total{reporter=\"destination\", connection_security_policy!=\"mutual_tls\", destination_workload_namespace=~\"$namespace\", destination_workload=~\"$workload\",response_code!~\"5.*\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[5m])) by (source_workload, source_workload_namespace) / sum(irate(istio_requests_total{reporter=\"destination\", connection_security_policy!=\"mutual_tls\", destination_workload_namespace=~\"$namespace\", destination_workload=~\"$workload\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[5m])) by (source_workload, source_workload_namespace)", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ source_workload }}.{{ source_workload_namespace }}", + "refId": "B", + "step": 2 + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Incoming Success Rate (non-5xx responses) By Source", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "percentunit", + "label": null, + "logBase": 1, + "max": "1.01", + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ] + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "description": "", + "fill": 1, + "gridPos": { + "h": 6, + "w": 8, + "x": 0, + "y": 20 + }, + "id": 27, + "legend": { + "alignAsTable": false, + "avg": false, + "current": false, + "hideEmpty": true, + "hideZero": false, + "max": false, + "min": false, + "rightSide": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "(histogram_quantile(0.50, sum(irate(istio_request_duration_milliseconds_bucket{reporter=\"destination\", connection_security_policy=\"mutual_tls\", destination_workload=~\"$workload\", destination_workload_namespace=~\"$namespace\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le)) / 1000) or histogram_quantile(0.50, sum(irate(istio_request_duration_seconds_bucket{reporter=\"destination\", connection_security_policy=\"mutual_tls\", destination_workload=~\"$workload\", destination_workload_namespace=~\"$namespace\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{source_workload}}.{{source_workload_namespace}} P50 (🔐mTLS)", + "refId": "D", + "step": 2 + }, + { + "expr": "(histogram_quantile(0.90, sum(irate(istio_request_duration_milliseconds_bucket{reporter=\"destination\", connection_security_policy=\"mutual_tls\", destination_workload=~\"$workload\", destination_workload_namespace=~\"$namespace\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le)) / 1000) or histogram_quantile(0.90, sum(irate(istio_request_duration_seconds_bucket{reporter=\"destination\", connection_security_policy=\"mutual_tls\", destination_workload=~\"$workload\", destination_workload_namespace=~\"$namespace\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{source_workload}}.{{source_workload_namespace}} P90 (🔐mTLS)", + "refId": "A", + "step": 2 + }, + { + "expr": "(histogram_quantile(0.95, sum(irate(istio_request_duration_milliseconds_bucket{reporter=\"destination\", connection_security_policy=\"mutual_tls\", destination_workload=~\"$workload\", destination_workload_namespace=~\"$namespace\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le)) / 1000) or histogram_quantile(0.95, sum(irate(istio_request_duration_seconds_bucket{reporter=\"destination\", connection_security_policy=\"mutual_tls\", destination_workload=~\"$workload\", destination_workload_namespace=~\"$namespace\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{source_workload}}.{{source_workload_namespace}} P95 (🔐mTLS)", + "refId": "B", + "step": 2 + }, + { + "expr": "(histogram_quantile(0.99, sum(irate(istio_request_duration_milliseconds_bucket{reporter=\"destination\", connection_security_policy=\"mutual_tls\", destination_workload=~\"$workload\", destination_workload_namespace=~\"$namespace\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le)) / 1000) or histogram_quantile(0.99, sum(irate(istio_request_duration_seconds_bucket{reporter=\"destination\", connection_security_policy=\"mutual_tls\", destination_workload=~\"$workload\", destination_workload_namespace=~\"$namespace\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{source_workload}}.{{source_workload_namespace}} P99 (🔐mTLS)", + "refId": "C", + "step": 2 + }, + { + "expr": "(histogram_quantile(0.50, sum(irate(istio_request_duration_milliseconds_bucket{reporter=\"destination\", connection_security_policy!=\"mutual_tls\", destination_workload=~\"$workload\", destination_workload_namespace=~\"$namespace\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le)) / 1000) or histogram_quantile(0.50, sum(irate(istio_request_duration_seconds_bucket{reporter=\"destination\", connection_security_policy!=\"mutual_tls\", destination_workload=~\"$workload\", destination_workload_namespace=~\"$namespace\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{source_workload}}.{{source_workload_namespace}} P50", + "refId": "E", + "step": 2 + }, + { + "expr": "(histogram_quantile(0.90, sum(irate(istio_request_duration_milliseconds_bucket{reporter=\"destination\", connection_security_policy!=\"mutual_tls\", destination_workload=~\"$workload\", destination_workload_namespace=~\"$namespace\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le)) / 1000) or histogram_quantile(0.90, sum(irate(istio_request_duration_seconds_bucket{reporter=\"destination\", connection_security_policy!=\"mutual_tls\", destination_workload=~\"$workload\", destination_workload_namespace=~\"$namespace\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{source_workload}}.{{source_workload_namespace}} P90", + "refId": "F", + "step": 2 + }, + { + "expr": "(histogram_quantile(0.95, sum(irate(istio_request_duration_milliseconds_bucket{reporter=\"destination\", connection_security_policy!=\"mutual_tls\", destination_workload=~\"$workload\", destination_workload_namespace=~\"$namespace\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le)) / 1000) or histogram_quantile(0.95, sum(irate(istio_request_duration_seconds_bucket{reporter=\"destination\", connection_security_policy!=\"mutual_tls\", destination_workload=~\"$workload\", destination_workload_namespace=~\"$namespace\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{source_workload}}.{{source_workload_namespace}} P95", + "refId": "G", + "step": 2 + }, + { + "expr": "(histogram_quantile(0.99, sum(irate(istio_request_duration_milliseconds_bucket{reporter=\"destination\", connection_security_policy!=\"mutual_tls\", destination_workload=~\"$workload\", destination_workload_namespace=~\"$namespace\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le)) / 1000) or histogram_quantile(0.99, sum(irate(istio_request_duration_seconds_bucket{reporter=\"destination\", connection_security_policy!=\"mutual_tls\", destination_workload=~\"$workload\", destination_workload_namespace=~\"$namespace\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{source_workload}}.{{source_workload_namespace}} P99", + "refId": "H", + "step": 2 + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Incoming Request Duration by Source", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "s", + "label": null, + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ] + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 6, + "w": 8, + "x": 8, + "y": 20 + }, + "id": 28, + "legend": { + "alignAsTable": false, + "avg": false, + "current": false, + "hideEmpty": true, + "max": false, + "min": false, + "rightSide": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "histogram_quantile(0.50, sum(irate(istio_request_bytes_bucket{reporter=\"destination\", connection_security_policy=\"mutual_tls\", destination_workload=~\"$workload\", destination_workload_namespace=~\"$namespace\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{source_workload}}.{{source_workload_namespace}} P50 (🔐mTLS)", + "refId": "D", + "step": 2 + }, + { + "expr": "histogram_quantile(0.90, sum(irate(istio_request_bytes_bucket{reporter=\"destination\", connection_security_policy=\"mutual_tls\", destination_workload=~\"$workload\", destination_workload_namespace=~\"$namespace\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{source_workload}}.{{source_workload_namespace}} P90 (🔐mTLS)", + "refId": "A", + "step": 2 + }, + { + "expr": "histogram_quantile(0.95, sum(irate(istio_request_bytes_bucket{reporter=\"destination\", connection_security_policy=\"mutual_tls\", destination_workload=~\"$workload\", destination_workload_namespace=~\"$namespace\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{source_workload}}.{{source_workload_namespace}} P95 (🔐mTLS)", + "refId": "B", + "step": 2 + }, + { + "expr": "histogram_quantile(0.99, sum(irate(istio_request_bytes_bucket{reporter=\"destination\", connection_security_policy=\"mutual_tls\", destination_workload=~\"$workload\", destination_workload_namespace=~\"$namespace\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{source_workload}}.{{source_workload_namespace}} P99 (🔐mTLS)", + "refId": "C", + "step": 2 + }, + { + "expr": "histogram_quantile(0.50, sum(irate(istio_request_bytes_bucket{reporter=\"destination\", connection_security_policy!=\"mutual_tls\", destination_workload=~\"$workload\", destination_workload_namespace=~\"$namespace\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{source_workload}}.{{source_workload_namespace}} P50", + "refId": "E", + "step": 2 + }, + { + "expr": "histogram_quantile(0.90, sum(irate(istio_request_bytes_bucket{reporter=\"destination\", connection_security_policy!=\"mutual_tls\", destination_workload=~\"$workload\", destination_workload_namespace=~\"$namespace\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{source_workload}}.{{source_workload_namespace}} P90", + "refId": "F", + "step": 2 + }, + { + "expr": "histogram_quantile(0.95, sum(irate(istio_request_bytes_bucket{reporter=\"destination\", connection_security_policy!=\"mutual_tls\", destination_workload=~\"$workload\", destination_workload_namespace=~\"$namespace\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{source_workload}}.{{source_workload_namespace}} P95", + "refId": "G", + "step": 2 + }, + { + "expr": "histogram_quantile(0.99, sum(irate(istio_request_bytes_bucket{reporter=\"destination\", connection_security_policy!=\"mutual_tls\", destination_workload=~\"$workload\", destination_workload_namespace=~\"$namespace\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{source_workload}}.{{source_workload_namespace}} P99", + "refId": "H", + "step": 2 + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Incoming Request Size By Source", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "decbytes", + "label": null, + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ] + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 6, + "w": 8, + "x": 16, + "y": 20 + }, + "id": 68, + "legend": { + "alignAsTable": false, + "avg": false, + "current": false, + "hideEmpty": true, + "max": false, + "min": false, + "rightSide": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "histogram_quantile(0.50, sum(irate(istio_response_bytes_bucket{reporter=\"destination\", connection_security_policy=\"mutual_tls\", destination_workload=~\"$workload\", destination_workload_namespace=~\"$namespace\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{source_workload}}.{{source_workload_namespace}} P50 (🔐mTLS)", + "refId": "D", + "step": 2 + }, + { + "expr": "histogram_quantile(0.90, sum(irate(istio_response_bytes_bucket{reporter=\"destination\", connection_security_policy=\"mutual_tls\", destination_workload=~\"$workload\", destination_workload_namespace=~\"$namespace\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{source_workload}}.{{source_workload_namespace}} P90 (🔐mTLS)", + "refId": "A", + "step": 2 + }, + { + "expr": "histogram_quantile(0.95, sum(irate(istio_response_bytes_bucket{reporter=\"destination\", connection_security_policy=\"mutual_tls\", destination_workload=~\"$workload\", destination_workload_namespace=~\"$namespace\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{source_workload}}.{{source_workload_namespace}} P95 (🔐mTLS)", + "refId": "B", + "step": 2 + }, + { + "expr": "histogram_quantile(0.99, sum(irate(istio_response_bytes_bucket{reporter=\"destination\", connection_security_policy=\"mutual_tls\", destination_workload=~\"$workload\", destination_workload_namespace=~\"$namespace\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{source_workload}}.{{source_workload_namespace}} P99 (🔐mTLS)", + "refId": "C", + "step": 2 + }, + { + "expr": "histogram_quantile(0.50, sum(irate(istio_response_bytes_bucket{reporter=\"destination\", connection_security_policy!=\"mutual_tls\", destination_workload=~\"$workload\", destination_workload_namespace=~\"$namespace\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{source_workload}}.{{source_workload_namespace}} P50", + "refId": "E", + "step": 2 + }, + { + "expr": "histogram_quantile(0.90, sum(irate(istio_response_bytes_bucket{reporter=\"destination\", connection_security_policy!=\"mutual_tls\", destination_workload=~\"$workload\", destination_workload_namespace=~\"$namespace\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{source_workload}}.{{source_workload_namespace}} P90", + "refId": "F", + "step": 2 + }, + { + "expr": "histogram_quantile(0.95, sum(irate(istio_response_bytes_bucket{reporter=\"destination\", connection_security_policy!=\"mutual_tls\", destination_workload=~\"$workload\", destination_workload_namespace=~\"$namespace\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{source_workload}}.{{source_workload_namespace}} P95", + "refId": "G", + "step": 2 + }, + { + "expr": "histogram_quantile(0.99, sum(irate(istio_response_bytes_bucket{reporter=\"destination\", connection_security_policy!=\"mutual_tls\", destination_workload=~\"$workload\", destination_workload_namespace=~\"$namespace\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{source_workload}}.{{source_workload_namespace}} P99", + "refId": "H", + "step": 2 + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Response Size By Source", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "decbytes", + "label": null, + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ] + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 6, + "w": 12, + "x": 0, + "y": 26 + }, + "id": 80, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "round(sum(irate(istio_tcp_received_bytes_total{reporter=\"destination\", connection_security_policy=\"mutual_tls\", destination_workload_namespace=~\"$namespace\", destination_workload=~\"$workload\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace), 0.001)", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ source_workload }}.{{ source_workload_namespace}} (🔐mTLS)", + "refId": "A", + "step": 2 + }, + { + "expr": "round(sum(irate(istio_tcp_received_bytes_total{reporter=\"destination\", connection_security_policy!=\"mutual_tls\", destination_workload_namespace=~\"$namespace\", destination_workload=~\"$workload\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace), 0.001)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{ source_workload }}.{{ source_workload_namespace}}", + "refId": "B", + "step": 2 + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Bytes Received from Incoming TCP Connection", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "Bps", + "label": null, + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ] + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 6, + "w": 12, + "x": 12, + "y": 26 + }, + "id": 82, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "round(sum(irate(istio_tcp_sent_bytes_total{connection_security_policy=\"mutual_tls\", reporter=\"destination\", destination_workload_namespace=~\"$namespace\", destination_workload=~\"$workload\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace), 0.001)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{ source_workload }}.{{ source_workload_namespace}} (🔐mTLS)", + "refId": "A", + "step": 2 + }, + { + "expr": "round(sum(irate(istio_tcp_sent_bytes_total{connection_security_policy!=\"mutual_tls\", reporter=\"destination\", destination_workload_namespace=~\"$namespace\", destination_workload=~\"$workload\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace), 0.001)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{ source_workload }}.{{ source_workload_namespace}}", + "refId": "B", + "step": 2 + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Bytes Sent to Incoming TCP Connection", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "Bps", + "label": null, + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ] + }, + { + "content": "
\nOUTBOUND SERVICES\n
", + "gridPos": { + "h": 3, + "w": 24, + "x": 0, + "y": 32 + }, + "id": 69, + "links": [], + "mode": "html", + "title": "", + "transparent": true, + "type": "text" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 0, + "gridPos": { + "h": 6, + "w": 12, + "x": 0, + "y": 35 + }, + "id": 70, + "legend": { + "avg": false, + "current": false, + "hideEmpty": true, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null as zero", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "round(sum(irate(istio_requests_total{connection_security_policy=\"mutual_tls\", source_workload_namespace=~\"$namespace\", source_workload=~\"$workload\", reporter=\"source\", destination_service=~\"$dstsvc\"}[5m])) by (destination_service, response_code), 0.001)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{ destination_service }} : {{ response_code }} (🔐mTLS)", + "refId": "B", + "step": 2 + }, + { + "expr": "round(sum(irate(istio_requests_total{connection_security_policy!=\"mutual_tls\", source_workload_namespace=~\"$namespace\", source_workload=~\"$workload\", reporter=\"source\", destination_service=~\"$dstsvc\"}[5m])) by (destination_service, response_code), 0.001)", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_service }} : {{ response_code }}", + "refId": "A", + "step": 2 + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Outgoing Requests by Destination And Response Code", + "tooltip": { + "shared": false, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [ + "total" + ] + }, + "yaxes": [ + { + "format": "ops", + "label": null, + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ] + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 6, + "w": 12, + "x": 12, + "y": 35 + }, + "id": 71, + "legend": { + "avg": false, + "current": false, + "hideEmpty": true, + "hideZero": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(irate(istio_requests_total{reporter=\"source\", connection_security_policy=\"mutual_tls\", source_workload_namespace=~\"$namespace\", source_workload=~\"$workload\",response_code!~\"5.*\", destination_service=~\"$dstsvc\"}[5m])) by (destination_service) / sum(irate(istio_requests_total{reporter=\"source\", connection_security_policy=\"mutual_tls\", source_workload_namespace=~\"$namespace\", source_workload=~\"$workload\", destination_service=~\"$dstsvc\"}[5m])) by (destination_service)", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_service }} (🔐mTLS)", + "refId": "A", + "step": 2 + }, + { + "expr": "sum(irate(istio_requests_total{reporter=\"source\", connection_security_policy!=\"mutual_tls\", source_workload_namespace=~\"$namespace\", source_workload=~\"$workload\",response_code!~\"5.*\", destination_service=~\"$dstsvc\"}[5m])) by (destination_service) / sum(irate(istio_requests_total{reporter=\"source\", connection_security_policy!=\"mutual_tls\", source_workload_namespace=~\"$namespace\", source_workload=~\"$workload\", destination_service=~\"$dstsvc\"}[5m])) by (destination_service)", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{destination_service }}", + "refId": "B", + "step": 2 + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Outgoing Success Rate (non-5xx responses) By Destination", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "percentunit", + "label": null, + "logBase": 1, + "max": "1.01", + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ] + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "description": "", + "fill": 1, + "gridPos": { + "h": 6, + "w": 8, + "x": 0, + "y": 41 + }, + "id": 72, + "legend": { + "alignAsTable": false, + "avg": false, + "current": false, + "hideEmpty": true, + "hideZero": false, + "max": false, + "min": false, + "rightSide": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "(histogram_quantile(0.50, sum(irate(istio_request_duration_milliseconds_bucket{reporter=\"source\", connection_security_policy=\"mutual_tls\", source_workload=~\"$workload\", source_workload_namespace=~\"$namespace\", destination_service=~\"$dstsvc\"}[1m])) by (destination_service, le)) / 1000) or histogram_quantile(0.50, sum(irate(istio_request_duration_seconds_bucket{reporter=\"source\", connection_security_policy=\"mutual_tls\", source_workload=~\"$workload\", source_workload_namespace=~\"$namespace\", destination_service=~\"$dstsvc\"}[1m])) by (destination_service, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_service }} P50 (🔐mTLS)", + "refId": "D", + "step": 2 + }, + { + "expr": "(histogram_quantile(0.90, sum(irate(istio_request_duration_milliseconds_bucket{reporter=\"source\", connection_security_policy=\"mutual_tls\", source_workload=~\"$workload\", source_workload_namespace=~\"$namespace\", destination_service=~\"$dstsvc\"}[1m])) by (destination_service, le)) / 1000) or histogram_quantile(0.90, sum(irate(istio_request_duration_seconds_bucket{reporter=\"source\", connection_security_policy=\"mutual_tls\", source_workload=~\"$workload\", source_workload_namespace=~\"$namespace\", destination_service=~\"$dstsvc\"}[1m])) by (destination_service, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_service }} P90 (🔐mTLS)", + "refId": "A", + "step": 2 + }, + { + "expr": "(histogram_quantile(0.95, sum(irate(istio_request_duration_milliseconds_bucket{reporter=\"source\", connection_security_policy=\"mutual_tls\", source_workload=~\"$workload\", source_workload_namespace=~\"$namespace\", destination_service=~\"$dstsvc\"}[1m])) by (destination_service, le)) / 1000) or histogram_quantile(0.95, sum(irate(istio_request_duration_seconds_bucket{reporter=\"source\", connection_security_policy=\"mutual_tls\", source_workload=~\"$workload\", source_workload_namespace=~\"$namespace\", destination_service=~\"$dstsvc\"}[1m])) by (destination_service, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_service }} P95 (🔐mTLS)", + "refId": "B", + "step": 2 + }, + { + "expr": "(histogram_quantile(0.99, sum(irate(istio_request_duration_milliseconds_bucket{reporter=\"source\", connection_security_policy=\"mutual_tls\", source_workload=~\"$workload\", source_workload_namespace=~\"$namespace\", destination_service=~\"$dstsvc\"}[1m])) by (destination_service, le)) / 1000) or histogram_quantile(0.99, sum(irate(istio_request_duration_seconds_bucket{reporter=\"source\", connection_security_policy=\"mutual_tls\", source_workload=~\"$workload\", source_workload_namespace=~\"$namespace\", destination_service=~\"$dstsvc\"}[1m])) by (destination_service, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_service }} P99 (🔐mTLS)", + "refId": "C", + "step": 2 + }, + { + "expr": "(histogram_quantile(0.50, sum(irate(istio_request_duration_milliseconds_bucket{reporter=\"source\", connection_security_policy!=\"mutual_tls\", source_workload=~\"$workload\", source_workload_namespace=~\"$namespace\", destination_service=~\"$dstsvc\"}[1m])) by (destination_service, le)) / 1000) or histogram_quantile(0.50, sum(irate(istio_request_duration_seconds_bucket{reporter=\"source\", connection_security_policy!=\"mutual_tls\", source_workload=~\"$workload\", source_workload_namespace=~\"$namespace\", destination_service=~\"$dstsvc\"}[1m])) by (destination_service, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_service }} P50", + "refId": "E", + "step": 2 + }, + { + "expr": "(histogram_quantile(0.90, sum(irate(istio_request_duration_milliseconds_bucket{reporter=\"source\", connection_security_policy!=\"mutual_tls\", source_workload=~\"$workload\", source_workload_namespace=~\"$namespace\", destination_service=~\"$dstsvc\"}[1m])) by (destination_service, le)) / 1000) or histogram_quantile(0.90, sum(irate(istio_request_duration_seconds_bucket{reporter=\"source\", connection_security_policy!=\"mutual_tls\", source_workload=~\"$workload\", source_workload_namespace=~\"$namespace\", destination_service=~\"$dstsvc\"}[1m])) by (destination_service, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_service }} P90", + "refId": "F", + "step": 2 + }, + { + "expr": "(histogram_quantile(0.95, sum(irate(istio_request_duration_milliseconds_bucket{reporter=\"source\", connection_security_policy!=\"mutual_tls\", source_workload=~\"$workload\", source_workload_namespace=~\"$namespace\", destination_service=~\"$dstsvc\"}[1m])) by (destination_service, le)) / 1000) or histogram_quantile(0.95, sum(irate(istio_request_duration_seconds_bucket{reporter=\"source\", connection_security_policy!=\"mutual_tls\", source_workload=~\"$workload\", source_workload_namespace=~\"$namespace\", destination_service=~\"$dstsvc\"}[1m])) by (destination_service, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_service }} P95", + "refId": "G", + "step": 2 + }, + { + "expr": "(histogram_quantile(0.99, sum(irate(istio_request_duration_milliseconds_bucket{reporter=\"source\", connection_security_policy!=\"mutual_tls\", source_workload=~\"$workload\", source_workload_namespace=~\"$namespace\", destination_service=~\"$dstsvc\"}[1m])) by (destination_service, le)) / 1000) or histogram_quantile(0.99, sum(irate(istio_request_duration_seconds_bucket{reporter=\"source\", connection_security_policy!=\"mutual_tls\", source_workload=~\"$workload\", source_workload_namespace=~\"$namespace\", destination_service=~\"$dstsvc\"}[1m])) by (destination_service, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_service }} P99", + "refId": "H", + "step": 2 + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Outgoing Request Duration by Destination", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "s", + "label": null, + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ] + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 6, + "w": 8, + "x": 8, + "y": 41 + }, + "id": 73, + "legend": { + "alignAsTable": false, + "avg": false, + "current": false, + "hideEmpty": true, + "max": false, + "min": false, + "rightSide": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "histogram_quantile(0.50, sum(irate(istio_request_bytes_bucket{reporter=\"source\", connection_security_policy=\"mutual_tls\", source_workload=~\"$workload\", source_workload_namespace=~\"$namespace\", destination_service=~\"$dstsvc\"}[1m])) by (destination_service, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_service }} P50 (🔐mTLS)", + "refId": "D", + "step": 2 + }, + { + "expr": "histogram_quantile(0.90, sum(irate(istio_request_bytes_bucket{reporter=\"source\", connection_security_policy=\"mutual_tls\", source_workload=~\"$workload\", source_workload_namespace=~\"$namespace\", destination_service=~\"$dstsvc\"}[1m])) by (destination_service, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_service }} P90 (🔐mTLS)", + "refId": "A", + "step": 2 + }, + { + "expr": "histogram_quantile(0.95, sum(irate(istio_request_bytes_bucket{reporter=\"source\", connection_security_policy=\"mutual_tls\", source_workload=~\"$workload\", source_workload_namespace=~\"$namespace\", destination_service=~\"$dstsvc\"}[1m])) by (destination_service, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_service }} P95 (🔐mTLS)", + "refId": "B", + "step": 2 + }, + { + "expr": "histogram_quantile(0.99, sum(irate(istio_request_bytes_bucket{reporter=\"source\", connection_security_policy=\"mutual_tls\", source_workload=~\"$workload\", source_workload_namespace=~\"$namespace\", destination_service=~\"$dstsvc\"}[1m])) by (destination_service, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_service }} P99 (🔐mTLS)", + "refId": "C", + "step": 2 + }, + { + "expr": "histogram_quantile(0.50, sum(irate(istio_request_bytes_bucket{reporter=\"source\", connection_security_policy!=\"mutual_tls\", source_workload=~\"$workload\", source_workload_namespace=~\"$namespace\", destination_service=~\"$dstsvc\"}[1m])) by (destination_service, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_service }} P50", + "refId": "E", + "step": 2 + }, + { + "expr": "histogram_quantile(0.90, sum(irate(istio_request_bytes_bucket{reporter=\"source\", connection_security_policy!=\"mutual_tls\", source_workload=~\"$workload\", source_workload_namespace=~\"$namespace\", destination_service=~\"$dstsvc\"}[1m])) by (destination_service, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_service }} P90", + "refId": "F", + "step": 2 + }, + { + "expr": "histogram_quantile(0.95, sum(irate(istio_request_bytes_bucket{reporter=\"source\", connection_security_policy!=\"mutual_tls\", source_workload=~\"$workload\", source_workload_namespace=~\"$namespace\", destination_service=~\"$dstsvc\"}[1m])) by (destination_service, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_service }} P95", + "refId": "G", + "step": 2 + }, + { + "expr": "histogram_quantile(0.99, sum(irate(istio_request_bytes_bucket{reporter=\"source\", connection_security_policy!=\"mutual_tls\", source_workload=~\"$workload\", source_workload_namespace=~\"$namespace\", destination_service=~\"$dstsvc\"}[1m])) by (destination_service, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_service }} P99", + "refId": "H", + "step": 2 + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Outgoing Request Size By Destination", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "decbytes", + "label": null, + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ] + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 6, + "w": 8, + "x": 16, + "y": 41 + }, + "id": 74, + "legend": { + "alignAsTable": false, + "avg": false, + "current": false, + "hideEmpty": true, + "max": false, + "min": false, + "rightSide": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "histogram_quantile(0.50, sum(irate(istio_response_bytes_bucket{reporter=\"source\", connection_security_policy=\"mutual_tls\", source_workload=~\"$workload\", source_workload_namespace=~\"$namespace\", destination_service=~\"$dstsvc\"}[1m])) by (destination_service, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_service }} P50 (🔐mTLS)", + "refId": "D", + "step": 2 + }, + { + "expr": "histogram_quantile(0.90, sum(irate(istio_response_bytes_bucket{reporter=\"source\", connection_security_policy=\"mutual_tls\", source_workload=~\"$workload\", source_workload_namespace=~\"$namespace\", destination_service=~\"$dstsvc\"}[1m])) by (destination_service, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_service }} P90 (🔐mTLS)", + "refId": "A", + "step": 2 + }, + { + "expr": "histogram_quantile(0.95, sum(irate(istio_response_bytes_bucket{reporter=\"source\", connection_security_policy=\"mutual_tls\", source_workload=~\"$workload\", source_workload_namespace=~\"$namespace\", destination_service=~\"$dstsvc\"}[1m])) by (destination_service, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_service }} P95 (🔐mTLS)", + "refId": "B", + "step": 2 + }, + { + "expr": "histogram_quantile(0.99, sum(irate(istio_response_bytes_bucket{reporter=\"source\", connection_security_policy=\"mutual_tls\", source_workload=~\"$workload\", source_workload_namespace=~\"$namespace\", destination_service=~\"$dstsvc\"}[1m])) by (destination_service, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_service }} P99 (🔐mTLS)", + "refId": "C", + "step": 2 + }, + { + "expr": "histogram_quantile(0.50, sum(irate(istio_response_bytes_bucket{reporter=\"source\", connection_security_policy!=\"mutual_tls\", source_workload=~\"$workload\", source_workload_namespace=~\"$namespace\", destination_service=~\"$dstsvc\"}[1m])) by (destination_service, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_service }} P50", + "refId": "E", + "step": 2 + }, + { + "expr": "histogram_quantile(0.90, sum(irate(istio_response_bytes_bucket{reporter=\"source\", connection_security_policy!=\"mutual_tls\", source_workload=~\"$workload\", source_workload_namespace=~\"$namespace\", destination_service=~\"$dstsvc\"}[1m])) by (destination_service, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_service }} P90", + "refId": "F", + "step": 2 + }, + { + "expr": "histogram_quantile(0.95, sum(irate(istio_response_bytes_bucket{reporter=\"source\", connection_security_policy!=\"mutual_tls\", source_workload=~\"$workload\", source_workload_namespace=~\"$namespace\", destination_service=~\"$dstsvc\"}[1m])) by (destination_service, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_service }} P95", + "refId": "G", + "step": 2 + }, + { + "expr": "histogram_quantile(0.99, sum(irate(istio_response_bytes_bucket{reporter=\"source\", connection_security_policy!=\"mutual_tls\", source_workload=~\"$workload\", source_workload_namespace=~\"$namespace\", destination_service=~\"$dstsvc\"}[1m])) by (destination_service, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_service }} P99", + "refId": "H", + "step": 2 + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Response Size By Destination", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "decbytes", + "label": null, + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ] + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 6, + "w": 12, + "x": 0, + "y": 47 + }, + "id": 76, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "round(sum(irate(istio_tcp_sent_bytes_total{connection_security_policy=\"mutual_tls\", reporter=\"source\", source_workload_namespace=~\"$namespace\", source_workload=~\"$workload\", destination_service=~\"$dstsvc\"}[1m])) by (destination_service), 0.001)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{ destination_service }} (🔐mTLS)", + "refId": "A", + "step": 2 + }, + { + "expr": "round(sum(irate(istio_tcp_sent_bytes_total{connection_security_policy!=\"mutual_tls\", reporter=\"source\", source_workload_namespace=~\"$namespace\", source_workload=~\"$workload\", destination_service=~\"$dstsvc\"}[1m])) by (destination_service), 0.001)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{ destination_service }}", + "refId": "B", + "step": 2 + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Bytes Sent on Outgoing TCP Connection", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "Bps", + "label": null, + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ] + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 6, + "w": 12, + "x": 12, + "y": 47 + }, + "id": 78, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "round(sum(irate(istio_tcp_received_bytes_total{reporter=\"source\", connection_security_policy=\"mutual_tls\", source_workload_namespace=~\"$namespace\", source_workload=~\"$workload\", destination_service=~\"$dstsvc\"}[1m])) by (destination_service), 0.001)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{ destination_service }} (🔐mTLS)", + "refId": "A", + "step": 2 + }, + { + "expr": "round(sum(irate(istio_tcp_received_bytes_total{reporter=\"source\", connection_security_policy!=\"mutual_tls\", source_workload_namespace=~\"$namespace\", source_workload=~\"$workload\", destination_service=~\"$dstsvc\"}[1m])) by (destination_service), 0.001)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{ destination_service }}", + "refId": "B", + "step": 2 + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Bytes Received from Outgoing TCP Connection", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "Bps", + "label": null, + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ] + } + ], + "refresh": "10s", + "schemaVersion": 16, + "style": "dark", + "tags": [], + "templating": { + "list": [ + { + "allValue": null, + "current": {}, + "datasource": "Prometheus", + "hide": 0, + "includeAll": false, + "label": "Namespace", + "multi": false, + "name": "namespace", + "options": [], + "query": "query_result(sum(istio_requests_total) by (destination_workload_namespace) or sum(istio_tcp_sent_bytes_total) by (destination_workload_namespace))", + "refresh": 1, + "regex": "/.*_namespace=\"([^\"]*).*/", + "sort": 0, + "tagValuesQuery": "", + "tags": [], + "tagsQuery": "", + "type": "query", + "useTags": false + }, + { + "allValue": null, + "current": {}, + "datasource": "Prometheus", + "hide": 0, + "includeAll": false, + "label": "Workload", + "multi": false, + "name": "workload", + "options": [], + "query": "query_result((sum(istio_requests_total{destination_workload_namespace=~\"$namespace\"}) by (destination_workload) or sum(istio_requests_total{source_workload_namespace=~\"$namespace\"}) by (source_workload)) or (sum(istio_tcp_sent_bytes_total{destination_workload_namespace=~\"$namespace\"}) by (destination_workload) or sum(istio_tcp_sent_bytes_total{source_workload_namespace=~\"$namespace\"}) by (source_workload)))", + "refresh": 1, + "regex": "/.*workload=\"([^\"]*).*/", + "sort": 1, + "tagValuesQuery": "", + "tags": [], + "tagsQuery": "", + "type": "query", + "useTags": false + }, + { + "allValue": null, + "current": {}, + "datasource": "Prometheus", + "hide": 0, + "includeAll": true, + "label": "Inbound Workload Namespace", + "multi": true, + "name": "srcns", + "options": [], + "query": "query_result( sum(istio_requests_total{reporter=\"destination\", destination_workload=\"$workload\", destination_workload_namespace=~\"$namespace\"}) by (source_workload_namespace) or sum(istio_tcp_sent_bytes_total{reporter=\"destination\", destination_workload=\"$workload\", destination_workload_namespace=~\"$namespace\"}) by (source_workload_namespace))", + "refresh": 1, + "regex": "/.*namespace=\"([^\"]*).*/", + "sort": 2, + "tagValuesQuery": "", + "tags": [], + "tagsQuery": "", + "type": "query", + "useTags": false + }, + { + "allValue": null, + "current": {}, + "datasource": "Prometheus", + "hide": 0, + "includeAll": true, + "label": "Inbound Workload", + "multi": true, + "name": "srcwl", + "options": [], + "query": "query_result( sum(istio_requests_total{reporter=\"destination\", destination_workload=\"$workload\", destination_workload_namespace=~\"$namespace\", source_workload_namespace=~\"$srcns\"}) by (source_workload) or sum(istio_tcp_sent_bytes_total{reporter=\"destination\", destination_workload=\"$workload\", destination_workload_namespace=~\"$namespace\", source_workload_namespace=~\"$srcns\"}) by (source_workload))", + "refresh": 1, + "regex": "/.*workload=\"([^\"]*).*/", + "sort": 3, + "tagValuesQuery": "", + "tags": [], + "tagsQuery": "", + "type": "query", + "useTags": false + }, + { + "allValue": null, + "current": {}, + "datasource": "Prometheus", + "hide": 0, + "includeAll": true, + "label": "Destination Service", + "multi": true, + "name": "dstsvc", + "options": [], + "query": "query_result( sum(istio_requests_total{reporter=\"source\", source_workload=~\"$workload\", source_workload_namespace=~\"$namespace\"}) by (destination_service) or sum(istio_tcp_sent_bytes_total{reporter=\"source\", source_workload=~\"$workload\", source_workload_namespace=~\"$namespace\"}) by (destination_service))", + "refresh": 1, + "regex": "/.*destination_service=\"([^\"]*).*/", + "sort": 4, + "tagValuesQuery": "", + "tags": [], + "tagsQuery": "", + "type": "query", + "useTags": false + } + ] + }, + "time": { + "from": "now-5m", + "to": "now" + }, + "timepicker": { + "refresh_intervals": [ + "5s", + "10s", + "30s", + "1m", + "5m", + "15m", + "30m", + "1h", + "2h", + "1d" + ], + "time_options": [ + "5m", + "15m", + "1h", + "6h", + "12h", + "24h", + "2d", + "7d", + "30d" + ] + }, + "timezone": "", + "title": "Istio Workload Dashboard", + "uid": "UbsSZTDik", + "version": 1 +} diff --git a/istio-1.5.0/install/kubernetes/helm/istio/charts/grafana/dashboards/mixer-dashboard.json b/istio-1.5.0/install/kubernetes/helm/istio/charts/grafana/dashboards/mixer-dashboard.json new file mode 100644 index 0000000..6da44ec --- /dev/null +++ b/istio-1.5.0/install/kubernetes/helm/istio/charts/grafana/dashboards/mixer-dashboard.json @@ -0,0 +1,1808 @@ +{ + "__inputs": [ + { + "name": "DS_PROMETHEUS", + "label": "Prometheus", + "description": "", + "type": "datasource", + "pluginId": "prometheus", + "pluginName": "Prometheus" + } + ], + "__requires": [ + { + "type": "grafana", + "id": "grafana", + "name": "Grafana", + "version": "5.2.3" + }, + { + "type": "panel", + "id": "graph", + "name": "Graph", + "version": "5.0.0" + }, + { + "type": "datasource", + "id": "prometheus", + "name": "Prometheus", + "version": "5.0.0" + }, + { + "type": "panel", + "id": "text", + "name": "Text", + "version": "5.0.0" + } + ], + "annotations": { + "list": [ + { + "builtIn": 1, + "datasource": "-- Grafana --", + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "limit": 100, + "name": "Annotations & Alerts", + "showIn": 0, + "type": "dashboard" + } + ] + }, + "editable": false, + "gnetId": null, + "graphTooltip": 1, + "id": null, + "iteration": 1543881232533, + "links": [], + "panels": [ + { + "content": "

Deployed Versions

", + "gridPos": { + "h": 3, + "w": 24, + "x": 0, + "y": 0 + }, + "height": "40", + "id": 62, + "links": [], + "mode": "html", + "title": "", + "transparent": true, + "type": "text" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 5, + "w": 24, + "x": 0, + "y": 3 + }, + "id": 64, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(istio_build{component=\"mixer\"}) by (tag)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{ tag }}", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Mixer Versions", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "content": "

Resource Usage

", + "gridPos": { + "h": 3, + "w": 24, + "x": 0, + "y": 8 + }, + "height": "40", + "id": 29, + "links": [], + "mode": "html", + "title": "", + "transparent": true, + "type": "text" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 7, + "w": 6, + "x": 0, + "y": 11 + }, + "id": 5, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(process_virtual_memory_bytes{job=~\"istio-telemetry|istio-policy\"}) by (job)", + "format": "time_series", + "instant": false, + "intervalFactor": 2, + "legendFormat": "Virtual Memory ({{ job }})", + "refId": "I" + }, + { + "expr": "sum(process_resident_memory_bytes{job=~\"istio-telemetry|istio-policy\"}) by (job)", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "Resident Memory ({{ job }})", + "refId": "H" + }, + { + "expr": "sum(go_memstats_heap_sys_bytes{job=~\"istio-telemetry|istio-policy\"}) by (job)", + "format": "time_series", + "hide": true, + "intervalFactor": 2, + "legendFormat": "heap sys ({{ job }})", + "refId": "A" + }, + { + "expr": "sum(go_memstats_heap_alloc_bytes{job=~\"istio-telemetry|istio-policy\"}) by (job)", + "format": "time_series", + "hide": true, + "intervalFactor": 2, + "legendFormat": "heap alloc ({{ job }})", + "refId": "D" + }, + { + "expr": "sum(go_memstats_alloc_bytes{job=~\"istio-telemetry|istio-policy\"}) by (job)", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "Alloc ({{ job }})", + "refId": "F" + }, + { + "expr": "sum(go_memstats_heap_inuse_bytes{job=~\"istio-telemetry|istio-policy\"}) by (job)", + "format": "time_series", + "hide": false, + "intervalFactor": 2, + "legendFormat": "Heap in-use ({{ job }})", + "refId": "E" + }, + { + "expr": "sum(go_memstats_stack_inuse_bytes{job=~\"istio-telemetry|istio-policy\"}) by (job)", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "Stack in-use ({{ job }})", + "refId": "G" + }, + { + "expr": "sum(label_replace(container_memory_usage_bytes{job=\"kubernetes-cadvisor\", container=~\"mixer|istio-proxy\", pod=~\"istio-telemetry-.*|istio-policy-.*\"}, \"service\", \"$1\" , \"pod\", \"(istio-telemetry|istio-policy)-.*\")) by (service)", + "format": "time_series", + "hide": false, + "intervalFactor": 2, + "legendFormat": "{{ service }} total (k8s)", + "refId": "C" + }, + { + "expr": "sum(label_replace(container_memory_usage_bytes{job=\"kubernetes-cadvisor\", container=~\"mixer|istio-proxy\", pod=~\"istio-telemetry-.*|istio-policy-.*\"}, \"service\", \"$1\" , \"pod\", \"(istio-telemetry|istio-policy)-.*\")) by (container, service)", + "format": "time_series", + "hide": false, + "intervalFactor": 2, + "legendFormat": "{{ service }} - {{ container }} (k8s)", + "refId": "B" + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Memory", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "bytes", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 7, + "w": 6, + "x": 6, + "y": 11 + }, + "id": 6, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "label_replace(sum(rate(container_cpu_usage_seconds_total{job=\"kubernetes-cadvisor\",container=~\"mixer|istio-proxy\", pod=~\"istio-telemetry-.*|istio-policy-.*\"}[1m])) by (pod), \"service\", \"$1\" , \"pod\", \"(istio-telemetry|istio-policy)-.*\")", + "format": "time_series", + "hide": false, + "intervalFactor": 2, + "legendFormat": "{{ service }} total (k8s)", + "refId": "A" + }, + { + "expr": "label_replace(sum(rate(container_cpu_usage_seconds_total{job=\"kubernetes-cadvisor\",container=~\"mixer|istio-proxy\", pod=~\"istio-telemetry-.*|istio-policy-.*\"}[1m])) by (container, pod), \"service\", \"$1\" , \"pod\", \"(istio-telemetry|istio-policy)-.*\")", + "format": "time_series", + "hide": false, + "intervalFactor": 2, + "legendFormat": "{{ service }} - {{ container }} (k8s)", + "refId": "B" + }, + { + "expr": "sum(irate(process_cpu_seconds_total{job=~\"istio-telemetry|istio-policy\"}[1m])) by (job)", + "format": "time_series", + "hide": false, + "intervalFactor": 2, + "legendFormat": "{{ job }} (self-reported)", + "refId": "C" + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "CPU", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 7, + "w": 6, + "x": 12, + "y": 11 + }, + "id": 7, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(process_open_fds{job=~\"istio-telemetry|istio-policy\"}) by (job)", + "format": "time_series", + "hide": true, + "instant": false, + "interval": "", + "intervalFactor": 2, + "legendFormat": "Open FDs ({{ job }})", + "refId": "A" + }, + { + "expr": "sum(label_replace(container_fs_usage_bytes{job=\"kubernetes-cadvisor\", container=~\"mixer|istio-proxy\", pod=~\"istio-telemetry-.*|istio-policy-.*\"}, \"service\", \"$1\" , \"pod\", \"(istio-telemetry|istio-policy)-.*\")) by (container, service)", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "{{ service }} - {{ container }}", + "refId": "B" + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Disk", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "bytes", + "label": "", + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "decimals": null, + "format": "none", + "label": "", + "logBase": 1024, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 7, + "w": 6, + "x": 18, + "y": 11 + }, + "id": 4, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": false, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(go_goroutines{job=~\"istio-telemetry|istio-policy\"}) by (job)", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "Number of Goroutines ({{ job }})", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Goroutines", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": "", + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "content": "

Mixer Overview

", + "gridPos": { + "h": 3, + "w": 24, + "x": 0, + "y": 18 + }, + "height": "40px", + "id": 30, + "links": [], + "mode": "html", + "title": "", + "transparent": true, + "type": "text" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 6, + "w": 6, + "x": 0, + "y": 21 + }, + "id": 9, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(rate(grpc_io_server_completed_rpcs[1m]))", + "format": "time_series", + "hide": false, + "intervalFactor": 2, + "legendFormat": "mixer (Total)", + "refId": "B" + }, + { + "expr": "sum(rate(grpc_io_server_completed_rpcs[1m])) by (grpc_server_method)", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "mixer ({{ grpc_server_method }})", + "refId": "C" + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Incoming Requests", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "ops", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 6, + "w": 6, + "x": 6, + "y": 21 + }, + "id": 8, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [ + { + "alias": "{}", + "yaxis": 1 + } + ], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "histogram_quantile(0.5, sum(rate(grpc_io_server_server_latency_bucket{}[1m])) by (grpc_server_method, le))", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "{{ grpc_server_method }} 0.5", + "refId": "B" + }, + { + "expr": "histogram_quantile(0.9, sum(rate(grpc_io_server_server_latency_bucket{}[1m])) by (grpc_server_method, le))", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "{{ grpc_server_method }} 0.9", + "refId": "C" + }, + { + "expr": "histogram_quantile(0.99, sum(rate(grpc_io_server_server_latency_bucket{}[1m])) by (grpc_server_method, le))", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "{{ grpc_server_method }} 0.99", + "refId": "D" + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Response Durations", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "ms", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 6, + "w": 6, + "x": 12, + "y": 21 + }, + "id": 11, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(rate(grpc_server_handled_total{grpc_code=~\"Unknown|Unimplemented|Internal|DataLoss\"}[1m])) by (grpc_method)", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "Mixer {{ grpc_method }}", + "refId": "B" + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Server Error Rate (5xx responses)", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 6, + "w": 6, + "x": 18, + "y": 21 + }, + "id": 12, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(irate(grpc_server_handled_total{grpc_code!=\"OK\",grpc_service=~\".*Mixer\"}[1m])) by (grpc_method)", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "Mixer {{ grpc_method }}", + "refId": "B" + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Non-successes (4xxs)", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "content": "

Adapters and Config

", + "gridPos": { + "h": 3, + "w": 24, + "x": 0, + "y": 27 + }, + "id": 28, + "links": [], + "mode": "html", + "title": "", + "transparent": true, + "type": "text" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 7, + "w": 12, + "x": 0, + "y": 30 + }, + "id": 13, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(irate(mixer_runtime_dispatches_total{adapter=~\"$adapter\"}[1m])) by (adapter)", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "{{ adapter }}", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Adapter Dispatch Count", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 7, + "w": 12, + "x": 12, + "y": 30 + }, + "id": 14, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "histogram_quantile(0.5, sum(irate(mixer_runtime_dispatch_duration_seconds_bucket{adapter=~\"$adapter\"}[1m])) by (adapter, le))", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "{{ adapter }} - p50", + "refId": "A" + }, + { + "expr": "histogram_quantile(0.9, sum(irate(mixer_runtime_dispatch_duration_seconds_bucket{adapter=~\"$adapter\"}[1m])) by (adapter, le))", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "{{ adapter }} - p90 ", + "refId": "B" + }, + { + "expr": "histogram_quantile(0.99, sum(irate(mixer_runtime_dispatch_duration_seconds_bucket{adapter=~\"$adapter\"}[1m])) by (adapter, le))", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "{{ adapter }} - p99", + "refId": "C" + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Adapter Dispatch Duration", + "tooltip": { + "shared": true, + "sort": 1, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "s", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 7, + "w": 6, + "x": 0, + "y": 37 + }, + "id": 60, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "scalar(topk(1, max(mixer_config_rule_config_count) by (configID)))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Rules", + "refId": "A" + }, + { + "expr": "scalar(topk(1, max(mixer_config_rule_config_error_count) by (configID)))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Config Errors", + "refId": "B" + }, + { + "expr": "scalar(topk(1, max(mixer_config_rule_config_match_error_count) by (configID)))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Match Errors", + "refId": "C" + }, + { + "expr": "scalar(topk(1, max(mixer_config_unsatisfied_action_handler_count) by (configID)))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Unsatisfied Actions", + "refId": "D" + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Rules", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 7, + "w": 6, + "x": 6, + "y": 37 + }, + "id": 56, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "scalar(topk(1, max(mixer_config_instance_config_count) by (configID)))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Instances", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Instances in Latest Config", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 7, + "w": 6, + "x": 12, + "y": 37 + }, + "id": 54, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "scalar(topk(1, max(mixer_config_handler_config_count) by (configID)))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Handlers", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Handlers in Latest Config", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 7, + "w": 6, + "x": 18, + "y": 37 + }, + "id": 58, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "scalar(topk(1, max(mixer_config_attribute_count) by (configID)))", + "format": "time_series", + "instant": false, + "intervalFactor": 1, + "legendFormat": "Attributes", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Attributes in Latest Config", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "content": "

Individual Adapters

", + "gridPos": { + "h": 3, + "w": 24, + "x": 0, + "y": 44 + }, + "id": 23, + "links": [], + "mode": "html", + "title": "", + "transparent": true, + "type": "text" + }, + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 47 + }, + "id": 46, + "panels": [], + "repeat": "adapter", + "title": "$adapter Adapter", + "type": "row" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 7, + "w": 12, + "x": 0, + "y": 48 + }, + "id": 17, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "label_replace(irate(mixer_runtime_dispatches_total{adapter=~\"$adapter\"}[1m]),\"handler\", \"$1 ($3)\", \"handler\", \"(.*)\\\\.(.*)\\\\.(.*)\")", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "{{ handler }} (error: {{ error }})", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Dispatch Count By Handler", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 7, + "w": 12, + "x": 12, + "y": 48 + }, + "id": 18, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "label_replace(histogram_quantile(0.5, sum(rate(mixer_runtime_dispatch_duration_seconds_bucket{adapter=~\"$adapter\"}[1m])) by (handler, error, le)), \"handler_short\", \"$1 ($3)\", \"handler\", \"(.*)\\\\.(.*)\\\\.(.*)\")", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "p50 - {{ handler_short }} (error: {{ error }})", + "refId": "A" + }, + { + "expr": "label_replace(histogram_quantile(0.9, sum(irate(mixer_runtime_dispatch_duration_seconds_bucket{adapter=~\"$adapter\"}[1m])) by (handler, error, le)), \"handler_short\", \"$1 ($3)\", \"handler\", \"(.*)\\\\.(.*)\\\\.(.*)\")", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "p90 - {{ handler_short }} (error: {{ error }})", + "refId": "D" + }, + { + "expr": "label_replace(histogram_quantile(0.99, sum(irate(mixer_runtime_dispatch_duration_seconds_bucket{adapter=~\"$adapter\"}[1m])) by (handler, error, le)), \"handler_short\", \"$1 ($3)\", \"handler\", \"(.*)\\\\.(.*)\\\\.(.*)\")", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "p99 - {{ handler_short }} (error: {{ error }})", + "refId": "E" + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Dispatch Duration By Handler", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "s", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + } + ], + "refresh": "5s", + "schemaVersion": 16, + "style": "dark", + "tags": [], + "templating": { + "list": [ + { + "allValue": null, + "current": {}, + "datasource": "Prometheus", + "hide": 0, + "includeAll": true, + "label": "Adapter", + "multi": true, + "name": "adapter", + "options": [], + "query": "label_values(adapter)", + "refresh": 2, + "regex": "", + "sort": 1, + "tagValuesQuery": "", + "tags": [], + "tagsQuery": "", + "type": "query", + "useTags": false + } + ] + }, + "time": { + "from": "now-5m", + "to": "now" + }, + "timepicker": { + "refresh_intervals": [ + "5s", + "10s", + "30s", + "1m", + "5m", + "15m", + "30m", + "1h", + "2h", + "1d" + ], + "time_options": [ + "5m", + "15m", + "1h", + "6h", + "12h", + "24h", + "2d", + "7d", + "30d" + ] + }, + "timezone": "", + "title": "Istio Mixer Dashboard", + "version": 4 +} diff --git a/istio-1.5.0/install/kubernetes/helm/istio/charts/grafana/dashboards/pilot-dashboard.json b/istio-1.5.0/install/kubernetes/helm/istio/charts/grafana/dashboards/pilot-dashboard.json new file mode 100644 index 0000000..bdc7e72 --- /dev/null +++ b/istio-1.5.0/install/kubernetes/helm/istio/charts/grafana/dashboards/pilot-dashboard.json @@ -0,0 +1,1591 @@ +{ + "annotations": { + "list": [ + { + "builtIn": 1, + "datasource": "-- Grafana --", + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations & Alerts", + "type": "dashboard" + } + ] + }, + "editable": false, + "gnetId": null, + "graphTooltip": 1, + "id": 11, + "links": [], + "panels": [ + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 0 + }, + "id": 60, + "panels": [], + "title": "Deployed Versions", + "type": "row" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 5, + "w": 24, + "x": 0, + "y": 1 + }, + "id": 56, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(istio_build{component=\"pilot\"}) by (tag)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{ tag }}", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Pilot Versions", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 6 + }, + "id": 62, + "panels": [], + "title": "Resource Usage", + "type": "row" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 7, + "w": 6, + "x": 0, + "y": 7 + }, + "id": 5, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "process_virtual_memory_bytes{job=\"pilot\"}", + "format": "time_series", + "instant": false, + "intervalFactor": 2, + "legendFormat": "Virtual Memory", + "refId": "I", + "step": 2 + }, + { + "expr": "process_resident_memory_bytes{job=\"pilot\"}", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "Resident Memory", + "refId": "H", + "step": 2 + }, + { + "expr": "go_memstats_heap_sys_bytes{job=\"pilot\"}", + "format": "time_series", + "hide": true, + "intervalFactor": 2, + "legendFormat": "heap sys", + "refId": "A" + }, + { + "expr": "go_memstats_heap_alloc_bytes{job=\"pilot\"}", + "format": "time_series", + "hide": true, + "intervalFactor": 2, + "legendFormat": "heap alloc", + "refId": "D" + }, + { + "expr": "go_memstats_alloc_bytes{job=\"pilot\"}", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "Alloc", + "refId": "F", + "step": 2 + }, + { + "expr": "go_memstats_heap_inuse_bytes{job=\"pilot\"}", + "format": "time_series", + "hide": false, + "intervalFactor": 2, + "legendFormat": "Heap in-use", + "refId": "E", + "step": 2 + }, + { + "expr": "go_memstats_stack_inuse_bytes{job=\"pilot\"}", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "Stack in-use", + "refId": "G", + "step": 2 + }, + { + "expr": "container_memory_usage_bytes{job=\"kubernetes-cadvisor\", container=~\"discovery\", pod=~\"istio-pilot-.*\"}", + "format": "time_series", + "hide": false, + "intervalFactor": 2, + "legendFormat": "Discovery (container)", + "refId": "B", + "step": 2 + }, + { + "expr": "container_memory_usage_bytes{job=\"kubernetes-cadvisor\", container=~\"istio-proxy\", pod=~\"istio-pilot-.*\"}", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Sidecar (container)", + "refId": "C" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Memory", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "bytes", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 7, + "w": 6, + "x": 6, + "y": 7 + }, + "id": 6, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(irate(container_cpu_usage_seconds_total{job=\"kubernetes-cadvisor\",container=\"discovery\", pod=~\"istio-pilot-.*\"}[1m]))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Discovery (container)", + "refId": "A" + }, + { + "expr": "irate(process_cpu_seconds_total{job=\"pilot\"}[1m])", + "format": "time_series", + "hide": false, + "intervalFactor": 2, + "legendFormat": "Discovery (process)", + "refId": "C", + "step": 2 + }, + { + "expr": "sum(irate(container_cpu_usage_seconds_total{job=\"kubernetes-cadvisor\",container=\"istio-proxy\", pod=~\"istio-pilot-.*\"}[1m]))", + "format": "time_series", + "hide": false, + "intervalFactor": 2, + "legendFormat": "Sidecar (container)", + "refId": "B", + "step": 2 + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "CPU", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 7, + "w": 6, + "x": 12, + "y": 7 + }, + "id": 7, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "container_fs_usage_bytes{job=\"kubernetes-cadvisor\", container=\"discovery\", pod=~\"istio-pilot-.*\"}", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "Discovery", + "refId": "B", + "step": 2 + }, + { + "expr": "container_fs_usage_bytes{job=\"kubernetes-cadvisor\", container=\"istio-proxy\", pod=~\"istio-pilot-.*\"}", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Sidecar", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Disk", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "bytes", + "label": "", + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "decimals": null, + "format": "none", + "label": "", + "logBase": 1024, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 7, + "w": 6, + "x": 18, + "y": 7 + }, + "id": 4, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": false, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "go_goroutines{job=\"pilot\"}", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "Number of Goroutines", + "refId": "A", + "step": 2 + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Goroutines", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": "", + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 14 + }, + "id": 58, + "panels": [], + "title": "Pilot Push Information", + "type": "row" + }, + { + "aliasColors": {}, + "bars": true, + "dashLength": 10, + "dashes": false, + "description": "Shows the rate of pilot pushes", + "fill": 1, + "gridPos": { + "h": 8, + "w": 8, + "x": 0, + "y": 15 + }, + "id": 622, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": false, + "linewidth": 1, + "links": [], + "nullPointMode": "null as zero", + "paceLength": 10, + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": true, + "steppedLine": false, + "targets": [ + { + "expr": "sum(irate(pilot_xds_pushes{type=\"cds\"}[1m]))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Cluster", + "refId": "C" + }, + { + "expr": "sum(irate(pilot_xds_pushes{type=\"eds\"}[1m]))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Endpoints", + "refId": "D" + }, + { + "expr": "sum(irate(pilot_xds_pushes{type=\"lds\"}[1m]))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Listeners", + "refId": "A" + }, + { + "expr": "sum(irate(pilot_xds_pushes{type=\"rds\"}[1m]))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Routes", + "refId": "E" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Pilot Pushes", + "tooltip": { + "shared": false, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [ + "total" + ] + }, + "yaxes": [ + { + "format": "ops", + "label": null, + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "description": "Captures a variety of pilot errors", + "fill": 1, + "gridPos": { + "h": 8, + "w": 8, + "x": 8, + "y": 15 + }, + "id": 67, + "legend": { + "avg": false, + "current": false, + "hideEmpty": true, + "hideZero": true, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(pilot_xds_cds_reject{job=\"pilot\"}) or (absent(pilot_xds_cds_reject{job=\"pilot\"}) - 1)", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "Rejected CDS Configs", + "refId": "C" + }, + { + "expr": "sum(pilot_xds_eds_reject{job=\"pilot\"}) or (absent(pilot_xds_eds_reject{job=\"pilot\"}) - 1)", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "Rejected EDS Configs", + "refId": "D" + }, + { + "expr": "sum(pilot_xds_rds_reject{job=\"pilot\"}) or (absent(pilot_xds_rds_reject{job=\"pilot\"}) - 1)", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "Rejected RDS Configs", + "refId": "A" + }, + { + "expr": "sum(pilot_xds_lds_reject{job=\"pilot\"}) or (absent(pilot_xds_lds_reject{job=\"pilot\"}) - 1)", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "Rejected LDS Configs", + "refId": "B" + }, + { + "expr": "sum(rate(pilot_xds_write_timeout{job=\"pilot\"}[1m]))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Write Timeouts", + "refId": "F" + }, + { + "expr": "sum(rate(pilot_total_xds_internal_errors{job=\"pilot\"}[1m]))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "Internal Errors", + "refId": "H" + }, + { + "expr": "sum(rate(pilot_total_xds_rejects{job=\"pilot\"}[1m]))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "Config Rejection Rate", + "refId": "E" + }, + { + "expr": "sum(rate(pilot_xds_push_context_errors{job=\"pilot\"}[1m]))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "Push Context Errors", + "refId": "K" + }, + { + "expr": "sum(rate(pilot_xds_pushes{type!~\"lds|cds|rds|eds\"}[1m])) by (type)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Push Errors ({{ type }})", + "refId": "L" + }, + { + "expr": "sum(rate(pilot_xds_push_errors{job=\"pilot\"}[1m])) by (type)", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "Push Errors ({{ type }})", + "refId": "I" + }, + { + "expr": "sum(rate(pilot_xds_push_timeout{job=\"pilot\"}[1m]))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Push Timeouts", + "refId": "G" + }, + { + "expr": "sum(rate(pilot_xds_push_timeout_failures{job=\"pilot\"}[1m]))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Push Timeouts Failures", + "refId": "J" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Pilot Errors", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "description": "Shows the total time it takes to push a config update to a proxy", + "fill": 1, + "gridPos": { + "h": 8, + "w": 8, + "x": 16, + "y": 15 + }, + "id": 624, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "histogram_quantile(0.5, sum(rate(pilot_proxy_convergence_time_bucket[1m])) by (le))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "p50 ", + "refId": "A" + }, + { + "expr": "histogram_quantile(0.9, sum(rate(pilot_proxy_convergence_time_bucket[1m])) by (le))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "p90", + "refId": "B" + }, + { + "expr": "histogram_quantile(0.99, sum(rate(pilot_proxy_convergence_time_bucket[1m])) by (le))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "p99", + "refId": "C" + }, + { + "expr": "histogram_quantile(0.999, sum(rate(pilot_proxy_convergence_time_bucket[1m])) by (le))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "p99.9", + "refId": "D" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Proxy Push Time", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "s", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 8, + "w": 8, + "x": 0, + "y": 23 + }, + "id": 45, + "legend": { + "avg": false, + "current": false, + "hideEmpty": true, + "hideZero": true, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null as zero", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "pilot_conflict_inbound_listener{job=\"pilot\"}", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "Inbound Listeners", + "refId": "B" + }, + { + "expr": "pilot_conflict_outbound_listener_http_over_current_tcp{job=\"pilot\"}", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "Outbound Listeners (http over current tcp)", + "refId": "A" + }, + { + "expr": "pilot_conflict_outbound_listener_tcp_over_current_tcp{job=\"pilot\"}", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "Outbound Listeners (tcp over current tcp)", + "refId": "C" + }, + { + "expr": "pilot_conflict_outbound_listener_tcp_over_current_http{job=\"pilot\"}", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "Outbound Listeners (tcp over current http)", + "refId": "D" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Conflicts", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 8, + "w": 8, + "x": 8, + "y": 23 + }, + "id": 47, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "pilot_virt_services{job=\"pilot\"}", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Virtual Services", + "refId": "A" + }, + { + "expr": "pilot_services{job=\"pilot\"}", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Services", + "refId": "B" + }, + { + "expr": "pilot_xds{job=\"pilot\"}", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Connected Endpoints", + "refId": "E" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "ADS Monitoring", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "columns": [], + "datasource": "Prometheus", + "description": "Clusters in this table do not have any endpoints known to pilot. This could be from referencing subsets that do not have any instances, or pods marked as NotReady", + "fontSize": "100%", + "gridPos": { + "h": 8, + "w": 8, + "x": 16, + "y": 23 + }, + "id": 51, + "links": [], + "pageSize": null, + "scroll": true, + "showHeader": true, + "sort": { + "col": null, + "desc": false + }, + "styles": [ + { + "alias": "Time", + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "pattern": "Time", + "type": "date" + }, + { + "alias": "Clusters", + "colorMode": null, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "decimals": 2, + "pattern": "/.*/", + "thresholds": [], + "type": "number", + "unit": "short" + } + ], + "targets": [ + { + "expr": "sum(pilot_xds_eds_instances{job=\"pilot\", cluster=~\".+\\\\|.+\"}) by (cluster) < 1", + "format": "time_series", + "hide": false, + "instant": true, + "intervalFactor": 1, + "legendFormat": "{{cluster}}", + "refId": "B" + } + ], + "timeFrom": null, + "timeShift": null, + "title": "Clusters with no known endpoints", + "transform": "timeseries_aggregations", + "type": "table" + }, + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 31 + }, + "id": 64, + "panels": [], + "title": "Envoy Information", + "type": "row" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "description": "Shows details about Envoy proxies in the mesh", + "fill": 1, + "gridPos": { + "h": 8, + "w": 8, + "x": 0, + "y": 32 + }, + "id": 40, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(irate(envoy_cluster_upstream_cx_total{cluster_name=\"xds-grpc\"}[1m]))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "XDS Connections", + "refId": "C" + }, + { + "expr": "sum(irate(envoy_cluster_upstream_cx_connect_fail{cluster_name=\"xds-grpc\"}[1m]))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "XDS Connection Failures", + "refId": "A" + }, + { + "expr": "sum(increase(envoy_server_hot_restart_epoch[1m]))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Envoy Restarts", + "refId": "B" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Envoy Details", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "ops", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "ops", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 8, + "w": 8, + "x": 8, + "y": 32 + }, + "id": 41, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(envoy_cluster_upstream_cx_active{cluster_name=\"xds-grpc\"})", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "XDS Active Connections", + "refId": "C", + "step": 2 + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "XDS Active Connections", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "description": "Shows the size of XDS requests and responses", + "fill": 1, + "gridPos": { + "h": 8, + "w": 8, + "x": 16, + "y": 32 + }, + "id": 42, + "legend": { + "avg": false, + "current": false, + "hideEmpty": false, + "hideZero": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "max(rate(envoy_cluster_upstream_cx_rx_bytes_total{cluster_name=\"xds-grpc\"}[1m]))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "XDS Response Bytes Max", + "refId": "D" + }, + { + "expr": "quantile(0.5, rate(envoy_cluster_upstream_cx_rx_bytes_total{cluster_name=\"xds-grpc\"}[1m]))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "XDS Response Bytes Average", + "refId": "B" + }, + { + "expr": "max(rate(envoy_cluster_upstream_cx_tx_bytes_total{cluster_name=\"xds-grpc\"}[1m]))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "XDS Request Bytes Max", + "refId": "A" + }, + { + "expr": "quantile(.5, rate(envoy_cluster_upstream_cx_tx_bytes_total{cluster_name=\"xds-grpc\"}[1m]))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "XDS Request Bytes Average", + "refId": "C" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "XDS Requests Size", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "Bps", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "ops", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + } + ], + "refresh": "5s", + "schemaVersion": 18, + "style": "dark", + "tags": [], + "templating": { + "list": [] + }, + "time": { + "from": "now-5m", + "to": "now" + }, + "timepicker": { + "refresh_intervals": [ + "5s", + "10s", + "30s", + "1m", + "5m", + "15m", + "30m", + "1h", + "2h", + "1d" + ], + "time_options": [ + "5m", + "15m", + "1h", + "6h", + "12h", + "24h", + "2d", + "7d", + "30d" + ] + }, + "timezone": "browser", + "title": "Istio Pilot Dashboard", + "uid": "3--MLVZZk", + "version": 11 +} \ No newline at end of file diff --git a/istio-1.5.0/install/kubernetes/helm/istio/charts/grafana/templates/_helpers.tpl b/istio-1.5.0/install/kubernetes/helm/istio/charts/grafana/templates/_helpers.tpl new file mode 100644 index 0000000..9d4c592 --- /dev/null +++ b/istio-1.5.0/install/kubernetes/helm/istio/charts/grafana/templates/_helpers.tpl @@ -0,0 +1,32 @@ +{{/* vim: set filetype=mustache: */}} +{{/* +Expand the name of the chart. +*/}} +{{- define "grafana.name" -}} +{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" -}} +{{- end -}} + +{{/* +Create a default fully qualified app name. +We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). +If release name contains chart name it will be used as a full name. +*/}} +{{- define "grafana.fullname" -}} +{{- if .Values.fullnameOverride -}} +{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" -}} +{{- else -}} +{{- $name := default .Chart.Name .Values.nameOverride -}} +{{- if contains $name .Release.Name -}} +{{- .Release.Name | trunc 63 | trimSuffix "-" -}} +{{- else -}} +{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" -}} +{{- end -}} +{{- end -}} +{{- end -}} + +{{/* +Create chart name and version as used by the chart label. +*/}} +{{- define "grafana.chart" -}} +{{- .Chart.Name | trunc 63 | trimSuffix "-" -}} +{{- end -}} diff --git a/istio-1.5.0/install/kubernetes/helm/istio/charts/grafana/templates/configmap-custom-resources.yaml b/istio-1.5.0/install/kubernetes/helm/istio/charts/grafana/templates/configmap-custom-resources.yaml new file mode 100644 index 0000000..b89bc07 --- /dev/null +++ b/istio-1.5.0/install/kubernetes/helm/istio/charts/grafana/templates/configmap-custom-resources.yaml @@ -0,0 +1,16 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: istio-grafana-custom-resources + namespace: {{ .Release.Namespace }} + labels: + app: {{ template "grafana.name" . }} + chart: {{ template "grafana.chart" . }} + heritage: {{ .Release.Service }} + release: {{ .Release.Name }} + istio: grafana +data: + custom-resources.yaml: |- + {{- include "grafana-default.yaml.tpl" . | indent 4}} + run.sh: |- + {{- include "install-custom-resources.sh.tpl" . | indent 4}} diff --git a/istio-1.5.0/install/kubernetes/helm/istio/charts/grafana/templates/configmap-dashboards.yaml b/istio-1.5.0/install/kubernetes/helm/istio/charts/grafana/templates/configmap-dashboards.yaml new file mode 100644 index 0000000..dd1ab0d --- /dev/null +++ b/istio-1.5.0/install/kubernetes/helm/istio/charts/grafana/templates/configmap-dashboards.yaml @@ -0,0 +1,18 @@ +{{- $files := .Files }} +{{- range $path, $bytes := .Files.Glob "dashboards/*.json" }} +{{- $filename := trimSuffix (ext $path) (base $path) }} +apiVersion: v1 +kind: ConfigMap +metadata: + name: istio-grafana-configuration-dashboards-{{ $filename }} + namespace: {{ $.Release.Namespace }} + labels: + app: {{ template "grafana.name" $ }} + chart: {{ template "grafana.chart" $ }} + heritage: {{ $.Release.Service }} + release: {{ $.Release.Name }} + istio: grafana +data: + {{ base $path }}: '{{ $files.Get $path }}' +--- +{{- end }} diff --git a/istio-1.5.0/install/kubernetes/helm/istio/charts/grafana/templates/configmap.yaml b/istio-1.5.0/install/kubernetes/helm/istio/charts/grafana/templates/configmap.yaml new file mode 100644 index 0000000..c86efe1 --- /dev/null +++ b/istio-1.5.0/install/kubernetes/helm/istio/charts/grafana/templates/configmap.yaml @@ -0,0 +1,25 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: istio-grafana + namespace: {{ .Release.Namespace }} + labels: + app: {{ template "grafana.name" . }} + chart: {{ template "grafana.chart" . }} + heritage: {{ .Release.Service }} + release: {{ .Release.Name }} + istio: grafana +data: +{{- if .Values.datasources }} + {{- range $key, $value := .Values.datasources }} + {{ $key }}: | +{{ toYaml $value | indent 4 }} + {{- end -}} +{{- end -}} + +{{- if .Values.dashboardProviders }} + {{- range $key, $value := .Values.dashboardProviders }} + {{ $key }}: | +{{ toYaml $value | indent 4 }} + {{- end -}} +{{- end -}} diff --git a/istio-1.5.0/install/kubernetes/helm/istio/charts/grafana/templates/create-custom-resources-job.yaml b/istio-1.5.0/install/kubernetes/helm/istio/charts/grafana/templates/create-custom-resources-job.yaml new file mode 100644 index 0000000..50de864 --- /dev/null +++ b/istio-1.5.0/install/kubernetes/helm/istio/charts/grafana/templates/create-custom-resources-job.yaml @@ -0,0 +1,103 @@ +apiVersion: v1 +kind: ServiceAccount +{{- if .Values.global.imagePullSecrets }} +imagePullSecrets: +{{- range .Values.global.imagePullSecrets }} + - name: {{ . }} +{{- end }} +{{- end }} +metadata: + name: istio-grafana-post-install-account + namespace: {{ .Release.Namespace }} + labels: + app: {{ template "grafana.name" . }} + chart: {{ template "grafana.chart" . }} + heritage: {{ .Release.Service }} + release: {{ .Release.Name }} +{{- if .Values.global.imagePullSecrets }} +imagePullSecrets: +{{- range .Values.global.imagePullSecrets }} + - name: {{ . }} +{{- end }} +{{- end }} +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: istio-grafana-post-install-{{ .Release.Namespace }} + labels: + app: {{ template "grafana.name" . }} + chart: {{ template "grafana.chart" . }} + heritage: {{ .Release.Service }} + release: {{ .Release.Name }} +rules: +- apiGroups: ["authentication.istio.io"] # needed to create default authn policy + resources: ["*"] + verbs: ["*"] +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: istio-grafana-post-install-role-binding-{{ .Release.Namespace }} + labels: + app: {{ template "grafana.name" . }} + chart: {{ template "grafana.chart" . }} + heritage: {{ .Release.Service }} + release: {{ .Release.Name }} +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: istio-grafana-post-install-{{ .Release.Namespace }} +subjects: + - kind: ServiceAccount + name: istio-grafana-post-install-account + namespace: {{ .Release.Namespace }} +--- +apiVersion: batch/v1 +kind: Job +metadata: + name: istio-grafana-post-install-{{ .Values.global.tag | printf "%v" | trunc 32 | trimSuffix "-" }} + namespace: {{ .Release.Namespace }} + annotations: + "helm.sh/hook": post-install + "helm.sh/hook-delete-policy": hook-succeeded + labels: + app: {{ template "grafana.name" . }} + chart: {{ template "grafana.chart" . }} + heritage: {{ .Release.Service }} + release: {{ .Release.Name }} +spec: + template: + metadata: + name: istio-grafana-post-install + labels: + app: istio-grafana + chart: {{ template "grafana.chart" . }} + heritage: {{ .Release.Service }} + release: {{ .Release.Name }} + annotations: + sidecar.istio.io/inject: "false" + spec: + serviceAccountName: istio-grafana-post-install-account + containers: + - name: kubectl + image: "{{ .Values.global.hub }}/kubectl:{{ .Values.global.tag }}" + command: [ "/bin/bash", "/tmp/grafana/run.sh", "/tmp/grafana/custom-resources.yaml" ] + volumeMounts: + - mountPath: "/tmp/grafana" + name: tmp-configmap-grafana + volumes: + - name: tmp-configmap-grafana + configMap: + name: istio-grafana-custom-resources + restartPolicy: OnFailure + affinity: + {{- include "nodeaffinity" . | indent 6 }} + {{- include "podAntiAffinity" . | indent 6 }} + {{- if .Values.tolerations }} + tolerations: +{{ toYaml .Values.tolerations | indent 6 }} + {{- else if .Values.global.defaultTolerations }} + tolerations: +{{ toYaml .Values.global.defaultTolerations | indent 6 }} + {{- end }} diff --git a/istio-1.5.0/install/kubernetes/helm/istio/charts/grafana/templates/deployment.yaml b/istio-1.5.0/install/kubernetes/helm/istio/charts/grafana/templates/deployment.yaml new file mode 100644 index 0000000..ba3037e --- /dev/null +++ b/istio-1.5.0/install/kubernetes/helm/istio/charts/grafana/templates/deployment.yaml @@ -0,0 +1,138 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: grafana + namespace: {{ .Release.Namespace }} + labels: + app: {{ template "grafana.name" . }} + chart: {{ template "grafana.chart" . }} + heritage: {{ .Release.Service }} + release: {{ .Release.Name }} +spec: + replicas: {{ .Values.replicaCount }} + selector: + matchLabels: + app: grafana + template: + metadata: + labels: + app: grafana + chart: {{ template "grafana.chart" . }} + heritage: {{ .Release.Service }} + release: {{ .Release.Name }} + annotations: + sidecar.istio.io/inject: "false" + prometheus.io/scrape: "true" + spec: + securityContext: + runAsUser: 472 + fsGroup: 472 +{{- if .Values.global.priorityClassName }} + priorityClassName: "{{ .Values.global.priorityClassName }}" +{{- end }} +{{- if .Values.global.imagePullSecrets }} + imagePullSecrets: +{{- range .Values.global.imagePullSecrets }} + - name: {{ . }} +{{- end }} +{{- end }} + containers: + - name: {{ .Chart.Name }} + image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}" + imagePullPolicy: {{ .Values.global.imagePullPolicy }} + ports: + - containerPort: 3000 + readinessProbe: + httpGet: + path: /api/health + port: 3000 + env: + - name: GRAFANA_PORT + value: "3000" +{{- if .Values.security.enabled }} + - name: GF_SECURITY_ADMIN_USER + valueFrom: + secretKeyRef: + name: {{ .Values.security.secretName }} + key: {{ .Values.security.usernameKey }} + - name: GF_SECURITY_ADMIN_PASSWORD + valueFrom: + secretKeyRef: + name: {{ .Values.security.secretName }} + key: {{ .Values.security.passphraseKey }} + - name: GF_AUTH_BASIC_ENABLED + value: "true" + - name: GF_AUTH_ANONYMOUS_ENABLED + value: "false" + - name: GF_AUTH_DISABLE_LOGIN_FORM + value: "false" +{{- else }} + - name: GF_AUTH_BASIC_ENABLED + value: "false" + - name: GF_AUTH_ANONYMOUS_ENABLED + value: "true" + - name: GF_AUTH_ANONYMOUS_ORG_ROLE + value: Admin +{{- end }} + - name: GF_PATHS_DATA + value: /data/grafana + {{- range $key, $value := $.Values.env }} + - name: {{ $key }} + value: {{ $value | quote }} + {{- end }} + {{- range $key, $secret := $.Values.envSecrets }} + - name: {{ $key }} + valueFrom: + secretKeyRef: + name: {{ $secret }} + key: {{ $key | quote }} + {{- end }} + resources: +{{- if .Values.resources }} +{{ toYaml .Values.resources | indent 12 }} +{{- else }} +{{ toYaml .Values.global.defaultResources | indent 12 }} +{{- end }} + volumeMounts: + - name: data + mountPath: /data/grafana + {{- range $path, $bytes := .Files.Glob "dashboards/*.json" }} + {{- $filename := trimSuffix (ext $path) (base $path) }} + - name: dashboards-istio-{{ $filename }} + mountPath: "/var/lib/grafana/dashboards/istio/{{ base $path }}" + subPath: {{ base $path }} + readOnly: true + {{- end }} + - name: config + mountPath: "/etc/grafana/provisioning/datasources/datasources.yaml" + subPath: datasources.yaml + - name: config + mountPath: "/etc/grafana/provisioning/dashboards/dashboardproviders.yaml" + subPath: dashboardproviders.yaml + affinity: + {{- include "nodeaffinity" . | indent 6 }} + {{- include "podAntiAffinity" . | indent 6 }} + {{- if .Values.tolerations }} + tolerations: +{{ toYaml .Values.tolerations | indent 6 }} + {{- else if .Values.global.defaultTolerations }} + tolerations: +{{ toYaml .Values.global.defaultTolerations | indent 6 }} + {{- end }} + volumes: + - name: config + configMap: + name: istio-grafana + - name: data +{{- if .Values.persist }} + persistentVolumeClaim: + claimName: istio-grafana-pvc +{{- else }} + emptyDir: {} +{{- end }} +{{- range $path, $bytes := .Files.Glob "dashboards/*.json" }} +{{- $filename := trimSuffix (ext $path) (base $path) }} + - name: dashboards-istio-{{ $filename }} + configMap: + name: istio-grafana-configuration-dashboards-{{ $filename }} +{{- end }} diff --git a/istio-1.5.0/install/kubernetes/helm/istio/charts/grafana/templates/grafana-ports-mtls.yaml b/istio-1.5.0/install/kubernetes/helm/istio/charts/grafana/templates/grafana-ports-mtls.yaml new file mode 100644 index 0000000..b9a3926 --- /dev/null +++ b/istio-1.5.0/install/kubernetes/helm/istio/charts/grafana/templates/grafana-ports-mtls.yaml @@ -0,0 +1,17 @@ +{{ define "grafana-default.yaml.tpl" }} +apiVersion: authentication.istio.io/v1alpha1 +kind: Policy +metadata: + name: grafana-ports-mtls-disabled + namespace: {{ .Release.Namespace }} + labels: + app: {{ template "grafana.name" . }} + chart: {{ template "grafana.chart" . }} + heritage: {{ .Release.Service }} + release: {{ .Release.Name }} +spec: + targets: + - name: grafana + ports: + - number: {{ .Values.service.externalPort }} +{{- end }} diff --git a/istio-1.5.0/install/kubernetes/helm/istio/charts/grafana/templates/ingress.yaml b/istio-1.5.0/install/kubernetes/helm/istio/charts/grafana/templates/ingress.yaml new file mode 100644 index 0000000..0ebe71f --- /dev/null +++ b/istio-1.5.0/install/kubernetes/helm/istio/charts/grafana/templates/ingress.yaml @@ -0,0 +1,40 @@ +{{- if .Values.ingress.enabled -}} +apiVersion: extensions/v1beta1 +kind: Ingress +metadata: + name: grafana + namespace: {{ .Release.Namespace }} + labels: + app: {{ template "grafana.name" . }} + chart: {{ template "grafana.chart" . }} + heritage: {{ .Release.Service }} + release: {{ .Release.Name }} + annotations: + {{- range $key, $value := .Values.ingress.annotations }} + {{ $key }}: {{ $value | quote }} + {{- end }} +spec: + rules: +{{- if .Values.ingress.hosts }} + {{- range $host := .Values.ingress.hosts }} + - host: {{ $host }} + http: + paths: + - path: {{ if $.Values.contextPath }} {{ $.Values.contextPath }} {{ else }} / {{ end }} + backend: + serviceName: grafana + servicePort: 3000 + {{- end -}} +{{- else }} + - http: + paths: + - path: {{ if .Values.contextPath }} {{ .Values.contextPath }} {{ else }} / {{ end }} + backend: + serviceName: grafana + servicePort: 3000 +{{- end }} + {{- if .Values.ingress.tls }} + tls: +{{ toYaml .Values.ingress.tls | indent 4 }} + {{- end -}} +{{- end -}} diff --git a/istio-1.5.0/install/kubernetes/helm/istio/charts/grafana/templates/pvc.yaml b/istio-1.5.0/install/kubernetes/helm/istio/charts/grafana/templates/pvc.yaml new file mode 100644 index 0000000..e376a13 --- /dev/null +++ b/istio-1.5.0/install/kubernetes/helm/istio/charts/grafana/templates/pvc.yaml @@ -0,0 +1,19 @@ +{{- if .Values.persist }} +kind: PersistentVolumeClaim +apiVersion: v1 +metadata: + name: istio-grafana-pvc + namespace: {{ .Release.Namespace }} + labels: + app: {{ template "grafana.name" . }} + chart: {{ template "grafana.chart" . }} + heritage: {{ .Release.Service }} + release: {{ .Release.Name }} +spec: + storageClassName: {{ .Values.storageClassName }} + accessModes: + - {{ .Values.accessMode }} + resources: + requests: + storage: 5Gi +{{- end }} diff --git a/istio-1.5.0/install/kubernetes/helm/istio/charts/grafana/templates/service.yaml b/istio-1.5.0/install/kubernetes/helm/istio/charts/grafana/templates/service.yaml new file mode 100644 index 0000000..b206679 --- /dev/null +++ b/istio-1.5.0/install/kubernetes/helm/istio/charts/grafana/templates/service.yaml @@ -0,0 +1,32 @@ +apiVersion: v1 +kind: Service +metadata: + name: grafana + namespace: {{ .Release.Namespace }} + annotations: + {{- range $key, $val := .Values.service.annotations }} + {{ $key }}: {{ $val | quote }} + {{- end }} + labels: + app: {{ template "grafana.name" . }} + chart: {{ template "grafana.chart" . }} + heritage: {{ .Release.Service }} + release: {{ .Release.Name }} +spec: + type: {{ .Values.service.type }} + ports: + - port: {{ .Values.service.externalPort }} + targetPort: 3000 + protocol: TCP + name: {{ .Values.service.name }} + selector: + app: grafana +{{- if .Values.service.loadBalancerIP }} + loadBalancerIP: "{{ .Values.service.loadBalancerIP }}" +{{- end }} + {{if .Values.service.loadBalancerSourceRanges}} + loadBalancerSourceRanges: + {{range $rangeList := .Values.service.loadBalancerSourceRanges}} + - {{ $rangeList }} + {{end}} + {{end}} diff --git a/istio-1.5.0/install/kubernetes/helm/istio/charts/grafana/templates/tests/test-grafana-connection.yaml b/istio-1.5.0/install/kubernetes/helm/istio/charts/grafana/templates/tests/test-grafana-connection.yaml new file mode 100644 index 0000000..e9268c4 --- /dev/null +++ b/istio-1.5.0/install/kubernetes/helm/istio/charts/grafana/templates/tests/test-grafana-connection.yaml @@ -0,0 +1,37 @@ +{{- if .Values.global.enableHelmTest }} +apiVersion: v1 +kind: Pod +metadata: + name: {{ template "grafana.fullname" . }}-test + namespace: {{ .Release.Namespace }} + labels: + app: grafana-test + chart: {{ template "grafana.chart" . }} + release: {{ .Release.Name }} + heritage: {{ .Release.Service }} + istio: grafana + annotations: + sidecar.istio.io/inject: "false" + helm.sh/hook: test-success +spec: +{{- if .Values.global.priorityClassName }} + priorityClassName: "{{ .Values.global.priorityClassName }}" +{{- end }} + containers: + - name: "{{ template "grafana.fullname" . }}-test" + image: pstauffer/curl:v1.0.3 + imagePullPolicy: "{{ .Values.global.imagePullPolicy }}" + command: ['curl'] + args: ['http://grafana:{{ .Values.grafana.service.externalPort }}'] + restartPolicy: Never + affinity: + {{- include "nodeaffinity" . | indent 4 }} + {{- include "podAntiAffinity" . | indent 4 }} + {{- if .Values.tolerations }} + tolerations: +{{ toYaml .Values.tolerations | indent 2 }} + {{- else if .Values.global.defaultTolerations }} + tolerations: +{{ toYaml .Values.global.defaultTolerations | indent 2 }} + {{- end }} +{{- end }} diff --git a/istio-1.5.0/install/kubernetes/helm/istio/charts/grafana/values.yaml b/istio-1.5.0/install/kubernetes/helm/istio/charts/grafana/values.yaml new file mode 100644 index 0000000..2c272bf --- /dev/null +++ b/istio-1.5.0/install/kubernetes/helm/istio/charts/grafana/values.yaml @@ -0,0 +1,117 @@ +# +# addon grafana configuration +# +enabled: false +replicaCount: 1 +image: + repository: grafana/grafana + tag: 6.4.3 +ingress: + enabled: false + ## Used to create an Ingress record. + hosts: + - grafana.local + annotations: {} + # kubernetes.io/ingress.class: nginx + # kubernetes.io/tls-acme: "true" + tls: [] + # Secrets must be manually created in the namespace. + # - secretName: grafana-tls + # hosts: + # - grafana.local +persist: false +storageClassName: "" +accessMode: ReadWriteMany +security: + enabled: false + secretName: grafana + usernameKey: username + passphraseKey: passphrase +nodeSelector: {} +tolerations: [] + +env: {} + # Define additional environment variables for configuring grafana. + # @see https://grafana.com/docs/installation/configuration/#using-environment-variables + # Format: env_variable_name: value + # For example: + # GF_SMTP_ENABLED: true + # GF_SMTP_HOST: email-smtp.eu-west-1.amazonaws.com:2587 + # GF_SMTP_FROM_ADDRESS: alerts@mydomain.com + # GF_SMTP_FROM_NAME: Grafana + +envSecrets: {} + # The key name and ENV name must match in the secrets file. + # @see https://grafana.com/docs/installation/configuration/#using-environment-variables + # For example: + # --- + # apiVersion: v1 + # kind: Secret + # metadata: + # name: grafana-secrets + # namespace: istio-system + # data: + # GF_SMTP_USER: bXl1c2Vy + # GF_SMTP_PASSWORD: bXlwYXNzd29yZA== + # type: Opaque + # --- + # env_variable_key_name: secretsName + # --- + # GF_SMTP_USER: grafana-secrets + # GF_SMTP_PASSWORD: grafana-secrets + +# Specify the pod anti-affinity that allows you to constrain which nodes +# your pod is eligible to be scheduled based on labels on pods that are +# already running on the node rather than based on labels on nodes. +# There are currently two types of anti-affinity: +# "requiredDuringSchedulingIgnoredDuringExecution" +# "preferredDuringSchedulingIgnoredDuringExecution" +# which denote "hard" vs. "soft" requirements, you can define your values +# in "podAntiAffinityLabelSelector" and "podAntiAffinityTermLabelSelector" +# correspondingly. +# For example: +# podAntiAffinityLabelSelector: +# - key: security +# operator: In +# values: S1,S2 +# topologyKey: "kubernetes.io/hostname" +# This pod anti-affinity rule says that the pod requires not to be scheduled +# onto a node if that node is already running a pod with label having key +# "security" and value "S1". +podAntiAffinityLabelSelector: [] +podAntiAffinityTermLabelSelector: [] + +contextPath: /grafana +service: + annotations: {} + name: http + type: ClusterIP + externalPort: 3000 + loadBalancerIP: + loadBalancerSourceRanges: [] + +datasources: + datasources.yaml: + apiVersion: 1 + datasources: + - name: Prometheus + type: prometheus + orgId: 1 + url: http://prometheus:9090 + access: proxy + isDefault: true + jsonData: + timeInterval: 5s + editable: true + +dashboardProviders: + dashboardproviders.yaml: + apiVersion: 1 + providers: + - name: 'istio' + orgId: 1 + folder: 'istio' + type: file + disableDeletion: false + options: + path: /var/lib/grafana/dashboards/istio diff --git a/istio-1.5.0/install/kubernetes/helm/istio/charts/istiocoredns/Chart.yaml b/istio-1.5.0/install/kubernetes/helm/istio/charts/istiocoredns/Chart.yaml new file mode 100644 index 0000000..6640caa --- /dev/null +++ b/istio-1.5.0/install/kubernetes/helm/istio/charts/istiocoredns/Chart.yaml @@ -0,0 +1,6 @@ +apiVersion: v1 +description: Istio CoreDNS provides DNS resolution for services in multicluster setups. +name: istiocoredns +version: 1.5.0 +appVersion: 0.1 +tillerVersion: ">=2.7.2" diff --git a/istio-1.5.0/install/kubernetes/helm/istio/charts/istiocoredns/templates/_helpers.tpl b/istio-1.5.0/install/kubernetes/helm/istio/charts/istiocoredns/templates/_helpers.tpl new file mode 100644 index 0000000..e7add11 --- /dev/null +++ b/istio-1.5.0/install/kubernetes/helm/istio/charts/istiocoredns/templates/_helpers.tpl @@ -0,0 +1,32 @@ +{{/* vim: set filetype=mustache: */}} +{{/* +Expand the name of the chart. +*/}} +{{- define "istiocoredns.name" -}} +{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" -}} +{{- end -}} + +{{/* +Create a default fully qualified app name. +We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). +If release name contains chart name it will be used as a full name. +*/}} +{{- define "istiocoredns.fullname" -}} +{{- if .Values.fullnameOverride -}} +{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" -}} +{{- else -}} +{{- $name := default .Chart.Name .Values.nameOverride -}} +{{- if contains $name .Release.Name -}} +{{- .Release.Name | trunc 63 | trimSuffix "-" -}} +{{- else -}} +{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" -}} +{{- end -}} +{{- end -}} +{{- end -}} + +{{/* +Create chart name and version as used by the chart label. +*/}} +{{- define "istiocoredns.chart" -}} +{{- .Chart.Name | trunc 63 | trimSuffix "-" -}} +{{- end -}} diff --git a/istio-1.5.0/install/kubernetes/helm/istio/charts/istiocoredns/templates/clusterrole.yaml b/istio-1.5.0/install/kubernetes/helm/istio/charts/istiocoredns/templates/clusterrole.yaml new file mode 100644 index 0000000..4242a32 --- /dev/null +++ b/istio-1.5.0/install/kubernetes/helm/istio/charts/istiocoredns/templates/clusterrole.yaml @@ -0,0 +1,13 @@ +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: istiocoredns + labels: + app: {{ template "istiocoredns.name" . }} + chart: {{ template "istiocoredns.chart" . }} + heritage: {{ .Release.Service }} + release: {{ .Release.Name }} +rules: +- apiGroups: ["networking.istio.io"] + resources: ["*"] + verbs: ["get", "watch", "list"] diff --git a/istio-1.5.0/install/kubernetes/helm/istio/charts/istiocoredns/templates/clusterrolebinding.yaml b/istio-1.5.0/install/kubernetes/helm/istio/charts/istiocoredns/templates/clusterrolebinding.yaml new file mode 100644 index 0000000..bafd0ca --- /dev/null +++ b/istio-1.5.0/install/kubernetes/helm/istio/charts/istiocoredns/templates/clusterrolebinding.yaml @@ -0,0 +1,17 @@ +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: istio-istiocoredns-role-binding-{{ .Release.Namespace }} + labels: + app: {{ template "istiocoredns.name" . }} + chart: {{ template "istiocoredns.chart" . }} + heritage: {{ .Release.Service }} + release: {{ .Release.Name }} +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: istiocoredns +subjects: +- kind: ServiceAccount + name: istiocoredns-service-account + namespace: {{ .Release.Namespace }} diff --git a/istio-1.5.0/install/kubernetes/helm/istio/charts/istiocoredns/templates/configmap.yaml b/istio-1.5.0/install/kubernetes/helm/istio/charts/istiocoredns/templates/configmap.yaml new file mode 100644 index 0000000..925626f --- /dev/null +++ b/istio-1.5.0/install/kubernetes/helm/istio/charts/istiocoredns/templates/configmap.yaml @@ -0,0 +1,32 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: coredns + namespace: {{ .Release.Namespace }} + labels: + app: {{ template "istiocoredns.name" . }} + chart: {{ template "istiocoredns.chart" . }} + heritage: {{ .Release.Service }} + release: {{ .Release.Name }} +data: + Corefile: | + .:53 { + errors + health + {{ if eq -1 (semver .Values.coreDNSTag | (semver "1.4.0").Compare) }} + # Removed support for the proxy plugin: https://coredns.io/2019/03/03/coredns-1.4.0-release/ + grpc global 127.0.0.1:8053 + forward . /etc/resolv.conf { + except global + } + {{ else }} + proxy global 127.0.0.1:8053 { + protocol grpc insecure + } + proxy . /etc/resolv.conf + {{ end }} + prometheus :9153 + cache 30 + reload + } +--- diff --git a/istio-1.5.0/install/kubernetes/helm/istio/charts/istiocoredns/templates/deployment.yaml b/istio-1.5.0/install/kubernetes/helm/istio/charts/istiocoredns/templates/deployment.yaml new file mode 100644 index 0000000..d5e0879 --- /dev/null +++ b/istio-1.5.0/install/kubernetes/helm/istio/charts/istiocoredns/templates/deployment.yaml @@ -0,0 +1,103 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: istiocoredns + namespace: {{ .Release.Namespace }} + labels: + app: {{ template "istiocoredns.name" . }} + chart: {{ template "istiocoredns.chart" . }} + heritage: {{ .Release.Service }} + release: {{ .Release.Name }} +spec: + replicas: {{ .Values.replicaCount }} + selector: + matchLabels: + app: istiocoredns + strategy: + rollingUpdate: + maxSurge: {{ .Values.rollingMaxSurge }} + maxUnavailable: {{ .Values.rollingMaxUnavailable }} + template: + metadata: + name: istiocoredns + labels: + app: istiocoredns + chart: {{ template "istiocoredns.chart" . }} + heritage: {{ .Release.Service }} + release: {{ .Release.Name }} + annotations: + sidecar.istio.io/inject: "false" + {{- if .Values.podAnnotations }} +{{ toYaml .Values.podAnnotations | indent 8 }} + {{- end }} + spec: + serviceAccountName: istiocoredns-service-account +{{- if .Values.global.priorityClassName }} + priorityClassName: "{{ .Values.global.priorityClassName }}" +{{- end }} + containers: + - name: coredns + image: {{ .Values.coreDNSImage }}:{{ .Values.coreDNSTag }} + imagePullPolicy: {{ .Values.global.imagePullPolicy }} + args: [ "-conf", "/etc/coredns/Corefile" ] + volumeMounts: + - name: config-volume + mountPath: /etc/coredns + ports: + - containerPort: 53 + name: dns + protocol: UDP + - containerPort: 53 + name: dns-tcp + protocol: TCP + - containerPort: 9153 + name: metrics + protocol: TCP + livenessProbe: + httpGet: + path: /health + port: 8080 + scheme: HTTP + initialDelaySeconds: 60 + timeoutSeconds: 5 + successThreshold: 1 + failureThreshold: 5 + resources: +{{- if .Values.resources }} +{{ toYaml .Values.resources | indent 10 }} +{{- else }} +{{ toYaml .Values.global.defaultResources | indent 10 }} +{{- end }} + - name: istio-coredns-plugin + command: + - /usr/local/bin/plugin + image: {{ .Values.coreDNSPluginImage }} + imagePullPolicy: {{ .Values.global.imagePullPolicy }} + ports: + - containerPort: 8053 + name: dns-grpc + protocol: TCP + resources: +{{- if .Values.resources }} +{{ toYaml .Values.resources | indent 10 }} +{{- else }} +{{ toYaml .Values.global.defaultResources | indent 10 }} +{{- end }} + dnsPolicy: Default + volumes: + - name: config-volume + configMap: + name: coredns + items: + - key: Corefile + path: Corefile + affinity: + {{- include "nodeaffinity" . | indent 6 }} + {{- include "podAntiAffinity" . | indent 6 }} + {{- if .Values.tolerations }} + tolerations: +{{ toYaml .Values.tolerations | indent 6 }} + {{- else if .Values.global.defaultTolerations }} + tolerations: +{{ toYaml .Values.global.defaultTolerations | indent 6 }} + {{- end }} diff --git a/istio-1.5.0/install/kubernetes/helm/istio/charts/istiocoredns/templates/service.yaml b/istio-1.5.0/install/kubernetes/helm/istio/charts/istiocoredns/templates/service.yaml new file mode 100644 index 0000000..a631101 --- /dev/null +++ b/istio-1.5.0/install/kubernetes/helm/istio/charts/istiocoredns/templates/service.yaml @@ -0,0 +1,20 @@ +apiVersion: v1 +kind: Service +metadata: + name: istiocoredns + namespace: {{ .Release.Namespace }} + labels: + app: {{ template "istiocoredns.name" . }} + chart: {{ template "istiocoredns.chart" . }} + heritage: {{ .Release.Service }} + release: {{ .Release.Name }} +spec: + selector: + app: istiocoredns + ports: + - name: dns + port: 53 + protocol: UDP + - name: dns-tcp + port: 53 + protocol: TCP diff --git a/istio-1.5.0/install/kubernetes/helm/istio/charts/istiocoredns/templates/serviceaccount.yaml b/istio-1.5.0/install/kubernetes/helm/istio/charts/istiocoredns/templates/serviceaccount.yaml new file mode 100644 index 0000000..e2627cf --- /dev/null +++ b/istio-1.5.0/install/kubernetes/helm/istio/charts/istiocoredns/templates/serviceaccount.yaml @@ -0,0 +1,16 @@ +apiVersion: v1 +kind: ServiceAccount +{{- if .Values.global.imagePullSecrets }} +imagePullSecrets: +{{- range .Values.global.imagePullSecrets }} + - name: {{ . }} +{{- end }} +{{- end }} +metadata: + name: istiocoredns-service-account + namespace: {{ .Release.Namespace }} + labels: + app: {{ template "istiocoredns.name" . }} + chart: {{ template "istiocoredns.chart" . }} + heritage: {{ .Release.Service }} + release: {{ .Release.Name }} diff --git a/istio-1.5.0/install/kubernetes/helm/istio/charts/istiocoredns/values.yaml b/istio-1.5.0/install/kubernetes/helm/istio/charts/istiocoredns/values.yaml new file mode 100644 index 0000000..6b31219 --- /dev/null +++ b/istio-1.5.0/install/kubernetes/helm/istio/charts/istiocoredns/values.yaml @@ -0,0 +1,37 @@ +# +# addon istiocoredns tracing configuration +# +enabled: false +replicaCount: 1 +rollingMaxSurge: 100% +rollingMaxUnavailable: 25% +coreDNSImage: coredns/coredns +coreDNSTag: 1.6.2 +# Source code for the plugin can be found at +# https://github.com/istio-ecosystem/istio-coredns-plugin +# The plugin listens for DNS requests from coredns server at 127.0.0.1:8053 +coreDNSPluginImage: istio/coredns-plugin:0.2-istio-1.1 +nodeSelector: {} +tolerations: [] +podAnnotations: {} + +# Specify the pod anti-affinity that allows you to constrain which nodes +# your pod is eligible to be scheduled based on labels on pods that are +# already running on the node rather than based on labels on nodes. +# There are currently two types of anti-affinity: +# "requiredDuringSchedulingIgnoredDuringExecution" +# "preferredDuringSchedulingIgnoredDuringExecution" +# which denote "hard" vs. "soft" requirements, you can define your values +# in "podAntiAffinityLabelSelector" and "podAntiAffinityTermLabelSelector" +# correspondingly. +# For example: +# podAntiAffinityLabelSelector: +# - key: security +# operator: In +# values: S1,S2 +# topologyKey: "kubernetes.io/hostname" +# This pod anti-affinity rule says that the pod requires not to be scheduled +# onto a node if that node is already running a pod with label having key +# "security" and value "S1". +podAntiAffinityLabelSelector: [] +podAntiAffinityTermLabelSelector: [] diff --git a/istio-1.5.0/install/kubernetes/helm/istio/charts/kiali/Chart.yaml b/istio-1.5.0/install/kubernetes/helm/istio/charts/kiali/Chart.yaml new file mode 100644 index 0000000..5057c69 --- /dev/null +++ b/istio-1.5.0/install/kubernetes/helm/istio/charts/kiali/Chart.yaml @@ -0,0 +1,6 @@ +apiVersion: v1 +description: Kiali is an open source project for service mesh observability, refer to https://www.kiali.io for details. +name: kiali +version: 1.9.0 +appVersion: 1.9.0 +tillerVersion: ">=2.7.2" diff --git a/istio-1.5.0/install/kubernetes/helm/istio/charts/kiali/templates/_helpers.tpl b/istio-1.5.0/install/kubernetes/helm/istio/charts/kiali/templates/_helpers.tpl new file mode 100644 index 0000000..6b00957 --- /dev/null +++ b/istio-1.5.0/install/kubernetes/helm/istio/charts/kiali/templates/_helpers.tpl @@ -0,0 +1,32 @@ +{{/* vim: set filetype=mustache: */}} +{{/* +Expand the name of the chart. +*/}} +{{- define "kiali.name" -}} +{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" -}} +{{- end -}} + +{{/* +Create a default fully qualified app name. +We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). +If release name contains chart name it will be used as a full name. +*/}} +{{- define "kiali.fullname" -}} +{{- if .Values.fullnameOverride -}} +{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" -}} +{{- else -}} +{{- $name := default .Chart.Name .Values.nameOverride -}} +{{- if contains $name .Release.Name -}} +{{- .Release.Name | trunc 63 | trimSuffix "-" -}} +{{- else -}} +{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" -}} +{{- end -}} +{{- end -}} +{{- end -}} + +{{/* +Create chart name and version as used by the chart label. +*/}} +{{- define "kiali.chart" -}} +{{- .Chart.Name | trunc 63 | trimSuffix "-" -}} +{{- end -}} diff --git a/istio-1.5.0/install/kubernetes/helm/istio/charts/kiali/templates/clusterrole.yaml b/istio-1.5.0/install/kubernetes/helm/istio/charts/kiali/templates/clusterrole.yaml new file mode 100644 index 0000000..8ad6e97 --- /dev/null +++ b/istio-1.5.0/install/kubernetes/helm/istio/charts/kiali/templates/clusterrole.yaml @@ -0,0 +1,134 @@ +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: kiali + labels: + app: {{ template "kiali.name" . }} + chart: {{ template "kiali.chart" . }} + heritage: {{ .Release.Service }} + release: {{ .Release.Name }} +rules: +- apiGroups: [""] + resources: + - configmaps + - endpoints + - namespaces + - nodes + - pods + - pods/log + - replicationcontrollers + - services + verbs: + - get + - list + - watch +- apiGroups: ["extensions", "apps"] + resources: + - deployments + - replicasets + - statefulsets + verbs: + - get + - list + - watch +- apiGroups: ["autoscaling"] + resources: + - horizontalpodautoscalers + verbs: + - get + - list + - watch +- apiGroups: ["batch"] + resources: + - cronjobs + - jobs + verbs: + - get + - list + - watch +- apiGroups: + - config.istio.io + - networking.istio.io + - authentication.istio.io + - rbac.istio.io + - security.istio.io + resources: ["*"] + verbs: + - create + - delete + - get + - list + - patch + - watch +- apiGroups: ["monitoring.kiali.io"] + resources: + - monitoringdashboards + verbs: + - get + - list +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: kiali-viewer + labels: + app: {{ template "kiali.name" . }} + chart: {{ template "kiali.chart" . }} + heritage: {{ .Release.Service }} + release: {{ .Release.Name }} +rules: +- apiGroups: [""] + resources: + - configmaps + - endpoints + - namespaces + - nodes + - pods + - pods/log + - replicationcontrollers + - services + verbs: + - get + - list + - watch +- apiGroups: ["extensions", "apps"] + resources: + - deployments + - replicasets + - statefulsets + verbs: + - get + - list + - watch +- apiGroups: ["autoscaling"] + resources: + - horizontalpodautoscalers + verbs: + - get + - list + - watch +- apiGroups: ["batch"] + resources: + - cronjobs + - jobs + verbs: + - get + - list + - watch +- apiGroups: + - config.istio.io + - networking.istio.io + - authentication.istio.io + - rbac.istio.io + - security.istio.io + resources: ["*"] + verbs: + - get + - list + - watch +- apiGroups: ["monitoring.kiali.io"] + resources: + - monitoringdashboards + verbs: + - get + - list diff --git a/istio-1.5.0/install/kubernetes/helm/istio/charts/kiali/templates/clusterrolebinding.yaml b/istio-1.5.0/install/kubernetes/helm/istio/charts/kiali/templates/clusterrolebinding.yaml new file mode 100644 index 0000000..8817967 --- /dev/null +++ b/istio-1.5.0/install/kubernetes/helm/istio/charts/kiali/templates/clusterrolebinding.yaml @@ -0,0 +1,37 @@ +{{- if not .Values.dashboard.viewOnlyMode }} +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: istio-kiali-admin-role-binding-{{ .Release.Namespace }} + labels: + app: {{ template "kiali.name" . }} + chart: {{ template "kiali.chart" . }} + heritage: {{ .Release.Service }} + release: {{ .Release.Name }} +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: kiali +subjects: +- kind: ServiceAccount + name: kiali-service-account + namespace: {{ .Release.Namespace }} +{{- else }} +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: istio-kiali-viewer-role-binding-{{ .Release.Namespace }} + labels: + app: {{ template "kiali.name" . }} + chart: {{ template "kiali.chart" . }} + heritage: {{ .Release.Service }} + release: {{ .Release.Name }} +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: kiali-viewer +subjects: +- kind: ServiceAccount + name: kiali-service-account + namespace: {{ .Release.Namespace }} +{{- end }} diff --git a/istio-1.5.0/install/kubernetes/helm/istio/charts/kiali/templates/configmap.yaml b/istio-1.5.0/install/kubernetes/helm/istio/charts/kiali/templates/configmap.yaml new file mode 100644 index 0000000..8ee130e --- /dev/null +++ b/istio-1.5.0/install/kubernetes/helm/istio/charts/kiali/templates/configmap.yaml @@ -0,0 +1,42 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: kiali + namespace: {{ .Release.Namespace }} + labels: + app: {{ template "kiali.name" . }} + chart: {{ template "kiali.chart" . }} + heritage: {{ .Release.Service }} + release: {{ .Release.Name }} +data: + config.yaml: | + istio_namespace: {{ .Release.Namespace }} + deployment: + accessible_namespaces: ['**'] + auth: + strategy: {{ .Values.dashboard.auth.strategy }} +{{- if eq .Values.dashboard.auth.strategy "ldap" }} + ldap: +{{- with .Values.dashboard.auth.strategy.ldap }} +{{ toYaml . | indent 8 }} +{{- end }} +{{- end }} + server: + port: 20001 +{{- if .Values.contextPath }} + web_root: {{ .Values.contextPath }} +{{- end }} + external_services: + tracing: + url: {{ .Values.dashboard.jaegerURL }} + in_cluster_url: {{ .Values.dashboard.jaegerInClusterURL }} + grafana: + url: {{ .Values.dashboard.grafanaURL }} + in_cluster_url: {{ .Values.dashboard.grafanaInClusterURL }} + prometheus: + url: {{ .Values.prometheusAddr }} +{{- if .Values.security.enabled }} + identity: + cert_file: {{ .Values.security.cert_file }} + private_key_file: {{ .Values.security.private_key_file }} +{{- end}} diff --git a/istio-1.5.0/install/kubernetes/helm/istio/charts/kiali/templates/demosecret.yaml b/istio-1.5.0/install/kubernetes/helm/istio/charts/kiali/templates/demosecret.yaml new file mode 100644 index 0000000..ad44298 --- /dev/null +++ b/istio-1.5.0/install/kubernetes/helm/istio/charts/kiali/templates/demosecret.yaml @@ -0,0 +1,16 @@ +{{- if .Values.createDemoSecret }} +apiVersion: v1 +kind: Secret +metadata: + name: {{ .Values.dashboard.secretName }} + namespace: {{ .Release.Namespace }} + labels: + app: {{ template "kiali.name" . }} + chart: {{ template "kiali.chart" . }} + heritage: {{ .Release.Service }} + release: {{ .Release.Name }} +type: Opaque +data: + username: YWRtaW4= # admin + passphrase: YWRtaW4= # admin +{{- end }} diff --git a/istio-1.5.0/install/kubernetes/helm/istio/charts/kiali/templates/deployment.yaml b/istio-1.5.0/install/kubernetes/helm/istio/charts/kiali/templates/deployment.yaml new file mode 100644 index 0000000..ed9009e --- /dev/null +++ b/istio-1.5.0/install/kubernetes/helm/istio/charts/kiali/templates/deployment.yaml @@ -0,0 +1,103 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: kiali + namespace: {{ .Release.Namespace }} + labels: + app: {{ template "kiali.name" . }} + chart: {{ template "kiali.chart" . }} + heritage: {{ .Release.Service }} + release: {{ .Release.Name }} +spec: + replicas: {{ .Values.replicaCount }} + selector: + matchLabels: + app: kiali + template: + metadata: + name: kiali + labels: + app: kiali + chart: {{ template "kiali.chart" . }} + heritage: {{ .Release.Service }} + release: {{ .Release.Name }} + annotations: + sidecar.istio.io/inject: "false" + scheduler.alpha.kubernetes.io/critical-pod: "" + prometheus.io/scrape: "true" + prometheus.io/port: "9090" + kiali.io/runtimes: go,kiali + {{- if .Values.podAnnotations }} +{{ toYaml .Values.podAnnotations | indent 8 }} + {{- end }} + spec: + serviceAccountName: kiali-service-account +{{- if .Values.global.priorityClassName }} + priorityClassName: "{{ .Values.global.priorityClassName }}" +{{- end }} + containers: + - image: "{{ .Values.hub }}/{{ .Values.image }}:{{ .Values.tag }}" + imagePullPolicy: {{ .Values.global.imagePullPolicy }} + name: kiali + command: + - "/opt/kiali/kiali" + - "-config" + - "/kiali-configuration/config.yaml" + - "-v" + - "3" + readinessProbe: + httpGet: + path: {{ .Values.contextPath }}/healthz + port: 20001 + scheme: {{ if .Values.security.enabled }} 'HTTPS' {{ else }} 'HTTP' {{ end }} + initialDelaySeconds: 5 + periodSeconds: 30 + livenessProbe: + httpGet: + path: {{ .Values.contextPath }}/healthz + port: 20001 + scheme: {{ if .Values.security.enabled }} 'HTTPS' {{ else }} 'HTTP' {{ end }} + initialDelaySeconds: 5 + periodSeconds: 30 + env: + - name: ACTIVE_NAMESPACE + valueFrom: + fieldRef: + fieldPath: metadata.namespace + volumeMounts: + - name: kiali-configuration + mountPath: "/kiali-configuration" + - name: kiali-cert + mountPath: "/kiali-cert" + - name: kiali-secret + mountPath: "/kiali-secret" + resources: +{{- if .Values.resources }} +{{ toYaml .Values.resources | indent 10 }} +{{- else }} +{{ toYaml .Values.global.defaultResources | indent 10 }} +{{- end }} + volumes: + - name: kiali-configuration + configMap: + name: kiali + - name: kiali-cert + secret: + secretName: istio.kiali-service-account +{{- if not .Values.security.enabled }} + optional: true +{{- end }} + - name: kiali-secret + secret: + secretName: {{ .Values.dashboard.secretName }} + optional: true + affinity: + {{- include "nodeaffinity" . | indent 6 }} + {{- include "podAntiAffinity" . | indent 6 }} + {{- if .Values.tolerations }} + tolerations: +{{ toYaml .Values.tolerations | indent 6 }} + {{- else if .Values.global.defaultTolerations }} + tolerations: +{{ toYaml .Values.global.defaultTolerations | indent 6 }} + {{- end }} diff --git a/istio-1.5.0/install/kubernetes/helm/istio/charts/kiali/templates/ingress.yaml b/istio-1.5.0/install/kubernetes/helm/istio/charts/kiali/templates/ingress.yaml new file mode 100644 index 0000000..2e2a0de --- /dev/null +++ b/istio-1.5.0/install/kubernetes/helm/istio/charts/kiali/templates/ingress.yaml @@ -0,0 +1,40 @@ +{{- if .Values.ingress.enabled -}} +apiVersion: extensions/v1beta1 +kind: Ingress +metadata: + name: kiali + namespace: {{ .Release.Namespace }} + labels: + app: {{ template "kiali.name" . }} + chart: {{ template "kiali.chart" . }} + heritage: {{ .Release.Service }} + release: {{ .Release.Name }} + annotations: + {{- range $key, $value := .Values.ingress.annotations }} + {{ $key }}: {{ $value | quote }} + {{- end }} +spec: + rules: +{{- if .Values.ingress.hosts }} + {{- range $host := .Values.ingress.hosts }} + - host: {{ $host }} + http: + paths: + - path: {{ if $.Values.contextPath }} {{ $.Values.contextPath }} {{ else }} / {{ end }} + backend: + serviceName: kiali + servicePort: 20001 + {{- end -}} +{{- else }} + - http: + paths: + - path: {{ if .Values.contextPath }} {{ .Values.contextPath }} {{ else }} / {{ end }} + backend: + serviceName: kiali + servicePort: 20001 +{{- end }} + {{- if .Values.ingress.tls }} + tls: +{{ toYaml .Values.ingress.tls | indent 4 }} + {{- end -}} +{{- end -}} diff --git a/istio-1.5.0/install/kubernetes/helm/istio/charts/kiali/templates/service.yaml b/istio-1.5.0/install/kubernetes/helm/istio/charts/kiali/templates/service.yaml new file mode 100644 index 0000000..1aa79bf --- /dev/null +++ b/istio-1.5.0/install/kubernetes/helm/istio/charts/kiali/templates/service.yaml @@ -0,0 +1,17 @@ +apiVersion: v1 +kind: Service +metadata: + name: kiali + namespace: {{ .Release.Namespace }} + labels: + app: {{ template "kiali.name" . }} + chart: {{ template "kiali.chart" . }} + heritage: {{ .Release.Service }} + release: {{ .Release.Name }} +spec: + ports: + - name: http-kiali + protocol: TCP + port: 20001 + selector: + app: kiali diff --git a/istio-1.5.0/install/kubernetes/helm/istio/charts/kiali/templates/serviceaccount.yaml b/istio-1.5.0/install/kubernetes/helm/istio/charts/kiali/templates/serviceaccount.yaml new file mode 100644 index 0000000..2ae38a1 --- /dev/null +++ b/istio-1.5.0/install/kubernetes/helm/istio/charts/kiali/templates/serviceaccount.yaml @@ -0,0 +1,16 @@ +apiVersion: v1 +kind: ServiceAccount +{{- if .Values.global.imagePullSecrets }} +imagePullSecrets: +{{- range .Values.global.imagePullSecrets }} + - name: {{ . }} +{{- end }} +{{- end }} +metadata: + name: kiali-service-account + namespace: {{ .Release.Namespace }} + labels: + app: {{ template "kiali.name" . }} + chart: {{ template "kiali.chart" . }} + heritage: {{ .Release.Service }} + release: {{ .Release.Name }} diff --git a/istio-1.5.0/install/kubernetes/helm/istio/charts/kiali/templates/tests/test-kiali-connection.yaml b/istio-1.5.0/install/kubernetes/helm/istio/charts/kiali/templates/tests/test-kiali-connection.yaml new file mode 100644 index 0000000..d798f7f --- /dev/null +++ b/istio-1.5.0/install/kubernetes/helm/istio/charts/kiali/templates/tests/test-kiali-connection.yaml @@ -0,0 +1,37 @@ +{{- if .Values.global.enableHelmTest }} +apiVersion: v1 +kind: Pod +metadata: + name: {{ template "kiali.fullname" . }}-test + namespace: {{ .Release.Namespace }} + labels: + app: kiali-test + chart: {{ template "kiali.chart" . }} + release: {{ .Release.Name }} + heritage: {{ .Release.Service }} + istio: kiali + annotations: + sidecar.istio.io/inject: "false" + helm.sh/hook: test-success +spec: +{{- if .Values.global.priorityClassName }} + priorityClassName: "{{ .Values.global.priorityClassName }}" +{{- end }} + containers: + - name: "{{ template "kiali.fullname" . }}-test" + image: pstauffer/curl:v1.0.3 + imagePullPolicy: "{{ .Values.global.imagePullPolicy }}" + command: ['curl'] + args: ['http://kiali:20001'] + restartPolicy: Never + affinity: + {{- include "nodeaffinity" . | indent 4 }} + {{- include "podAntiAffinity" . | indent 4 }} + {{- if .Values.tolerations }} + tolerations: +{{ toYaml .Values.tolerations | indent 2 }} + {{- else if .Values.global.defaultTolerations }} + tolerations: +{{ toYaml .Values.global.defaultTolerations | indent 2 }} + {{- end }} +{{- end }} diff --git a/istio-1.5.0/install/kubernetes/helm/istio/charts/kiali/values.yaml b/istio-1.5.0/install/kubernetes/helm/istio/charts/kiali/values.yaml new file mode 100644 index 0000000..3818e84 --- /dev/null +++ b/istio-1.5.0/install/kubernetes/helm/istio/charts/kiali/values.yaml @@ -0,0 +1,80 @@ +# +# addon kiali +# +enabled: false # Note that if using the demo or demo-auth yaml when installing via Helm, this default will be `true`. +replicaCount: 1 +hub: quay.io/kiali +image: kiali +tag: v1.9 +contextPath: /kiali # The root context path to access the Kiali UI. +nodeSelector: {} +tolerations: [] +podAnnotations: {} + +# Specify the pod anti-affinity that allows you to constrain which nodes +# your pod is eligible to be scheduled based on labels on pods that are +# already running on the node rather than based on labels on nodes. +# There are currently two types of anti-affinity: +# "requiredDuringSchedulingIgnoredDuringExecution" +# "preferredDuringSchedulingIgnoredDuringExecution" +# which denote "hard" vs. "soft" requirements, you can define your values +# in "podAntiAffinityLabelSelector" and "podAntiAffinityTermLabelSelector" +# correspondingly. +# For example: +# podAntiAffinityLabelSelector: +# - key: security +# operator: In +# values: S1,S2 +# topologyKey: "kubernetes.io/hostname" +# This pod anti-affinity rule says that the pod requires not to be scheduled +# onto a node if that node is already running a pod with label having key +# "security" and value "S1". +podAntiAffinityLabelSelector: [] +podAntiAffinityTermLabelSelector: [] + +ingress: + enabled: false + ## Used to create an Ingress record. + hosts: + - kiali.local + annotations: {} + # kubernetes.io/ingress.class: nginx + # kubernetes.io/tls-acme: "true" + tls: + # Secrets must be manually created in the namespace. + # - secretName: kiali-tls + # hosts: + # - kiali.local + +dashboard: + auth: + strategy: login # Can be anonymous, login, openshift, or ldap + # ldap: # This is required to use the ldap strategy + # ldap_base: "DC=example,DC=com" + # ldap_bind_dn: "CN={USERID},OU=xyz,OU=Users,OU=Accounts,DC=example,DC=com" + # ldap_group_filter: "(cn=%s)" + # ldap_host: "ldap-service.ldap-namespace" + # ldap_insecure_skip_verify: true + # ldap_mail_id_key: "mail" + # ldap_member_of_key: "memberOf" + # ldap_port: 123 + # ldap_role_filter: ".*xyz.*" + # ldap_search_filter: "(&(name={USERID}))" + # ldap_use_ssl: false + # ldap_user_filter: "(cn=%s)" + # ldap_user_id_key: "cn" + secretName: kiali # You must create a secret with this name - one is not provided out-of-box. + viewOnlyMode: false # Bind the service account to a role with only read access + grafanaURL: # If you have Grafana installed and it is accessible to client browsers, then set this to its external URL. Kiali will redirect users to this URL when Grafana metrics are to be shown. + grafanaInClusterURL: "http://grafana:3000" # In Kubernetes cluster with ELB in front this option is needed, since public IP of ELB is not reachable from inside the cluster + jaegerURL: # If you have Jaeger installed and it is accessible to client browsers, then set this property to its external URL. Kiali will redirect users to this URL when Jaeger tracing is to be shown. + jaegerInClusterURL: "http://tracing/jaeger" # If you have Jaeger installed and accessible from Kiali pod (typically in cluster), then set this property to enable more tracing charts within Kiali. +prometheusAddr: http://prometheus:9090 + +# When true, a secret will be created with a default username and password. Useful for demos. +createDemoSecret: false + +security: + enabled: false + cert_file: /kiali-cert/cert-chain.pem + private_key_file: /kiali-cert/key.pem diff --git a/istio-1.5.0/install/kubernetes/helm/istio/charts/mixer/Chart.yaml b/istio-1.5.0/install/kubernetes/helm/istio/charts/mixer/Chart.yaml new file mode 100644 index 0000000..d9fa42e --- /dev/null +++ b/istio-1.5.0/install/kubernetes/helm/istio/charts/mixer/Chart.yaml @@ -0,0 +1,13 @@ +apiVersion: v1 +name: mixer +version: 1.5.0 +appVersion: 1.5.0 +tillerVersion: ">=2.7.2" +description: Helm chart for mixer deployment +keywords: + - istio + - mixer +sources: + - http://github.com/istio/istio +engine: gotpl +icon: https://istio.io/favicons/android-192x192.png diff --git a/istio-1.5.0/install/kubernetes/helm/istio/charts/mixer/templates/_helpers.tpl b/istio-1.5.0/install/kubernetes/helm/istio/charts/mixer/templates/_helpers.tpl new file mode 100644 index 0000000..dac6da0 --- /dev/null +++ b/istio-1.5.0/install/kubernetes/helm/istio/charts/mixer/templates/_helpers.tpl @@ -0,0 +1,32 @@ +{{/* vim: set filetype=mustache: */}} +{{/* +Expand the name of the chart. +*/}} +{{- define "mixer.name" -}} +{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" -}} +{{- end -}} + +{{/* +Create a default fully qualified app name. +We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). +If release name contains chart name it will be used as a full name. +*/}} +{{- define "mixer.fullname" -}} +{{- if .Values.fullnameOverride -}} +{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" -}} +{{- else -}} +{{- $name := default .Chart.Name .Values.nameOverride -}} +{{- if contains $name .Release.Name -}} +{{- .Release.Name | trunc 63 | trimSuffix "-" -}} +{{- else -}} +{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" -}} +{{- end -}} +{{- end -}} +{{- end -}} + +{{/* +Create chart name and version as used by the chart label. +*/}} +{{- define "mixer.chart" -}} +{{- .Chart.Name | trunc 63 | trimSuffix "-" -}} +{{- end -}} diff --git a/istio-1.5.0/install/kubernetes/helm/istio/charts/mixer/templates/autoscale.yaml b/istio-1.5.0/install/kubernetes/helm/istio/charts/mixer/templates/autoscale.yaml new file mode 100644 index 0000000..377b47d --- /dev/null +++ b/istio-1.5.0/install/kubernetes/helm/istio/charts/mixer/templates/autoscale.yaml @@ -0,0 +1,29 @@ +{{- range $key, $spec := .Values }} +{{- if or (eq $key "policy") (eq $key "telemetry") }} +{{- if and $spec.enabled $spec.autoscaleEnabled $spec.autoscaleMin $spec.autoscaleMax }} +apiVersion: autoscaling/v2beta1 +kind: HorizontalPodAutoscaler +metadata: + name: istio-{{ $key }} + namespace: {{ $.Release.Namespace }} + labels: + app: {{ template "mixer.name" $ }} + chart: {{ template "mixer.chart" $ }} + heritage: {{ $.Release.Service }} + release: {{ $.Release.Name }} +spec: + maxReplicas: {{ $spec.autoscaleMax }} + minReplicas: {{ $spec.autoscaleMin }} + scaleTargetRef: + apiVersion: apps/v1 + kind: Deployment + name: istio-{{ $key }} + metrics: + - type: Resource + resource: + name: cpu + targetAverageUtilization: {{ $spec.cpu.targetAverageUtilization }} +--- +{{- end }} +{{- end }} +{{- end }} diff --git a/istio-1.5.0/install/kubernetes/helm/istio/charts/mixer/templates/clusterrole.yaml b/istio-1.5.0/install/kubernetes/helm/istio/charts/mixer/templates/clusterrole.yaml new file mode 100644 index 0000000..3d7438f --- /dev/null +++ b/istio-1.5.0/install/kubernetes/helm/istio/charts/mixer/templates/clusterrole.yaml @@ -0,0 +1,24 @@ +{{- if or (.Values.policy.enabled) (.Values.telemetry.enabled) }} +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: istio-mixer-{{ .Release.Namespace }} + labels: + app: {{ template "mixer.name" . }} + chart: {{ template "mixer.chart" . }} + heritage: {{ .Release.Service }} + release: {{ .Release.Name }} +rules: +- apiGroups: ["config.istio.io"] # istio CRD watcher + resources: ["*"] + verbs: ["create", "get", "list", "watch", "patch"] +- apiGroups: ["apiextensions.k8s.io"] + resources: ["customresourcedefinitions"] + verbs: ["get", "list", "watch"] +- apiGroups: [""] + resources: ["configmaps", "endpoints", "pods", "services", "namespaces", "secrets", "replicationcontrollers"] + verbs: ["get", "list", "watch"] +- apiGroups: ["extensions", "apps"] + resources: ["replicasets"] + verbs: ["get", "list", "watch"] +{{- end }} diff --git a/istio-1.5.0/install/kubernetes/helm/istio/charts/mixer/templates/clusterrolebinding.yaml b/istio-1.5.0/install/kubernetes/helm/istio/charts/mixer/templates/clusterrolebinding.yaml new file mode 100644 index 0000000..773e68b --- /dev/null +++ b/istio-1.5.0/install/kubernetes/helm/istio/charts/mixer/templates/clusterrolebinding.yaml @@ -0,0 +1,19 @@ +{{- if or (.Values.policy.enabled) (.Values.telemetry.enabled) }} +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: istio-mixer-admin-role-binding-{{ .Release.Namespace }} + labels: + app: {{ template "mixer.name" . }} + chart: {{ template "mixer.chart" . }} + heritage: {{ .Release.Service }} + release: {{ .Release.Name }} +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: istio-mixer-{{ .Release.Namespace }} +subjects: + - kind: ServiceAccount + name: istio-mixer-service-account + namespace: {{ .Release.Namespace }} +{{- end }} diff --git a/istio-1.5.0/install/kubernetes/helm/istio/charts/mixer/templates/config.yaml b/istio-1.5.0/install/kubernetes/helm/istio/charts/mixer/templates/config.yaml new file mode 100644 index 0000000..e2ef31d --- /dev/null +++ b/istio-1.5.0/install/kubernetes/helm/istio/charts/mixer/templates/config.yaml @@ -0,0 +1,1084 @@ +{{- if or (.Values.policy.enabled) (.Values.telemetry.enabled) }} +apiVersion: "config.istio.io/v1alpha2" +kind: attributemanifest +metadata: + name: istioproxy + namespace: {{ .Release.Namespace }} + labels: + app: {{ template "mixer.name" . }} + chart: {{ template "mixer.chart" . }} + heritage: {{ .Release.Service }} + release: {{ .Release.Name }} +spec: + attributes: + origin.ip: + valueType: IP_ADDRESS + origin.uid: + valueType: STRING + origin.user: + valueType: STRING + request.headers: + valueType: STRING_MAP + request.id: + valueType: STRING + request.host: + valueType: STRING + request.method: + valueType: STRING + request.path: + valueType: STRING + request.url_path: + valueType: STRING + request.query_params: + valueType: STRING_MAP + request.reason: + valueType: STRING + request.referer: + valueType: STRING + request.scheme: + valueType: STRING + request.total_size: + valueType: INT64 + request.size: + valueType: INT64 + request.time: + valueType: TIMESTAMP + request.useragent: + valueType: STRING + response.code: + valueType: INT64 + response.duration: + valueType: DURATION + response.headers: + valueType: STRING_MAP + response.total_size: + valueType: INT64 + response.size: + valueType: INT64 + response.time: + valueType: TIMESTAMP + response.grpc_status: + valueType: STRING + response.grpc_message: + valueType: STRING + source.uid: + valueType: STRING + source.user: # DEPRECATED + valueType: STRING + source.principal: + valueType: STRING + destination.uid: + valueType: STRING + destination.principal: + valueType: STRING + destination.port: + valueType: INT64 + connection.event: + valueType: STRING + connection.id: + valueType: STRING + connection.received.bytes: + valueType: INT64 + connection.received.bytes_total: + valueType: INT64 + connection.sent.bytes: + valueType: INT64 + connection.sent.bytes_total: + valueType: INT64 + connection.duration: + valueType: DURATION + connection.mtls: + valueType: BOOL + connection.requested_server_name: + valueType: STRING + context.protocol: + valueType: STRING + context.proxy_error_code: + valueType: STRING + context.timestamp: + valueType: TIMESTAMP + context.time: + valueType: TIMESTAMP + # Deprecated, kept for compatibility + context.reporter.local: + valueType: BOOL + context.reporter.kind: + valueType: STRING + context.reporter.uid: + valueType: STRING + api.service: + valueType: STRING + api.version: + valueType: STRING + api.operation: + valueType: STRING + api.protocol: + valueType: STRING + request.auth.principal: + valueType: STRING + request.auth.audiences: + valueType: STRING + request.auth.presenter: + valueType: STRING + request.auth.claims: + valueType: STRING_MAP + request.auth.raw_claims: + valueType: STRING + request.api_key: + valueType: STRING + rbac.permissive.response_code: + valueType: STRING + rbac.permissive.effective_policy_id: + valueType: STRING + check.error_code: + valueType: INT64 + check.error_message: + valueType: STRING + check.cache_hit: + valueType: BOOL + quota.cache_hit: + valueType: BOOL + context.proxy_version: + valueType: STRING + +--- +apiVersion: "config.istio.io/v1alpha2" +kind: attributemanifest +metadata: + name: kubernetes + namespace: {{ .Release.Namespace }} + labels: + app: {{ template "mixer.name" . }} + chart: {{ template "mixer.chart" . }} + heritage: {{ .Release.Service }} + release: {{ .Release.Name }} +spec: + attributes: + source.ip: + valueType: IP_ADDRESS + source.labels: + valueType: STRING_MAP + source.metadata: + valueType: STRING_MAP + source.name: + valueType: STRING + source.namespace: + valueType: STRING + source.owner: + valueType: STRING + source.serviceAccount: + valueType: STRING + source.services: + valueType: STRING + source.workload.uid: + valueType: STRING + source.workload.name: + valueType: STRING + source.workload.namespace: + valueType: STRING + destination.ip: + valueType: IP_ADDRESS + destination.labels: + valueType: STRING_MAP + destination.metadata: + valueType: STRING_MAP + destination.owner: + valueType: STRING + destination.name: + valueType: STRING + destination.container.name: + valueType: STRING + destination.namespace: + valueType: STRING + destination.service.uid: + valueType: STRING + destination.service.name: + valueType: STRING + destination.service.namespace: + valueType: STRING + destination.service.host: + valueType: STRING + destination.serviceAccount: + valueType: STRING + destination.workload.uid: + valueType: STRING + destination.workload.name: + valueType: STRING + destination.workload.namespace: + valueType: STRING +--- +{{- if and .Values.adapters.stdio.enabled .Values.telemetry.enabled }} +apiVersion: "config.istio.io/v1alpha2" +kind: handler +metadata: + name: stdio + namespace: {{ .Release.Namespace }} + labels: + app: {{ template "mixer.name" . }} + chart: {{ template "mixer.chart" . }} + heritage: {{ .Release.Service }} + release: {{ .Release.Name }} +spec: + compiledAdapter: stdio + params: + outputAsJson: {{ .Values.adapters.stdio.outputAsJson }} +--- +apiVersion: "config.istio.io/v1alpha2" +kind: instance +metadata: + name: accesslog + namespace: {{ .Release.Namespace }} + labels: + app: {{ template "mixer.name" . }} + chart: {{ template "mixer.chart" . }} + heritage: {{ .Release.Service }} + release: {{ .Release.Name }} +spec: + compiledTemplate: logentry + params: + severity: '"Info"' + timestamp: request.time + variables: + sourceIp: source.ip | ip("0.0.0.0") + sourceApp: source.labels["app"] | "" + sourcePrincipal: source.principal | "" + sourceName: source.name | "" + sourceWorkload: source.workload.name | "" + sourceNamespace: source.namespace | "" + sourceOwner: source.owner | "" + destinationApp: destination.labels["app"] | "" + destinationIp: destination.ip | ip("0.0.0.0") + destinationServiceHost: destination.service.host | request.host | "" + destinationWorkload: destination.workload.name | "" + destinationName: destination.name | "" + destinationNamespace: destination.namespace | "" + destinationOwner: destination.owner | "" + destinationPrincipal: destination.principal | "" + apiClaims: request.auth.raw_claims | "" + apiKey: request.api_key | request.headers["x-api-key"] | "" + protocol: api.protocol | context.protocol | "http" + method: request.method | "" + url: request.path | "" + responseCode: response.code | 0 + responseFlags: context.proxy_error_code | "" + responseSize: response.size | 0 + permissiveResponseCode: rbac.permissive.response_code | "none" + permissiveResponsePolicyID: rbac.permissive.effective_policy_id | "none" + requestSize: request.size | 0 + requestId: request.headers["x-request-id"] | "" + clientTraceId: request.headers["x-client-trace-id"] | "" + latency: response.duration | "0ms" + connection_security_policy: conditional((context.reporter.kind | "inbound") == "outbound", "unknown", conditional(connection.mtls | false, "mutual_tls", "none")) + requestedServerName: connection.requested_server_name | "" + userAgent: request.useragent | "" + responseTimestamp: response.time + receivedBytes: request.total_size | 0 + sentBytes: response.total_size | 0 + referer: request.referer | "" + httpAuthority: request.headers[":authority"] | request.host | "" + xForwardedFor: request.headers["x-forwarded-for"] | "0.0.0.0" + reporter: conditional((context.reporter.kind | "inbound") == "outbound", "source", "destination") + grpcStatus: response.grpc_status | "" + grpcMessage: response.grpc_message | "" + monitored_resource_type: '"global"' +--- +apiVersion: "config.istio.io/v1alpha2" +kind: instance +metadata: + name: tcpaccesslog + namespace: {{ .Release.Namespace }} + labels: + app: {{ template "mixer.name" . }} + chart: {{ template "mixer.chart" . }} + heritage: {{ .Release.Service }} + release: {{ .Release.Name }} +spec: + compiledTemplate: logentry + params: + severity: '"Info"' + timestamp: context.time | timestamp("2017-01-01T00:00:00Z") + variables: + connectionEvent: connection.event | "" + sourceIp: source.ip | ip("0.0.0.0") + sourceApp: source.labels["app"] | "" + sourcePrincipal: source.principal | "" + sourceName: source.name | "" + sourceWorkload: source.workload.name | "" + sourceNamespace: source.namespace | "" + sourceOwner: source.owner | "" + destinationApp: destination.labels["app"] | "" + destinationIp: destination.ip | ip("0.0.0.0") + destinationServiceHost: destination.service.host | "" + destinationWorkload: destination.workload.name | "" + destinationName: destination.name | "" + destinationNamespace: destination.namespace | "" + destinationOwner: destination.owner | "" + destinationPrincipal: destination.principal | "" + protocol: context.protocol | "tcp" + connectionDuration: connection.duration | "0ms" + connection_security_policy: conditional((context.reporter.kind | "inbound") == "outbound", "unknown", conditional(connection.mtls | false, "mutual_tls", "none")) + requestedServerName: connection.requested_server_name | "" + receivedBytes: connection.received.bytes | 0 + sentBytes: connection.sent.bytes | 0 + totalReceivedBytes: connection.received.bytes_total | 0 + totalSentBytes: connection.sent.bytes_total | 0 + reporter: conditional((context.reporter.kind | "inbound") == "outbound", "source", "destination") + responseFlags: context.proxy_error_code | "" + monitored_resource_type: '"global"' +--- +apiVersion: "config.istio.io/v1alpha2" +kind: rule +metadata: + name: stdio + namespace: {{ .Release.Namespace }} + labels: + app: {{ template "mixer.name" . }} + chart: {{ template "mixer.chart" . }} + heritage: {{ .Release.Service }} + release: {{ .Release.Name }} +spec: + match: context.protocol == "http" || context.protocol == "grpc" + actions: + - handler: stdio + instances: + - accesslog +--- +apiVersion: "config.istio.io/v1alpha2" +kind: rule +metadata: + name: stdiotcp + namespace: {{ .Release.Namespace }} + labels: + app: {{ template "mixer.name" . }} + chart: {{ template "mixer.chart" . }} + heritage: {{ .Release.Service }} + release: {{ .Release.Name }} +spec: + match: context.protocol == "tcp" + actions: + - handler: stdio + instances: + - tcpaccesslog +{{- end }} +--- +{{- if and .Values.adapters.prometheus.enabled .Values.telemetry.enabled }} +apiVersion: "config.istio.io/v1alpha2" +kind: instance +metadata: + name: requestcount + namespace: {{ .Release.Namespace }} + labels: + app: {{ template "mixer.name" . }} + chart: {{ template "mixer.chart" . }} + heritage: {{ .Release.Service }} + release: {{ .Release.Name }} +spec: + compiledTemplate: metric + params: + value: "1" + dimensions: + reporter: conditional((context.reporter.kind | "inbound") == "outbound", "source", "destination") + source_workload: source.workload.name | "unknown" + source_workload_namespace: source.workload.namespace | "unknown" + source_principal: source.principal | "unknown" + source_app: source.labels["app"] | "unknown" + source_version: source.labels["version"] | "unknown" + destination_workload: destination.workload.name | "unknown" + destination_workload_namespace: destination.workload.namespace | "unknown" + destination_principal: destination.principal | "unknown" + destination_app: destination.labels["app"] | "unknown" + destination_version: destination.labels["version"] | "unknown" + destination_service: destination.service.host | conditional((destination.service.name | "unknown") == "unknown", "unknown", request.host) + destination_service_name: destination.service.name | "unknown" + destination_service_namespace: destination.service.namespace | "unknown" + request_protocol: api.protocol | context.protocol | "unknown" + response_code: response.code | 200 + grpc_response_status: response.grpc_status | "" + response_flags: context.proxy_error_code | "-" + connection_security_policy: conditional((context.reporter.kind | "inbound") == "outbound", "unknown", conditional(connection.mtls | false, "mutual_tls", "none")) + monitored_resource_type: '"UNSPECIFIED"' +--- +apiVersion: "config.istio.io/v1alpha2" +kind: instance +metadata: + name: requestduration + namespace: {{ .Release.Namespace }} + labels: + app: {{ template "mixer.name" . }} + chart: {{ template "mixer.chart" . }} + heritage: {{ .Release.Service }} + release: {{ .Release.Name }} +spec: + compiledTemplate: metric + params: + value: response.duration | "0ms" + dimensions: + reporter: conditional((context.reporter.kind | "inbound") == "outbound", "source", "destination") + source_workload: source.workload.name | "unknown" + source_workload_namespace: source.workload.namespace | "unknown" + source_principal: source.principal | "unknown" + source_app: source.labels["app"] | "unknown" + source_version: source.labels["version"] | "unknown" + destination_workload: destination.workload.name | "unknown" + destination_workload_namespace: destination.workload.namespace | "unknown" + destination_principal: destination.principal | "unknown" + destination_app: destination.labels["app"] | "unknown" + destination_version: destination.labels["version"] | "unknown" + destination_service: destination.service.host | conditional((destination.service.name | "unknown") == "unknown", "unknown", request.host) + destination_service_name: destination.service.name | "unknown" + destination_service_namespace: destination.service.namespace | "unknown" + request_protocol: api.protocol | context.protocol | "unknown" + response_code: response.code | 200 + grpc_response_status: response.grpc_status | "" + response_flags: context.proxy_error_code | "-" + connection_security_policy: conditional((context.reporter.kind | "inbound") == "outbound", "unknown", conditional(connection.mtls | false, "mutual_tls", "none")) + monitored_resource_type: '"UNSPECIFIED"' +--- +apiVersion: "config.istio.io/v1alpha2" +kind: instance +metadata: + name: requestsize + namespace: {{ .Release.Namespace }} + labels: + app: {{ template "mixer.name" . }} + chart: {{ template "mixer.chart" . }} + heritage: {{ .Release.Service }} + release: {{ .Release.Name }} +spec: + compiledTemplate: metric + params: + value: request.size | 0 + dimensions: + reporter: conditional((context.reporter.kind | "inbound") == "outbound", "source", "destination") + source_workload: source.workload.name | "unknown" + source_workload_namespace: source.workload.namespace | "unknown" + source_principal: source.principal | "unknown" + source_app: source.labels["app"] | "unknown" + source_version: source.labels["version"] | "unknown" + destination_workload: destination.workload.name | "unknown" + destination_workload_namespace: destination.workload.namespace | "unknown" + destination_principal: destination.principal | "unknown" + destination_app: destination.labels["app"] | "unknown" + destination_version: destination.labels["version"] | "unknown" + destination_service: destination.service.host | conditional((destination.service.name | "unknown") == "unknown", "unknown", request.host) + destination_service_name: destination.service.name | "unknown" + destination_service_namespace: destination.service.namespace | "unknown" + request_protocol: api.protocol | context.protocol | "unknown" + response_code: response.code | 200 + grpc_response_status: response.grpc_status | "" + response_flags: context.proxy_error_code | "-" + connection_security_policy: conditional((context.reporter.kind | "inbound") == "outbound", "unknown", conditional(connection.mtls | false, "mutual_tls", "none")) + monitored_resource_type: '"UNSPECIFIED"' +--- +apiVersion: "config.istio.io/v1alpha2" +kind: instance +metadata: + name: responsesize + namespace: {{ .Release.Namespace }} + labels: + app: {{ template "mixer.name" . }} + chart: {{ template "mixer.chart" . }} + heritage: {{ .Release.Service }} + release: {{ .Release.Name }} +spec: + compiledTemplate: metric + params: + value: response.size | 0 + dimensions: + reporter: conditional((context.reporter.kind | "inbound") == "outbound", "source", "destination") + source_workload: source.workload.name | "unknown" + source_workload_namespace: source.workload.namespace | "unknown" + source_principal: source.principal | "unknown" + source_app: source.labels["app"] | "unknown" + source_version: source.labels["version"] | "unknown" + destination_workload: destination.workload.name | "unknown" + destination_workload_namespace: destination.workload.namespace | "unknown" + destination_principal: destination.principal | "unknown" + destination_app: destination.labels["app"] | "unknown" + destination_version: destination.labels["version"] | "unknown" + destination_service: destination.service.host | conditional((destination.service.name | "unknown") == "unknown", "unknown", request.host) + destination_service_name: destination.service.name | "unknown" + destination_service_namespace: destination.service.namespace | "unknown" + request_protocol: api.protocol | context.protocol | "unknown" + response_code: response.code | 200 + grpc_response_status: response.grpc_status | "" + response_flags: context.proxy_error_code | "-" + connection_security_policy: conditional((context.reporter.kind | "inbound") == "outbound", "unknown", conditional(connection.mtls | false, "mutual_tls", "none")) + monitored_resource_type: '"UNSPECIFIED"' +--- +apiVersion: "config.istio.io/v1alpha2" +kind: instance +metadata: + name: tcpbytesent + namespace: {{ .Release.Namespace }} + labels: + app: {{ template "mixer.name" . }} + chart: {{ template "mixer.chart" . }} + heritage: {{ .Release.Service }} + release: {{ .Release.Name }} +spec: + compiledTemplate: metric + params: + value: connection.sent.bytes | 0 + dimensions: + reporter: conditional((context.reporter.kind | "inbound") == "outbound", "source", "destination") + source_workload: source.workload.name | "unknown" + source_workload_namespace: source.workload.namespace | "unknown" + source_principal: source.principal | "unknown" + source_app: source.labels["app"] | "unknown" + source_version: source.labels["version"] | "unknown" + destination_workload: destination.workload.name | "unknown" + destination_workload_namespace: destination.workload.namespace | "unknown" + destination_principal: destination.principal | "unknown" + destination_app: destination.labels["app"] | "unknown" + destination_version: destination.labels["version"] | "unknown" + destination_service: destination.service.host | "unknown" + destination_service_name: destination.service.name | "unknown" + destination_service_namespace: destination.service.namespace | "unknown" + connection_security_policy: conditional((context.reporter.kind | "inbound") == "outbound", "unknown", conditional(connection.mtls | false, "mutual_tls", "none")) + response_flags: context.proxy_error_code | "-" + monitored_resource_type: '"UNSPECIFIED"' +--- +apiVersion: "config.istio.io/v1alpha2" +kind: instance +metadata: + name: tcpbytereceived + namespace: {{ .Release.Namespace }} + labels: + app: {{ template "mixer.name" . }} + chart: {{ template "mixer.chart" . }} + heritage: {{ .Release.Service }} + release: {{ .Release.Name }} +spec: + compiledTemplate: metric + params: + value: connection.received.bytes | 0 + dimensions: + reporter: conditional((context.reporter.kind | "inbound") == "outbound", "source", "destination") + source_workload: source.workload.name | "unknown" + source_workload_namespace: source.workload.namespace | "unknown" + source_principal: source.principal | "unknown" + source_app: source.labels["app"] | "unknown" + source_version: source.labels["version"] | "unknown" + destination_workload: destination.workload.name | "unknown" + destination_workload_namespace: destination.workload.namespace | "unknown" + destination_principal: destination.principal | "unknown" + destination_app: destination.labels["app"] | "unknown" + destination_version: destination.labels["version"] | "unknown" + destination_service: destination.service.host | "unknown" + destination_service_name: destination.service.name | "unknown" + destination_service_namespace: destination.service.namespace | "unknown" + connection_security_policy: conditional((context.reporter.kind | "inbound") == "outbound", "unknown", conditional(connection.mtls | false, "mutual_tls", "none")) + response_flags: context.proxy_error_code | "-" + monitored_resource_type: '"UNSPECIFIED"' +--- +apiVersion: "config.istio.io/v1alpha2" +kind: instance +metadata: + name: tcpconnectionsopened + namespace: {{ .Release.Namespace }} + labels: + app: {{ template "mixer.name" . }} + chart: {{ template "mixer.chart" . }} + heritage: {{ .Release.Service }} + release: {{ .Release.Name }} +spec: + compiledTemplate: metric + params: + value: "1" + dimensions: + reporter: conditional((context.reporter.kind | "inbound") == "outbound", "source", "destination") + source_workload: source.workload.name | "unknown" + source_workload_namespace: source.workload.namespace | "unknown" + source_principal: source.principal | "unknown" + source_app: source.labels["app"] | "unknown" + source_version: source.labels["version"] | "unknown" + destination_workload: destination.workload.name | "unknown" + destination_workload_namespace: destination.workload.namespace | "unknown" + destination_principal: destination.principal | "unknown" + destination_app: destination.labels["app"] | "unknown" + destination_version: destination.labels["version"] | "unknown" + destination_service: destination.service.host | "unknown" + destination_service_name: destination.service.name | "unknown" + destination_service_namespace: destination.service.namespace | "unknown" + connection_security_policy: conditional((context.reporter.kind | "inbound") == "outbound", "unknown", conditional(connection.mtls | false, "mutual_tls", "none")) + response_flags: context.proxy_error_code | "-" + monitored_resource_type: '"UNSPECIFIED"' +--- +apiVersion: "config.istio.io/v1alpha2" +kind: instance +metadata: + name: tcpconnectionsclosed + namespace: {{ .Release.Namespace }} + labels: + app: {{ template "mixer.name" . }} + chart: {{ template "mixer.chart" . }} + heritage: {{ .Release.Service }} + release: {{ .Release.Name }} +spec: + compiledTemplate: metric + params: + value: "1" + dimensions: + reporter: conditional((context.reporter.kind | "inbound") == "outbound", "source", "destination") + source_workload: source.workload.name | "unknown" + source_workload_namespace: source.workload.namespace | "unknown" + source_principal: source.principal | "unknown" + source_app: source.labels["app"] | "unknown" + source_version: source.labels["version"] | "unknown" + destination_workload: destination.workload.name | "unknown" + destination_workload_namespace: destination.workload.namespace | "unknown" + destination_principal: destination.principal | "unknown" + destination_app: destination.labels["app"] | "unknown" + destination_version: destination.labels["version"] | "unknown" + destination_service: destination.service.host | "unknown" + destination_service_name: destination.service.name | "unknown" + destination_service_namespace: destination.service.namespace | "unknown" + connection_security_policy: conditional((context.reporter.kind | "inbound") == "outbound", "unknown", conditional(connection.mtls | false, "mutual_tls", "none")) + response_flags: context.proxy_error_code | "-" + monitored_resource_type: '"UNSPECIFIED"' +--- +apiVersion: "config.istio.io/v1alpha2" +kind: handler +metadata: + name: prometheus + namespace: {{ .Release.Namespace }} + labels: + app: {{ template "mixer.name" . }} + chart: {{ template "mixer.chart" . }} + heritage: {{ .Release.Service }} + release: {{ .Release.Name }} +spec: + compiledAdapter: prometheus + params: + metricsExpirationPolicy: + metricsExpiryDuration: "{{ .Values.adapters.prometheus.metricsExpiryDuration }}" + metrics: + - name: requests_total + instance_name: requestcount.instance.{{ .Release.Namespace }} + kind: COUNTER + label_names: + - reporter + - source_app + - source_principal + - source_workload + - source_workload_namespace + - source_version + - destination_app + - destination_principal + - destination_workload + - destination_workload_namespace + - destination_version + - destination_service + - destination_service_name + - destination_service_namespace + - request_protocol + - response_code + - grpc_response_status + - response_flags + - connection_security_policy + - name: request_duration_seconds + instance_name: requestduration.instance.{{ .Release.Namespace }} + kind: DISTRIBUTION + label_names: + - reporter + - source_app + - source_principal + - source_workload + - source_workload_namespace + - source_version + - destination_app + - destination_principal + - destination_workload + - destination_workload_namespace + - destination_version + - destination_service + - destination_service_name + - destination_service_namespace + - request_protocol + - response_code + - grpc_response_status + - response_flags + - connection_security_policy + buckets: + explicit_buckets: + bounds: [0.005, 0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 1, 2.5, 5, 10] + - name: request_bytes + instance_name: requestsize.instance.{{ .Release.Namespace }} + kind: DISTRIBUTION + label_names: + - reporter + - source_app + - source_principal + - source_workload + - source_workload_namespace + - source_version + - destination_app + - destination_principal + - destination_workload + - destination_workload_namespace + - destination_version + - destination_service + - destination_service_name + - destination_service_namespace + - request_protocol + - response_code + - grpc_response_status + - response_flags + - connection_security_policy + buckets: + exponentialBuckets: + numFiniteBuckets: 8 + scale: 1 + growthFactor: 10 + - name: response_bytes + instance_name: responsesize.instance.{{ .Release.Namespace }} + kind: DISTRIBUTION + label_names: + - reporter + - source_app + - source_principal + - source_workload + - source_workload_namespace + - source_version + - destination_app + - destination_principal + - destination_workload + - destination_workload_namespace + - destination_version + - destination_service + - destination_service_name + - destination_service_namespace + - request_protocol + - response_code + - grpc_response_status + - response_flags + - connection_security_policy + buckets: + exponentialBuckets: + numFiniteBuckets: 8 + scale: 1 + growthFactor: 10 + - name: tcp_sent_bytes_total + instance_name: tcpbytesent.instance.{{ .Release.Namespace }} + kind: COUNTER + label_names: + - reporter + - source_app + - source_principal + - source_workload + - source_workload_namespace + - source_version + - destination_app + - destination_principal + - destination_workload + - destination_workload_namespace + - destination_version + - destination_service + - destination_service_name + - destination_service_namespace + - connection_security_policy + - response_flags + - name: tcp_received_bytes_total + instance_name: tcpbytereceived.instance.{{ .Release.Namespace }} + kind: COUNTER + label_names: + - reporter + - source_app + - source_principal + - source_workload + - source_workload_namespace + - source_version + - destination_app + - destination_principal + - destination_workload + - destination_workload_namespace + - destination_version + - destination_service + - destination_service_name + - destination_service_namespace + - connection_security_policy + - response_flags + - name: tcp_connections_opened_total + instance_name: tcpconnectionsopened.instance.{{ .Release.Namespace }} + kind: COUNTER + label_names: + - reporter + - source_app + - source_principal + - source_workload + - source_workload_namespace + - source_version + - destination_app + - destination_principal + - destination_workload + - destination_workload_namespace + - destination_version + - destination_service + - destination_service_name + - destination_service_namespace + - connection_security_policy + - response_flags + - name: tcp_connections_closed_total + instance_name: tcpconnectionsclosed.instance.{{ .Release.Namespace }} + kind: COUNTER + label_names: + - reporter + - source_app + - source_principal + - source_workload + - source_workload_namespace + - source_version + - destination_app + - destination_principal + - destination_workload + - destination_workload_namespace + - destination_version + - destination_service + - destination_service_name + - destination_service_namespace + - connection_security_policy + - response_flags +--- +apiVersion: "config.istio.io/v1alpha2" +kind: rule +metadata: + name: promhttp + namespace: {{ .Release.Namespace }} + labels: + app: {{ template "mixer.name" . }} + chart: {{ template "mixer.chart" . }} + heritage: {{ .Release.Service }} + release: {{ .Release.Name }} +spec: + match: (context.protocol == "http" || context.protocol == "grpc") && (match((request.useragent | "-"), "kube-probe*") == false) && (match((request.useragent | "-"), "Prometheus*") == false) + actions: + - handler: prometheus + instances: + - requestcount + - requestduration + - requestsize + - responsesize +--- +apiVersion: "config.istio.io/v1alpha2" +kind: rule +metadata: + name: promtcp + namespace: {{ .Release.Namespace }} + labels: + app: {{ template "mixer.name" . }} + chart: {{ template "mixer.chart" . }} + heritage: {{ .Release.Service }} + release: {{ .Release.Name }} +spec: + match: context.protocol == "tcp" + actions: + - handler: prometheus + instances: + - tcpbytesent + - tcpbytereceived +--- +apiVersion: "config.istio.io/v1alpha2" +kind: rule +metadata: + name: promtcpconnectionopen + namespace: {{ .Release.Namespace }} + labels: + app: {{ template "mixer.name" . }} + chart: {{ template "mixer.chart" . }} + heritage: {{ .Release.Service }} + release: {{ .Release.Name }} +spec: + match: context.protocol == "tcp" && ((connection.event | "na") == "open") + actions: + - handler: prometheus + instances: + - tcpconnectionsopened +--- +apiVersion: "config.istio.io/v1alpha2" +kind: rule +metadata: + name: promtcpconnectionclosed + namespace: {{ .Release.Namespace }} + labels: + app: {{ template "mixer.name" . }} + chart: {{ template "mixer.chart" . }} + heritage: {{ .Release.Service }} + release: {{ .Release.Name }} +spec: + match: context.protocol == "tcp" && ((connection.event | "na") == "close") + actions: + - handler: prometheus + instances: + - tcpconnectionsclosed +{{- end }} +--- +{{- if and .Values.adapters.kubernetesenv.enabled (or .Values.policy.enabled .Values.telemetry.enabled) }} +apiVersion: "config.istio.io/v1alpha2" +kind: handler +metadata: + name: kubernetesenv + namespace: {{ .Release.Namespace }} + labels: + app: {{ template "mixer.name" . }} + chart: {{ template "mixer.chart" . }} + heritage: {{ .Release.Service }} + release: {{ .Release.Name }} +spec: + compiledAdapter: kubernetesenv + params: {} + # when running from mixer root, use the following config after adding a + # symbolic link to a kubernetes config file via: + # + # $ ln -s ~/.kube/config mixer/adapter/kubernetes/kubeconfig + # + # kubeconfig_path: "mixer/adapter/kubernetes/kubeconfig" + +--- +apiVersion: "config.istio.io/v1alpha2" +kind: rule +metadata: + name: kubeattrgenrulerule + namespace: {{ .Release.Namespace }} + labels: + app: {{ template "mixer.name" . }} + chart: {{ template "mixer.chart" . }} + heritage: {{ .Release.Service }} + release: {{ .Release.Name }} +spec: + actions: + - handler: kubernetesenv + instances: + - attributes +--- +apiVersion: "config.istio.io/v1alpha2" +kind: rule +metadata: + name: tcpkubeattrgenrulerule + namespace: {{ .Release.Namespace }} + labels: + app: {{ template "mixer.name" . }} + chart: {{ template "mixer.chart" . }} + heritage: {{ .Release.Service }} + release: {{ .Release.Name }} +spec: + match: context.protocol == "tcp" + actions: + - handler: kubernetesenv + instances: + - attributes +--- +apiVersion: "config.istio.io/v1alpha2" +kind: instance +metadata: + name: attributes + namespace: {{ .Release.Namespace }} + labels: + app: {{ template "mixer.name" . }} + chart: {{ template "mixer.chart" . }} + heritage: {{ .Release.Service }} + release: {{ .Release.Name }} +spec: + compiledTemplate: kubernetes + params: + # Pass the required attribute data to the adapter + source_uid: source.uid | "" + source_ip: source.ip | ip("0.0.0.0") # default to unspecified ip addr + destination_uid: destination.uid | "" + destination_port: destination.port | 0 + attributeBindings: + # Fill the new attributes from the adapter produced output. + # $out refers to an instance of OutputTemplate message + source.ip: $out.source_pod_ip | ip("0.0.0.0") + source.uid: $out.source_pod_uid | "unknown" + source.labels: $out.source_labels | emptyStringMap() + source.name: $out.source_pod_name | "unknown" + source.namespace: $out.source_namespace | "default" + source.owner: $out.source_owner | "unknown" + source.serviceAccount: $out.source_service_account_name | "unknown" + source.workload.uid: $out.source_workload_uid | "unknown" + source.workload.name: $out.source_workload_name | "unknown" + source.workload.namespace: $out.source_workload_namespace | "unknown" + destination.ip: $out.destination_pod_ip | ip("0.0.0.0") + destination.uid: $out.destination_pod_uid | "unknown" + destination.labels: $out.destination_labels | emptyStringMap() + destination.name: $out.destination_pod_name | "unknown" + destination.container.name: $out.destination_container_name | "unknown" + destination.namespace: $out.destination_namespace | "default" + destination.owner: $out.destination_owner | "unknown" + destination.serviceAccount: $out.destination_service_account_name | "unknown" + destination.workload.uid: $out.destination_workload_uid | "unknown" + destination.workload.name: $out.destination_workload_name | "unknown" + destination.workload.namespace: $out.destination_workload_namespace | "unknown" +{{- end }} +--- +{{- if .Values.policy.enabled }} +# Configuration needed by Mixer. +# Mixer cluster is delivered via CDS +# Specify mixer cluster settings +apiVersion: networking.istio.io/v1alpha3 +kind: DestinationRule +metadata: + name: istio-policy + namespace: {{ .Release.Namespace }} + labels: + app: {{ template "mixer.name" . }} + chart: {{ template "mixer.chart" . }} + heritage: {{ .Release.Service }} + release: {{ .Release.Name }} +spec: + host: istio-policy.{{ .Release.Namespace }}.svc.{{ .Values.global.proxy.clusterDomain }} + {{- if .Values.global.defaultConfigVisibilitySettings }} + exportTo: + - '*' + {{- end }} + trafficPolicy: + portLevelSettings: + - port: + number: 15004 # grpc-mixer-mtls + tls: + mode: ISTIO_MUTUAL + - port: + number: 9091 # grpc-mixer + tls: + mode: DISABLE + connectionPool: + http: + http2MaxRequests: 10000 + maxRequestsPerConnection: 10000 +{{- end }} +--- +{{- if .Values.telemetry.enabled }} +apiVersion: networking.istio.io/v1alpha3 +kind: DestinationRule +metadata: + name: istio-telemetry + namespace: {{ .Release.Namespace }} + labels: + app: {{ template "mixer.name" . }} + chart: {{ template "mixer.chart" . }} + heritage: {{ .Release.Service }} + release: {{ .Release.Name }} +spec: + host: istio-telemetry.{{ .Release.Namespace }}.svc.{{ .Values.global.proxy.clusterDomain }} + {{- if .Values.global.defaultConfigVisibilitySettings }} + exportTo: + - '*' + {{- end }} + trafficPolicy: + portLevelSettings: + - port: + number: 15004 # grpc-mixer-mtls + tls: + mode: ISTIO_MUTUAL + - port: + number: 9091 # grpc-mixer + tls: + mode: DISABLE + connectionPool: + http: + http2MaxRequests: 10000 + maxRequestsPerConnection: 10000 +{{- end }} +--- +{{- end }} diff --git a/istio-1.5.0/install/kubernetes/helm/istio/charts/mixer/templates/deployment.yaml b/istio-1.5.0/install/kubernetes/helm/istio/charts/mixer/templates/deployment.yaml new file mode 100644 index 0000000..b7a4088 --- /dev/null +++ b/istio-1.5.0/install/kubernetes/helm/istio/charts/mixer/templates/deployment.yaml @@ -0,0 +1,447 @@ +{{- define "policy_container" }} + spec: + serviceAccountName: istio-mixer-service-account +{{- if $.Values.global.priorityClassName }} + priorityClassName: "{{ $.Values.global.priorityClassName }}" +{{- end }} + volumes: + - name: istio-certs + secret: + secretName: istio.istio-mixer-service-account + optional: true + {{- if $.Values.global.sds.enabled }} + - hostPath: + path: /var/run/sds + name: sds-uds-path + - name: istio-token + projected: + sources: + - serviceAccountToken: + audience: {{ $.Values.global.sds.token.aud }} + expirationSeconds: 43200 + path: istio-token + {{- end }} + - name: uds-socket + emptyDir: {} + - name: policy-adapter-secret + secret: + secretName: policy-adapter-secret + optional: true + affinity: + {{- include "nodeaffinity" . | indent 6 }} + {{- include "podAntiAffinity" . | indent 6 }} + {{- if .Values.tolerations }} + tolerations: +{{ toYaml .Values.tolerations | indent 6 }} + {{- else if .Values.global.defaultTolerations }} + tolerations: +{{ toYaml .Values.global.defaultTolerations | indent 6 }} + {{- end }} + containers: + - name: mixer +{{- if contains "/" .Values.image }} + image: "{{ .Values.image }}" +{{- else }} + image: "{{ $.Values.global.hub }}/{{ $.Values.image }}:{{ $.Values.global.tag }}" +{{- end }} + imagePullPolicy: {{ $.Values.global.imagePullPolicy }} + ports: + - containerPort: {{ .Values.global.monitoringPort }} + - containerPort: 42422 + args: + - --monitoringPort={{ .Values.global.monitoringPort }} + - --address + - unix:///sock/mixer.socket +{{- if $.Values.global.logging.level }} + - --log_output_level={{ $.Values.global.logging.level }} +{{- end}} +{{- if $.Values.global.useMCP }} + {{- if $.Values.global.controlPlaneSecurityEnabled}} + - --configStoreURL=mcps://istio-galley.{{ $.Release.Namespace }}.svc:9901 + {{- else }} + - --configStoreURL=mcp://istio-galley.{{ $.Release.Namespace }}.svc:9901 + {{- end }} +{{- else }} + - --configStoreURL=k8s:// +{{- end }} + - --configDefaultNamespace={{ $.Release.Namespace }} + {{- if $.Values.adapters.useAdapterCRDs }} + - --useAdapterCRDs=true + {{- else }} + - --useAdapterCRDs=false + {{- end }} + - --useTemplateCRDs=false + {{- if $.Values.global.tracer.zipkin.address }} + - --trace_zipkin_url=http://{{- $.Values.global.tracer.zipkin.address }}/api/v1/spans + {{- else }} + - --trace_zipkin_url=http://zipkin.{{ $.Release.Namespace }}:9411/api/v1/spans + {{- end }} + env: + - name: POD_NAMESPACE + valueFrom: + fieldRef: + apiVersion: v1 + fieldPath: metadata.namespace + {{- if .Values.env }} + {{- range $key, $val := .Values.env }} + - name: {{ $key }} + value: "{{ $val }}" + {{- end }} + {{- end }} + resources: +{{- if .Values.policy.resources }} +{{ toYaml .Values.policy.resources | indent 10 }} +{{- else if .Values.resources }} +{{ toYaml .Values.resources | indent 10 }} +{{- else }} +{{ toYaml .Values.global.defaultResources | indent 10 }} +{{- end }} + volumeMounts: +{{- if $.Values.global.useMCP }} + - name: istio-certs + mountPath: /etc/certs + readOnly: true +{{- end }} + - name: uds-socket + mountPath: /sock + livenessProbe: + httpGet: + path: /version + port: {{ .Values.global.monitoringPort }} + initialDelaySeconds: 5 + periodSeconds: 5 + - name: istio-proxy +{{- if contains "/" $.Values.global.proxy.image }} + image: "{{ $.Values.global.proxy.image }}" +{{- else }} + image: "{{ $.Values.global.hub }}/{{ $.Values.global.proxy.image }}:{{ $.Values.global.tag }}" +{{- end }} + imagePullPolicy: {{ $.Values.global.imagePullPolicy }} + ports: + - containerPort: 9091 + - containerPort: 15004 + - containerPort: 15090 + protocol: TCP + name: http-envoy-prom + args: + - proxy + - --domain + - $(POD_NAMESPACE).svc.{{ $.Values.global.proxy.clusterDomain }} + - --serviceCluster + - istio-policy + - --templateFile + - /etc/istio/proxy/envoy_policy.yaml.tmpl + {{- if $.Values.global.controlPlaneSecurityEnabled }} + - --controlPlaneAuthPolicy + - MUTUAL_TLS + {{- else }} + - --controlPlaneAuthPolicy + - NONE + {{- end }} + {{- if $.Values.global.trustDomain }} + - --trust-domain={{ $.Values.global.trustDomain }} + {{- end }} + {{- if $.Values.global.proxy.logLevel }} + - --proxyLogLevel={{ $.Values.global.proxy.logLevel }} + {{- end}} + {{- if $.Values.global.proxy.componentLogLevel }} + - --proxyComponentLogLevel={{ $.Values.global.proxy.componentLogLevel }} + {{- end}} + {{- if $.Values.global.logging.level }} + - --log_output_level={{ $.Values.global.logging.level }} + {{- end}} + env: + - name: POD_NAME + valueFrom: + fieldRef: + apiVersion: v1 + fieldPath: metadata.name + - name: POD_NAMESPACE + valueFrom: + fieldRef: + apiVersion: v1 + fieldPath: metadata.namespace + - name: INSTANCE_IP + valueFrom: + fieldRef: + apiVersion: v1 + fieldPath: status.podIP + - name: SDS_ENABLED + value: "{{ $.Values.global.sds.enabled }}" + resources: +{{- if $.Values.global.proxy.resources }} +{{ toYaml $.Values.global.proxy.resources | indent 10 }} +{{- else }} +{{ toYaml .Values.global.defaultResources | indent 10 }} +{{- end }} + volumeMounts: + - name: istio-certs + mountPath: /etc/certs + readOnly: true + {{- if $.Values.global.sds.enabled }} + - name: sds-uds-path + mountPath: /var/run/sds + readOnly: true + - name: istio-token + mountPath: /var/run/secrets/tokens + {{- end }} + - name: uds-socket + mountPath: /sock + - name: policy-adapter-secret + mountPath: /var/run/secrets/istio.io/policy/adapter + readOnly: true +{{- end }} + +{{- define "telemetry_container" }} + spec: + serviceAccountName: istio-mixer-service-account +{{- if $.Values.global.priorityClassName }} + priorityClassName: "{{ $.Values.global.priorityClassName }}" +{{- end }} + volumes: + - name: istio-certs + secret: + secretName: istio.istio-mixer-service-account + optional: true + {{- if $.Values.global.sds.enabled }} + - hostPath: + path: /var/run/sds + name: sds-uds-path + - name: istio-token + projected: + sources: + - serviceAccountToken: + audience: {{ $.Values.global.sds.token.aud }} + expirationSeconds: 43200 + path: istio-token + {{- end }} + - name: uds-socket + emptyDir: {} + - name: telemetry-adapter-secret + secret: + secretName: telemetry-adapter-secret + optional: true + affinity: + {{- include "nodeaffinity" . | indent 6 }} + {{- include "podAntiAffinity" . | indent 6 }} + {{- if .Values.tolerations }} + tolerations: +{{ toYaml .Values.tolerations | indent 6 }} + {{- else if .Values.global.defaultTolerations }} + tolerations: +{{ toYaml .Values.global.defaultTolerations | indent 6 }} + {{- end }} + containers: + - name: mixer +{{- if contains "/" .Values.image }} + image: "{{ .Values.image }}" +{{- else }} + image: "{{ $.Values.global.hub }}/{{ $.Values.image }}:{{ $.Values.global.tag }}" +{{- end }} + imagePullPolicy: {{ $.Values.global.imagePullPolicy }} + ports: + - containerPort: {{ .Values.global.monitoringPort }} + - containerPort: 42422 + args: + - --monitoringPort={{ .Values.global.monitoringPort }} + - --address + - unix:///sock/mixer.socket +{{- if $.Values.global.logging.level }} + - --log_output_level={{ $.Values.global.logging.level }} +{{- end}} +{{- if $.Values.global.useMCP }} + {{- if $.Values.global.controlPlaneSecurityEnabled}} + - --configStoreURL=mcps://istio-galley.{{ $.Release.Namespace }}.svc:9901 + - --certFile=/etc/certs/cert-chain.pem + - --keyFile=/etc/certs/key.pem + - --caCertFile=/etc/certs/root-cert.pem + {{- else }} + - --configStoreURL=mcp://istio-galley.{{ $.Release.Namespace }}.svc:9901 + {{- end }} +{{- else }} + - --configStoreURL=k8s:// +{{- end }} + - --configDefaultNamespace={{ $.Release.Namespace }} + {{- if $.Values.adapters.useAdapterCRDs }} + - --useAdapterCRDs=true + {{- else }} + - --useAdapterCRDs=false + {{- end }} + - --useTemplateCRDs=false + {{- if $.Values.global.tracer.zipkin.address }} + - --trace_zipkin_url=http://{{- $.Values.global.tracer.zipkin.address }}/api/v1/spans + {{- else }} + - --trace_zipkin_url=http://zipkin.{{ $.Release.Namespace }}:9411/api/v1/spans + {{- end }} + - --averageLatencyThreshold + - {{ $.Values.telemetry.loadshedding.latencyThreshold }} + - --loadsheddingMode + - {{ $.Values.telemetry.loadshedding.mode }} + {{- if .Values.env }} + env: + - name: POD_NAMESPACE + valueFrom: + fieldRef: + apiVersion: v1 + fieldPath: metadata.namespace + {{- range $key, $val := .Values.env }} + - name: {{ $key }} + value: "{{ $val }}" + {{- end }} + {{- end }} + resources: +{{- if .Values.telemetry.resources }} +{{ toYaml .Values.telemetry.resources | indent 10 }} +{{- else if .Values.resources }} +{{ toYaml .Values.resources | indent 10 }} +{{- else }} +{{ toYaml .Values.global.defaultResources | indent 10 }} +{{- end }} + volumeMounts: +{{- if $.Values.global.useMCP }} + - name: istio-certs + mountPath: /etc/certs + readOnly: true +{{- end }} + - name: telemetry-adapter-secret + mountPath: /var/run/secrets/istio.io/telemetry/adapter + readOnly: true + - name: uds-socket + mountPath: /sock + livenessProbe: + httpGet: + path: /version + port: {{ .Values.global.monitoringPort }} + initialDelaySeconds: 5 + periodSeconds: 5 + - name: istio-proxy +{{- if contains "/" $.Values.global.proxy.image }} + image: "{{ $.Values.global.proxy.image }}" +{{- else }} + image: "{{ $.Values.global.hub }}/{{ $.Values.global.proxy.image }}:{{ $.Values.global.tag }}" +{{- end }} + imagePullPolicy: {{ $.Values.global.imagePullPolicy }} + ports: + - containerPort: 9091 + - containerPort: 15004 + - containerPort: 15090 + protocol: TCP + name: http-envoy-prom + args: + - proxy + - --domain + - $(POD_NAMESPACE).svc.{{ .Values.global.proxy.clusterDomain }} + - --serviceCluster + - istio-telemetry + - --templateFile + - /etc/istio/proxy/envoy_telemetry.yaml.tmpl + {{- if $.Values.global.controlPlaneSecurityEnabled }} + - --controlPlaneAuthPolicy + - MUTUAL_TLS + {{- else }} + - --controlPlaneAuthPolicy + - NONE + {{- end }} + {{- if $.Values.global.proxy.logLevel }} + - --proxyLogLevel={{ $.Values.global.proxy.logLevel }} + {{- end}} + {{- if $.Values.global.proxy.componentLogLevel }} + - --proxyComponentLogLevel={{ $.Values.global.proxy.componentLogLevel }} + {{- end}} + {{- if $.Values.global.logging.level }} + - --log_output_level={{ $.Values.global.logging.level }} + {{- end}} + env: + - name: POD_NAME + valueFrom: + fieldRef: + apiVersion: v1 + fieldPath: metadata.name + - name: POD_NAMESPACE + valueFrom: + fieldRef: + apiVersion: v1 + fieldPath: metadata.namespace + - name: INSTANCE_IP + valueFrom: + fieldRef: + apiVersion: v1 + fieldPath: status.podIP + - name: SDS_ENABLED + value: "{{ $.Values.global.sds.enabled }}" + resources: +{{- if $.Values.global.proxy.resources }} +{{ toYaml $.Values.global.proxy.resources | indent 10 }} +{{- else }} +{{ toYaml .Values.global.defaultResources | indent 10 }} +{{- end }} + volumeMounts: + - name: istio-certs + mountPath: /etc/certs + readOnly: true + {{- if $.Values.global.sds.enabled }} + - name: sds-uds-path + mountPath: /var/run/sds + readOnly: true + - name: istio-token + mountPath: /var/run/secrets/tokens + {{- end }} + - name: uds-socket + mountPath: /sock +{{- end }} + + +{{- range $key, $spec := .Values }} +{{- if or (eq $key "policy") (eq $key "telemetry") }} +{{- if $spec.enabled }} +apiVersion: apps/v1 +kind: Deployment +metadata: + name: istio-{{ $key }} + namespace: {{ $.Release.Namespace }} + labels: + app: istio-mixer + chart: {{ template "mixer.chart" $ }} + heritage: {{ $.Release.Service }} + release: {{ $.Release.Name }} + istio: mixer +spec: +{{- if not $spec.autoscaleEnabled }} +{{- if $spec.replicaCount }} + replicas: {{ $spec.replicaCount }} +{{- else }} + replicas: 1 +{{- end }} +{{- end }} + strategy: + rollingUpdate: + maxSurge: {{ $spec.rollingMaxSurge }} + maxUnavailable: {{ $spec.rollingMaxUnavailable }} + selector: + matchLabels: + istio: mixer + istio-mixer-type: {{ $key }} + template: + metadata: + labels: + app: {{ $key }} + chart: {{ template "mixer.chart" $ }} + heritage: {{ $.Release.Service }} + release: {{ $.Release.Name }} + istio: mixer + istio-mixer-type: {{ $key }} + annotations: + sidecar.istio.io/inject: "false" +{{- with $.Values.podAnnotations }} +{{ toYaml . | indent 8 }} +{{- end }} +{{- if eq $key "policy"}} +{{- template "policy_container" $ }} +{{- else }} +{{- template "telemetry_container" $ }} +{{- end }} + +--- +{{- end }} +{{- end }} +{{- end }} {{/* range */}} diff --git a/istio-1.5.0/install/kubernetes/helm/istio/charts/mixer/templates/poddisruptionbudget.yaml b/istio-1.5.0/install/kubernetes/helm/istio/charts/mixer/templates/poddisruptionbudget.yaml new file mode 100644 index 0000000..35bbc40 --- /dev/null +++ b/istio-1.5.0/install/kubernetes/helm/istio/charts/mixer/templates/poddisruptionbudget.yaml @@ -0,0 +1,30 @@ +{{- range $key, $spec := .Values }} +{{- if or (eq $key "policy") (eq $key "telemetry") }} +{{- if $spec.enabled }} +{{- if $.Values.global.defaultPodDisruptionBudget.enabled }} +apiVersion: policy/v1beta1 +kind: PodDisruptionBudget +metadata: + name: istio-{{ $key }} + namespace: {{ $.Release.Namespace }} + labels: + app: {{ $key }} + chart: {{ template "mixer.chart" $ }} + heritage: {{ $.Release.Service }} + release: {{ $.Release.Name }} + version: {{ $.Chart.Version }} + istio: mixer + istio-mixer-type: {{ $key }} +spec: +{{ include "podDisruptionBudget.spec" $.Values.global.defaultPodDisruptionBudget }} + selector: + matchLabels: + app: {{ $key }} + release: {{ $.Release.Name }} + istio: mixer + istio-mixer-type: {{ $key }} +--- +{{- end }} +{{- end }} +{{- end }} +{{- end }} diff --git a/istio-1.5.0/install/kubernetes/helm/istio/charts/mixer/templates/service.yaml b/istio-1.5.0/install/kubernetes/helm/istio/charts/mixer/templates/service.yaml new file mode 100644 index 0000000..79cc4a5 --- /dev/null +++ b/istio-1.5.0/install/kubernetes/helm/istio/charts/mixer/templates/service.yaml @@ -0,0 +1,39 @@ +{{- range $key, $spec := .Values }} +{{- if or (eq $key "policy") (eq $key "telemetry") }} +{{- if $spec.enabled }} +apiVersion: v1 +kind: Service +metadata: + name: istio-{{ $key }} + namespace: {{ $.Release.Namespace }} + annotations: + networking.istio.io/exportTo: "*" + labels: + app: {{ template "mixer.name" $ }} + chart: {{ template "mixer.chart" $ }} + heritage: {{ $.Release.Service }} + release: {{ $.Release.Name }} + istio: mixer +spec: + ports: + - name: grpc-mixer + port: 9091 + - name: grpc-mixer-mtls + port: 15004 + - name: http-monitoring + port: {{ $.Values.global.monitoringPort }} +{{- if eq $key "telemetry" }} + - name: prometheus + port: 42422 +{{- if $spec.sessionAffinityEnabled }} + sessionAffinity: ClientIP +{{- end }} +{{- end }} + selector: + istio: mixer + istio-mixer-type: {{ $key }} +--- +{{- end }} +{{- end }} +{{- end }} + diff --git a/istio-1.5.0/install/kubernetes/helm/istio/charts/mixer/templates/serviceaccount.yaml b/istio-1.5.0/install/kubernetes/helm/istio/charts/mixer/templates/serviceaccount.yaml new file mode 100644 index 0000000..9d3da7d --- /dev/null +++ b/istio-1.5.0/install/kubernetes/helm/istio/charts/mixer/templates/serviceaccount.yaml @@ -0,0 +1,18 @@ +{{- if or (.Values.policy.enabled) (.Values.telemetry.enabled) }} +apiVersion: v1 +kind: ServiceAccount +{{- if .Values.global.imagePullSecrets }} +imagePullSecrets: +{{- range .Values.global.imagePullSecrets }} + - name: {{ . }} +{{- end }} +{{- end }} +metadata: + name: istio-mixer-service-account + namespace: {{ .Release.Namespace }} + labels: + app: {{ template "mixer.name" . }} + chart: {{ template "mixer.chart" . }} + heritage: {{ .Release.Service }} + release: {{ .Release.Name }} +{{- end }} diff --git a/istio-1.5.0/install/kubernetes/helm/istio/charts/mixer/values.yaml b/istio-1.5.0/install/kubernetes/helm/istio/charts/mixer/values.yaml new file mode 100644 index 0000000..d335c36 --- /dev/null +++ b/istio-1.5.0/install/kubernetes/helm/istio/charts/mixer/values.yaml @@ -0,0 +1,98 @@ +# +# mixer configuration +# +image: mixer + +env: + # max procs should be ceil(cpu limit + 1) + GOMAXPROCS: "6" + +policy: + # if policy is enabled, global.disablePolicyChecks has affect. + enabled: false + replicaCount: 1 + autoscaleEnabled: true + autoscaleMin: 1 + autoscaleMax: 5 + cpu: + targetAverageUtilization: 80 + rollingMaxSurge: 100% + rollingMaxUnavailable: 25% + +telemetry: + enabled: true + replicaCount: 1 + autoscaleEnabled: true + autoscaleMin: 1 + autoscaleMax: 5 + cpu: + targetAverageUtilization: 80 + rollingMaxSurge: 100% + rollingMaxUnavailable: 25% + sessionAffinityEnabled: false + + # mixer load shedding configuration. + # When mixer detects that it is overloaded, it starts rejecting grpc requests. + loadshedding: + # disabled, logonly or enforce + mode: enforce + # based on measurements 100ms p50 translates to p99 of under 1s. This is ok for telemetry which is inherently async. + latencyThreshold: 100ms + resources: + requests: + cpu: 1000m + memory: 1G + limits: + # It is best to do horizontal scaling of mixer using moderate cpu allocation. + # We have experimentally found that these values work well. + cpu: 4800m + memory: 4G + + # Set reportBatchMaxEntries to 0 to use the default batching behavior (i.e., every 100 requests). + # A positive value indicates the number of requests that are batched before telemetry data + # is sent to the mixer server + reportBatchMaxEntries: 100 + + # Set reportBatchMaxTime to 0 to use the default batching behavior (i.e., every 1 second). + # A positive time value indicates the maximum wait time since the last request will telemetry data + # be batched before being sent to the mixer server + reportBatchMaxTime: 1s + +podAnnotations: {} +nodeSelector: {} +tolerations: [] + +# Specify the pod anti-affinity that allows you to constrain which nodes +# your pod is eligible to be scheduled based on labels on pods that are +# already running on the node rather than based on labels on nodes. +# There are currently two types of anti-affinity: +# "requiredDuringSchedulingIgnoredDuringExecution" +# "preferredDuringSchedulingIgnoredDuringExecution" +# which denote "hard" vs. "soft" requirements, you can define your values +# in "podAntiAffinityLabelSelector" and "podAntiAffinityTermLabelSelector" +# correspondingly. +# For example: +# podAntiAffinityLabelSelector: +# - key: security +# operator: In +# values: S1,S2 +# topologyKey: "kubernetes.io/hostname" +# This pod anti-affinity rule says that the pod requires not to be scheduled +# onto a node if that node is already running a pod with label having key +# "security" and value "S1". +podAntiAffinityLabelSelector: [] +podAntiAffinityTermLabelSelector: [] + +adapters: + kubernetesenv: + enabled: true + + # stdio is a debug adapter in istio-telemetry, it is not recommended for production use. + stdio: + enabled: false + outputAsJson: true + prometheus: + enabled: true + metricsExpiryDuration: 10m + # Setting this to false sets the useAdapterCRDs mixer startup argument to false + useAdapterCRDs: false diff --git a/istio-1.5.0/install/kubernetes/helm/istio/charts/nodeagent/Chart.yaml b/istio-1.5.0/install/kubernetes/helm/istio/charts/nodeagent/Chart.yaml new file mode 100644 index 0000000..ceef4c6 --- /dev/null +++ b/istio-1.5.0/install/kubernetes/helm/istio/charts/nodeagent/Chart.yaml @@ -0,0 +1,13 @@ +apiVersion: v1 +name: nodeagent +version: 1.5.0 +appVersion: 1.5.0 +tillerVersion: ">=2.7.2" +description: Helm chart for nodeagent deployment +keywords: + - istio + - nodeagent +sources: + - http://github.com/istio/istio +engine: gotpl +icon: https://istio.io/favicons/android-192x192.png diff --git a/istio-1.5.0/install/kubernetes/helm/istio/charts/nodeagent/templates/_helpers.tpl b/istio-1.5.0/install/kubernetes/helm/istio/charts/nodeagent/templates/_helpers.tpl new file mode 100644 index 0000000..fda6043 --- /dev/null +++ b/istio-1.5.0/install/kubernetes/helm/istio/charts/nodeagent/templates/_helpers.tpl @@ -0,0 +1,32 @@ +{{/* vim: set filetype=mustache: */}} +{{/* +Expand the name of the chart. +*/}} +{{- define "nodeagent.name" -}} +{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" -}} +{{- end -}} + +{{/* +Create a default fully qualified app name. +We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). +If release name contains chart name it will be used as a full name. +*/}} +{{- define "nodeagent.fullname" -}} +{{- if .Values.fullnameOverride -}} +{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" -}} +{{- else -}} +{{- $name := default .Chart.Name .Values.nameOverride -}} +{{- if contains $name .Release.Name -}} +{{- .Release.Name | trunc 63 | trimSuffix "-" -}} +{{- else -}} +{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" -}} +{{- end -}} +{{- end -}} +{{- end -}} + +{{/* +Create chart name and version as used by the chart label. +*/}} +{{- define "nodeagent.chart" -}} +{{- .Chart.Name | trunc 63 | trimSuffix "-" -}} +{{- end -}} diff --git a/istio-1.5.0/install/kubernetes/helm/istio/charts/nodeagent/templates/clusterrole.yaml b/istio-1.5.0/install/kubernetes/helm/istio/charts/nodeagent/templates/clusterrole.yaml new file mode 100644 index 0000000..8e4ab6d --- /dev/null +++ b/istio-1.5.0/install/kubernetes/helm/istio/charts/nodeagent/templates/clusterrole.yaml @@ -0,0 +1,13 @@ +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: istio-nodeagent-{{ .Release.Namespace }} + labels: + app: {{ template "nodeagent.name" . }} + chart: {{ template "nodeagent.chart" . }} + heritage: {{ .Release.Service }} + release: {{ .Release.Name }} +rules: +- apiGroups: [""] + resources: ["configmaps"] + verbs: ["get"] diff --git a/istio-1.5.0/install/kubernetes/helm/istio/charts/nodeagent/templates/clusterrolebinding.yaml b/istio-1.5.0/install/kubernetes/helm/istio/charts/nodeagent/templates/clusterrolebinding.yaml new file mode 100644 index 0000000..591e482 --- /dev/null +++ b/istio-1.5.0/install/kubernetes/helm/istio/charts/nodeagent/templates/clusterrolebinding.yaml @@ -0,0 +1,17 @@ +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: istio-nodeagent-{{ .Release.Namespace }} + labels: + app: {{ template "nodeagent.name" . }} + chart: {{ template "nodeagent.chart" . }} + heritage: {{ .Release.Service }} + release: {{ .Release.Name }} +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: istio-nodeagent-{{ .Release.Namespace }} +subjects: + - kind: ServiceAccount + name: istio-nodeagent-service-account + namespace: {{ .Release.Namespace }} diff --git a/istio-1.5.0/install/kubernetes/helm/istio/charts/nodeagent/templates/daemonset.yaml b/istio-1.5.0/install/kubernetes/helm/istio/charts/nodeagent/templates/daemonset.yaml new file mode 100644 index 0000000..58f1efb --- /dev/null +++ b/istio-1.5.0/install/kubernetes/helm/istio/charts/nodeagent/templates/daemonset.yaml @@ -0,0 +1,70 @@ +apiVersion: apps/v1 +kind: DaemonSet +metadata: + name: istio-nodeagent + namespace: {{ .Release.Namespace }} + labels: + app: {{ template "nodeagent.name" . }} + chart: {{ template "nodeagent.chart" . }} + release: {{ .Release.Name }} + heritage: {{ .Release.Service }} + istio: nodeagent +spec: + selector: + matchLabels: + istio: nodeagent + template: + metadata: + labels: + app: {{ template "nodeagent.name" . }} + chart: {{ template "nodeagent.chart" . }} + release: {{ .Release.Name }} + heritage: {{ .Release.Service }} + istio: nodeagent + annotations: + sidecar.istio.io/inject: "false" + spec: + serviceAccountName: istio-nodeagent-service-account +{{- if .Values.global.priorityClassName }} + priorityClassName: "{{ .Values.global.priorityClassName }}" +{{- end }} + containers: + - name: nodeagent +{{- if contains "/" .Values.image }} + image: "{{ .Values.image }}" +{{- else }} + image: "{{ .Values.global.hub }}/{{ .Values.image }}:{{ .Values.global.tag }}" +{{- end }} + imagePullPolicy: {{ .Values.global.imagePullPolicy }} + volumeMounts: + - mountPath: /var/run/sds + name: sdsudspath + env: + {{- if .Values.env }} + {{- range $key, $val := .Values.env }} + - name: {{ $key }} + value: "{{ $val }}" + {{- end }} + {{- end }} + - name: "TRUST_DOMAIN" + value: "{{ .Values.global.trustDomain }}" + - name: NAMESPACE + valueFrom: + fieldRef: + fieldPath: metadata.namespace + volumes: + - name: sdsudspath + hostPath: + path: /var/run/sds + affinity: + {{- include "nodeaffinity" . | indent 6 }} + {{- include "podAntiAffinity" . | indent 6 }} + {{- if .Values.tolerations }} + tolerations: +{{ toYaml .Values.tolerations | indent 6 }} + {{- else if .Values.global.defaultTolerations }} + tolerations: +{{ toYaml .Values.global.defaultTolerations | indent 6 }} + {{- end }} + updateStrategy: + type: RollingUpdate diff --git a/istio-1.5.0/install/kubernetes/helm/istio/charts/nodeagent/templates/serviceaccount.yaml b/istio-1.5.0/install/kubernetes/helm/istio/charts/nodeagent/templates/serviceaccount.yaml new file mode 100644 index 0000000..86853d7 --- /dev/null +++ b/istio-1.5.0/install/kubernetes/helm/istio/charts/nodeagent/templates/serviceaccount.yaml @@ -0,0 +1,16 @@ +apiVersion: v1 +kind: ServiceAccount +{{- if .Values.global.imagePullSecrets }} +imagePullSecrets: +{{- range .Values.global.imagePullSecrets }} + - name: {{ . }} +{{- end }} +{{- end }} +metadata: + name: istio-nodeagent-service-account + namespace: {{ .Release.Namespace }} + labels: + app: {{ template "nodeagent.name" . }} + chart: {{ template "nodeagent.chart" . }} + heritage: {{ .Release.Service }} + release: {{ .Release.Name }} diff --git a/istio-1.5.0/install/kubernetes/helm/istio/charts/nodeagent/values.yaml b/istio-1.5.0/install/kubernetes/helm/istio/charts/nodeagent/values.yaml new file mode 100644 index 0000000..3e1c090 --- /dev/null +++ b/istio-1.5.0/install/kubernetes/helm/istio/charts/nodeagent/values.yaml @@ -0,0 +1,36 @@ +# +# nodeagent configuration +# +enabled: false +image: node-agent-k8s +env: + # name of authentication provider. + CA_PROVIDER: "Citadel" + # CA endpoint. + CA_ADDR: "istio-citadel:8060" + # names of authentication provider's plugins. + PLUGINS: "" + VALID_TOKEN: true +nodeSelector: {} +tolerations: [] + +# Specify the pod anti-affinity that allows you to constrain which nodes +# your pod is eligible to be scheduled based on labels on pods that are +# already running on the node rather than based on labels on nodes. +# There are currently two types of anti-affinity: +# "requiredDuringSchedulingIgnoredDuringExecution" +# "preferredDuringSchedulingIgnoredDuringExecution" +# which denote "hard" vs. "soft" requirements, you can define your values +# in "podAntiAffinityLabelSelector" and "podAntiAffinityTermLabelSelector" +# correspondingly. +# For example: +# podAntiAffinityLabelSelector: +# - key: security +# operator: In +# values: S1,S2 +# topologyKey: "kubernetes.io/hostname" +# This pod anti-affinity rule says that the pod requires not to be scheduled +# onto a node if that node is already running a pod with label having key +# "security" and value "S1". +podAntiAffinityLabelSelector: [] +podAntiAffinityTermLabelSelector: [] diff --git a/istio-1.5.0/install/kubernetes/helm/istio/charts/pilot/Chart.yaml b/istio-1.5.0/install/kubernetes/helm/istio/charts/pilot/Chart.yaml new file mode 100644 index 0000000..b913b3d --- /dev/null +++ b/istio-1.5.0/install/kubernetes/helm/istio/charts/pilot/Chart.yaml @@ -0,0 +1,13 @@ +apiVersion: v1 +name: pilot +version: 1.5.0 +appVersion: 1.5.0 +tillerVersion: ">=2.7.2" +description: Helm chart for pilot deployment +keywords: + - istio + - pilot +sources: + - http://github.com/istio/istio +engine: gotpl +icon: https://istio.io/favicons/android-192x192.png diff --git a/istio-1.5.0/install/kubernetes/helm/istio/charts/pilot/templates/_helpers.tpl b/istio-1.5.0/install/kubernetes/helm/istio/charts/pilot/templates/_helpers.tpl new file mode 100644 index 0000000..c812c37 --- /dev/null +++ b/istio-1.5.0/install/kubernetes/helm/istio/charts/pilot/templates/_helpers.tpl @@ -0,0 +1,32 @@ +{{/* vim: set filetype=mustache: */}} +{{/* +Expand the name of the chart. +*/}} +{{- define "pilot.name" -}} +{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" -}} +{{- end -}} + +{{/* +Create a default fully qualified app name. +We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). +If release name contains chart name it will be used as a full name. +*/}} +{{- define "pilot.fullname" -}} +{{- if .Values.fullnameOverride -}} +{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" -}} +{{- else -}} +{{- $name := default .Chart.Name .Values.nameOverride -}} +{{- if contains $name .Release.Name -}} +{{- .Release.Name | trunc 63 | trimSuffix "-" -}} +{{- else -}} +{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" -}} +{{- end -}} +{{- end -}} +{{- end -}} + +{{/* +Create chart name and version as used by the chart label. +*/}} +{{- define "pilot.chart" -}} +{{- .Chart.Name | trunc 63 | trimSuffix "-" -}} +{{- end -}} diff --git a/istio-1.5.0/install/kubernetes/helm/istio/charts/pilot/templates/autoscale.yaml b/istio-1.5.0/install/kubernetes/helm/istio/charts/pilot/templates/autoscale.yaml new file mode 100644 index 0000000..1a99451 --- /dev/null +++ b/istio-1.5.0/install/kubernetes/helm/istio/charts/pilot/templates/autoscale.yaml @@ -0,0 +1,25 @@ +{{- if and .Values.autoscaleEnabled .Values.autoscaleMin .Values.autoscaleMax }} +apiVersion: autoscaling/v2beta1 +kind: HorizontalPodAutoscaler +metadata: + name: istio-pilot + namespace: {{ .Release.Namespace }} + labels: + app: {{ template "pilot.name" . }} + chart: {{ template "pilot.chart" . }} + heritage: {{ .Release.Service }} + release: {{ .Release.Name }} +spec: + maxReplicas: {{ .Values.autoscaleMax }} + minReplicas: {{ .Values.autoscaleMin }} + scaleTargetRef: + apiVersion: apps/v1 + kind: Deployment + name: istio-pilot + metrics: + - type: Resource + resource: + name: cpu + targetAverageUtilization: {{ .Values.cpu.targetAverageUtilization }} +--- +{{- end }} diff --git a/istio-1.5.0/install/kubernetes/helm/istio/charts/pilot/templates/clusterrole.yaml b/istio-1.5.0/install/kubernetes/helm/istio/charts/pilot/templates/clusterrole.yaml new file mode 100644 index 0000000..d149176 --- /dev/null +++ b/istio-1.5.0/install/kubernetes/helm/istio/charts/pilot/templates/clusterrole.yaml @@ -0,0 +1,39 @@ +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: istio-pilot-{{ .Release.Namespace }} + labels: + app: {{ template "pilot.name" . }} + chart: {{ template "pilot.chart" . }} + heritage: {{ .Release.Service }} + release: {{ .Release.Name }} +rules: +- apiGroups: + - config.istio.io + - rbac.istio.io + - security.istio.io + - networking.istio.io + - authentication.istio.io + resources: ["*"] + verbs: ["get", "list", "watch"] +- apiGroups: ["extensions"] + resources: ["ingresses", "ingresses/status"] + verbs: ["*"] +- apiGroups: [""] + resources: ["configmaps"] + verbs: ["create", "get", "list", "watch", "update"] +- apiGroups: [""] + resources: ["endpoints", "pods", "services", "namespaces", "nodes"] + verbs: ["get", "list", "watch"] +- apiGroups: ["discovery.k8s.io"] + resources: ["endpointslices"] + verbs: ["get", "list", "watch"] +- apiGroups: [""] + resources: ["secrets"] + verbs: ["create", "get", "watch", "list", "update", "delete"] +- apiGroups: ["certificates.k8s.io"] + resources: + - "certificatesigningrequests" + - "certificatesigningrequests/approval" + - "certificatesigningrequests/status" + verbs: ["update", "create", "get", "delete"] diff --git a/istio-1.5.0/install/kubernetes/helm/istio/charts/pilot/templates/clusterrolebinding.yaml b/istio-1.5.0/install/kubernetes/helm/istio/charts/pilot/templates/clusterrolebinding.yaml new file mode 100644 index 0000000..ef9281c --- /dev/null +++ b/istio-1.5.0/install/kubernetes/helm/istio/charts/pilot/templates/clusterrolebinding.yaml @@ -0,0 +1,17 @@ +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: istio-pilot-{{ .Release.Namespace }} + labels: + app: {{ template "pilot.name" . }} + chart: {{ template "pilot.chart" . }} + heritage: {{ .Release.Service }} + release: {{ .Release.Name }} +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: istio-pilot-{{ .Release.Namespace }} +subjects: + - kind: ServiceAccount + name: istio-pilot-service-account + namespace: {{ .Release.Namespace }} diff --git a/istio-1.5.0/install/kubernetes/helm/istio/charts/pilot/templates/configmap.yaml b/istio-1.5.0/install/kubernetes/helm/istio/charts/pilot/templates/configmap.yaml new file mode 100644 index 0000000..3fe5143 --- /dev/null +++ b/istio-1.5.0/install/kubernetes/helm/istio/charts/pilot/templates/configmap.yaml @@ -0,0 +1,14 @@ +{{- if .Values.jwksResolverExtraRootCA }} +apiVersion: v1 +kind: ConfigMap +metadata: + name: istio-jwks-extra-cacerts + namespace: {{ .Release.Namespace }} + labels: + app: {{ template "pilot.name" . }} + chart: {{ template "pilot.chart" . }} + heritage: {{ .Release.Service }} + release: {{ .Release.Name }} +data: + extra.pem: {{ .Values.jwksResolverExtraRootCA | quote }} +{{- end }} diff --git a/istio-1.5.0/install/kubernetes/helm/istio/charts/pilot/templates/deployment.yaml b/istio-1.5.0/install/kubernetes/helm/istio/charts/pilot/templates/deployment.yaml new file mode 100644 index 0000000..093bc06 --- /dev/null +++ b/istio-1.5.0/install/kubernetes/helm/istio/charts/pilot/templates/deployment.yaml @@ -0,0 +1,242 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: istio-pilot + namespace: {{ .Release.Namespace }} + # TODO: default template doesn't have this, which one is right ? + labels: + app: {{ template "pilot.name" . }} + chart: {{ template "pilot.chart" . }} + heritage: {{ .Release.Service }} + release: {{ .Release.Name }} + istio: pilot +spec: +{{- if not .Values.autoscaleEnabled }} +{{- if .Values.replicaCount }} + replicas: {{ .Values.replicaCount }} +{{- else }} + replicas: 1 +{{- end }} +{{- end }} + strategy: + rollingUpdate: + maxSurge: {{ .Values.rollingMaxSurge }} + maxUnavailable: {{ .Values.rollingMaxUnavailable }} + selector: + matchLabels: + istio: pilot + template: + metadata: + labels: + app: {{ template "pilot.name" . }} + chart: {{ template "pilot.chart" . }} + heritage: {{ .Release.Service }} + release: {{ .Release.Name }} + istio: pilot + annotations: + sidecar.istio.io/inject: "false" + {{- if .Values.podAnnotations }} +{{ toYaml .Values.podAnnotations | indent 8 }} + {{- end }} + spec: + serviceAccountName: istio-pilot-service-account +{{- if .Values.global.priorityClassName }} + priorityClassName: "{{ .Values.global.priorityClassName }}" +{{- end }} + containers: + - name: discovery +{{- if contains "/" .Values.image }} + image: "{{ .Values.image }}" +{{- else }} + image: "{{ .Values.global.hub }}/{{ .Values.image }}:{{ .Values.global.tag }}" +{{- end }} + imagePullPolicy: {{ .Values.global.imagePullPolicy }} + args: + - "discovery" + - --monitoringAddr=:{{ .Values.global.monitoringPort }} +{{- if $.Values.global.logging.level }} + - --log_output_level={{ $.Values.global.logging.level }} +{{- end}} + - --domain + - {{ .Values.global.proxy.clusterDomain }} +{{- if .Values.global.oneNamespace }} + - "-a" + - {{ .Release.Namespace }} +{{- end }} +{{- if and $.Values.global.controlPlaneSecurityEnabled (not .Values.sidecar)}} + - --secureGrpcAddr + - ":15011" +{{- else }} + - --secureGrpcAddr + - "" +{{- end }} +{{- if .Values.global.trustDomain }} + - --trust-domain={{ .Values.global.trustDomain }} +{{- end }} + - --keepaliveMaxServerConnectionAge + - "{{ .Values.keepaliveMaxServerConnectionAge }}" + ports: + - containerPort: 8080 + - containerPort: 15010 +{{- if not .Values.sidecar }} + - containerPort: 15011 +{{- end }} + readinessProbe: + httpGet: + path: /ready + port: 8080 + initialDelaySeconds: 5 + periodSeconds: 5 + timeoutSeconds: 5 + env: + - name: POD_NAME + valueFrom: + fieldRef: + apiVersion: v1 + fieldPath: metadata.name + - name: POD_NAMESPACE + valueFrom: + fieldRef: + apiVersion: v1 + fieldPath: metadata.namespace + {{- if .Values.env }} + {{- range $key, $val := .Values.env }} + - name: {{ $key }} + value: "{{ $val }}" + {{- end }} + {{- end }} +{{- if .Values.traceSampling }} + - name: PILOT_TRACE_SAMPLING + value: "{{ .Values.traceSampling }}" +{{- end }} + - name: PILOT_ENABLE_PROTOCOL_SNIFFING_FOR_OUTBOUND + value: "{{ .Values.enableProtocolSniffingForOutbound }}" + - name: PILOT_ENABLE_PROTOCOL_SNIFFING_FOR_INBOUND + value: "{{ .Values.enableProtocolSniffingForInbound }}" + resources: +{{- if .Values.resources }} +{{ toYaml .Values.resources | indent 12 }} +{{- else }} +{{ toYaml .Values.global.defaultResources | indent 12 }} +{{- end }} + volumeMounts: + - name: config-volume + mountPath: /etc/istio/config + - name: istio-certs + mountPath: /etc/certs + readOnly: true +{{- if .Values.jwksResolverExtraRootCA }} + - name: extracacerts + mountPath: /cacerts +{{- end }} +{{- if .Values.sidecar }} + - name: istio-proxy +{{- if contains "/" .Values.global.proxy.image }} + image: "{{ .Values.global.proxy.image }}" +{{- else }} + image: "{{ .Values.global.hub }}/{{ .Values.global.proxy.image }}:{{ .Values.global.tag }}" +{{- end }} + imagePullPolicy: {{ .Values.global.imagePullPolicy }} + ports: + - containerPort: 15003 + - containerPort: 15005 + - containerPort: 15007 + - containerPort: 15011 + args: + - proxy + - --domain + - $(POD_NAMESPACE).svc.{{ .Values.global.proxy.clusterDomain }} + - --serviceCluster + - istio-pilot + - --templateFile + - /etc/istio/proxy/envoy_pilot.yaml.tmpl + {{- if $.Values.global.controlPlaneSecurityEnabled}} + - --controlPlaneAuthPolicy + - MUTUAL_TLS + {{- else }} + - --controlPlaneAuthPolicy + - NONE + {{- end }} + {{- if .Values.global.trustDomain }} + - --trust-domain={{ .Values.global.trustDomain }} + {{- end }} + {{- if $.Values.global.proxy.logLevel }} + - --proxyLogLevel={{ $.Values.global.proxy.logLevel }} + {{- end}} + {{- if $.Values.global.proxy.componentLogLevel }} + - --proxyComponentLogLevel={{ $.Values.global.proxy.componentLogLevel }} + {{- end}} + {{- if $.Values.global.logging.level }} + - --log_output_level={{ $.Values.global.logging.level }} + {{- end}} + env: + - name: POD_NAME + valueFrom: + fieldRef: + apiVersion: v1 + fieldPath: metadata.name + - name: POD_NAMESPACE + valueFrom: + fieldRef: + apiVersion: v1 + fieldPath: metadata.namespace + - name: INSTANCE_IP + valueFrom: + fieldRef: + apiVersion: v1 + fieldPath: status.podIP + - name: SDS_ENABLED + value: "{{ $.Values.global.sds.enabled }}" + resources: +{{- if .Values.global.proxy.resources }} +{{ toYaml .Values.global.proxy.resources | indent 12 }} +{{- else }} +{{ toYaml .Values.global.defaultResources | indent 12 }} +{{- end }} + volumeMounts: + - name: istio-certs + mountPath: /etc/certs + readOnly: true + {{- if $.Values.global.sds.enabled }} + - name: sds-uds-path + mountPath: /var/run/sds + readOnly: true + - name: istio-token + mountPath: /var/run/secrets/tokens + {{- end }} +{{- end }} + volumes: + {{- if $.Values.global.sds.enabled }} + - hostPath: + path: /var/run/sds + name: sds-uds-path + - name: istio-token + projected: + sources: + - serviceAccountToken: + audience: {{ $.Values.global.sds.token.aud }} + expirationSeconds: 43200 + path: istio-token + {{- end }} + - name: config-volume + configMap: + name: istio + - name: istio-certs + secret: + secretName: istio.istio-pilot-service-account + optional: true +{{- if .Values.jwksResolverExtraRootCA }} + - name: extracacerts + configMap: + name: istio-jwks-extra-cacerts +{{- end }} + affinity: + {{- include "nodeaffinity" . | indent 6 }} + {{- include "podAntiAffinity" . | indent 6 }} + {{- if .Values.tolerations }} + tolerations: +{{ toYaml .Values.tolerations | indent 6 }} + {{- else if .Values.global.defaultTolerations }} + tolerations: +{{ toYaml .Values.global.defaultTolerations | indent 6 }} + {{- end }} diff --git a/istio-1.5.0/install/kubernetes/helm/istio/charts/pilot/templates/meshexpansion.yaml b/istio-1.5.0/install/kubernetes/helm/istio/charts/pilot/templates/meshexpansion.yaml new file mode 100644 index 0000000..4f3d595 --- /dev/null +++ b/istio-1.5.0/install/kubernetes/helm/istio/charts/pilot/templates/meshexpansion.yaml @@ -0,0 +1,91 @@ +{{- if .Values.global.meshExpansion.enabled }} +{{- if .Values.global.meshExpansion.useILB }} +apiVersion: networking.istio.io/v1alpha3 +kind: VirtualService +metadata: + name: meshexpansion-ilb-vs-pilot + namespace: {{ .Release.Namespace }} + labels: + app: {{ template "pilot.name" . }} + chart: {{ template "pilot.chart" . }} + heritage: {{ .Release.Service }} + release: {{ .Release.Name }} +spec: + hosts: + - istio-pilot.{{ .Release.Namespace }}.svc.{{ .Values.global.proxy.clusterDomain }} + gateways: + - meshexpansion-ilb-gateway + tcp: + - match: + - port: 15011 + route: + - destination: + host: istio-pilot.{{ .Release.Namespace }}.svc.{{ .Values.global.proxy.clusterDomain }} + port: + number: 15011 + - match: + - port: 15010 + route: + - destination: + host: istio-pilot.{{ .Release.Namespace }}.svc.{{ .Values.global.proxy.clusterDomain }} + port: + number: 15010 + - match: + - port: 5353 + route: + - destination: + host: kube-dns.kube-system.svc.{{ .Values.global.proxy.clusterDomain }} + port: + number: 53 +--- +{{- else }} + +apiVersion: networking.istio.io/v1alpha3 +kind: VirtualService +metadata: + name: meshexpansion-vs-pilot + namespace: {{ .Release.Namespace }} + labels: + app: {{ template "pilot.name" . }} + chart: {{ template "pilot.chart" . }} + heritage: {{ .Release.Service }} + release: {{ .Release.Name }} +spec: + hosts: + - istio-pilot.{{ $.Release.Namespace }}.svc.{{ .Values.global.proxy.clusterDomain }} + gateways: + - meshexpansion-gateway + tcp: + - match: + - port: 15011 + route: + - destination: + host: istio-pilot.{{ $.Release.Namespace }}.svc.{{ .Values.global.proxy.clusterDomain }} + port: + number: 15011 +--- +{{- end }} + +{{- if .Values.global.controlPlaneSecurityEnabled }} +apiVersion: networking.istio.io/v1alpha3 +kind: DestinationRule +metadata: + name: meshexpansion-dr-pilot + namespace: {{ .Release.Namespace }} + labels: + app: {{ template "pilot.name" . }} + chart: {{ template "pilot.chart" . }} + heritage: {{ .Release.Service }} + release: {{ .Release.Name }} +spec: + host: istio-pilot.{{ .Release.Namespace }}.svc.{{ .Values.global.proxy.clusterDomain }} + trafficPolicy: + portLevelSettings: + - port: + number: 15011 + tls: + mode: DISABLE +--- +{{- end }} +{{- end }} + diff --git a/istio-1.5.0/install/kubernetes/helm/istio/charts/pilot/templates/poddisruptionbudget.yaml b/istio-1.5.0/install/kubernetes/helm/istio/charts/pilot/templates/poddisruptionbudget.yaml new file mode 100644 index 0000000..a432023 --- /dev/null +++ b/istio-1.5.0/install/kubernetes/helm/istio/charts/pilot/templates/poddisruptionbudget.yaml @@ -0,0 +1,20 @@ +{{- if .Values.global.defaultPodDisruptionBudget.enabled }} +apiVersion: policy/v1beta1 +kind: PodDisruptionBudget +metadata: + name: istio-pilot + namespace: {{ .Release.Namespace }} + labels: + app: {{ template "pilot.name" . }} + chart: {{ template "pilot.chart" . }} + heritage: {{ .Release.Service }} + release: {{ .Release.Name }} + istio: pilot +spec: +{{ include "podDisruptionBudget.spec" .Values.global.defaultPodDisruptionBudget }} + selector: + matchLabels: + app: {{ template "pilot.name" . }} + release: {{ .Release.Name }} + istio: pilot +{{- end }} diff --git a/istio-1.5.0/install/kubernetes/helm/istio/charts/pilot/templates/service.yaml b/istio-1.5.0/install/kubernetes/helm/istio/charts/pilot/templates/service.yaml new file mode 100644 index 0000000..a61d930 --- /dev/null +++ b/istio-1.5.0/install/kubernetes/helm/istio/charts/pilot/templates/service.yaml @@ -0,0 +1,23 @@ +apiVersion: v1 +kind: Service +metadata: + name: istio-pilot + namespace: {{ .Release.Namespace }} + labels: + app: {{ template "pilot.name" . }} + chart: {{ template "pilot.chart" . }} + heritage: {{ .Release.Service }} + release: {{ .Release.Name }} + istio: pilot +spec: + ports: + - port: 15010 + name: grpc-xds # direct + - port: 15011 + name: https-xds # mTLS + - port: 8080 + name: http-legacy-discovery # direct + - port: {{ .Values.global.monitoringPort }} + name: http-monitoring + selector: + istio: pilot diff --git a/istio-1.5.0/install/kubernetes/helm/istio/charts/pilot/templates/serviceaccount.yaml b/istio-1.5.0/install/kubernetes/helm/istio/charts/pilot/templates/serviceaccount.yaml new file mode 100644 index 0000000..7ec2a66 --- /dev/null +++ b/istio-1.5.0/install/kubernetes/helm/istio/charts/pilot/templates/serviceaccount.yaml @@ -0,0 +1,16 @@ +apiVersion: v1 +kind: ServiceAccount +{{- if .Values.global.imagePullSecrets }} +imagePullSecrets: +{{- range .Values.global.imagePullSecrets }} + - name: {{ . }} +{{- end }} +{{- end }} +metadata: + name: istio-pilot-service-account + namespace: {{ .Release.Namespace }} + labels: + app: {{ template "pilot.name" . }} + chart: {{ template "pilot.chart" . }} + heritage: {{ .Release.Service }} + release: {{ .Release.Name }} diff --git a/istio-1.5.0/install/kubernetes/helm/istio/charts/pilot/values.yaml b/istio-1.5.0/install/kubernetes/helm/istio/charts/pilot/values.yaml new file mode 100644 index 0000000..0d37ec5 --- /dev/null +++ b/istio-1.5.0/install/kubernetes/helm/istio/charts/pilot/values.yaml @@ -0,0 +1,63 @@ +# +# pilot configuration +# +enabled: true +autoscaleEnabled: true +autoscaleMin: 1 +autoscaleMax: 5 +# specify replicaCount when autoscaleEnabled: false +# replicaCount: 1 +rollingMaxSurge: 100% +rollingMaxUnavailable: 25% +image: pilot +sidecar: true +traceSampling: 1.0 +# if protocol sniffing is enabled for outbound +enableProtocolSniffingForOutbound: true +# if protocol sniffing is enabled for inbound +enableProtocolSniffingForInbound: false +# Resources for a small pilot install +resources: + requests: + cpu: 500m + memory: 2048Mi +env: + PILOT_PUSH_THROTTLE: 100 +cpu: + targetAverageUtilization: 80 +nodeSelector: {} +tolerations: [] +podAnnotations: {} + +# Specify the pod anti-affinity that allows you to constrain which nodes +# your pod is eligible to be scheduled based on labels on pods that are +# already running on the node rather than based on labels on nodes. +# There are currently two types of anti-affinity: +# "requiredDuringSchedulingIgnoredDuringExecution" +# "preferredDuringSchedulingIgnoredDuringExecution" +# which denote "hard" vs. "soft" requirements, you can define your values +# in "podAntiAffinityLabelSelector" and "podAntiAffinityTermLabelSelector" +# correspondingly. +# For example: +# podAntiAffinityLabelSelector: +# - key: security +# operator: In +# values: S1,S2 +# topologyKey: "kubernetes.io/hostname" +# This pod anti-affinity rule says that the pod requires not to be scheduled +# onto a node if that node is already running a pod with label having key +# "security" and value "S1". +podAntiAffinityLabelSelector: [] +podAntiAffinityTermLabelSelector: [] + +# The following is used to limit how long a sidecar can be connected +# to a pilot. It balances out load across pilot instances at the cost of +# increasing system churn. +keepaliveMaxServerConnectionAge: 30m + +# This is used to set the source of configuration for +# the associated address in configSource, if nothing is specificed +# the default MCP is assumed. The alternative option is SERVICE_REGISTRY +# which describes the source is only forwarding synthetic service entries +configSource: + subscribedResources: diff --git a/istio-1.5.0/install/kubernetes/helm/istio/charts/prometheus/Chart.yaml b/istio-1.5.0/install/kubernetes/helm/istio/charts/prometheus/Chart.yaml new file mode 100644 index 0000000..9b3424f --- /dev/null +++ b/istio-1.5.0/install/kubernetes/helm/istio/charts/prometheus/Chart.yaml @@ -0,0 +1,6 @@ +apiVersion: v1 +description: A Helm chart for Kubernetes +name: prometheus +version: 1.5.0 +appVersion: 2.8.0 +tillerVersion: ">=2.7.2" diff --git a/istio-1.5.0/install/kubernetes/helm/istio/charts/prometheus/templates/_helpers.tpl b/istio-1.5.0/install/kubernetes/helm/istio/charts/prometheus/templates/_helpers.tpl new file mode 100644 index 0000000..0393883 --- /dev/null +++ b/istio-1.5.0/install/kubernetes/helm/istio/charts/prometheus/templates/_helpers.tpl @@ -0,0 +1,32 @@ +{{/* vim: set filetype=mustache: */}} +{{/* +Expand the name of the chart. +*/}} +{{- define "prometheus.name" -}} +{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" -}} +{{- end -}} + +{{/* +Create a default fully qualified app name. +We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). +If release name contains chart name it will be used as a full name. +*/}} +{{- define "prometheus.fullname" -}} +{{- if .Values.fullnameOverride -}} +{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" -}} +{{- else -}} +{{- $name := default .Chart.Name .Values.nameOverride -}} +{{- if contains $name .Release.Name -}} +{{- .Release.Name | trunc 63 | trimSuffix "-" -}} +{{- else -}} +{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" -}} +{{- end -}} +{{- end -}} +{{- end -}} + +{{/* +Create chart name and version as used by the chart label. +*/}} +{{- define "prometheus.chart" -}} +{{- .Chart.Name | trunc 63 | trimSuffix "-" -}} +{{- end -}} diff --git a/istio-1.5.0/install/kubernetes/helm/istio/charts/prometheus/templates/clusterrole.yaml b/istio-1.5.0/install/kubernetes/helm/istio/charts/prometheus/templates/clusterrole.yaml new file mode 100644 index 0000000..06fdfaf --- /dev/null +++ b/istio-1.5.0/install/kubernetes/helm/istio/charts/prometheus/templates/clusterrole.yaml @@ -0,0 +1,24 @@ +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: prometheus-{{ .Release.Namespace }} + labels: + app: prometheus + chart: {{ template "prometheus.chart" . }} + heritage: {{ .Release.Service }} + release: {{ .Release.Name }} +rules: +- apiGroups: [""] + resources: + - nodes + - services + - endpoints + - pods + - nodes/proxy + verbs: ["get", "list", "watch"] +- apiGroups: [""] + resources: + - configmaps + verbs: ["get"] +- nonResourceURLs: ["/metrics"] + verbs: ["get"] diff --git a/istio-1.5.0/install/kubernetes/helm/istio/charts/prometheus/templates/clusterrolebindings.yaml b/istio-1.5.0/install/kubernetes/helm/istio/charts/prometheus/templates/clusterrolebindings.yaml new file mode 100644 index 0000000..295e0df --- /dev/null +++ b/istio-1.5.0/install/kubernetes/helm/istio/charts/prometheus/templates/clusterrolebindings.yaml @@ -0,0 +1,17 @@ +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: prometheus-{{ .Release.Namespace }} + labels: + app: prometheus + chart: {{ template "prometheus.chart" . }} + heritage: {{ .Release.Service }} + release: {{ .Release.Name }} +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: prometheus-{{ .Release.Namespace }} +subjects: +- kind: ServiceAccount + name: prometheus + namespace: {{ .Release.Namespace }} diff --git a/istio-1.5.0/install/kubernetes/helm/istio/charts/prometheus/templates/configmap.yaml b/istio-1.5.0/install/kubernetes/helm/istio/charts/prometheus/templates/configmap.yaml new file mode 100644 index 0000000..cfd0d43 --- /dev/null +++ b/istio-1.5.0/install/kubernetes/helm/istio/charts/prometheus/templates/configmap.yaml @@ -0,0 +1,294 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: prometheus + namespace: {{ .Release.Namespace }} + labels: + app: prometheus + chart: {{ template "prometheus.chart" . }} + heritage: {{ .Release.Service }} + release: {{ .Release.Name }} +data: + prometheus.yml: |- + global: + scrape_interval: {{ .Values.scrapeInterval }} + scrape_configs: + + - job_name: 'istio-mesh' + kubernetes_sd_configs: + - role: endpoints + namespaces: + names: + - {{ .Release.Namespace }} + + relabel_configs: + - source_labels: [__meta_kubernetes_service_name, __meta_kubernetes_endpoint_port_name] + action: keep + regex: istio-telemetry;prometheus + + # Scrape config for envoy stats + - job_name: 'envoy-stats' + metrics_path: /stats/prometheus + kubernetes_sd_configs: + - role: pod + + relabel_configs: + - source_labels: [__meta_kubernetes_pod_container_port_name] + action: keep + regex: '.*-envoy-prom' + - source_labels: [__address__, __meta_kubernetes_pod_annotation_prometheus_io_port] + action: replace + regex: ([^:]+)(?::\d+)?;(\d+) + replacement: $1:15090 + target_label: __address__ + - action: labelmap + regex: __meta_kubernetes_pod_label_(.+) + - source_labels: [__meta_kubernetes_namespace] + action: replace + target_label: namespace + - source_labels: [__meta_kubernetes_pod_name] + action: replace + target_label: pod_name + + - job_name: 'istio-policy' + kubernetes_sd_configs: + - role: endpoints + namespaces: + names: + - {{ .Release.Namespace }} + + + relabel_configs: + - source_labels: [__meta_kubernetes_service_name, __meta_kubernetes_endpoint_port_name] + action: keep + regex: istio-policy;http-monitoring + + - job_name: 'istio-telemetry' + kubernetes_sd_configs: + - role: endpoints + namespaces: + names: + - {{ .Release.Namespace }} + + relabel_configs: + - source_labels: [__meta_kubernetes_service_name, __meta_kubernetes_endpoint_port_name] + action: keep + regex: istio-telemetry;http-monitoring + + - job_name: 'pilot' + kubernetes_sd_configs: + - role: endpoints + namespaces: + names: + - {{ .Release.Namespace }} + + relabel_configs: + - source_labels: [__meta_kubernetes_service_name, __meta_kubernetes_endpoint_port_name] + action: keep + regex: istio-pilot;http-monitoring + + - job_name: 'galley' + kubernetes_sd_configs: + - role: endpoints + namespaces: + names: + - {{ .Release.Namespace }} + + relabel_configs: + - source_labels: [__meta_kubernetes_service_name, __meta_kubernetes_endpoint_port_name] + action: keep + regex: istio-galley;http-monitoring + + - job_name: 'citadel' + kubernetes_sd_configs: + - role: endpoints + namespaces: + names: + - {{ .Release.Namespace }} + + relabel_configs: + - source_labels: [__meta_kubernetes_service_name, __meta_kubernetes_endpoint_port_name] + action: keep + regex: istio-citadel;http-monitoring + + - job_name: 'sidecar-injector' + + kubernetes_sd_configs: + - role: endpoints + namespaces: + names: + - {{ .Release.Namespace }} + + relabel_configs: + - source_labels: [__meta_kubernetes_service_name, __meta_kubernetes_endpoint_port_name] + action: keep + regex: istio-sidecar-injector;http-monitoring + + # scrape config for API servers + - job_name: 'kubernetes-apiservers' + kubernetes_sd_configs: + - role: endpoints + namespaces: + names: + - default + scheme: https + tls_config: + ca_file: /var/run/secrets/kubernetes.io/serviceaccount/ca.crt + bearer_token_file: /var/run/secrets/kubernetes.io/serviceaccount/token + relabel_configs: + - source_labels: [__meta_kubernetes_service_name, __meta_kubernetes_endpoint_port_name] + action: keep + regex: kubernetes;https + + # scrape config for nodes (kubelet) + - job_name: 'kubernetes-nodes' + scheme: https + tls_config: + ca_file: /var/run/secrets/kubernetes.io/serviceaccount/ca.crt + bearer_token_file: /var/run/secrets/kubernetes.io/serviceaccount/token + kubernetes_sd_configs: + - role: node + relabel_configs: + - action: labelmap + regex: __meta_kubernetes_node_label_(.+) + - target_label: __address__ + replacement: kubernetes.default.svc:443 + - source_labels: [__meta_kubernetes_node_name] + regex: (.+) + target_label: __metrics_path__ + replacement: /api/v1/nodes/${1}/proxy/metrics + + # Scrape config for Kubelet cAdvisor. + # + # This is required for Kubernetes 1.7.3 and later, where cAdvisor metrics + # (those whose names begin with 'container_') have been removed from the + # Kubelet metrics endpoint. This job scrapes the cAdvisor endpoint to + # retrieve those metrics. + # + # In Kubernetes 1.7.0-1.7.2, these metrics are only exposed on the cAdvisor + # HTTP endpoint; use "replacement: /api/v1/nodes/${1}:4194/proxy/metrics" + # in that case (and ensure cAdvisor's HTTP server hasn't been disabled with + # the --cadvisor-port=0 Kubelet flag). + # + # This job is not necessary and should be removed in Kubernetes 1.6 and + # earlier versions, or it will cause the metrics to be scraped twice. + - job_name: 'kubernetes-cadvisor' + scheme: https + tls_config: + ca_file: /var/run/secrets/kubernetes.io/serviceaccount/ca.crt + bearer_token_file: /var/run/secrets/kubernetes.io/serviceaccount/token + kubernetes_sd_configs: + - role: node + relabel_configs: + - action: labelmap + regex: __meta_kubernetes_node_label_(.+) + - target_label: __address__ + replacement: kubernetes.default.svc:443 + - source_labels: [__meta_kubernetes_node_name] + regex: (.+) + target_label: __metrics_path__ + replacement: /api/v1/nodes/${1}/proxy/metrics/cadvisor + + # scrape config for service endpoints. + - job_name: 'kubernetes-service-endpoints' + kubernetes_sd_configs: + - role: endpoints + relabel_configs: + - source_labels: [__meta_kubernetes_service_annotation_prometheus_io_scrape] + action: keep + regex: true + - source_labels: [__meta_kubernetes_service_annotation_prometheus_io_scheme] + action: replace + target_label: __scheme__ + regex: (https?) + - source_labels: [__meta_kubernetes_service_annotation_prometheus_io_path] + action: replace + target_label: __metrics_path__ + regex: (.+) + - source_labels: [__address__, __meta_kubernetes_service_annotation_prometheus_io_port] + action: replace + target_label: __address__ + regex: ([^:]+)(?::\d+)?;(\d+) + replacement: $1:$2 + - action: labelmap + regex: __meta_kubernetes_service_label_(.+) + - source_labels: [__meta_kubernetes_namespace] + action: replace + target_label: kubernetes_namespace + - source_labels: [__meta_kubernetes_service_name] + action: replace + target_label: kubernetes_name + + - job_name: 'kubernetes-pods' + kubernetes_sd_configs: + - role: pod + relabel_configs: # If first two labels are present, pod should be scraped by the istio-secure job. + - source_labels: [__meta_kubernetes_pod_annotation_prometheus_io_scrape] + action: keep + regex: true + # Keep target if there's no sidecar or if prometheus.io/scheme is explicitly set to "http" + - source_labels: [__meta_kubernetes_pod_annotation_sidecar_istio_io_status, __meta_kubernetes_pod_annotation_prometheus_io_scheme] + action: keep + regex: ((;.*)|(.*;http)) + - source_labels: [__meta_kubernetes_pod_annotation_istio_mtls] + action: drop + regex: (true) + - source_labels: [__meta_kubernetes_pod_annotation_prometheus_io_path] + action: replace + target_label: __metrics_path__ + regex: (.+) + - source_labels: [__address__, __meta_kubernetes_pod_annotation_prometheus_io_port] + action: replace + regex: ([^:]+)(?::\d+)?;(\d+) + replacement: $1:$2 + target_label: __address__ + - action: labelmap + regex: __meta_kubernetes_pod_label_(.+) + - source_labels: [__meta_kubernetes_namespace] + action: replace + target_label: namespace + - source_labels: [__meta_kubernetes_pod_name] + action: replace + target_label: pod_name + + - job_name: 'kubernetes-pods-istio-secure' + scheme: https + tls_config: + ca_file: /etc/istio-certs/root-cert.pem + cert_file: /etc/istio-certs/cert-chain.pem + key_file: /etc/istio-certs/key.pem + insecure_skip_verify: true # prometheus does not support secure naming. + kubernetes_sd_configs: + - role: pod + relabel_configs: + - source_labels: [__meta_kubernetes_pod_annotation_prometheus_io_scrape] + action: keep + regex: true + # sidecar status annotation is added by sidecar injector and + # istio_workload_mtls_ability can be specifically placed on a pod to indicate its ability to receive mtls traffic. + - source_labels: [__meta_kubernetes_pod_annotation_sidecar_istio_io_status, __meta_kubernetes_pod_annotation_istio_mtls] + action: keep + regex: (([^;]+);([^;]*))|(([^;]*);(true)) + - source_labels: [__meta_kubernetes_pod_annotation_prometheus_io_scheme] + action: drop + regex: (http) + - source_labels: [__meta_kubernetes_pod_annotation_prometheus_io_path] + action: replace + target_label: __metrics_path__ + regex: (.+) + - source_labels: [__address__] # Only keep address that is host:port + action: keep # otherwise an extra target with ':443' is added for https scheme + regex: ([^:]+):(\d+) + - source_labels: [__address__, __meta_kubernetes_pod_annotation_prometheus_io_port] + action: replace + regex: ([^:]+)(?::\d+)?;(\d+) + replacement: $1:$2 + target_label: __address__ + - action: labelmap + regex: __meta_kubernetes_pod_label_(.+) + - source_labels: [__meta_kubernetes_namespace] + action: replace + target_label: namespace + - source_labels: [__meta_kubernetes_pod_name] + action: replace + target_label: pod_name diff --git a/istio-1.5.0/install/kubernetes/helm/istio/charts/prometheus/templates/deployment.yaml b/istio-1.5.0/install/kubernetes/helm/istio/charts/prometheus/templates/deployment.yaml new file mode 100644 index 0000000..64214e0 --- /dev/null +++ b/istio-1.5.0/install/kubernetes/helm/istio/charts/prometheus/templates/deployment.yaml @@ -0,0 +1,80 @@ +# TODO: the original template has service account, roles, etc +apiVersion: apps/v1 +kind: Deployment +metadata: + name: prometheus + namespace: {{ .Release.Namespace }} + labels: + app: prometheus + chart: {{ template "prometheus.chart" . }} + heritage: {{ .Release.Service }} + release: {{ .Release.Name }} +spec: + replicas: {{ .Values.replicaCount }} + selector: + matchLabels: + app: prometheus + template: + metadata: + labels: + app: prometheus + chart: {{ template "prometheus.chart" . }} + heritage: {{ .Release.Service }} + release: {{ .Release.Name }} + annotations: + sidecar.istio.io/inject: "false" + spec: + serviceAccountName: prometheus +{{- if .Values.global.priorityClassName }} + priorityClassName: "{{ .Values.global.priorityClassName }}" +{{- end }} + containers: + - name: prometheus + image: "{{ .Values.hub }}/{{ .Values.image }}:{{ .Values.tag }}" + imagePullPolicy: {{ .Values.global.imagePullPolicy }} + args: + - '--storage.tsdb.retention={{ .Values.retention }}' + - '--config.file=/etc/prometheus/prometheus.yml' + ports: + - containerPort: 9090 + name: http + livenessProbe: + httpGet: + path: /-/healthy + port: 9090 + readinessProbe: + httpGet: + path: /-/ready + port: 9090 + resources: +{{- if .Values.resources }} +{{ toYaml .Values.resources | indent 12 }} +{{- else }} +{{ toYaml .Values.global.defaultResources | indent 12 }} +{{- end }} + volumeMounts: + - name: config-volume + mountPath: /etc/prometheus + - mountPath: /etc/istio-certs + name: istio-certs + volumes: + - name: config-volume + configMap: + name: prometheus + - name: istio-certs + secret: + defaultMode: 420 +{{- if not .Values.security.enabled }} + optional: true +{{- end }} + secretName: istio.default + affinity: + {{- include "nodeaffinity" . | indent 6 }} + {{- include "podAntiAffinity" . | indent 6 }} + {{- if .Values.tolerations }} + tolerations: +{{ toYaml .Values.tolerations | indent 6 }} + {{- else if .Values.global.defaultTolerations }} + tolerations: +{{ toYaml .Values.global.defaultTolerations | indent 6 }} + {{- end }} diff --git a/istio-1.5.0/install/kubernetes/helm/istio/charts/prometheus/templates/ingress.yaml b/istio-1.5.0/install/kubernetes/helm/istio/charts/prometheus/templates/ingress.yaml new file mode 100644 index 0000000..43be655 --- /dev/null +++ b/istio-1.5.0/install/kubernetes/helm/istio/charts/prometheus/templates/ingress.yaml @@ -0,0 +1,40 @@ +{{- if .Values.ingress.enabled -}} +apiVersion: extensions/v1beta1 +kind: Ingress +metadata: + name: prometheus + namespace: {{ .Release.Namespace }} + labels: + app: prometheus + chart: {{ template "prometheus.chart" . }} + heritage: {{ .Release.Service }} + release: {{ .Release.Name }} + annotations: + {{- range $key, $value := .Values.ingress.annotations }} + {{ $key }}: {{ $value | quote }} + {{- end }} +spec: + rules: +{{- if .Values.ingress.hosts }} + {{- range $host := .Values.ingress.hosts }} + - host: {{ $host }} + http: + paths: + - path: {{ if $.Values.contextPath }} {{ $.Values.contextPath }} {{ else }} / {{ end }} + backend: + serviceName: prometheus + servicePort: 9090 + {{- end -}} +{{- else }} + - http: + paths: + - path: {{ if .Values.contextPath }} {{ .Values.contextPath }} {{ else }} / {{ end }} + backend: + serviceName: prometheus + servicePort: 9090 +{{- end }} + {{- if .Values.ingress.tls }} + tls: +{{ toYaml .Values.ingress.tls | indent 4 }} + {{- end -}} +{{- end -}} diff --git a/istio-1.5.0/install/kubernetes/helm/istio/charts/prometheus/templates/service.yaml b/istio-1.5.0/install/kubernetes/helm/istio/charts/prometheus/templates/service.yaml new file mode 100644 index 0000000..d92525d --- /dev/null +++ b/istio-1.5.0/install/kubernetes/helm/istio/charts/prometheus/templates/service.yaml @@ -0,0 +1,45 @@ +apiVersion: v1 +kind: Service +metadata: + name: prometheus + namespace: {{ .Release.Namespace }} + annotations: + prometheus.io/scrape: 'true' + {{- range $key, $val := .Values.service.annotations }} + {{ $key }}: {{ $val | quote }} + {{- end }} + labels: + app: prometheus + chart: {{ template "prometheus.chart" . }} + heritage: {{ .Release.Service }} + release: {{ .Release.Name }} +spec: + selector: + app: prometheus + ports: + - name: http-prometheus + protocol: TCP + port: 9090 + +{{- if .Values.service.nodePort.enabled }} +# Using separate ingress for nodeport, to avoid conflict with pilot e2e test configs. +--- +apiVersion: v1 +kind: Service +metadata: + name: prometheus-nodeport + namespace: {{ .Release.Namespace }} + labels: + app: prometheus + chart: {{ template "prometheus.chart" . }} + heritage: {{ .Release.Service }} + release: {{ .Release.Name }} +spec: + type: NodePort + ports: + - port: 9090 + nodePort: {{ .Values.service.nodePort.port }} + name: http-prometheus + selector: + app: prometheus +{{- end }} diff --git a/istio-1.5.0/install/kubernetes/helm/istio/charts/prometheus/templates/serviceaccount.yaml b/istio-1.5.0/install/kubernetes/helm/istio/charts/prometheus/templates/serviceaccount.yaml new file mode 100644 index 0000000..7c2fab3 --- /dev/null +++ b/istio-1.5.0/install/kubernetes/helm/istio/charts/prometheus/templates/serviceaccount.yaml @@ -0,0 +1,16 @@ +apiVersion: v1 +kind: ServiceAccount +{{- if .Values.global.imagePullSecrets }} +imagePullSecrets: +{{- range .Values.global.imagePullSecrets }} + - name: {{ . }} +{{- end }} +{{- end }} +metadata: + name: prometheus + namespace: {{ .Release.Namespace }} + labels: + app: prometheus + chart: {{ template "prometheus.chart" . }} + heritage: {{ .Release.Service }} + release: {{ .Release.Name }} diff --git a/istio-1.5.0/install/kubernetes/helm/istio/charts/prometheus/templates/tests/test-prometheus-connection.yaml b/istio-1.5.0/install/kubernetes/helm/istio/charts/prometheus/templates/tests/test-prometheus-connection.yaml new file mode 100644 index 0000000..45b025e --- /dev/null +++ b/istio-1.5.0/install/kubernetes/helm/istio/charts/prometheus/templates/tests/test-prometheus-connection.yaml @@ -0,0 +1,36 @@ +{{- if .Values.global.enableHelmTest }} +apiVersion: v1 +kind: Pod +metadata: + name: {{ template "prometheus.fullname" . }}-test + namespace: {{ .Release.Namespace }} + labels: + app: prometheus-test + chart: {{ template "prometheus.chart" . }} + release: {{ .Release.Name }} + heritage: {{ .Release.Service }} + istio: prometheus + annotations: + sidecar.istio.io/inject: "false" + helm.sh/hook: test-success +spec: +{{- if .Values.global.priorityClassName }} + priorityClassName: "{{ .Values.global.priorityClassName }}" +{{- end }} + containers: + - name: "{{ template "prometheus.fullname" . }}-test" + image: pstauffer/curl:v1.0.3 + imagePullPolicy: "{{ .Values.global.imagePullPolicy }}" + command: ['sh', '-c', 'for i in 1 2 3; do curl http://prometheus:9090/-/ready && exit 0 || sleep 15; done; exit 1'] + restartPolicy: Never + affinity: + {{- include "nodeaffinity" . | indent 4 }} + {{- include "podAntiAffinity" . | indent 4 }} + {{- if .Values.tolerations }} + tolerations: +{{ toYaml .Values.tolerations | indent 2 }} + {{- else if .Values.global.defaultTolerations }} + tolerations: +{{ toYaml .Values.global.defaultTolerations | indent 2 }} + {{- end }} +{{- end }} diff --git a/istio-1.5.0/install/kubernetes/helm/istio/charts/prometheus/values.yaml b/istio-1.5.0/install/kubernetes/helm/istio/charts/prometheus/values.yaml new file mode 100644 index 0000000..76bda84 --- /dev/null +++ b/istio-1.5.0/install/kubernetes/helm/istio/charts/prometheus/values.yaml @@ -0,0 +1,60 @@ +# +# addon prometheus configuration +# +enabled: true +replicaCount: 1 +hub: docker.io/prom +image: prometheus +tag: v2.12.0 +retention: 6h +nodeSelector: {} +tolerations: [] + +# Specify the pod anti-affinity that allows you to constrain which nodes +# your pod is eligible to be scheduled based on labels on pods that are +# already running on the node rather than based on labels on nodes. +# There are currently two types of anti-affinity: +# "requiredDuringSchedulingIgnoredDuringExecution" +# "preferredDuringSchedulingIgnoredDuringExecution" +# which denote "hard" vs. "soft" requirements, you can define your values +# in "podAntiAffinityLabelSelector" and "podAntiAffinityTermLabelSelector" +# correspondingly. +# For example: +# podAntiAffinityLabelSelector: +# - key: security +# operator: In +# values: S1,S2 +# topologyKey: "kubernetes.io/hostname" +# This pod anti-affinity rule says that the pod requires not to be scheduled +# onto a node if that node is already running a pod with label having key +# "security" and value "S1". +podAntiAffinityLabelSelector: [] +podAntiAffinityTermLabelSelector: [] + +# Controls the frequency of prometheus scraping +scrapeInterval: 15s + +contextPath: /prometheus + +ingress: + enabled: false + ## Used to create an Ingress record. + hosts: + - prometheus.local + annotations: + # kubernetes.io/ingress.class: nginx + # kubernetes.io/tls-acme: "true" + tls: + # Secrets must be manually created in the namespace. + # - secretName: prometheus-tls + # hosts: + # - prometheus.local + +service: + annotations: {} + nodePort: + enabled: false + port: 32090 + +security: + enabled: true diff --git a/istio-1.5.0/install/kubernetes/helm/istio/charts/security/Chart.yaml b/istio-1.5.0/install/kubernetes/helm/istio/charts/security/Chart.yaml new file mode 100644 index 0000000..454140f --- /dev/null +++ b/istio-1.5.0/install/kubernetes/helm/istio/charts/security/Chart.yaml @@ -0,0 +1,13 @@ +apiVersion: v1 +name: security +version: 1.5.0 +appVersion: 1.5.0 +tillerVersion: ">=2.7.2" +description: Helm chart for istio authentication +keywords: + - istio + - security +sources: + - http://github.com/istio/istio +engine: gotpl +icon: https://istio.io/favicons/android-192x192.png diff --git a/istio-1.5.0/install/kubernetes/helm/istio/charts/security/templates/_helpers.tpl b/istio-1.5.0/install/kubernetes/helm/istio/charts/security/templates/_helpers.tpl new file mode 100644 index 0000000..7f36f9d --- /dev/null +++ b/istio-1.5.0/install/kubernetes/helm/istio/charts/security/templates/_helpers.tpl @@ -0,0 +1,32 @@ +{{/* vim: set filetype=mustache: */}} +{{/* +Expand the name of the chart. +*/}} +{{- define "security.name" -}} +{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" -}} +{{- end -}} + +{{/* +Create a default fully qualified app name. +We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). +If release name contains chart name it will be used as a full name. +*/}} +{{- define "security.fullname" -}} +{{- if .Values.fullnameOverride -}} +{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" -}} +{{- else -}} +{{- $name := default .Chart.Name .Values.nameOverride -}} +{{- if contains $name .Release.Name -}} +{{- .Release.Name | trunc 63 | trimSuffix "-" -}} +{{- else -}} +{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" -}} +{{- end -}} +{{- end -}} +{{- end -}} + +{{/* +Create chart name and version as used by the chart label. +*/}} +{{- define "security.chart" -}} +{{- .Chart.Name | trunc 63 | trimSuffix "-" -}} +{{- end -}} diff --git a/istio-1.5.0/install/kubernetes/helm/istio/charts/security/templates/clusterrole.yaml b/istio-1.5.0/install/kubernetes/helm/istio/charts/security/templates/clusterrole.yaml new file mode 100644 index 0000000..75f2dec --- /dev/null +++ b/istio-1.5.0/install/kubernetes/helm/istio/charts/security/templates/clusterrole.yaml @@ -0,0 +1,22 @@ +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: istio-citadel-{{ .Release.Namespace }} + labels: + app: {{ template "security.name" . }} + chart: {{ template "security.chart" . }} + heritage: {{ .Release.Service }} + release: {{ .Release.Name }} +rules: +- apiGroups: [""] + resources: ["configmaps"] + verbs: ["create", "get", "update"] +- apiGroups: [""] + resources: ["secrets"] + verbs: ["create", "get", "watch", "list", "update", "delete"] +- apiGroups: [""] + resources: ["serviceaccounts", "services", "namespaces"] + verbs: ["get", "watch", "list"] +- apiGroups: ["authentication.k8s.io"] + resources: ["tokenreviews"] + verbs: ["create"] diff --git a/istio-1.5.0/install/kubernetes/helm/istio/charts/security/templates/clusterrolebinding.yaml b/istio-1.5.0/install/kubernetes/helm/istio/charts/security/templates/clusterrolebinding.yaml new file mode 100644 index 0000000..0a15799 --- /dev/null +++ b/istio-1.5.0/install/kubernetes/helm/istio/charts/security/templates/clusterrolebinding.yaml @@ -0,0 +1,17 @@ +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: istio-citadel-{{ .Release.Namespace }} + labels: + app: {{ template "security.name" . }} + chart: {{ template "security.chart" . }} + heritage: {{ .Release.Service }} + release: {{ .Release.Name }} +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: istio-citadel-{{ .Release.Namespace }} +subjects: + - kind: ServiceAccount + name: istio-citadel-service-account + namespace: {{ .Release.Namespace }} diff --git a/istio-1.5.0/install/kubernetes/helm/istio/charts/security/templates/configmap.yaml b/istio-1.5.0/install/kubernetes/helm/istio/charts/security/templates/configmap.yaml new file mode 100644 index 0000000..14749fd --- /dev/null +++ b/istio-1.5.0/install/kubernetes/helm/istio/charts/security/templates/configmap.yaml @@ -0,0 +1,20 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: istio-security-custom-resources + namespace: {{ .Release.Namespace }} + labels: + app: {{ template "security.name" . }} + chart: {{ template "security.chart" . }} + heritage: {{ .Release.Service }} + release: {{ .Release.Name }} + istio: citadel +data: + custom-resources.yaml: |- + {{- if .Values.global.mtls.enabled }} + {{- include "security-default.yaml.tpl" . | indent 4}} + {{- else }} + {{- include "security-permissive.yaml.tpl" . | indent 4}} + {{- end }} + run.sh: |- + {{- include "install-custom-resources.sh.tpl" . | indent 4}} diff --git a/istio-1.5.0/install/kubernetes/helm/istio/charts/security/templates/create-custom-resources-job.yaml b/istio-1.5.0/install/kubernetes/helm/istio/charts/security/templates/create-custom-resources-job.yaml new file mode 100644 index 0000000..0558d6e --- /dev/null +++ b/istio-1.5.0/install/kubernetes/helm/istio/charts/security/templates/create-custom-resources-job.yaml @@ -0,0 +1,109 @@ +{{- if .Values.createMeshPolicy }} +apiVersion: v1 +kind: ServiceAccount +{{- if .Values.global.imagePullSecrets }} +imagePullSecrets: +{{- range .Values.global.imagePullSecrets }} + - name: {{ . }} +{{- end }} +{{- end }} +metadata: + name: istio-security-post-install-account + namespace: {{ .Release.Namespace }} + labels: + app: {{ template "security.name" . }} + chart: {{ template "security.chart" . }} + heritage: {{ .Release.Service }} + release: {{ .Release.Name }} +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: istio-security-post-install-{{ .Release.Namespace }} + labels: + app: {{ template "security.name" . }} + chart: {{ template "security.chart" . }} + heritage: {{ .Release.Service }} + release: {{ .Release.Name }} +rules: +- apiGroups: ["authentication.istio.io"] # needed to create default authn policy + resources: ["*"] + verbs: ["*"] +- apiGroups: ["networking.istio.io"] # needed to create security destination rules + resources: ["*"] + verbs: ["*"] +- apiGroups: ["admissionregistration.k8s.io"] + resources: ["validatingwebhookconfigurations"] + verbs: ["get"] +- apiGroups: ["extensions", "apps"] + resources: ["deployments", "replicasets"] + verbs: ["get", "list", "watch"] +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: istio-security-post-install-role-binding-{{ .Release.Namespace }} + labels: + app: {{ template "security.name" . }} + chart: {{ template "security.chart" . }} + heritage: {{ .Release.Service }} + release: {{ .Release.Name }} +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: istio-security-post-install-{{ .Release.Namespace }} +subjects: + - kind: ServiceAccount + name: istio-security-post-install-account + namespace: {{ .Release.Namespace }} +--- +apiVersion: batch/v1 +kind: Job +metadata: + name: istio-security-post-install-{{ .Values.global.tag | printf "%v" | trunc 32 | trimSuffix "-" }} + namespace: {{ .Release.Namespace }} + annotations: + "helm.sh/hook": post-install,post-upgrade + "helm.sh/hook-delete-policy": hook-succeeded + labels: + app: {{ template "security.name" . }} + chart: {{ template "security.chart" . }} + heritage: {{ .Release.Service }} + release: {{ .Release.Name }} +spec: + template: + metadata: + name: istio-security-post-install + labels: + app: {{ template "security.name" . }} + chart: {{ template "security.chart" . }} + heritage: {{ .Release.Service }} + release: {{ .Release.Name }} + annotations: + sidecar.istio.io/inject: "false" + spec: + serviceAccountName: istio-security-post-install-account + containers: + - name: kubectl + image: "{{ .Values.global.hub }}/kubectl:{{ .Values.global.tag }}" + imagePullPolicy: IfNotPresent + command: [ "/bin/bash", "/tmp/security/run.sh", "/tmp/security/custom-resources.yaml" ] + volumeMounts: + - mountPath: "/tmp/security" + name: tmp-configmap-security + volumes: + - name: tmp-configmap-security + configMap: + name: istio-security-custom-resources + restartPolicy: OnFailure + affinity: + {{- include "nodeaffinity" . | indent 6 }} + {{- include "podAntiAffinity" . | indent 6 }} + {{- if .Values.tolerations }} + tolerations: +{{ toYaml .Values.tolerations | indent 6 }} + {{- else if .Values.global.defaultTolerations }} + tolerations: +{{ toYaml .Values.global.defaultTolerations | indent 6 }} + {{- end }} +{{- end }} diff --git a/istio-1.5.0/install/kubernetes/helm/istio/charts/security/templates/deployment.yaml b/istio-1.5.0/install/kubernetes/helm/istio/charts/security/templates/deployment.yaml new file mode 100644 index 0000000..2b3c8fe --- /dev/null +++ b/istio-1.5.0/install/kubernetes/helm/istio/charts/security/templates/deployment.yaml @@ -0,0 +1,123 @@ +# istio CA watching all namespaces +apiVersion: apps/v1 +kind: Deployment +metadata: + name: istio-citadel + namespace: {{ .Release.Namespace }} + labels: + app: {{ template "security.name" . }} + chart: {{ template "security.chart" . }} + heritage: {{ .Release.Service }} + release: {{ .Release.Name }} + istio: citadel +spec: + replicas: {{ .Values.replicaCount }} + selector: + matchLabels: + istio: citadel + strategy: + rollingUpdate: + maxSurge: {{ .Values.rollingMaxSurge }} + maxUnavailable: {{ .Values.rollingMaxUnavailable }} + template: + metadata: + labels: + app: {{ template "security.name" . }} + chart: {{ template "security.chart" . }} + heritage: {{ .Release.Service }} + release: {{ .Release.Name }} + istio: citadel + annotations: + sidecar.istio.io/inject: "false" + {{- if .Values.podAnnotations }} +{{ toYaml .Values.podAnnotations | indent 8 }} + {{- end }} + spec: + serviceAccountName: istio-citadel-service-account +{{- if .Values.global.priorityClassName }} + priorityClassName: "{{ .Values.global.priorityClassName }}" +{{- end }} + containers: + - name: citadel +{{- if contains "/" .Values.image }} + image: "{{ .Values.image }}" +{{- else }} + image: "{{ .Values.global.hub }}/{{ .Values.image }}:{{ .Values.global.tag }}" +{{- end }} + imagePullPolicy: {{ .Values.global.imagePullPolicy }} + args: + {{- if .Values.global.sds.enabled }} + - --sds-enabled=true + {{- end }} + - --append-dns-names=true + - --grpc-port=8060 + - --citadel-storage-namespace={{ .Release.Namespace }} + - --custom-dns-names=istio-pilot-service-account.{{ .Release.Namespace }}:istio-pilot.{{ .Release.Namespace }} + - --monitoring-port={{ .Values.global.monitoringPort }} + {{- if .Values.selfSigned }} + - --self-signed-ca=true + {{- else }} + - --self-signed-ca=false + - --signing-cert=/etc/cacerts/ca-cert.pem + - --signing-key=/etc/cacerts/ca-key.pem + - --root-cert=/etc/cacerts/root-cert.pem + - --cert-chain=/etc/cacerts/cert-chain.pem + {{- end }} + {{- if .Values.global.trustDomain }} + - --trust-domain={{ .Values.global.trustDomain }} + {{- end }} + {{- if .Values.workloadCertTtl }} + - --workload-cert-ttl={{ .Values.workloadCertTtl }} + {{- end }} + {{- if .Values.citadelHealthCheck }} + - --liveness-probe-path=/tmp/ca.liveness # path to the liveness health check status file + - --liveness-probe-interval=60s # interval for health check file update + - --probe-check-interval=15s # interval for health status check + {{- end }} + env: + - name: CITADEL_ENABLE_NAMESPACES_BY_DEFAULT + value: "{{ .Values.enableNamespacesByDefault }}" + {{- if .Values.env }} + {{- range $key, $val := .Values.env }} + - name: {{ $key }} + value: {{ $val | quote }} + {{- end }} + {{- end }} + {{- if .Values.citadelHealthCheck }} + livenessProbe: + exec: + command: + - /usr/local/bin/istio_ca + - probe + - --probe-path=/tmp/ca.liveness # path to the liveness health check status file + - --interval=125s # the maximum time gap allowed between the file mtime and the current sys clock + initialDelaySeconds: 60 + periodSeconds: 60 + {{- end }} + resources: +{{- if .Values.resources }} +{{ toYaml .Values.resources | indent 12 }} +{{- else }} +{{ toYaml .Values.global.defaultResources | indent 12 }} +{{- end }} +{{- if not .Values.selfSigned }} + volumeMounts: + - name: cacerts + mountPath: /etc/cacerts + readOnly: true + volumes: + - name: cacerts + secret: + secretName: cacerts + optional: true +{{- end }} + affinity: + {{- include "nodeaffinity" . | indent 6 }} + {{- include "podAntiAffinity" . | indent 6 }} + {{- if .Values.tolerations }} + tolerations: +{{ toYaml .Values.tolerations | indent 6 }} + {{- else if .Values.global.defaultTolerations }} + tolerations: +{{ toYaml .Values.global.defaultTolerations | indent 6 }} + {{- end }} diff --git a/istio-1.5.0/install/kubernetes/helm/istio/charts/security/templates/enable-mesh-mtls.yaml b/istio-1.5.0/install/kubernetes/helm/istio/charts/security/templates/enable-mesh-mtls.yaml new file mode 100644 index 0000000..6616178 --- /dev/null +++ b/istio-1.5.0/install/kubernetes/helm/istio/charts/security/templates/enable-mesh-mtls.yaml @@ -0,0 +1,65 @@ +{{- define "security-default.yaml.tpl" }} +# These policy and destination rules effectively enable mTLS for all services in the mesh. For now, +# they are added to Istio installation yaml for backward compatible. In future, they should be in +# a separated yaml file so that customer can enable mTLS independent from installation. + +# Authentication policy to enable mutual TLS for all services (that have sidecar) in the mesh. +apiVersion: "authentication.istio.io/v1alpha1" +kind: "MeshPolicy" +metadata: + name: "default" + labels: + app: {{ template "security.name" . }} + chart: {{ template "security.chart" . }} + heritage: {{ .Release.Service }} + release: {{ .Release.Name }} +spec: + peers: + - mtls: {} +{{- if not .Values.global.mtls.auto }} +--- +# Corresponding destination rule to configure client side to use mutual TLS when talking to +# any service (host) in the mesh. +apiVersion: networking.istio.io/v1alpha3 +kind: DestinationRule +metadata: + name: "default" + namespace: {{ .Release.Namespace }} + labels: + app: {{ template "security.name" . }} + chart: {{ template "security.chart" . }} + heritage: {{ .Release.Service }} + release: {{ .Release.Name }} +spec: + host: "*.local" + {{- if .Values.global.defaultConfigVisibilitySettings }} + exportTo: + - '*' + {{- end }} + trafficPolicy: + tls: + mode: ISTIO_MUTUAL +--- +# Destination rule to disable (m)TLS when talking to API server, as API server doesn't have sidecar. +# Customer should add similar destination rules for other services that don't have sidecar. +apiVersion: networking.istio.io/v1alpha3 +kind: DestinationRule +metadata: + name: "api-server" + namespace: {{ .Release.Namespace }} + labels: + app: {{ template "security.name" . }} + chart: {{ template "security.chart" . }} + heritage: {{ .Release.Service }} + release: {{ .Release.Name }} +spec: + host: "kubernetes.default.svc.{{ .Values.global.proxy.clusterDomain }}" + {{- if .Values.global.defaultConfigVisibilitySettings }} + exportTo: + - '*' + {{- end }} + trafficPolicy: + tls: + mode: DISABLE +{{- end }} +{{- end }} diff --git a/istio-1.5.0/install/kubernetes/helm/istio/charts/security/templates/enable-mesh-permissive.yaml b/istio-1.5.0/install/kubernetes/helm/istio/charts/security/templates/enable-mesh-permissive.yaml new file mode 100644 index 0000000..a6931b3 --- /dev/null +++ b/istio-1.5.0/install/kubernetes/helm/istio/charts/security/templates/enable-mesh-permissive.yaml @@ -0,0 +1,16 @@ +{{- define "security-permissive.yaml.tpl" }} +# Authentication policy to enable permissive mode for all services (that have sidecar) in the mesh. +apiVersion: "authentication.istio.io/v1alpha1" +kind: "MeshPolicy" +metadata: + name: "default" + labels: + app: {{ template "security.name" . }} + chart: {{ template "security.chart" . }} + heritage: {{ .Release.Service }} + release: {{ .Release.Name }} +spec: + peers: + - mtls: + mode: PERMISSIVE +{{- end }} diff --git a/istio-1.5.0/install/kubernetes/helm/istio/charts/security/templates/meshexpansion.yaml b/istio-1.5.0/install/kubernetes/helm/istio/charts/security/templates/meshexpansion.yaml new file mode 100644 index 0000000..581ce96 --- /dev/null +++ b/istio-1.5.0/install/kubernetes/helm/istio/charts/security/templates/meshexpansion.yaml @@ -0,0 +1,56 @@ +{{- if .Values.global.meshExpansion.enabled }} +{{- if .Values.global.meshExpansion.useILB }} +apiVersion: networking.istio.io/v1alpha3 +kind: VirtualService +metadata: + name: meshexpansion-vs-citadel-ilb + namespace: {{ .Release.Namespace }} + labels: + app: {{ template "security.name" . }} + chart: {{ template "security.chart" . }} + heritage: {{ .Release.Service }} + release: {{ .Release.Name }} + istio: citadel +spec: + hosts: + - istio-citadel.{{ .Release.Namespace }}.svc.{{ .Values.global.proxy.clusterDomain }} + gateways: + - meshexpansion-ilb-gateway + tcp: + - match: + - port: 8060 + route: + - destination: + host: istio-citadel.{{ .Release.Namespace }}.svc.{{ .Values.global.proxy.clusterDomain }} + port: + number: 8060 +--- +{{- else }} + +apiVersion: networking.istio.io/v1alpha3 +kind: VirtualService +metadata: + name: meshexpansion-vs-citadel + namespace: {{ .Release.Namespace }} + labels: + app: {{ template "security.name" . }} + chart: {{ template "security.chart" . }} + heritage: {{ .Release.Service }} + release: {{ .Release.Name }} + istio: citadel +spec: + hosts: + - istio-citadel.{{ .Release.Namespace }}.svc.{{ .Values.global.proxy.clusterDomain }} + gateways: + - meshexpansion-gateway + tcp: + - match: + - port: 8060 + route: + - destination: + host: istio-citadel.{{ .Release.Namespace }}.svc.{{ .Values.global.proxy.clusterDomain }} + port: + number: 8060 +--- +{{- end }} +{{- end }} diff --git a/istio-1.5.0/install/kubernetes/helm/istio/charts/security/templates/poddisruptionbudget.yaml b/istio-1.5.0/install/kubernetes/helm/istio/charts/security/templates/poddisruptionbudget.yaml new file mode 100644 index 0000000..1a88095 --- /dev/null +++ b/istio-1.5.0/install/kubernetes/helm/istio/charts/security/templates/poddisruptionbudget.yaml @@ -0,0 +1,20 @@ +{{- if .Values.global.defaultPodDisruptionBudget.enabled }} +apiVersion: policy/v1beta1 +kind: PodDisruptionBudget +metadata: + name: istio-citadel + namespace: {{ .Release.Namespace }} + labels: + app: {{ template "security.name" . }} + chart: {{ template "security.chart" . }} + heritage: {{ .Release.Service }} + release: {{ .Release.Name }} + istio: citadel +spec: +{{ include "podDisruptionBudget.spec" .Values.global.defaultPodDisruptionBudget }} + selector: + matchLabels: + app: {{ template "security.name" . }} + release: {{ .Release.Name }} + istio: citadel +{{- end }} diff --git a/istio-1.5.0/install/kubernetes/helm/istio/charts/security/templates/service.yaml b/istio-1.5.0/install/kubernetes/helm/istio/charts/security/templates/service.yaml new file mode 100644 index 0000000..efea175 --- /dev/null +++ b/istio-1.5.0/install/kubernetes/helm/istio/charts/security/templates/service.yaml @@ -0,0 +1,23 @@ +apiVersion: v1 +kind: Service +metadata: + # we use the normal name here (e.g. 'prometheus') + # as grafana is configured to use this as a data source + name: istio-citadel + namespace: {{ .Release.Namespace }} + labels: + app: {{ template "security.name" . }} + chart: {{ template "security.chart" . }} + heritage: {{ .Release.Service }} + release: {{ .Release.Name }} + istio: citadel +spec: + ports: + - name: grpc-citadel + port: 8060 + targetPort: 8060 + protocol: TCP + - name: http-monitoring + port: {{ .Values.global.monitoringPort }} + selector: + istio: citadel diff --git a/istio-1.5.0/install/kubernetes/helm/istio/charts/security/templates/serviceaccount.yaml b/istio-1.5.0/install/kubernetes/helm/istio/charts/security/templates/serviceaccount.yaml new file mode 100644 index 0000000..d07d566 --- /dev/null +++ b/istio-1.5.0/install/kubernetes/helm/istio/charts/security/templates/serviceaccount.yaml @@ -0,0 +1,16 @@ +apiVersion: v1 +kind: ServiceAccount +{{- if .Values.global.imagePullSecrets }} +imagePullSecrets: +{{- range .Values.global.imagePullSecrets }} + - name: {{ . }} +{{- end }} +{{- end }} +metadata: + name: istio-citadel-service-account + namespace: {{ .Release.Namespace }} + labels: + app: {{ template "security.name" . }} + chart: {{ template "security.chart" . }} + heritage: {{ .Release.Service }} + release: {{ .Release.Name }} diff --git a/istio-1.5.0/install/kubernetes/helm/istio/charts/security/templates/tests/test-citadel-connection.yaml b/istio-1.5.0/install/kubernetes/helm/istio/charts/security/templates/tests/test-citadel-connection.yaml new file mode 100644 index 0000000..6fc742a --- /dev/null +++ b/istio-1.5.0/install/kubernetes/helm/istio/charts/security/templates/tests/test-citadel-connection.yaml @@ -0,0 +1,36 @@ +{{- if .Values.global.enableHelmTest }} +apiVersion: v1 +kind: Pod +metadata: + name: {{ template "security.fullname" . }}-test + namespace: {{ .Release.Namespace }} + labels: + app: istio-citadel-test + chart: {{ template "security.chart" . }} + release: {{ .Release.Name }} + heritage: {{ .Release.Service }} + istio: citadel + annotations: + sidecar.istio.io/inject: "false" + helm.sh/hook: test-success +spec: +{{- if .Values.global.priorityClassName }} + priorityClassName: "{{ .Values.global.priorityClassName }}" +{{- end }} + containers: + - name: "{{ template "security.fullname" . }}-test" + image: pstauffer/curl:v1.0.3 + imagePullPolicy: "{{ .Values.global.imagePullPolicy }}" + command: ['sh', '-c', 'for i in 1 2 3; do curl http://istio-citadel:{{ .Values.global.monitoringPort }}/version && exit 0 || sleep 15; done; exit 1'] + restartPolicy: Never + affinity: + {{- include "nodeaffinity" . | indent 4 }} + {{- include "podAntiAffinity" . | indent 4 }} + {{- if .Values.tolerations }} + tolerations: +{{ toYaml .Values.tolerations | indent 2 }} + {{- else if .Values.global.defaultTolerations }} + tolerations: +{{ toYaml .Values.global.defaultTolerations | indent 2 }} + {{- end }} +{{- end }} diff --git a/istio-1.5.0/install/kubernetes/helm/istio/charts/security/values.yaml b/istio-1.5.0/install/kubernetes/helm/istio/charts/security/values.yaml new file mode 100644 index 0000000..ee16f2c --- /dev/null +++ b/istio-1.5.0/install/kubernetes/helm/istio/charts/security/values.yaml @@ -0,0 +1,52 @@ +# +# security configuration +# +enabled: true +replicaCount: 1 +rollingMaxSurge: 100% +rollingMaxUnavailable: 25% +image: citadel +selfSigned: true # indicate if self-signed CA is used. +createMeshPolicy: true +nodeSelector: {} +tolerations: [] +podAnnotations: {} + +# Enable health checking on the Citadel CSR signing API. +# https://istio.io/docs/tasks/security/health-check/ +citadelHealthCheck: false +# 90*24hour = 2160h +workloadCertTtl: 2160h +# Environment variables that configure Citadel. +env: {} + +# Determines Citadel default behavior if the ca.istio.io/env or ca.istio.io/override +# labels are not found on a given namespace. +# +# For example: consider a namespace called "target", which has neither the "ca.istio.io/env" +# nor the "ca.istio.io/override" namespace labels. To decide whether or not to generate secrets +# for service accounts created in this "target" namespace, Citadel will defer to this option. If the value +# of this option is "true" in this case, secrets will be generated for the "target" namespace. +# If the value of this option is "false" Citadel will not generate secrets upon service account creation. +enableNamespacesByDefault: true + +# Specify the pod anti-affinity that allows you to constrain which nodes +# your pod is eligible to be scheduled based on labels on pods that are +# already running on the node rather than based on labels on nodes. +# There are currently two types of anti-affinity: +# "requiredDuringSchedulingIgnoredDuringExecution" +# "preferredDuringSchedulingIgnoredDuringExecution" +# which denote "hard" vs. "soft" requirements, you can define your values +# in "podAntiAffinityLabelSelector" and "podAntiAffinityTermLabelSelector" +# correspondingly. +# For example: +# podAntiAffinityLabelSelector: +# - key: security +# operator: In +# values: S1,S2 +# topologyKey: "kubernetes.io/hostname" +# This pod anti-affinity rule says that the pod requires not to be scheduled +# onto a node if that node is already running a pod with label having key +# "security" and value "S1". +podAntiAffinityLabelSelector: [] +podAntiAffinityTermLabelSelector: [] diff --git a/istio-1.5.0/install/kubernetes/helm/istio/charts/sidecarInjectorWebhook/Chart.yaml b/istio-1.5.0/install/kubernetes/helm/istio/charts/sidecarInjectorWebhook/Chart.yaml new file mode 100644 index 0000000..8131013 --- /dev/null +++ b/istio-1.5.0/install/kubernetes/helm/istio/charts/sidecarInjectorWebhook/Chart.yaml @@ -0,0 +1,13 @@ +apiVersion: v1 +name: sidecarInjectorWebhook +version: 1.5.0 +appVersion: 1.5.0 +tillerVersion: ">=2.7.2" +description: Helm chart for sidecar injector webhook deployment +keywords: + - istio + - sidecarInjectorWebhook +sources: + - http://github.com/istio/istio +engine: gotpl +icon: https://istio.io/favicons/android-192x192.png diff --git a/istio-1.5.0/install/kubernetes/helm/istio/charts/sidecarInjectorWebhook/templates/_helpers.tpl b/istio-1.5.0/install/kubernetes/helm/istio/charts/sidecarInjectorWebhook/templates/_helpers.tpl new file mode 100644 index 0000000..f3b9fb1 --- /dev/null +++ b/istio-1.5.0/install/kubernetes/helm/istio/charts/sidecarInjectorWebhook/templates/_helpers.tpl @@ -0,0 +1,32 @@ +{{/* vim: set filetype=mustache: */}} +{{/* +Expand the name of the chart. +*/}} +{{- define "sidecar-injector.name" -}} +{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" -}} +{{- end -}} + +{{/* +Create a default fully qualified app name. +We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). +If release name contains chart name it will be used as a full name. +*/}} +{{- define "sidecar-injector.fullname" -}} +{{- if .Values.fullnameOverride -}} +{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" -}} +{{- else -}} +{{- $name := default .Chart.Name .Values.nameOverride -}} +{{- if contains $name .Release.Name -}} +{{- .Release.Name | trunc 63 | trimSuffix "-" -}} +{{- else -}} +{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" -}} +{{- end -}} +{{- end -}} +{{- end -}} + +{{/* +Create chart name and version as used by the chart label. +*/}} +{{- define "sidecar-injector.chart" -}} +{{- .Chart.Name | trunc 63 | trimSuffix "-" -}} +{{- end -}} diff --git a/istio-1.5.0/install/kubernetes/helm/istio/charts/sidecarInjectorWebhook/templates/clusterrole.yaml b/istio-1.5.0/install/kubernetes/helm/istio/charts/sidecarInjectorWebhook/templates/clusterrole.yaml new file mode 100644 index 0000000..c56c702 --- /dev/null +++ b/istio-1.5.0/install/kubernetes/helm/istio/charts/sidecarInjectorWebhook/templates/clusterrole.yaml @@ -0,0 +1,19 @@ +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: istio-sidecar-injector-{{ .Release.Namespace }} + labels: + app: {{ template "sidecar-injector.name" . }} + chart: {{ template "sidecar-injector.chart" . }} + heritage: {{ .Release.Service }} + release: {{ .Release.Name }} + istio: sidecar-injector +rules: +- apiGroups: [""] + resources: ["configmaps"] + verbs: ["get", "list", "watch"] +{{- if not .Values.global.operatorManageWebhooks }} +- apiGroups: ["admissionregistration.k8s.io"] + resources: ["mutatingwebhookconfigurations"] + verbs: ["get", "list", "watch", "patch"] +{{- end }} diff --git a/istio-1.5.0/install/kubernetes/helm/istio/charts/sidecarInjectorWebhook/templates/clusterrolebinding.yaml b/istio-1.5.0/install/kubernetes/helm/istio/charts/sidecarInjectorWebhook/templates/clusterrolebinding.yaml new file mode 100644 index 0000000..748a932 --- /dev/null +++ b/istio-1.5.0/install/kubernetes/helm/istio/charts/sidecarInjectorWebhook/templates/clusterrolebinding.yaml @@ -0,0 +1,18 @@ +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: istio-sidecar-injector-admin-role-binding-{{ .Release.Namespace }} + labels: + app: {{ template "sidecar-injector.name" . }} + chart: {{ template "sidecar-injector.chart" . }} + heritage: {{ .Release.Service }} + release: {{ .Release.Name }} + istio: sidecar-injector +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: istio-sidecar-injector-{{ .Release.Namespace }} +subjects: + - kind: ServiceAccount + name: istio-sidecar-injector-service-account + namespace: {{ .Release.Namespace }} diff --git a/istio-1.5.0/install/kubernetes/helm/istio/charts/sidecarInjectorWebhook/templates/deployment.yaml b/istio-1.5.0/install/kubernetes/helm/istio/charts/sidecarInjectorWebhook/templates/deployment.yaml new file mode 100644 index 0000000..26ca347 --- /dev/null +++ b/istio-1.5.0/install/kubernetes/helm/istio/charts/sidecarInjectorWebhook/templates/deployment.yaml @@ -0,0 +1,122 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: istio-sidecar-injector + namespace: {{ .Release.Namespace }} + labels: + app: {{ template "sidecar-injector.name" . }} + chart: {{ template "sidecar-injector.chart" . }} + heritage: {{ .Release.Service }} + release: {{ .Release.Name }} + istio: sidecar-injector +spec: + replicas: {{ .Values.replicaCount }} + selector: + matchLabels: + istio: sidecar-injector + strategy: + rollingUpdate: + maxSurge: {{ .Values.rollingMaxSurge }} + maxUnavailable: {{ .Values.rollingMaxUnavailable }} + template: + metadata: + labels: + app: {{ template "sidecar-injector.name" . }} + chart: {{ template "sidecar-injector.chart" . }} + heritage: {{ .Release.Service }} + release: {{ .Release.Name }} + istio: sidecar-injector + annotations: + sidecar.istio.io/inject: "false" + {{- if .Values.podAnnotations }} +{{ toYaml .Values.podAnnotations | indent 8 }} + {{- end }} + spec: + serviceAccountName: istio-sidecar-injector-service-account +{{- if .Values.global.priorityClassName }} + priorityClassName: "{{ .Values.global.priorityClassName }}" +{{- end }} + containers: + - name: sidecar-injector-webhook +{{- if contains "/" .Values.image }} + image: "{{ .Values.image }}" +{{- else }} + image: "{{ .Values.global.hub }}/{{ .Values.image }}:{{ .Values.global.tag }}" +{{- end }} + imagePullPolicy: {{ .Values.global.imagePullPolicy }} + args: + - --caCertFile=/etc/istio/certs/root-cert.pem + - --tlsCertFile=/etc/istio/certs/cert-chain.pem + - --tlsKeyFile=/etc/istio/certs/key.pem + - --injectConfig=/etc/istio/inject/config + - --meshConfig=/etc/istio/config/mesh + - --healthCheckInterval=2s + - --healthCheckFile=/tmp/health +{{- if .Values.global.operatorManageWebhooks }} + - --reconcileWebhookConfig=false +{{- else }} + - --reconcileWebhookConfig=true +{{- end }} + volumeMounts: + - name: config-volume + mountPath: /etc/istio/config + readOnly: true + - name: certs + mountPath: /etc/istio/certs + readOnly: true + - name: inject-config + mountPath: /etc/istio/inject + readOnly: true + livenessProbe: + exec: + command: + - /usr/local/bin/sidecar-injector + - probe + - --probe-path=/tmp/health + - --interval=4s + initialDelaySeconds: 4 + periodSeconds: 4 + readinessProbe: + exec: + command: + - /usr/local/bin/sidecar-injector + - probe + - --probe-path=/tmp/health + - --interval=4s + initialDelaySeconds: 4 + periodSeconds: 4 + resources: +{{- if .Values.resources }} +{{ toYaml .Values.resources | indent 12 }} +{{- else }} +{{ toYaml .Values.global.defaultResources | indent 12 }} +{{- end }} + volumes: + - name: config-volume + configMap: + name: istio + - name: certs + secret: +{{- if .Values.global.certificates }} + secretName: dns.istio-sidecar-injector-service-account +{{- else }} + secretName: istio.istio-sidecar-injector-service-account +{{- end }} + - name: inject-config + configMap: + name: istio-sidecar-injector + items: + - key: config + path: config + - key: values + path: values + affinity: + {{- include "nodeaffinity" . | indent 6 }} + {{- include "podAntiAffinity" . | indent 6 }} + {{- if .Values.tolerations }} + tolerations: +{{ toYaml .Values.tolerations | indent 6 }} + {{- else if .Values.global.defaultTolerations }} + tolerations: +{{ toYaml .Values.global.defaultTolerations | indent 6 }} + {{- end }} diff --git a/istio-1.5.0/install/kubernetes/helm/istio/charts/sidecarInjectorWebhook/templates/mutatingwebhook.yaml b/istio-1.5.0/install/kubernetes/helm/istio/charts/sidecarInjectorWebhook/templates/mutatingwebhook.yaml new file mode 100644 index 0000000..4a31415 --- /dev/null +++ b/istio-1.5.0/install/kubernetes/helm/istio/charts/sidecarInjectorWebhook/templates/mutatingwebhook.yaml @@ -0,0 +1,40 @@ +{{- if not .Values.global.operatorManageWebhooks }} +apiVersion: admissionregistration.k8s.io/v1beta1 +kind: MutatingWebhookConfiguration +metadata: + name: istio-sidecar-injector + labels: + app: {{ template "sidecar-injector.name" . }} + chart: {{ template "sidecar-injector.chart" . }} + heritage: {{ .Release.Service }} + release: {{ .Release.Name }} +webhooks: + - name: sidecar-injector.istio.io + clientConfig: + service: + name: istio-sidecar-injector + namespace: {{ .Release.Namespace }} + path: "/inject" + caBundle: "" + rules: + - operations: [ "CREATE" ] + apiGroups: [""] + apiVersions: ["v1"] + resources: ["pods"] + failurePolicy: Fail + namespaceSelector: +{{- if .Values.enableNamespacesByDefault }} + matchExpressions: + - key: name + operator: NotIn + values: + - {{ .Release.Namespace }} + - key: istio-injection + operator: NotIn + values: + - disabled +{{- else }} + matchLabels: + istio-injection: enabled +{{- end }} +{{- end }} diff --git a/istio-1.5.0/install/kubernetes/helm/istio/charts/sidecarInjectorWebhook/templates/poddisruptionbudget.yaml b/istio-1.5.0/install/kubernetes/helm/istio/charts/sidecarInjectorWebhook/templates/poddisruptionbudget.yaml new file mode 100644 index 0000000..870b925 --- /dev/null +++ b/istio-1.5.0/install/kubernetes/helm/istio/charts/sidecarInjectorWebhook/templates/poddisruptionbudget.yaml @@ -0,0 +1,18 @@ +{{- if .Values.global.defaultPodDisruptionBudget.enabled }} +apiVersion: policy/v1beta1 +kind: PodDisruptionBudget +metadata: + name: istio-sidecar-injector + namespace: {{ .Release.Namespace }} + labels: + app: {{ template "sidecar-injector.name" . }} + release: {{ .Release.Name }} + istio: sidecar-injector +spec: +{{ include "podDisruptionBudget.spec" .Values.global.defaultPodDisruptionBudget }} + selector: + matchLabels: + app: {{ template "sidecar-injector.name" . }} + release: {{ .Release.Name }} + istio: sidecar-injector + {{- end }} diff --git a/istio-1.5.0/install/kubernetes/helm/istio/charts/sidecarInjectorWebhook/templates/service.yaml b/istio-1.5.0/install/kubernetes/helm/istio/charts/sidecarInjectorWebhook/templates/service.yaml new file mode 100644 index 0000000..ea03cd8 --- /dev/null +++ b/istio-1.5.0/install/kubernetes/helm/istio/charts/sidecarInjectorWebhook/templates/service.yaml @@ -0,0 +1,20 @@ +apiVersion: v1 +kind: Service +metadata: + name: istio-sidecar-injector + namespace: {{ .Release.Namespace }} + labels: + app: {{ template "sidecar-injector.name" . }} + chart: {{ template "sidecar-injector.chart" . }} + heritage: {{ .Release.Service }} + release: {{ .Release.Name }} + istio: sidecar-injector +spec: + ports: + - port: 443 + name: https-inject + targetPort: 9443 + - port: {{ .Values.global.monitoringPort }} + name: http-monitoring + selector: + istio: sidecar-injector diff --git a/istio-1.5.0/install/kubernetes/helm/istio/charts/sidecarInjectorWebhook/templates/serviceaccount.yaml b/istio-1.5.0/install/kubernetes/helm/istio/charts/sidecarInjectorWebhook/templates/serviceaccount.yaml new file mode 100644 index 0000000..d4020b5 --- /dev/null +++ b/istio-1.5.0/install/kubernetes/helm/istio/charts/sidecarInjectorWebhook/templates/serviceaccount.yaml @@ -0,0 +1,17 @@ +apiVersion: v1 +kind: ServiceAccount +{{- if .Values.global.imagePullSecrets }} +imagePullSecrets: +{{- range .Values.global.imagePullSecrets }} + - name: {{ . }} +{{- end }} +{{- end }} +metadata: + name: istio-sidecar-injector-service-account + namespace: {{ .Release.Namespace }} + labels: + app: {{ template "sidecar-injector.name" . }} + chart: {{ template "sidecar-injector.chart" . }} + heritage: {{ .Release.Service }} + release: {{ .Release.Name }} + istio: sidecar-injector diff --git a/istio-1.5.0/install/kubernetes/helm/istio/charts/sidecarInjectorWebhook/values.yaml b/istio-1.5.0/install/kubernetes/helm/istio/charts/sidecarInjectorWebhook/values.yaml new file mode 100644 index 0000000..84cbb74 --- /dev/null +++ b/istio-1.5.0/install/kubernetes/helm/istio/charts/sidecarInjectorWebhook/values.yaml @@ -0,0 +1,59 @@ +# +# sidecar-injector webhook configuration +# +enabled: true +replicaCount: 1 +rollingMaxSurge: 100% +rollingMaxUnavailable: 25% +image: sidecar_injector +enableNamespacesByDefault: false +nodeSelector: {} +tolerations: [] +podAnnotations: {} + +# Specify the pod anti-affinity that allows you to constrain which nodes +# your pod is eligible to be scheduled based on labels on pods that are +# already running on the node rather than based on labels on nodes. +# There are currently two types of anti-affinity: +# "requiredDuringSchedulingIgnoredDuringExecution" +# "preferredDuringSchedulingIgnoredDuringExecution" +# which denote "hard" vs. "soft" requirements, you can define your values +# in "podAntiAffinityLabelSelector" and "podAntiAffinityTermLabelSelector" +# correspondingly. +# For example: +# podAntiAffinityLabelSelector: +# - key: security +# operator: In +# values: S1,S2 +# topologyKey: "kubernetes.io/hostname" +# This pod anti-affinity rule says that the pod requires not to be scheduled +# onto a node if that node is already running a pod with label having key +# "security" and value "S1". +podAntiAffinityLabelSelector: [] +podAntiAffinityTermLabelSelector: [] + +# If true, webhook or istioctl injector will rewrite PodSpec for liveness +# health check to redirect request to sidecar. This makes liveness check work +# even when mTLS is enabled. +rewriteAppHTTPProbe: false + +# You can use the field called alwaysInjectSelector and neverInjectSelector which will always inject the sidecar or +# always skip the injection on pods that match that label selector, regardless of the global policy. +# See https://istio.io/docs/setup/kubernetes/additional-setup/sidecar-injection/#more-control-adding-exceptions +neverInjectSelector: [] + +alwaysInjectSelector: [] + +# injectedAnnotations are additional annotations that will be added to the pod spec after injection +# This is primarily to support PSP annotations. For example, if you defined a PSP with the annotations: +# +# annotations: +# apparmor.security.beta.kubernetes.io/allowedProfileNames: runtime/default +# apparmor.security.beta.kubernetes.io/defaultProfileName: runtime/default +# +# The PSP controller would add corresponding annotations to the pod spec for each container. However, this happens before +# the inject adds additional containers, so we must specify them explicitly here. With the above example, we could specify: +# injectedAnnotations: +# container.apparmor.security.beta.kubernetes.io/istio-init: runtime/default +# container.apparmor.security.beta.kubernetes.io/istio-proxy: runtime/default +injectedAnnotations: {} diff --git a/istio-1.5.0/install/kubernetes/helm/istio/charts/tracing/Chart.yaml b/istio-1.5.0/install/kubernetes/helm/istio/charts/tracing/Chart.yaml new file mode 100644 index 0000000..ca05374 --- /dev/null +++ b/istio-1.5.0/install/kubernetes/helm/istio/charts/tracing/Chart.yaml @@ -0,0 +1,6 @@ +apiVersion: v1 +description: A Helm chart for Kubernetes +name: tracing +version: 1.5.0 +appVersion: 1.5.1 +tillerVersion: ">=2.7.2" diff --git a/istio-1.5.0/install/kubernetes/helm/istio/charts/tracing/templates/_helpers.tpl b/istio-1.5.0/install/kubernetes/helm/istio/charts/tracing/templates/_helpers.tpl new file mode 100644 index 0000000..e246b59 --- /dev/null +++ b/istio-1.5.0/install/kubernetes/helm/istio/charts/tracing/templates/_helpers.tpl @@ -0,0 +1,32 @@ +{{/* vim: set filetype=mustache: */}} +{{/* +Expand the name of the chart. +*/}} +{{- define "tracing.name" -}} +{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" -}} +{{- end -}} + +{{/* +Create a default fully qualified app name. +We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). +If release name contains chart name it will be used as a full name. +*/}} +{{- define "tracing.fullname" -}} +{{- if .Values.fullnameOverride -}} +{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" -}} +{{- else -}} +{{- $name := default .Chart.Name .Values.nameOverride -}} +{{- if contains $name .Release.Name -}} +{{- .Release.Name | trunc 63 | trimSuffix "-" -}} +{{- else -}} +{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" -}} +{{- end -}} +{{- end -}} +{{- end -}} + +{{/* +Create chart name and version as used by the chart label. +*/}} +{{- define "tracing.chart" -}} +{{- .Chart.Name | trunc 63 | trimSuffix "-" -}} +{{- end -}} diff --git a/istio-1.5.0/install/kubernetes/helm/istio/charts/tracing/templates/deployment-jaeger.yaml b/istio-1.5.0/install/kubernetes/helm/istio/charts/tracing/templates/deployment-jaeger.yaml new file mode 100644 index 0000000..916c25c --- /dev/null +++ b/istio-1.5.0/install/kubernetes/helm/istio/charts/tracing/templates/deployment-jaeger.yaml @@ -0,0 +1,119 @@ +{{ if eq .Values.provider "jaeger" }} + +apiVersion: apps/v1 +kind: Deployment +metadata: + name: istio-tracing + namespace: {{ .Release.Namespace }} + labels: + app: jaeger + chart: {{ template "tracing.chart" . }} + heritage: {{ .Release.Service }} + release: {{ .Release.Name }} +spec: + selector: + matchLabels: + app: jaeger + template: + metadata: + labels: + app: jaeger + chart: {{ template "tracing.chart" . }} + heritage: {{ .Release.Service }} + release: {{ .Release.Name }} + annotations: + sidecar.istio.io/inject: "false" + prometheus.io/scrape: "true" + prometheus.io/port: "14269" +{{- if .Values.jaeger.podAnnotations }} +{{ toYaml .Values.jaeger.podAnnotations | indent 8 }} +{{- end }} + spec: +{{- if .Values.global.priorityClassName }} + priorityClassName: "{{ .Values.global.priorityClassName }}" +{{- end }} +{{- if .Values.global.imagePullSecrets }} + imagePullSecrets: +{{- range .Values.global.imagePullSecrets }} + - name: {{ . }} +{{- end }} +{{- end }} + containers: + - name: jaeger + image: "{{ .Values.jaeger.hub }}/{{ .Values.jaeger.image }}:{{ .Values.jaeger.tag }}" + imagePullPolicy: {{ .Values.global.imagePullPolicy }} + ports: + - containerPort: 9411 + - containerPort: 16686 + - containerPort: 14250 + - containerPort: 14267 + - containerPort: 14268 + - containerPort: 14269 + - containerPort: 5775 + protocol: UDP + - containerPort: 6831 + protocol: UDP + - containerPort: 6832 + protocol: UDP + env: + - name: POD_NAMESPACE + valueFrom: + fieldRef: + apiVersion: v1 + fieldPath: metadata.namespace + {{- if eq .Values.jaeger.spanStorageType "badger" }} + - name: BADGER_EPHEMERAL + value: "false" + - name: SPAN_STORAGE_TYPE + value: "badger" + - name: BADGER_DIRECTORY_VALUE + value: "/badger/data" + - name: BADGER_DIRECTORY_KEY + value: "/badger/key" + {{- end }} + - name: COLLECTOR_ZIPKIN_HTTP_PORT + value: "9411" + - name: MEMORY_MAX_TRACES + value: "{{ .Values.jaeger.memory.max_traces }}" + - name: QUERY_BASE_PATH + value: {{ if .Values.contextPath }} {{ .Values.contextPath }} {{ else }} /{{ .Values.provider }} {{ end }} + livenessProbe: + httpGet: + path: / + port: 14269 + readinessProbe: + httpGet: + path: / + port: 14269 +{{- if eq .Values.jaeger.spanStorageType "badger" }} + volumeMounts: + - name: data + mountPath: /badger +{{- end }} + resources: +{{- if .Values.jaeger.resources }} +{{ toYaml .Values.jaeger.resources | indent 12 }} +{{- else }} +{{ toYaml .Values.global.defaultResources | indent 12 }} +{{- end }} + affinity: + {{- include "nodeaffinity" . | indent 6 }} + {{- include "podAntiAffinity" . | indent 6 }} + {{- if .Values.tolerations }} + tolerations: +{{ toYaml .Values.tolerations | indent 6 }} + {{- else if .Values.global.defaultTolerations }} + tolerations: +{{ toYaml .Values.global.defaultTolerations | indent 6 }} + {{- end }} +{{- if eq .Values.jaeger.spanStorageType "badger" }} + volumes: + - name: data +{{- if .Values.jaeger.persist }} + persistentVolumeClaim: + claimName: istio-jaeger-pvc +{{- else }} + emptyDir: {} +{{- end }} +{{- end }} +{{ end }} diff --git a/istio-1.5.0/install/kubernetes/helm/istio/charts/tracing/templates/deployment-zipkin.yaml b/istio-1.5.0/install/kubernetes/helm/istio/charts/tracing/templates/deployment-zipkin.yaml new file mode 100644 index 0000000..da779bf --- /dev/null +++ b/istio-1.5.0/install/kubernetes/helm/istio/charts/tracing/templates/deployment-zipkin.yaml @@ -0,0 +1,85 @@ +{{ if eq .Values.provider "zipkin" }} + +apiVersion: apps/v1 +kind: Deployment +metadata: + name: istio-tracing + namespace: {{ .Release.Namespace }} + labels: + app: zipkin + chart: {{ template "tracing.chart" . }} + heritage: {{ .Release.Service }} + release: {{ .Release.Name }} +spec: + selector: + matchLabels: + app: zipkin + template: + metadata: + labels: + app: zipkin + chart: {{ template "tracing.chart" . }} + heritage: {{ .Release.Service }} + release: {{ .Release.Name }} + annotations: + sidecar.istio.io/inject: "false" + scheduler.alpha.kubernetes.io/critical-pod: "" +{{- if .Values.zipkin.podAnnotations }} +{{ toYaml .Values.zipkin.podAnnotations | indent 8 }} +{{- end }} + spec: +{{- if .Values.global.priorityClassName }} + priorityClassName: "{{ .Values.global.priorityClassName }}" +{{- end }} +{{- if .Values.global.imagePullSecrets }} + imagePullSecrets: +{{- range .Values.global.imagePullSecrets }} + - name: {{ . }} +{{- end }} +{{- end }} + containers: + - name: zipkin + image: "{{ .Values.zipkin.hub }}/{{ .Values.zipkin.image }}:{{ .Values.zipkin.tag }}" + imagePullPolicy: {{ .Values.global.imagePullPolicy }} + ports: + - containerPort: {{ .Values.zipkin.queryPort }} + livenessProbe: + initialDelaySeconds: {{ .Values.zipkin.probeStartupDelay }} + tcpSocket: + port: {{ .Values.zipkin.queryPort }} + readinessProbe: + initialDelaySeconds: {{ .Values.zipkin.probeStartupDelay }} + httpGet: + path: /health + port: {{ .Values.zipkin.queryPort }} + resources: +{{- if .Values.zipkin.resources }} +{{ toYaml .Values.zipkin.resources | indent 12 }} +{{- else }} +{{ toYaml .Values.global.defaultResources | indent 12 }} +{{- end }} + env: + - name: POD_NAMESPACE + valueFrom: + fieldRef: + apiVersion: v1 + fieldPath: metadata.namespace + - name: QUERY_PORT + value: "{{ .Values.zipkin.queryPort }}" + - name: JAVA_OPTS + value: "-XX:ConcGCThreads={{ .Values.zipkin.node.cpus }} -XX:ParallelGCThreads={{ .Values.zipkin.node.cpus }} -Djava.util.concurrent.ForkJoinPool.common.parallelism={{ .Values.zipkin.node.cpus }} -Xms{{ .Values.zipkin.javaOptsHeap }}M -Xmx{{ .Values.zipkin.javaOptsHeap }}M -XX:+UseG1GC -server" + - name: STORAGE_METHOD + value: "mem" + - name: ZIPKIN_STORAGE_MEM_MAXSPANS + value: "{{ .Values.zipkin.maxSpans }}" + affinity: + {{- include "nodeaffinity" . | indent 6 }} + {{- include "podAntiAffinity" . | indent 6 }} + {{- if .Values.tolerations }} + tolerations: +{{ toYaml .Values.tolerations | indent 6 }} + {{- else if .Values.global.defaultTolerations }} + tolerations: +{{ toYaml .Values.global.defaultTolerations | indent 6 }} + {{- end }} +{{ end }} diff --git a/istio-1.5.0/install/kubernetes/helm/istio/charts/tracing/templates/ingress.yaml b/istio-1.5.0/install/kubernetes/helm/istio/charts/tracing/templates/ingress.yaml new file mode 100644 index 0000000..72f3621 --- /dev/null +++ b/istio-1.5.0/install/kubernetes/helm/istio/charts/tracing/templates/ingress.yaml @@ -0,0 +1,41 @@ +{{- if .Values.ingress.enabled -}} +apiVersion: extensions/v1beta1 +kind: Ingress +metadata: + name: {{ template "tracing.fullname" . }} + namespace: {{ .Release.Namespace }} + labels: + app: {{ .Values.provider }} + chart: {{ template "tracing.chart" . }} + heritage: {{ .Release.Service }} + release: {{ .Release.Name }} + annotations: + {{- range $key, $value := .Values.ingress.annotations }} + {{ $key }}: {{ $value | quote }} + {{- end }} +spec: + rules: +{{- if .Values.ingress.hosts }} + {{- range $host := .Values.ingress.hosts }} + - host: {{ $host }} + http: + paths: + - path: {{ if $.Values.contextPath }} {{ $.Values.contextPath }} {{ else }} /{{ $.Values.provider }} {{ end }} + backend: + serviceName: tracing + servicePort: 80 + + {{- end -}} +{{- else }} + - http: + paths: + - path: {{ if .Values.contextPath }} {{ .Values.contextPath }} {{ else }} /{{ .Values.provider }} {{ end }} + backend: + serviceName: tracing + servicePort: 80 +{{- end }} + {{- if .Values.ingress.tls }} + tls: +{{ toYaml .Values.ingress.tls | indent 4 }} + {{- end -}} +{{- end -}} diff --git a/istio-1.5.0/install/kubernetes/helm/istio/charts/tracing/templates/pvc.yaml b/istio-1.5.0/install/kubernetes/helm/istio/charts/tracing/templates/pvc.yaml new file mode 100644 index 0000000..6014049 --- /dev/null +++ b/istio-1.5.0/install/kubernetes/helm/istio/charts/tracing/templates/pvc.yaml @@ -0,0 +1,21 @@ +{{- if eq .Values.provider "jaeger" }} +{{- if .Values.jaeger.persist }} +kind: PersistentVolumeClaim +apiVersion: v1 +metadata: + name: istio-jaeger-pvc + namespace: {{ .Release.Namespace }} + labels: + app: jaeger + chart: {{ template "tracing.chart" . }} + heritage: {{ .Release.Service }} + release: {{ .Release.Name }} +spec: + storageClassName: {{ .Values.jaeger.storageClassName }} + accessModes: + - {{ .Values.jaeger.accessMode }} + resources: + requests: + storage: 5Gi +{{- end }} +{{- end }} diff --git a/istio-1.5.0/install/kubernetes/helm/istio/charts/tracing/templates/service-jaeger.yaml b/istio-1.5.0/install/kubernetes/helm/istio/charts/tracing/templates/service-jaeger.yaml new file mode 100644 index 0000000..f7ab769 --- /dev/null +++ b/istio-1.5.0/install/kubernetes/helm/istio/charts/tracing/templates/service-jaeger.yaml @@ -0,0 +1,114 @@ +{{ if eq .Values.provider "jaeger" }} + +apiVersion: v1 +kind: List +metadata: + name: jaeger-services + namespace: {{ .Release.Namespace }} + labels: + app: jaeger + chart: {{ template "tracing.chart" . }} + heritage: {{ .Release.Service }} + release: {{ .Release.Name }} +items: +- apiVersion: v1 + kind: Service + metadata: + name: jaeger-query + namespace: {{ .Release.Namespace }} + annotations: + {{- range $key, $val := .Values.service.annotations }} + {{ $key }}: {{ $val | quote }} + {{- end }} + labels: + app: jaeger + jaeger-infra: jaeger-service + chart: {{ template "tracing.chart" . }} + heritage: {{ .Release.Service }} + release: {{ .Release.Name }} + spec: + ports: + - name: query-http + port: 16686 + protocol: TCP + targetPort: 16686 + selector: + app: jaeger +- apiVersion: v1 + kind: Service + metadata: + name: jaeger-collector + namespace: {{ .Release.Namespace }} + labels: + app: jaeger + jaeger-infra: collector-service + chart: {{ template "tracing.chart" . }} + heritage: {{ .Release.Service }} + release: {{ .Release.Name }} + spec: + ports: + - name: jaeger-collector-tchannel + port: 14267 + protocol: TCP + targetPort: 14267 + - name: jaeger-collector-http + port: 14268 + targetPort: 14268 + protocol: TCP + - name: jaeger-collector-grpc + port: 14250 + targetPort: 14250 + protocol: TCP + selector: + app: jaeger + type: ClusterIP +- apiVersion: v1 + kind: Service + metadata: + name: jaeger-collector-headless + namespace: {{ .Release.Namespace }} + labels: + app: jaeger + jaeger-infra: collector-service + chart: {{ template "tracing.chart" . }} + heritage: {{ .Release.Service }} + release: {{ .Release.Name }} + spec: + ports: + - name: jaeger-collector-grpc + port: 14250 + targetPort: 14250 + protocol: TCP + selector: + app: jaeger + clusterIP: None +- apiVersion: v1 + kind: Service + metadata: + name: jaeger-agent + namespace: {{ .Release.Namespace }} + labels: + app: jaeger + jaeger-infra: agent-service + chart: {{ template "tracing.chart" . }} + heritage: {{ .Release.Service }} + release: {{ .Release.Name }} + spec: + ports: + - name: agent-zipkin-thrift + port: 5775 + protocol: UDP + targetPort: 5775 + - name: agent-compact + port: 6831 + protocol: UDP + targetPort: 6831 + - name: agent-binary + port: 6832 + protocol: UDP + targetPort: 6832 + clusterIP: None + selector: + app: jaeger +{{ end }} + diff --git a/istio-1.5.0/install/kubernetes/helm/istio/charts/tracing/templates/service.yaml b/istio-1.5.0/install/kubernetes/helm/istio/charts/tracing/templates/service.yaml new file mode 100644 index 0000000..7988297 --- /dev/null +++ b/istio-1.5.0/install/kubernetes/helm/istio/charts/tracing/templates/service.yaml @@ -0,0 +1,56 @@ +apiVersion: v1 +kind: List +metadata: + name: tracing-services + namespace: {{ .Release.Namespace }} + labels: + app: {{ .Values.provider }} + chart: {{ template "tracing.chart" . }} + heritage: {{ .Release.Service }} + release: {{ .Release.Name }} +items: +- apiVersion: v1 + kind: Service + metadata: + name: zipkin + namespace: {{ .Release.Namespace }} + labels: + app: {{ .Values.provider }} + chart: {{ template "tracing.chart" . }} + heritage: {{ .Release.Service }} + release: {{ .Release.Name }} + spec: + ports: + - port: {{ .Values.zipkin.queryPort }} + targetPort: {{ .Values.zipkin.queryPort }} + protocol: TCP + name: {{ .Values.service.name }} + selector: + app: {{ .Values.provider }} +- apiVersion: v1 + kind: Service + metadata: + name: tracing + namespace: {{ .Release.Namespace }} + annotations: + {{- range $key, $val := .Values.service.annotations }} + {{ $key }}: {{ $val | quote }} + {{- end }} + labels: + app: {{ .Values.provider }} + chart: {{ template "tracing.chart" . }} + heritage: {{ .Release.Service }} + release: {{ .Release.Name }} + spec: + type: {{ .Values.service.type }} + ports: + - name: http-query + port: {{ .Values.service.externalPort }} + protocol: TCP +{{ if eq .Values.provider "jaeger" }} + targetPort: 16686 +{{ else }} + targetPort: {{ .Values.zipkin.queryPort }} +{{ end}} + selector: + app: {{ .Values.provider }} diff --git a/istio-1.5.0/install/kubernetes/helm/istio/charts/tracing/templates/tests/test-tracing-connection.yaml b/istio-1.5.0/install/kubernetes/helm/istio/charts/tracing/templates/tests/test-tracing-connection.yaml new file mode 100644 index 0000000..b87f487 --- /dev/null +++ b/istio-1.5.0/install/kubernetes/helm/istio/charts/tracing/templates/tests/test-tracing-connection.yaml @@ -0,0 +1,40 @@ +{{- if .Values.global.enableHelmTest }} +apiVersion: v1 +kind: Pod +metadata: + name: {{ .Release.Name }}-{{ .Values.provider }}-test + namespace: {{ .Release.Namespace }} + labels: + app: {{ .Values.provider }}-test + chart: {{ template "tracing.chart" . }} + release: {{ .Release.Name }} + heritage: {{ .Release.Service }} + annotations: + sidecar.istio.io/inject: "false" + helm.sh/hook: test-success +spec: +{{- if .Values.global.priorityClassName }} + priorityClassName: "{{ .Values.global.priorityClassName }}" +{{- end }} + containers: + - name: "{{ .Values.provider }}-test" + image: pstauffer/curl:v1.0.3 + imagePullPolicy: "{{ .Values.global.imagePullPolicy }}" + command: ['curl'] + {{- if eq .Values.provider "jaeger" }} + args: ['http://tracing:80{{ .Values.jaeger.contextPath}}'] + {{- else }} + args: ['http://tracing:80'] + {{- end }} + restartPolicy: Never + affinity: + {{- include "nodeaffinity" . | indent 4 }} + {{- include "podAntiAffinity" . | indent 4 }} + {{- if .Values.tolerations }} + tolerations: +{{ toYaml .Values.tolerations | indent 2 }} + {{- else if .Values.global.defaultTolerations }} + tolerations: +{{ toYaml .Values.global.defaultTolerations | indent 2 }} + {{- end }} +{{- end }} diff --git a/istio-1.5.0/install/kubernetes/helm/istio/charts/tracing/values.yaml b/istio-1.5.0/install/kubernetes/helm/istio/charts/tracing/values.yaml new file mode 100644 index 0000000..03381bf --- /dev/null +++ b/istio-1.5.0/install/kubernetes/helm/istio/charts/tracing/values.yaml @@ -0,0 +1,87 @@ +# +# addon jaeger tracing configuration +# +enabled: false + +provider: jaeger +nodeSelector: {} +tolerations: [] + +# Specify the pod anti-affinity that allows you to constrain which nodes +# your pod is eligible to be scheduled based on labels on pods that are +# already running on the node rather than based on labels on nodes. +# There are currently two types of anti-affinity: +# "requiredDuringSchedulingIgnoredDuringExecution" +# "preferredDuringSchedulingIgnoredDuringExecution" +# which denote "hard" vs. "soft" requirements, you can define your values +# in "podAntiAffinityLabelSelector" and "podAntiAffinityTermLabelSelector" +# correspondingly. +# For example: +# podAntiAffinityLabelSelector: +# - key: security +# operator: In +# values: S1,S2 +# topologyKey: "kubernetes.io/hostname" +# This pod anti-affinity rule says that the pod requires not to be scheduled +# onto a node if that node is already running a pod with label having key +# "security" and value "S1". +podAntiAffinityLabelSelector: [] +podAntiAffinityTermLabelSelector: [] + +jaeger: + hub: docker.io/jaegertracing + image: all-in-one + tag: 1.16 + podAnnotations: {} + memory: + max_traces: 50000 + # spanStorageType value can be "memory" and "badger" for all-in-one image + spanStorageType: badger + persist: false + storageClassName: "" + accessMode: ReadWriteMany + + +zipkin: + hub: docker.io/openzipkin + image: zipkin + tag: 2.14.2 + podAnnotations: {} + probeStartupDelay: 200 + queryPort: 9411 + resources: + limits: + cpu: 300m + memory: 900Mi + requests: + cpu: 150m + memory: 900Mi + javaOptsHeap: 700 + # From: https://github.com/openzipkin/zipkin/blob/master/zipkin-server/src/main/resources/zipkin-server-shared.yml#L51 + # Maximum number of spans to keep in memory. When exceeded, oldest traces (and their spans) will be purged. + # A safe estimate is 1K of memory per span (each span with 2 annotations + 1 binary annotation), plus + # 100 MB for a safety buffer. You'll need to verify in your own environment. + maxSpans: 500000 + node: + cpus: 2 + +service: + annotations: {} + name: http + type: ClusterIP + externalPort: 80 + +ingress: + enabled: false + # Used to create an Ingress record. + hosts: + # - tracing.local + annotations: + # kubernetes.io/ingress.class: nginx + # kubernetes.io/tls-acme: "true" + tls: + # Secrets must be manually created in the namespace. + # - secretName: tracing-tls + # hosts: + # - tracing.local + diff --git a/istio-1.5.0/install/kubernetes/helm/istio/example-values/README.md b/istio-1.5.0/install/kubernetes/helm/istio/example-values/README.md new file mode 100644 index 0000000..74fedcb --- /dev/null +++ b/istio-1.5.0/install/kubernetes/helm/istio/example-values/README.md @@ -0,0 +1,5 @@ +# Example Values + +These files provide various example values for different Istio setups. + +To use them, [read the docs](https://istio.io/docs/setup/kubernetes/helm-install/) and add the flag `--values example-file.yaml`. diff --git a/istio-1.5.0/install/kubernetes/helm/istio/example-values/values-istio-dns-cert.yaml b/istio-1.5.0/install/kubernetes/helm/istio/example-values/values-istio-dns-cert.yaml new file mode 100644 index 0000000..c00676f --- /dev/null +++ b/istio-1.5.0/install/kubernetes/helm/istio/example-values/values-istio-dns-cert.yaml @@ -0,0 +1,6 @@ +global: + certificates: + - secretName: dns.istio-galley-service-account + dnsNames: [istio-galley.istio-system.svc, istio-galley.istio-system] + - secretName: dns.istio-sidecar-injector-service-account + dnsNames: [istio-sidecar-injector.istio-system.svc, istio-sidecar-injector.istio-system] diff --git a/istio-1.5.0/install/kubernetes/helm/istio/example-values/values-istio-example-sds-vault.yaml b/istio-1.5.0/install/kubernetes/helm/istio/example-values/values-istio-example-sds-vault.yaml new file mode 100644 index 0000000..a8aa337 --- /dev/null +++ b/istio-1.5.0/install/kubernetes/helm/istio/example-values/values-istio-example-sds-vault.yaml @@ -0,0 +1,26 @@ +global: + controlPlaneSecurityEnabled: false + + mtls: + # Default setting for service-to-service mtls. Can be set explicitly using + # destination rules or service annotations. + enabled: true + + sds: + enabled: true + udsPath: "unix:/var/run/sds/uds_path" + +nodeagent: + enabled: true + image: node-agent-k8s + env: + # The IP address and the port number of a publicly accessible example Vault server. + CA_ADDR: "https://34.83.129.211:8200" + CA_PROVIDER: "VaultCA" + VALID_TOKEN: true + # The IP address and the port number of a publicly accessible example Vault server. + VAULT_ADDR: "https://34.83.129.211:8200" + VAULT_AUTH_PATH: "auth/kubernetes/login" + VAULT_ROLE: "istio-cert" + VAULT_SIGN_CSR_PATH: "istio_ca/sign/istio-pki-role" + VAULT_TLS_ROOT_CERT: '-----BEGIN CERTIFICATE-----\nMIIC3jCCAcagAwIBAgIRAO1S7vuRQmo2He+RtBq3fv8wDQYJKoZIhvcNAQELBQAw\nEDEOMAwGA1UEChMFVmF1bHQwIBcNMTkwNDI3MTY1ODE1WhgPMjExOTA0MDMxNjU4\nMTVaMBAxDjAMBgNVBAoTBVZhdWx0MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB\nCgKCAQEA7/CTbnENEIvFZg9hmVtYnOx3OfMy/GNCuP7sqtAeVVTopAKKkcAAWQck\nrhpBooEGpCugNxXGNCuJh/2nu0AfGFRfdafwSJRoI6yHwQouDm0o4r3h9uL3tu5N\nD+x9j+eejbFsoZVn84CxGkEB6oyeXYHjc6eWh3PFGMtKuOQD4pezvDH0yNCx5waK\nhtPuYtl0ebfdbyh+WQuptO+Q9VSaQNqE3ipZ461y8PduwRRll241W0gQB2iasX03\nD36F2ZrMz3KEVRVKM1yCUDCy2RPJqkXPdnVMWmDGbe8Uw69zr25JltzuRZFT9HL3\nY1RnMTecmSc4ikTUHcMhFX3PYbfR5wIDAQABozEwLzAOBgNVHQ8BAf8EBAMCBaAw\nDAYDVR0TAQH/BAIwADAPBgNVHREECDAGhwQiU4HTMA0GCSqGSIb3DQEBCwUAA4IB\nAQCdLh6olDVQB71LD6srbfAE4EsxLEBbIRnv7Nf1S0KQwgW/QxK8DHBwJBxJkr1N\nzgEPx86f2Fo2UsY9m6rvgP3+iquyMsKi0ooUah3y3LSnONuZcdfSTl/HYd38S6Dp\nVkVOZ7781xxpFVUqQ5voQX1Y1Ipn5qw0FyIcNYWLkNX+iMf1b9kpEIWQNhRC/Yiv\nTS0VA/BzQemGyf2UB6QsuZLH+JFEZnzU859qURnNIITa1Wf4YUtka5Sp1kDnEll3\nwj4IlXKU+Wl1CzxJyn4SSQAXy/Lb08ZKrF/YSzcIISnRX5j+wa8ApOSwwA/B7iaT\nTWz1g+RlV9qHap70eIjPsQvb\n-----END CERTIFICATE-----' diff --git a/istio-1.5.0/install/kubernetes/helm/istio/example-values/values-istio-gateways.yaml b/istio-1.5.0/install/kubernetes/helm/istio/example-values/values-istio-gateways.yaml new file mode 100644 index 0000000..b9930d0 --- /dev/null +++ b/istio-1.5.0/install/kubernetes/helm/istio/example-values/values-istio-gateways.yaml @@ -0,0 +1,135 @@ +# Common settings. +global: + # Omit the istio-sidecar-injector configmap when generate a + # standalone gateway. Gateways may be created in namespaces other + # than `istio-system` and we don't want to re-create the injector + # configmap in those. + omitSidecarInjectorConfigMap: true + + # Istio control plane namespace: This specifies where the Istio control + # plane was installed earlier. Modify this if you installed the control + # plane in a different namespace than istio-system. + istioNamespace: istio-system + + proxy: + # Sets the destination Statsd in envoy (the value of the "--statsdUdpAddress" proxy argument + # would be :). + # Disabled by default. + # The istio-statsd-prom-bridge is deprecated and should not be used moving forward. + envoyStatsd: + # If enabled is set to true, host and port must also be provided. Istio no longer provides a statsd collector. + enabled: false + host: # example: statsd-svc.istio-system + port: # example: 9125 + + +# +# Gateways Configuration +# By default (if enabled) a pair of Ingress and Egress Gateways will be created for the mesh. +# You can add more gateways in addition to the defaults but make sure those are uniquely named +# and that NodePorts are not conflicting. +# Disable specific gateway by setting the `enabled` to false. +# +gateways: + enabled: true + + custom-gateway: + enabled: true + labels: + app: custom-gateway + replicaCount: 1 + autoscaleMin: 1 + autoscaleMax: 5 + resources: {} + # limits: + # cpu: 100m + # memory: 128Mi + #requests: + # cpu: 1800m + # memory: 256Mi + cpu: + targetAverageUtilization: 80 + loadBalancerIP: "" + loadBalancerSourceRanges: {} + externalIPs: [] + serviceAnnotations: {} + podAnnotations: {} + type: LoadBalancer #change to NodePort, ClusterIP or LoadBalancer if need be + #externalTrafficPolicy: Local #change to Local to preserve source IP or Cluster for default behaviour or leave commented out + ports: + ## You can add custom gateway ports + - port: 80 + targetPort: 80 + name: http2 + # nodePort: 31380 + - port: 443 + name: https + # nodePort: 31390 + - port: 31400 + name: tcp + # nodePort: 31400 + # Pilot and Citadel MTLS ports are enabled in gateway - but will only redirect + # to pilot/citadel if global.meshExpansion settings are enabled. + - port: 15011 + targetPort: 15011 + name: tcp-pilot-grpc-tls + - port: 8060 + targetPort: 8060 + name: tcp-citadel-grpc-tls + # Addon ports for kiali are enabled in gateway - but will only redirect if + # the gateway configuration for the various components are enabled. + - port: 15029 + targetPort: 15029 + name: http2-kiali + # Telemetry-related ports are enabled in gateway - but will only redirect if + # the gateway configuration for the various components are enabled. + - port: 15030 + targetPort: 15030 + name: http2-prometheus + - port: 15031 + targetPort: 15031 + name: http2-grafana + - port: 15032 + targetPort: 15032 + name: http2-tracing + secretVolumes: + - name: customgateway-certs + secretName: istio-customgateway-certs + mountPath: /etc/istio/customgateway-certs + - name: customgateway-ca-certs + secretName: istio-customgateway-ca-certs + mountPath: /etc/istio/customgateway-ca-certs + +# all other components are disabled except the gateways +security: + enabled: false + +sidecarInjectorWebhook: + enabled: false + +galley: + enabled: false + +mixer: + policy: + enabled: false + telemetry: + enabled: false + +pilot: + enabled: false + +grafana: + enabled: false + +prometheus: + enabled: false + +tracing: + enabled: false + +kiali: + enabled: false + +certmanager: + enabled: false diff --git a/istio-1.5.0/install/kubernetes/helm/istio/example-values/values-istio-googleca.yaml b/istio-1.5.0/install/kubernetes/helm/istio/example-values/values-istio-googleca.yaml new file mode 100644 index 0000000..0e6d153 --- /dev/null +++ b/istio-1.5.0/install/kubernetes/helm/istio/example-values/values-istio-googleca.yaml @@ -0,0 +1,28 @@ +global: + controlPlaneSecurityEnabled: true + + mtls: + # Default setting for service-to-service mtls. Can be set explicitly using + # destination rules or service annotations. + enabled: true + + sds: + enabled: true + udsPath: "unix:/var/run/sds/uds_path" + # For GoogleCA, the aud field need to be set to the trustDomain, which is also set at the + # installation/configuration time, e.g. by running helm template. + token: + aud: "" + + trustDomain: "" + + useMCP: true + +nodeagent: + enabled: true + image: node-agent-k8s + env: + CA_PROVIDER: "GoogleCA" + CA_ADDR: "meshca.googleapis.com:443" + PLUGINS: "GoogleTokenExchange" + GKE_CLUSTER_URL: "" diff --git a/istio-1.5.0/install/kubernetes/helm/istio/example-values/values-istio-meshexpansion-gateways.yaml b/istio-1.5.0/install/kubernetes/helm/istio/example-values/values-istio-meshexpansion-gateways.yaml new file mode 100644 index 0000000..51a1ded --- /dev/null +++ b/istio-1.5.0/install/kubernetes/helm/istio/example-values/values-istio-meshexpansion-gateways.yaml @@ -0,0 +1,28 @@ +global: + # Provides dns resolution for global services + podDNSSearchNamespaces: + - global + + multiCluster: + enabled: true + + controlPlaneSecurityEnabled: true + meshExpansion: + enabled: true + +# Multicluster with gateways requires a root CA +# Cluster local CAs are bootstrapped with the root CA. +security: + selfSigned: false + +# Provides dns resolution for service entries of form +# name.namespace.global +istiocoredns: + enabled: true + +gateways: + istio-egressgateway: + enabled: true + env: + # Needed to route traffic via egress gateway if desired. + ISTIO_META_REQUESTED_NETWORK_VIEW: "external" diff --git a/istio-1.5.0/install/kubernetes/helm/istio/example-values/values-istio-multicluster-gateways.yaml b/istio-1.5.0/install/kubernetes/helm/istio/example-values/values-istio-multicluster-gateways.yaml new file mode 100644 index 0000000..3524a3d --- /dev/null +++ b/istio-1.5.0/install/kubernetes/helm/istio/example-values/values-istio-multicluster-gateways.yaml @@ -0,0 +1,27 @@ +global: + # Provides dns resolution for global services + podDNSSearchNamespaces: + - global + - "{{ valueOrDefault .DeploymentMeta.Namespace \"default\" }}.global" + + multiCluster: + enabled: true + + controlPlaneSecurityEnabled: true + +# Multicluster with gateways requires a root CA +# Cluster local CAs are bootstrapped with the root CA. +security: + selfSigned: false + +# Provides dns resolution for service entries of form +# name.namespace.global +istiocoredns: + enabled: true + +gateways: + istio-egressgateway: + enabled: true + env: + # Needed to route traffic via egress gateway if desired. + ISTIO_META_REQUESTED_NETWORK_VIEW: "external" diff --git a/istio-1.5.0/install/kubernetes/helm/istio/files/injection-template.yaml b/istio-1.5.0/install/kubernetes/helm/istio/files/injection-template.yaml new file mode 100644 index 0000000..a4fffb7 --- /dev/null +++ b/istio-1.5.0/install/kubernetes/helm/istio/files/injection-template.yaml @@ -0,0 +1,445 @@ +rewriteAppHTTPProbe: {{ valueOrDefault .Values.sidecarInjectorWebhook.rewriteAppHTTPProbe false }} +initContainers: +{{ if ne (annotation .ObjectMeta `sidecar.istio.io/interceptionMode` .ProxyConfig.InterceptionMode) `NONE` }} +{{ if .Values.istio_cni.enabled -}} +- name: istio-validation +{{ else -}} +- name: istio-init +{{ end -}} +{{- if contains "/" .Values.global.proxy_init.image }} + image: "{{ .Values.global.proxy_init.image }}" +{{- else }} + image: "{{ .Values.global.hub }}/{{ .Values.global.proxy_init.image }}:{{ .Values.global.tag }}" +{{- end }} + command: + - istio-iptables + - "-p" + - "15001" + - "-z" + - "15006" + - "-u" + - 1337 + - "-m" + - "{{ annotation .ObjectMeta `sidecar.istio.io/interceptionMode` .ProxyConfig.InterceptionMode }}" + - "-i" + - "{{ annotation .ObjectMeta `traffic.sidecar.istio.io/includeOutboundIPRanges` .Values.global.proxy.includeIPRanges }}" + - "-x" + - "{{ annotation .ObjectMeta `traffic.sidecar.istio.io/excludeOutboundIPRanges` .Values.global.proxy.excludeIPRanges }}" + - "-b" + - "{{ annotation .ObjectMeta `traffic.sidecar.istio.io/includeInboundPorts` `*` }}" + - "-d" + - "{{ excludeInboundPort (annotation .ObjectMeta `status.sidecar.istio.io/port` .Values.global.proxy.statusPort) (annotation .ObjectMeta `traffic.sidecar.istio.io/excludeInboundPorts` .Values.global.proxy.excludeInboundPorts) }}" + {{ if or (isset .ObjectMeta.Annotations `traffic.sidecar.istio.io/excludeOutboundPorts`) (ne (valueOrDefault .Values.global.proxy.excludeOutboundPorts "") "") -}} + - "-o" + - "{{ annotation .ObjectMeta `traffic.sidecar.istio.io/excludeOutboundPorts` .Values.global.proxy.excludeOutboundPorts }}" + {{ end -}} + {{ if (isset .ObjectMeta.Annotations `traffic.sidecar.istio.io/kubevirtInterfaces`) -}} + - "-k" + - "{{ index .ObjectMeta.Annotations `traffic.sidecar.istio.io/kubevirtInterfaces` }}" + {{ end -}} + {{ if .Values.istio_cni.enabled -}} + - "--run-validation" + - "--skip-rule-apply" + {{ end -}} + imagePullPolicy: "{{ valueOrDefault .Values.global.imagePullPolicy `Always` }}" +{{- if .Values.global.proxy_init.resources }} + resources: + {{ toYaml .Values.global.proxy_init.resources | indent 4 }} +{{- else }} + resources: {} +{{- end }} + securityContext: + allowPrivilegeEscalation: {{ .Values.global.proxy.privileged }} + privileged: {{ .Values.global.proxy.privileged }} + capabilities: + {{- if not .Values.istio_cni.enabled }} + add: + - NET_ADMIN + - NET_RAW + {{- end }} + drop: + - ALL + readOnlyRootFilesystem: false + {{- if not .Values.istio_cni.enabled }} + runAsGroup: 0 + runAsNonRoot: false + runAsUser: 0 + {{- else }} + runAsGroup: 1337 + runAsUser: 1337 + runAsNonRoot: true + {{- end }} + restartPolicy: Always +{{ end -}} +{{- if eq (annotation .ObjectMeta `sidecar.istio.io/enableCoreDump` .Values.global.proxy.enableCoreDump) "true" }} +- name: enable-core-dump + args: + - -c + - sysctl -w kernel.core_pattern=/var/lib/istio/core.proxy && ulimit -c unlimited + command: + - /bin/sh + image: {{ $.Values.global.proxy.enableCoreDumpImage }} + imagePullPolicy: IfNotPresent + resources: {} + securityContext: + allowPrivilegeEscalation: true + capabilities: + add: + - SYS_ADMIN + drop: + - ALL + privileged: true + readOnlyRootFilesystem: false + runAsGroup: 0 + runAsNonRoot: false + runAsUser: 0 +{{ end }} +containers: +- name: istio-proxy +{{- if contains "/" (annotation .ObjectMeta `sidecar.istio.io/proxyImage` .Values.global.proxy.image) }} + image: "{{ annotation .ObjectMeta `sidecar.istio.io/proxyImage` .Values.global.proxy.image }}" +{{- else }} + image: "{{ annotation .ObjectMeta `sidecar.istio.io/proxyImage` .Values.global.hub }}/{{ .Values.global.proxy.image }}:{{ .Values.global.tag }}" +{{- end }} + ports: + - containerPort: 15090 + protocol: TCP + name: http-envoy-prom + args: + - proxy + - sidecar + - --domain + - $(POD_NAMESPACE).svc.{{ .Values.global.proxy.clusterDomain }} + - --configPath + - "{{ .ProxyConfig.ConfigPath }}" + - --binaryPath + - "{{ .ProxyConfig.BinaryPath }}" + - --serviceCluster + {{ if ne "" (index .ObjectMeta.Labels "app") -}} + - "{{ index .ObjectMeta.Labels `app` }}.$(POD_NAMESPACE)" + {{ else -}} + - "{{ valueOrDefault .DeploymentMeta.Name `istio-proxy` }}.{{ valueOrDefault .DeploymentMeta.Namespace `default` }}" + {{ end -}} + - --drainDuration + - "{{ formatDuration .ProxyConfig.DrainDuration }}" + - --parentShutdownDuration + - "{{ formatDuration .ProxyConfig.ParentShutdownDuration }}" + - --discoveryAddress + - "{{ annotation .ObjectMeta `sidecar.istio.io/discoveryAddress` .ProxyConfig.DiscoveryAddress }}" +{{- if eq .Values.global.proxy.tracer "lightstep" }} + - --lightstepAddress + - "{{ .ProxyConfig.GetTracing.GetLightstep.GetAddress }}" + - --lightstepAccessToken + - "{{ .ProxyConfig.GetTracing.GetLightstep.GetAccessToken }}" + - --lightstepSecure={{ .ProxyConfig.GetTracing.GetLightstep.GetSecure }} +{{- if .ProxyConfig.GetTracing.GetLightstep.GetSecure }} + - --lightstepCacertPath + - "{{ .ProxyConfig.GetTracing.GetLightstep.GetCacertPath }}" +{{- end }} +{{- else if eq .Values.global.proxy.tracer "zipkin" }} + - --zipkinAddress + - "{{ .ProxyConfig.GetTracing.GetZipkin.GetAddress }}" +{{- else if eq .Values.global.proxy.tracer "datadog" }} + - --datadogAgentAddress + - "{{ .ProxyConfig.GetTracing.GetDatadog.GetAddress }}" +{{- end }} +{{- if .Values.global.proxy.logLevel }} + - --proxyLogLevel={{ .Values.global.proxy.logLevel }} +{{- end}} +{{- if .Values.global.proxy.componentLogLevel }} + - --proxyComponentLogLevel={{ .Values.global.proxy.componentLogLevel }} +{{- end}} +{{- if .Values.global.proxy.outlierLogPath }} + - --outlierLogPath={{ .Values.global.proxy.outlierLogPath }} +{{- end}} + - --dnsRefreshRate + - {{ .Values.global.proxy.dnsRefreshRate }} + - --connectTimeout + - "{{ formatDuration .ProxyConfig.ConnectTimeout }}" +{{- if .Values.global.proxy.envoyStatsd.enabled }} + - --statsdUdpAddress + - "{{ .ProxyConfig.StatsdUdpAddress }}" +{{- end }} +{{- if .Values.global.proxy.envoyMetricsService.enabled }} + - --envoyMetricsService + - '{{ protoToJSON .ProxyConfig.EnvoyMetricsService }}' +{{- end }} +{{- if .Values.global.proxy.envoyAccessLogService.enabled }} + - --envoyAccessLogService + - '{{ protoToJSON .ProxyConfig.EnvoyAccessLogService }}' +{{- end }} + - --proxyAdminPort + - "{{ .ProxyConfig.ProxyAdminPort }}" + {{ if gt .ProxyConfig.Concurrency 0 -}} + - --concurrency + - "{{ .ProxyConfig.Concurrency }}" + {{ end -}} + - --controlPlaneAuthPolicy + - "{{ annotation .ObjectMeta `sidecar.istio.io/controlPlaneAuthPolicy` .ProxyConfig.ControlPlaneAuthPolicy }}" +{{- if (ne (annotation .ObjectMeta "status.sidecar.istio.io/port" (valueOrDefault .Values.global.proxy.statusPort 0 )) `0`) }} + - --statusPort + - "{{ annotation .ObjectMeta `status.sidecar.istio.io/port` .Values.global.proxy.statusPort }}" +{{- end }} +{{- if .Values.global.trustDomain }} + - --trust-domain={{ .Values.global.trustDomain }} +{{- end }} +{{- if .Values.global.proxy.lifecycle }} + lifecycle: + {{ toYaml .Values.global.proxy.lifecycle | indent 4 }} +{{- end }} + env: + - name: POD_NAME + valueFrom: + fieldRef: + fieldPath: metadata.name + - name: ISTIO_META_POD_PORTS + value: |- + [ + {{- $first := true }} + {{- range $index1, $c := .Spec.Containers }} + {{- range $index2, $p := $c.Ports }} + {{- if (structToJSON $p) }} + {{if not $first}},{{end}}{{ structToJSON $p }} + {{- $first = false }} + {{- end }} + {{- end}} + {{- end}} + ] + - name: ISTIO_META_CLUSTER_ID + value: "{{ valueOrDefault .Values.global.multiCluster.clusterName `Kubernetes` }}" + - name: POD_NAMESPACE + valueFrom: + fieldRef: + fieldPath: metadata.namespace + - name: INSTANCE_IP + valueFrom: + fieldRef: + fieldPath: status.podIP + - name: SERVICE_ACCOUNT + valueFrom: + fieldRef: + fieldPath: spec.serviceAccountName + {{- if .Values.global.mtls.auto }} + - name: ISTIO_AUTO_MTLS_ENABLED + value: "true" + {{- end }} +{{- if eq .Values.global.proxy.tracer "datadog" }} + - name: HOST_IP + valueFrom: + fieldRef: + fieldPath: status.hostIP +{{- if isset .ObjectMeta.Annotations `apm.datadoghq.com/env` }} +{{- range $key, $value := fromJSON (index .ObjectMeta.Annotations `apm.datadoghq.com/env`) }} + - name: {{ $key }} + value: "{{ $value }}" +{{- end }} +{{- end }} +{{- end }} + - name: ISTIO_META_POD_NAME + valueFrom: + fieldRef: + fieldPath: metadata.name + - name: ISTIO_META_CONFIG_NAMESPACE + valueFrom: + fieldRef: + fieldPath: metadata.namespace + - name: SDS_ENABLED + value: {{ $.Values.global.sds.enabled }} + - name: ISTIO_META_INTERCEPTION_MODE + value: "{{ or (index .ObjectMeta.Annotations `sidecar.istio.io/interceptionMode`) .ProxyConfig.InterceptionMode.String }}" + {{- if .Values.global.network }} + - name: ISTIO_META_NETWORK + value: "{{ .Values.global.network }}" + {{- end }} + {{ if .ObjectMeta.Annotations }} + - name: ISTIO_METAJSON_ANNOTATIONS + value: | + {{ toJSON .ObjectMeta.Annotations }} + {{ end }} + {{ if .ObjectMeta.Labels }} + - name: ISTIO_METAJSON_LABELS + value: | + {{ toJSON .ObjectMeta.Labels }} + {{ end }} + {{- if .DeploymentMeta.Name }} + - name: ISTIO_META_WORKLOAD_NAME + value: {{ .DeploymentMeta.Name }} + {{ end }} + {{- if and .TypeMeta.APIVersion .DeploymentMeta.Name }} + - name: ISTIO_META_OWNER + value: kubernetes://apis/{{ .TypeMeta.APIVersion }}/namespaces/{{ valueOrDefault .DeploymentMeta.Namespace `default` }}/{{ toLower .TypeMeta.Kind}}s/{{ .DeploymentMeta.Name }} + {{- end}} + {{- if (isset .ObjectMeta.Annotations `sidecar.istio.io/bootstrapOverride`) }} + - name: ISTIO_BOOTSTRAP_OVERRIDE + value: "/etc/istio/custom-bootstrap/custom_bootstrap.json" + {{- end }} + {{- if .Values.global.sds.customTokenDirectory }} + - name: ISTIO_META_SDS_TOKEN_PATH + value: "{{ .Values.global.sds.customTokenDirectory -}}/sdstoken" + {{- end }} + {{- if .Values.global.meshID }} + - name: ISTIO_META_MESH_ID + value: "{{ .Values.global.meshID }}" + {{- else if .Values.global.trustDomain }} + - name: ISTIO_META_MESH_ID + value: "{{ .Values.global.trustDomain }}" + {{- end }} + {{- if eq .Values.global.proxy.tracer "stackdriver" }} + - name: STACKDRIVER_TRACING_ENABLED + value: "true" + - name: STACKDRIVER_TRACING_DEBUG + value: "{{ .ProxyConfig.GetTracing.GetStackdriver.GetDebug }}" + {{- if .ProxyConfig.GetTracing.GetStackdriver.GetMaxNumberOfAnnotations }} + - name: STACKDRIVER_TRACING_MAX_NUMBER_OF_ANNOTATIONS + value: "{{ .ProxyConfig.GetTracing.GetStackdriver.GetMaxNumberOfAnnotations.Value }}" + {{- end }} + {{- if .ProxyConfig.GetTracing.GetStackdriver.GetMaxNumberOfAttributes }} + - name: STACKDRIVER_TRACING_MAX_NUMBER_OF_ATTRIBUTES + value: "{{ .ProxyConfig.GetTracing.GetStackdriver.GetMaxNumberOfAttributes.Value }}" + {{- end }} + {{- if .ProxyConfig.GetTracing.GetStackdriver.GetMaxNumberOfMessageEvents }} + - name: STACKDRIVER_TRACING_MAX_NUMBER_OF_MESSAGE_EVENTS + value: "{{ .ProxyConfig.GetTracing.GetStackdriver.GetMaxNumberOfMessageEvents.Value }}" + {{- end }} + {{- end }} + imagePullPolicy: {{ .Values.global.imagePullPolicy }} + {{ if ne (annotation .ObjectMeta `status.sidecar.istio.io/port` (valueOrDefault .Values.global.proxy.statusPort 0 )) `0` }} + readinessProbe: + httpGet: + path: /healthz/ready + port: {{ annotation .ObjectMeta `status.sidecar.istio.io/port` .Values.global.proxy.statusPort }} + initialDelaySeconds: {{ annotation .ObjectMeta `readiness.status.sidecar.istio.io/initialDelaySeconds` .Values.global.proxy.readinessInitialDelaySeconds }} + periodSeconds: {{ annotation .ObjectMeta `readiness.status.sidecar.istio.io/periodSeconds` .Values.global.proxy.readinessPeriodSeconds }} + failureThreshold: {{ annotation .ObjectMeta `readiness.status.sidecar.istio.io/failureThreshold` .Values.global.proxy.readinessFailureThreshold }} + {{ end -}} + securityContext: + allowPrivilegeEscalation: {{ .Values.global.proxy.privileged }} + capabilities: + {{ if eq (annotation .ObjectMeta `sidecar.istio.io/interceptionMode` .ProxyConfig.InterceptionMode) `TPROXY` -}} + add: + - NET_ADMIN + {{- end }} + drop: + - ALL + privileged: {{ .Values.global.proxy.privileged }} + readOnlyRootFilesystem: {{ ne (annotation .ObjectMeta `sidecar.istio.io/enableCoreDump` .Values.global.proxy.enableCoreDump) "true" }} + runAsGroup: 1337 + {{ if eq (annotation .ObjectMeta `sidecar.istio.io/interceptionMode` .ProxyConfig.InterceptionMode) `TPROXY` -}} + runAsNonRoot: false + runAsUser: 0 + {{- else -}} + runAsNonRoot: true + runAsUser: 1337 + {{- end }} + resources: + {{ if or (isset .ObjectMeta.Annotations `sidecar.istio.io/proxyCPU`) (isset .ObjectMeta.Annotations `sidecar.istio.io/proxyMemory`) -}} + requests: + {{ if (isset .ObjectMeta.Annotations `sidecar.istio.io/proxyCPU`) -}} + cpu: "{{ index .ObjectMeta.Annotations `sidecar.istio.io/proxyCPU` }}" + {{ end}} + {{ if (isset .ObjectMeta.Annotations `sidecar.istio.io/proxyMemory`) -}} + memory: "{{ index .ObjectMeta.Annotations `sidecar.istio.io/proxyMemory` }}" + {{ end }} + {{ else -}} +{{- if .Values.global.proxy.resources }} + {{ toYaml .Values.global.proxy.resources | indent 4 }} +{{- end }} + {{ end -}} + volumeMounts: + {{ if (isset .ObjectMeta.Annotations `sidecar.istio.io/bootstrapOverride`) }} + - mountPath: /etc/istio/custom-bootstrap + name: custom-bootstrap-volume + {{- end }} + - mountPath: /etc/istio/proxy + name: istio-envoy + {{- if .Values.global.sds.enabled }} + - mountPath: /var/run/sds + name: sds-uds-path + readOnly: true + - mountPath: /var/run/secrets/tokens + name: istio-token + {{- if .Values.global.sds.customTokenDirectory }} + - mountPath: "{{ .Values.global.sds.customTokenDirectory -}}" + name: custom-sds-token + readOnly: true + {{- end }} + {{- else }} + - mountPath: /etc/certs/ + name: istio-certs + readOnly: true + {{- end }} + {{- if and (eq .Values.global.proxy.tracer "lightstep") .Values.global.tracer.lightstep.cacertPath }} + - mountPath: {{ directory .ProxyConfig.GetTracing.GetLightstep.GetCacertPath }} + name: lightstep-certs + readOnly: true + {{- end }} + {{- if isset .ObjectMeta.Annotations `sidecar.istio.io/userVolumeMount` }} + {{ range $index, $value := fromJSON (index .ObjectMeta.Annotations `sidecar.istio.io/userVolumeMount`) }} + - name: "{{ $index }}" + {{ toYaml $value | indent 4 }} + {{ end }} + {{- end }} +volumes: +{{- if (isset .ObjectMeta.Annotations `sidecar.istio.io/bootstrapOverride`) }} +- name: custom-bootstrap-volume + configMap: + name: {{ annotation .ObjectMeta `sidecar.istio.io/bootstrapOverride` "" }} +{{- end }} +- emptyDir: + medium: Memory + name: istio-envoy +{{- if .Values.global.sds.enabled }} +- name: sds-uds-path + hostPath: + path: /var/run/sds +- name: istio-token + projected: + sources: + - serviceAccountToken: + path: istio-token + expirationSeconds: 43200 + audience: {{ .Values.global.sds.token.aud }} +{{- if .Values.global.sds.customTokenDirectory }} +- name: custom-sds-token + secret: + secretName: sdstokensecret +{{- end }} +{{- else }} +- name: istio-certs + secret: + optional: true + {{ if eq .Spec.ServiceAccountName "" }} + secretName: istio.default + {{ else -}} + secretName: {{ printf "istio.%s" .Spec.ServiceAccountName }} + {{ end -}} + {{- if isset .ObjectMeta.Annotations `sidecar.istio.io/userVolume` }} + {{range $index, $value := fromJSON (index .ObjectMeta.Annotations `sidecar.istio.io/userVolume`) }} +- name: "{{ $index }}" + {{ toYaml $value | indent 2 }} + {{ end }} + {{ end }} +{{- end }} +{{- if and (eq .Values.global.proxy.tracer "lightstep") .Values.global.tracer.lightstep.cacertPath }} +- name: lightstep-certs + secret: + optional: true + secretName: lightstep.cacert +{{- end }} +{{- if .Values.global.podDNSSearchNamespaces }} +dnsConfig: + searches: + {{- range .Values.global.podDNSSearchNamespaces }} + - {{ render . }} + {{- end }} +{{- end }} +podRedirectAnnot: + sidecar.istio.io/interceptionMode: "{{ annotation .ObjectMeta `sidecar.istio.io/interceptionMode` .ProxyConfig.InterceptionMode }}" + traffic.sidecar.istio.io/includeOutboundIPRanges: "{{ annotation .ObjectMeta `traffic.sidecar.istio.io/includeOutboundIPRanges` .Values.global.proxy.includeIPRanges }}" + traffic.sidecar.istio.io/excludeOutboundIPRanges: "{{ annotation .ObjectMeta `traffic.sidecar.istio.io/excludeOutboundIPRanges` .Values.global.proxy.excludeIPRanges }}" + traffic.sidecar.istio.io/includeInboundPorts: "{{ annotation .ObjectMeta `traffic.sidecar.istio.io/includeInboundPorts` (includeInboundPorts .Spec.Containers) }}" + traffic.sidecar.istio.io/excludeInboundPorts: "{{ excludeInboundPort (annotation .ObjectMeta `status.sidecar.istio.io/port` .Values.global.proxy.statusPort) (annotation .ObjectMeta `traffic.sidecar.istio.io/excludeInboundPorts` .Values.global.proxy.excludeInboundPorts) }}" +{{ if or (isset .ObjectMeta.Annotations `traffic.sidecar.istio.io/excludeOutboundPorts`) (ne .Values.global.proxy.excludeOutboundPorts "") }} + traffic.sidecar.istio.io/excludeOutboundPorts: "{{ annotation .ObjectMeta `traffic.sidecar.istio.io/excludeOutboundPorts` .Values.global.proxy.excludeOutboundPorts }}" +{{- end }} + traffic.sidecar.istio.io/kubevirtInterfaces: "{{ index .ObjectMeta.Annotations `traffic.sidecar.istio.io/kubevirtInterfaces` }}" diff --git a/istio-1.5.0/install/kubernetes/helm/istio/requirements.yaml b/istio-1.5.0/install/kubernetes/helm/istio/requirements.yaml new file mode 100644 index 0000000..0e4d45a --- /dev/null +++ b/istio-1.5.0/install/kubernetes/helm/istio/requirements.yaml @@ -0,0 +1,40 @@ +dependencies: + - name: sidecarInjectorWebhook + version: 1.5.0 + condition: sidecarInjectorWebhook.enabled + - name: security + version: 1.5.0 + condition: security.enabled + - name: gateways + version: 1.5.0 + condition: gateways.enabled + - name: mixer + version: 1.5.0 + condition: or mixer.policy.enabled mixer.telemetry.enabled + - name: nodeagent + version: 1.5.0 + condition: nodeagent.enabled + - name: pilot + version: 1.5.0 + condition: pilot.enabled + - name: grafana + version: 1.5.0 + condition: grafana.enabled + - name: prometheus + version: 1.5.0 + condition: prometheus.enabled + - name: tracing + version: 1.5.0 + condition: tracing.enabled + - name: galley + version: 1.5.0 + condition: galley.enabled + - name: kiali + version: 1.5.0 + condition: kiali.enabled + - name: istiocoredns + version: 1.5.0 + condition: istiocoredns.enabled + - name: certmanager + version: 1.5.0 + condition: certmanager.enabled diff --git a/istio-1.5.0/install/kubernetes/helm/istio/templates/NOTES.txt b/istio-1.5.0/install/kubernetes/helm/istio/templates/NOTES.txt new file mode 100644 index 0000000..3b32359 --- /dev/null +++ b/istio-1.5.0/install/kubernetes/helm/istio/templates/NOTES.txt @@ -0,0 +1,29 @@ +Thank you for installing {{ .Chart.Name | title }}. + +Your release is named {{ .Release.Name | title }}. + +To get started running application with Istio, execute the following steps: + +{{- if index .Values "sidecarInjectorWebhook" "enabled" }} +1. Label namespace that application object will be deployed to by the following command (take default namespace as an example) + +$ kubectl label namespace default istio-injection=enabled +$ kubectl get namespace -L istio-injection + +2. Deploy your applications + +$ kubectl apply -f .yaml +{{- else }} +1. Download the latest release package to get sidecar injection tool + +$ curl -L https://git.io/getLatestIstio | sh - +$ mv istio-* istio-latest +$ export PATH="$PATH:$PWD/istio-latest/bin" + +2. Deploy your application by manually injecting envoy sidecar with `istioctl kube-inject` + +$ kubectl apply -f <(istioctl kube-inject -f .yaml) +{{- end }} + +For more information on running Istio, visit: +https://istio.io/ diff --git a/istio-1.5.0/install/kubernetes/helm/istio/templates/_affinity.tpl b/istio-1.5.0/install/kubernetes/helm/istio/templates/_affinity.tpl new file mode 100644 index 0000000..7639be4 --- /dev/null +++ b/istio-1.5.0/install/kubernetes/helm/istio/templates/_affinity.tpl @@ -0,0 +1,93 @@ +{{/* affinity - https://kubernetes.io/docs/concepts/configuration/assign-pod-node/ */}} + +{{- define "nodeaffinity" }} + nodeAffinity: + requiredDuringSchedulingIgnoredDuringExecution: + {{- include "nodeAffinityRequiredDuringScheduling" . }} + preferredDuringSchedulingIgnoredDuringExecution: + {{- include "nodeAffinityPreferredDuringScheduling" . }} +{{- end }} + +{{- define "nodeAffinityRequiredDuringScheduling" }} + nodeSelectorTerms: + - matchExpressions: + - key: beta.kubernetes.io/arch + operator: In + values: + {{- range $key, $val := .Values.global.arch }} + {{- if gt ($val | int) 0 }} + - {{ $key | quote }} + {{- end }} + {{- end }} + {{- $nodeSelector := default .Values.global.defaultNodeSelector .Values.nodeSelector -}} + {{- range $key, $val := $nodeSelector }} + - key: {{ $key }} + operator: In + values: + - {{ $val | quote }} + {{- end }} +{{- end }} + +{{- define "nodeAffinityPreferredDuringScheduling" }} + {{- range $key, $val := .Values.global.arch }} + {{- if gt ($val | int) 0 }} + - weight: {{ $val | int }} + preference: + matchExpressions: + - key: beta.kubernetes.io/arch + operator: In + values: + - {{ $key | quote }} + {{- end }} + {{- end }} +{{- end }} + +{{- define "podAntiAffinity" }} +{{- if or .Values.podAntiAffinityLabelSelector .Values.podAntiAffinityTermLabelSelector}} + podAntiAffinity: + {{- if .Values.podAntiAffinityLabelSelector }} + requiredDuringSchedulingIgnoredDuringExecution: + {{- include "podAntiAffinityRequiredDuringScheduling" . }} + {{- end }} + {{- if or .Values.podAntiAffinityTermLabelSelector}} + preferredDuringSchedulingIgnoredDuringExecution: + {{- include "podAntiAffinityPreferredDuringScheduling" . }} + {{- end }} +{{- end }} +{{- end }} + +{{- define "podAntiAffinityRequiredDuringScheduling" }} + {{- range $index, $item := .Values.podAntiAffinityLabelSelector }} + - labelSelector: + matchExpressions: + - key: {{ $item.key }} + operator: {{ $item.operator }} + {{- if $item.values }} + values: + {{- $vals := split "," $item.values }} + {{- range $i, $v := $vals }} + - {{ $v | quote }} + {{- end }} + {{- end }} + topologyKey: {{ $item.topologyKey }} + {{- end }} +{{- end }} + +{{- define "podAntiAffinityPreferredDuringScheduling" }} + {{- range $index, $item := .Values.podAntiAffinityTermLabelSelector }} + - podAffinityTerm: + labelSelector: + matchExpressions: + - key: {{ $item.key }} + operator: {{ $item.operator }} + {{- if $item.values }} + values: + {{- $vals := split "," $item.values }} + {{- range $i, $v := $vals }} + - {{ $v | quote }} + {{- end }} + {{- end }} + topologyKey: {{ $item.topologyKey }} + weight: 100 + {{- end }} +{{- end }} diff --git a/istio-1.5.0/install/kubernetes/helm/istio/templates/_helpers.tpl b/istio-1.5.0/install/kubernetes/helm/istio/templates/_helpers.tpl new file mode 100644 index 0000000..b1f54a4 --- /dev/null +++ b/istio-1.5.0/install/kubernetes/helm/istio/templates/_helpers.tpl @@ -0,0 +1,39 @@ +{{/* vim: set filetype=mustache: */}} +{{/* +Expand the name of the chart. +*/}} +{{- define "istio.name" -}} +{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" -}} +{{- end -}} + +{{/* +Create a default fully qualified app name. +We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). +If release name contains chart name it will be used as a full name. +*/}} +{{- define "istio.fullname" -}} +{{- if .Values.fullnameOverride -}} +{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" -}} +{{- else -}} +{{- $name := default .Chart.Name .Values.nameOverride -}} +{{- if contains $name .Release.Name -}} +{{- .Release.Name | trunc 63 | trimSuffix "-" -}} +{{- else -}} +{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" -}} +{{- end -}} +{{- end -}} +{{- end -}} + +{{/* +Create chart name and version as used by the chart label. +*/}} +{{- define "istio.chart" -}} +{{- .Chart.Name | trunc 63 | trimSuffix "-" -}} +{{- end -}} + +{{/* +Create a fully qualified configmap name. +*/}} +{{- define "istio.configmap.fullname" -}} +{{- printf "%s-%s" .Release.Name "istio-mesh-config" | trunc 63 | trimSuffix "-" -}} +{{- end -}} diff --git a/istio-1.5.0/install/kubernetes/helm/istio/templates/_podDisruptionBudget.tpl b/istio-1.5.0/install/kubernetes/helm/istio/templates/_podDisruptionBudget.tpl new file mode 100644 index 0000000..ebb8606 --- /dev/null +++ b/istio-1.5.0/install/kubernetes/helm/istio/templates/_podDisruptionBudget.tpl @@ -0,0 +1,3 @@ +{{- define "podDisruptionBudget.spec" }} + minAvailable: 1 +{{- end }} diff --git a/istio-1.5.0/install/kubernetes/helm/istio/templates/clusterrole.yaml b/istio-1.5.0/install/kubernetes/helm/istio/templates/clusterrole.yaml new file mode 100644 index 0000000..b92c9ef --- /dev/null +++ b/istio-1.5.0/install/kubernetes/helm/istio/templates/clusterrole.yaml @@ -0,0 +1,11 @@ +kind: ClusterRole +apiVersion: rbac.authorization.k8s.io/v1 +metadata: + name: istio-reader +rules: + - apiGroups: [''] + resources: ['nodes', 'pods', 'services', 'endpoints', "replicationcontrollers"] + verbs: ['get', 'watch', 'list'] + - apiGroups: ["extensions", "apps"] + resources: ["replicasets"] + verbs: ["get", "list", "watch"] diff --git a/istio-1.5.0/install/kubernetes/helm/istio/templates/clusterrolebinding.yaml b/istio-1.5.0/install/kubernetes/helm/istio/templates/clusterrolebinding.yaml new file mode 100644 index 0000000..9d9b37d --- /dev/null +++ b/istio-1.5.0/install/kubernetes/helm/istio/templates/clusterrolebinding.yaml @@ -0,0 +1,29 @@ +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: istio-multi + labels: + chart: {{ .Chart.Name }}-{{ .Chart.Version }} +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: istio-reader +subjects: +- kind: ServiceAccount + name: istio-multi + namespace: {{ .Release.Namespace }} +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: istio-reader + labels: + chart: {{ .Chart.Name }}-{{ .Chart.Version }} +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: istio-reader +subjects: +- kind: ServiceAccount + name: istio-reader + namespace: {{ .Release.Namespace }} diff --git a/istio-1.5.0/install/kubernetes/helm/istio/templates/configmap.yaml b/istio-1.5.0/install/kubernetes/helm/istio/templates/configmap.yaml new file mode 100644 index 0000000..9043849 --- /dev/null +++ b/istio-1.5.0/install/kubernetes/helm/istio/templates/configmap.yaml @@ -0,0 +1,345 @@ +{{- if or .Values.pilot.enabled .Values.global.istioRemote }} +apiVersion: v1 +kind: ConfigMap +metadata: + name: istio + namespace: {{ .Release.Namespace }} + labels: + app: {{ template "istio.name" . }} + chart: {{ template "istio.chart" . }} + heritage: {{ .Release.Service }} + release: {{ .Release.Name }} +data: + mesh: |- + # Set the following variable to true to disable policy checks by Mixer. + # Note that metrics will still be reported to Mixer. + {{- if .Values.mixer.policy.enabled }} + disablePolicyChecks: {{ .Values.global.disablePolicyChecks }} + {{- else }} + disablePolicyChecks: true + {{- end }} + + disableMixerHttpReports: false + + {{- if .Values.mixer.telemetry.reportBatchMaxEntries }} + # reportBatchMaxEntries is the number of requests that are batched before telemetry data is sent to the mixer server + reportBatchMaxEntries: {{ .Values.mixer.telemetry.reportBatchMaxEntries }} + {{- end }} + + {{- if .Values.mixer.telemetry.reportBatchMaxTime }} + # reportBatchMaxTime is the max waiting time before the telemetry data of a request is sent to the mixer server + reportBatchMaxTime: {{ .Values.mixer.telemetry.reportBatchMaxTime }} + {{- end }} + + {{- if .Values.mixer.telemetry.sessionAffinityEnabled }} + # sidecarToTelemetrySessionAffinity will create a STRICT_DNS type cluster for istio-telemetry. + sidecarToTelemetrySessionAffinity: {{ .Values.mixer.telemetry.sessionAffinityEnabled }} + {{- end }} + + # Set enableTracing to false to disable request tracing. + enableTracing: {{ .Values.global.enableTracing }} + + # Set accessLogFile to empty string to disable access log. + accessLogFile: "{{ .Values.global.proxy.accessLogFile }}" + + # If accessLogEncoding is TEXT, value will be used directly as the log format + # example: "[%START_TIME%] %REQ(:METHOD)% %REQ(X-ENVOY-ORIGINAL-PATH?:PATH)% %PROTOCOL%\n" + # If AccessLogEncoding is JSON, value will be parsed as map[string]string + # example: '{"start_time": "%START_TIME%", "req_method": "%REQ(:METHOD)%"}' + # Leave empty to use default log format + accessLogFormat: {{ .Values.global.proxy.accessLogFormat | quote }} + + # Set accessLogEncoding to JSON or TEXT to configure sidecar access log + accessLogEncoding: '{{ .Values.global.proxy.accessLogEncoding }}' + + enableEnvoyAccessLogService: {{ .Values.global.proxy.envoyAccessLogService.enabled }} + + {{- if .Values.global.istioRemote }} + + {{- if .Values.global.remotePolicyAddress }} + {{- if .Values.global.createRemoteSvcEndpoints }} + mixerCheckServer: istio-policy.{{ .Release.Namespace }}:15004 + {{- else }} + mixerCheckServer: {{ .Values.global.remotePolicyAddress }}:15004 + {{- end }} + {{- end }} + {{- if .Values.global.remoteTelemetryAddress }} + {{- if .Values.global.createRemoteSvcEndpoints }} + mixerReportServer: istio-telemetry.{{ .Release.Namespace }}:15004 + {{- else }} + mixerReportServer: {{ .Values.global.remoteTelemetryAddress }}:15004 + {{- end }} + {{- end }} + + {{- else }} + + {{- if .Values.mixer.policy.enabled }} + {{- if .Values.global.controlPlaneSecurityEnabled }} + mixerCheckServer: istio-policy.{{ .Release.Namespace }}.svc.{{ .Values.global.proxy.clusterDomain }}:15004 + {{- else }} + mixerCheckServer: istio-policy.{{ .Release.Namespace }}.svc.{{ .Values.global.proxy.clusterDomain }}:9091 + {{- end }} + {{- end }} + {{- if .Values.mixer.telemetry.enabled }} + {{- if .Values.global.controlPlaneSecurityEnabled }} + mixerReportServer: istio-telemetry.{{ .Release.Namespace }}.svc.{{ .Values.global.proxy.clusterDomain }}:15004 + {{- else }} + mixerReportServer: istio-telemetry.{{ .Release.Namespace }}.svc.{{ .Values.global.proxy.clusterDomain }}:9091 + {{- end }} + {{- end }} + + {{- end }} + + {{- if or .Values.mixer.policy.enabled (and .Values.global.istioRemote .Values.global.remotePolicyAddress) }} + # policyCheckFailOpen allows traffic in cases when the mixer policy service cannot be reached. + # Default is false which means the traffic is denied when the client is unable to connect to Mixer. + policyCheckFailOpen: {{ .Values.global.policyCheckFailOpen }} + {{- end }} + + {{- if .Values.gateways.enabled }} + # Let Pilot give ingresses the public IP of the Istio ingressgateway + ingressService: istio-ingressgateway + {{- end }} + + # Default connect timeout for dynamic clusters generated by Pilot and returned via XDS + connectTimeout: 10s + + # Automatic protocol detection uses a set of heuristics to + # determine whether the connection is using TLS or not (on the + # server side), as well as the application protocol being used + # (e.g., http vs tcp). These heuristics rely on the client sending + # the first bits of data. For server first protocols like MySQL, + # MongoDB, etc., Envoy will timeout on the protocol detection after + # the specified period, defaulting to non mTLS plain TCP + # traffic. Set this field to tweak the period that Envoy will wait + # for the client to send the first bits of data. (MUST BE >=1ms) + protocolDetectionTimeout: {{ .Values.global.proxy.protocolDetectionTimeout }} + + # DNS refresh rate for Envoy clusters of type STRICT_DNS + dnsRefreshRate: {{ .Values.global.proxy.dnsRefreshRate }} + + # Unix Domain Socket through which envoy communicates with NodeAgent SDS to get + # key/cert for mTLS. Use secret-mount files instead of SDS if set to empty. + sdsUdsPath: {{ .Values.global.sds.udsPath | quote }} + + # The trust domain corresponds to the trust root of a system. + # Refer to https://github.com/spiffe/spiffe/blob/master/standards/SPIFFE-ID.md#21-trust-domain + trustDomain: {{ .Values.global.trustDomain | quote }} + + # The trust domain aliases represent the aliases of trust_domain. + # For example, if we have + # trustDomain: td1 + # trustDomainAliases: [“td2”, "td3"] + # Any service with the identity "td1/ns/foo/sa/a-service-account", "td2/ns/foo/sa/a-service-account", + # or "td3/ns/foo/sa/a-service-account" will be treated the same in the Istio mesh. + trustDomainAliases: + {{- range .Values.global.trustDomainAliases }} + - {{ . | quote }} + {{- end }} + + # If true, automatically configure client side mTLS settings to match the corresponding service's + # server side mTLS authentication policy, when destination rule for that service does not specify + # TLS settings. + enableAutoMtls: {{ .Values.global.mtls.auto }} + + # Set the default behavior of the sidecar for handling outbound traffic from the application: + # ALLOW_ANY - outbound traffic to unknown destinations will be allowed, in case there are no + # services or ServiceEntries for the destination port + # REGISTRY_ONLY - restrict outbound traffic to services defined in the service registry as well + # as those defined through ServiceEntries + outboundTrafficPolicy: + mode: {{ .Values.global.outboundTrafficPolicy.mode }} + + {{- if .Values.global.localityLbSetting.enabled }} + localityLbSetting: +{{ toYaml .Values.global.localityLbSetting | trim | indent 6 }} + {{- end }} + # The namespace to treat as the administrative root namespace for istio + # configuration. +{{- if .Values.global.configRootNamespace }} + rootNamespace: {{ .Values.global.configRootNamespace }} +{{- else }} + rootNamespace: {{ .Release.Namespace }} +{{- end }} + + # Configures DNS certificates provisioned through Chiron linked into Pilot. + certificates: +{{ toYaml .Values.global.certificates | trim | indent 6 }} + + {{- if .Values.global.defaultConfigVisibilitySettings }} + defaultServiceExportTo: + {{- range .Values.global.defaultConfigVisibilitySettings }} + - {{ . | quote }} + {{- end }} + defaultVirtualServiceExportTo: + {{- range .Values.global.defaultConfigVisibilitySettings }} + - {{ . | quote }} + {{- end }} + defaultDestinationRuleExportTo: + {{- range .Values.global.defaultConfigVisibilitySettings }} + - {{ . | quote }} + {{- end }} + {{- end }} + + {{- if $.Values.global.useMCP }} + configSources: + - address: istio-galley.{{ $.Release.Namespace }}.svc:9901 + {{- if .Values.pilot.configSource.subscribedResources }} + subscribedResources: + {{- range .Values.pilot.configSource.subscribedResources }} + - {{ . }} + {{- end }} + {{- end}} + {{- if $.Values.global.controlPlaneSecurityEnabled}} + tlsSettings: + mode: ISTIO_MUTUAL + {{- end }} + {{- end }} + + defaultConfig: + # + # TCP connection timeout between Envoy & the application, and between Envoys. Used for static clusters + # defined in Envoy's configuration file + connectTimeout: 10s + # + ### ADVANCED SETTINGS ############# + # Where should envoy's configuration be stored in the istio-proxy container + configPath: "/etc/istio/proxy" + binaryPath: "/usr/local/bin/envoy" + # The pseudo service name used for Envoy. + serviceCluster: istio-proxy + # These settings that determine how long an old Envoy + # process should be kept alive after an occasional reload. + drainDuration: 45s + parentShutdownDuration: 1m0s + # + # The mode used to redirect inbound connections to Envoy. This setting + # has no effect on outbound traffic: iptables REDIRECT is always used for + # outbound connections. + # If "REDIRECT", use iptables REDIRECT to NAT and redirect to Envoy. + # The "REDIRECT" mode loses source addresses during redirection. + # If "TPROXY", use iptables TPROXY to redirect to Envoy. + # The "TPROXY" mode preserves both the source and destination IP + # addresses and ports, so that they can be used for advanced filtering + # and manipulation. + # The "TPROXY" mode also configures the sidecar to run with the + # CAP_NET_ADMIN capability, which is required to use TPROXY. + #interceptionMode: REDIRECT + # + # Port where Envoy listens (on local host) for admin commands + # You can exec into the istio-proxy container in a pod and + # curl the admin port (curl http://localhost:15000/) to obtain + # diagnostic information from Envoy. See + # https://lyft.github.io/envoy/docs/operations/admin.html + # for more details + proxyAdminPort: 15000 + # + # Set concurrency to a specific number to control the number of Proxy worker threads. + # If set to 0 (default), then start worker thread for each CPU thread/core. + concurrency: {{ .Values.global.proxy.concurrency }} + # + {{- if eq .Values.global.proxy.tracer "lightstep" }} + tracing: + lightstep: + # Address of the LightStep Satellite pool + address: {{ .Values.global.tracer.lightstep.address }} + # Access Token used to communicate with the Satellite pool + accessToken: {{ .Values.global.tracer.lightstep.accessToken }} + # Whether communication with the Satellite pool should be secure + secure: {{ .Values.global.tracer.lightstep.secure }} + {{- if .Values.global.tracer.lightstep.secure }} + # Path to the file containing the cacert to use when verifying TLS + cacertPath: {{ .Values.global.tracer.lightstep.cacertPath }} + {{- end }} + {{- else if eq .Values.global.proxy.tracer "zipkin" }} + tracing: + zipkin: + # Address of the Zipkin collector + {{- if .Values.global.tracer.zipkin.address }} + address: {{ .Values.global.tracer.zipkin.address }} + {{- else if .Values.global.remoteZipkinAddress }} + address: {{ .Values.global.remoteZipkinAddress }}:9411 + {{- else }} + address: zipkin.{{ .Release.Namespace }}:9411 + {{- end }} + {{- else if eq .Values.global.proxy.tracer "datadog" }} + tracing: + datadog: + # Address of the Datadog Agent + address: {{ .Values.global.tracer.datadog.address }} + {{- else if eq .Values.global.proxy.tracer "stackdriver" }} + tracing: + stackdriver: {} + {{- end }} + + {{- if .Values.global.proxy.envoyStatsd.enabled }} + # + # Statsd metrics collector converts statsd metrics into Prometheus metrics. + statsdUdpAddress: {{ .Values.global.proxy.envoyStatsd.host }}:{{ .Values.global.proxy.envoyStatsd.port }} + {{- end }} + + {{- if .Values.global.proxy.envoyMetricsService.enabled }} + # + # Envoy's Metrics Service stats sink pushes Envoy metrics to a remote collector via the Metrics Service gRPC API. + envoyMetricsService: + address: {{ .Values.global.proxy.envoyMetricsService.host }}:{{ .Values.global.proxy.envoyMetricsService.port }} + {{- if .Values.global.proxy.envoyMetricsService.tlsSettings }} + tlsSettings: +{{ toYaml .Values.global.proxy.envoyMetricsService.tlsSettings | trim | indent 10 }} + {{- end}} + {{- if .Values.global.proxy.envoyMetricsService.tcpKeepalive }} + tcpKeepalive: +{{ toYaml .Values.global.proxy.envoyMetricsService.tcpKeepalive | trim | indent 10 }} + {{- end}} + {{- end}} + + {{- if .Values.global.proxy.envoyAccessLogService.enabled }} + # + # Envoy's AccessLog Service pushes access logs to a remote collector via the Access Log Service gRPC API. + envoyAccessLogService: + address: {{ .Values.global.proxy.envoyAccessLogService.host }}:{{ .Values.global.proxy.envoyAccessLogService.port }} + {{- if .Values.global.proxy.envoyAccessLogService.tlsSettings }} + tlsSettings: +{{ toYaml .Values.global.proxy.envoyAccessLogService.tlsSettings | trim | indent 10 }} + {{- end}} + {{- if .Values.global.proxy.envoyAccessLogService.tcpKeepalive }} + tcpKeepalive: +{{ toYaml .Values.global.proxy.envoyAccessLogService.tcpKeepalive | trim | indent 10 }} + {{- end}} + {{- end}} + + {{- $defPilotHostname := printf "istio-pilot.%s" .Release.Namespace }} + {{- $pilotAddress := .Values.global.remotePilotAddress | default $defPilotHostname }} + {{- if .Values.global.controlPlaneSecurityEnabled }} + # + # Mutual TLS authentication between sidecars and istio control plane. + controlPlaneAuthPolicy: MUTUAL_TLS + # + # Address where istio Pilot service is running + {{- if or .Values.global.remotePilotCreateSvcEndpoint .Values.global.createRemoteSvcEndpoints }} + discoveryAddress: {{ $defPilotHostname }}:15011 + {{- else }} + discoveryAddress: {{ $pilotAddress }}:15011 + {{- end }} + {{- else }} + # + # Mutual TLS authentication between sidecars and istio control plane. + controlPlaneAuthPolicy: NONE + # + # Address where istio Pilot service is running + {{- if or .Values.global.remotePilotCreateSvcEndpoint .Values.global.createRemoteSvcEndpoints }} + discoveryAddress: {{ $defPilotHostname }}:15010 + {{- else }} + discoveryAddress: {{ $pilotAddress }}:15010 + {{- end }} + {{- end }} + + # Configuration file for the mesh networks to be used by the Split Horizon EDS. + meshNetworks: |- + {{- if .Values.global.meshNetworks }} + networks: +{{ toYaml .Values.global.meshNetworks | trim | indent 6 }} + {{- else }} + networks: {} + {{- end }} +{{- end }} diff --git a/istio-1.5.0/install/kubernetes/helm/istio/templates/endpoints.yaml b/istio-1.5.0/install/kubernetes/helm/istio/templates/endpoints.yaml new file mode 100644 index 0000000..81b8218 --- /dev/null +++ b/istio-1.5.0/install/kubernetes/helm/istio/templates/endpoints.yaml @@ -0,0 +1,63 @@ +{{- if or .Values.global.remotePilotCreateSvcEndpoint .Values.global.createRemoteSvcEndpoints }} +apiVersion: v1 +kind: Endpoints +metadata: + name: istio-pilot + namespace: {{ .Release.Namespace }} +subsets: +- addresses: + - ip: {{ .Values.global.remotePilotAddress }} + ports: + - port: 15003 + name: http-old-discovery # mTLS or non-mTLS depending on auth setting + - port: 15005 + name: https-discovery # always mTLS + - port: 15007 + name: http-discovery # always plain-text + - port: 15010 + name: grpc-xds # direct + - port: 15011 + name: https-xds # mTLS or non-mTLS depending on auth setting + - port: 8080 + name: http-legacy-discovery # direct + - port: 15014 + name: http-monitoring +{{- end }} +{{- if and .Values.global.remotePolicyAddress .Values.global.createRemoteSvcEndpoints }} +--- +apiVersion: v1 +kind: Endpoints +metadata: + name: istio-policy + namespace: {{ .Release.Namespace }} +subsets: +- addresses: + - ip: {{ .Values.global.remotePolicyAddress }} + ports: + - name: grpc-mixer + port: 9091 + - name: grpc-mixer-mtls + port: 15004 + - name: http-monitoring + port: 15014 +{{- end }} +{{- if and .Values.global.remoteTelemetryAddress .Values.global.createRemoteSvcEndpoints }} +--- +apiVersion: v1 +kind: Endpoints +metadata: + name: istio-telemetry + namespace: {{ .Release.Namespace }} +subsets: +- addresses: + - ip: {{ .Values.global.remoteTelemetryAddress }} + ports: + - name: grpc-mixer + port: 9091 + - name: grpc-mixer-mtls + port: 15004 + - name: http-monitoring + port: 15014 + - name: prometheus + port: 42422 +{{- end }} diff --git a/istio-1.5.0/install/kubernetes/helm/istio/templates/install-custom-resources.sh.tpl b/istio-1.5.0/install/kubernetes/helm/istio/templates/install-custom-resources.sh.tpl new file mode 100644 index 0000000..a5525a1 --- /dev/null +++ b/istio-1.5.0/install/kubernetes/helm/istio/templates/install-custom-resources.sh.tpl @@ -0,0 +1,32 @@ +{{ define "install-custom-resources.sh.tpl" }} +#!/bin/sh + +set -x + +if [ "$#" -ne "1" ]; then + echo "first argument should be path to custom resource yaml" + exit 1 +fi + +pathToResourceYAML=${1} + +kubectl get validatingwebhookconfiguration istio-galley 2>/dev/null +if [ "$?" -eq 0 ]; then + echo "istio-galley validatingwebhookconfiguration found - waiting for istio-galley deployment to be ready" + while true; do + kubectl -n {{ .Release.Namespace }} get deployment istio-galley 2>/dev/null + if [ "$?" -eq 0 ]; then + break + fi + sleep 1 + done + kubectl -n {{ .Release.Namespace }} rollout status deployment istio-galley + if [ "$?" -ne 0 ]; then + echo "istio-galley deployment rollout status check failed" + exit 1 + fi + echo "istio-galley deployment ready for configuration validation" +fi +sleep 5 +kubectl apply -f ${pathToResourceYAML} +{{ end }} diff --git a/istio-1.5.0/install/kubernetes/helm/istio/templates/service.yaml b/istio-1.5.0/install/kubernetes/helm/istio/templates/service.yaml new file mode 100644 index 0000000..732cdef --- /dev/null +++ b/istio-1.5.0/install/kubernetes/helm/istio/templates/service.yaml @@ -0,0 +1,60 @@ +{{- if or .Values.global.remotePilotCreateSvcEndpoint .Values.global.createRemoteSvcEndpoints }} +apiVersion: v1 +kind: Service +metadata: + name: istio-pilot + namespace: {{ .Release.Namespace }} +spec: + ports: + - port: 15003 + name: http-old-discovery # mTLS or non-mTLS depending on auth setting + - port: 15005 + name: https-discovery # always mTLS + - port: 15007 + name: http-discovery # always plain-text + - port: 15010 + name: grpc-xds # direct + - port: 15011 + name: https-xds # mTLS or non-mTLS depending on auth setting + - port: 8080 + name: http-legacy-discovery # direct + - port: 15014 + name: http-monitoring + clusterIP: None +{{- end }} +{{- if and .Values.global.remotePolicyAddress .Values.global.createRemoteSvcEndpoints }} +--- +apiVersion: v1 +kind: Service +metadata: + name: istio-policy + namespace: {{ .Release.Namespace }} +spec: + ports: + - name: grpc-mixer + port: 9091 + - name: grpc-mixer-mtls + port: 15004 + - name: http-monitoring + port: 15014 + clusterIP: None +{{- end }} +{{- if and .Values.global.remoteTelemetryAddress .Values.global.createRemoteSvcEndpoints }} +--- +apiVersion: v1 +kind: Service +metadata: + name: istio-telemetry + namespace: {{ .Release.Namespace }} +spec: + ports: + - name: grpc-mixer + port: 9091 + - name: grpc-mixer-mtls + port: 15004 + - name: http-monitoring + port: 15014 + - name: prometheus + port: 42422 + clusterIP: None +{{- end }} diff --git a/istio-1.5.0/install/kubernetes/helm/istio/templates/serviceaccount.yaml b/istio-1.5.0/install/kubernetes/helm/istio/templates/serviceaccount.yaml new file mode 100644 index 0000000..96b74d3 --- /dev/null +++ b/istio-1.5.0/install/kubernetes/helm/istio/templates/serviceaccount.yaml @@ -0,0 +1,11 @@ +apiVersion: v1 +kind: ServiceAccount +metadata: + name: istio-multi + namespace: {{ .Release.Namespace }} +--- +apiVersion: v1 +kind: ServiceAccount +metadata: + name: istio-reader + namespace: {{ .Release.Namespace }} diff --git a/istio-1.5.0/install/kubernetes/helm/istio/templates/sidecar-injector-configmap.yaml b/istio-1.5.0/install/kubernetes/helm/istio/templates/sidecar-injector-configmap.yaml new file mode 100644 index 0000000..5cb25b9 --- /dev/null +++ b/istio-1.5.0/install/kubernetes/helm/istio/templates/sidecar-injector-configmap.yaml @@ -0,0 +1,29 @@ +{{- if not .Values.global.omitSidecarInjectorConfigMap }} +apiVersion: v1 +kind: ConfigMap +metadata: + name: istio-sidecar-injector + namespace: {{ .Release.Namespace }} + labels: + app: {{ template "istio.name" . }} + chart: {{ template "istio.chart" . }} + heritage: {{ .Release.Service }} + release: {{ .Release.Name }} + istio: sidecar-injector +data: + values: |- + {{ .Values | toJson }} + + config: |- + policy: {{ .Values.global.proxy.autoInject }} + alwaysInjectSelector: +{{ toYaml .Values.sidecarInjectorWebhook.alwaysInjectSelector | trim | indent 6 }} + neverInjectSelector: +{{ toYaml .Values.sidecarInjectorWebhook.neverInjectSelector | trim | indent 6 }} + template: |- +{{ .Files.Get "files/injection-template.yaml" | trim | indent 6 }} + injectedAnnotations: + {{- range $key, $val := .Values.sidecarInjectorWebhook.injectedAnnotations }} + "{{ $key }}": "{{ $val }}" + {{- end }} +{{- end }} diff --git a/istio-1.5.0/install/kubernetes/helm/istio/test-values/README.md b/istio-1.5.0/install/kubernetes/helm/istio/test-values/README.md new file mode 100644 index 0000000..8e5ff27 --- /dev/null +++ b/istio-1.5.0/install/kubernetes/helm/istio/test-values/README.md @@ -0,0 +1,7 @@ +# Test Values + +These files are intended to be used to install Istio for E2E tests. + +The rendered files can be generated with `make generate_e2e_yaml`. + +These files will all have `values-e2e.yaml` applied to them *first*, so if there are settings there that should not be included in the test the must be overridden. diff --git a/istio-1.5.0/install/kubernetes/helm/istio/test-values/values-e2e.yaml b/istio-1.5.0/install/kubernetes/helm/istio/test-values/values-e2e.yaml new file mode 100644 index 0000000..b5e00c8 --- /dev/null +++ b/istio-1.5.0/install/kubernetes/helm/istio/test-values/values-e2e.yaml @@ -0,0 +1,101 @@ +# This file overrides values for e2e testing. + +global: + proxy: + concurrency: 0 + resources: + requests: + cpu: 10m + memory: 40Mi + + accessLogFile: "/dev/stdout" + enableCoreDump: true + + disablePolicyChecks: false + outboundTrafficPolicy: + mode: REGISTRY_ONLY + +prometheus: + scrapeInterval: 5s + +gateways: + istio-ingressgateway: + autoscaleMax: 1 + resources: + requests: + cpu: 10m + memory: 40Mi + limits: + cpu: 100m + memory: 128Mi + # Disable the specific nodePort mappings for testing + # These occasionally cause port conflict flakes (#14190) + # Lacking a good way to override just part of a list, this is copied from + # the prod values.yaml with nodePort omitted + ports: + - port: 15020 + targetPort: 15020 + name: status-port + - port: 80 + targetPort: 80 + name: http2 + - port: 443 + name: https + - port: 31400 + name: tcp + - port: 15029 + targetPort: 15029 + name: https-kiali + - port: 15030 + targetPort: 15030 + name: https-prometheus + - port: 15031 + targetPort: 15031 + name: https-grafana + - port: 15032 + targetPort: 15032 + name: https-tracing + - port: 15443 + targetPort: 15443 + name: tls + + istio-egressgateway: + enabled: true + autoscaleMax: 1 + resources: + requests: + cpu: 10m + memory: 40Mi + limits: + cpu: 100m + memory: 128Mi + +mixer: + policy: + enabled: true + replicaCount: 2 + autoscaleEnabled: false + resources: + requests: + cpu: 10m + memory: 100Mi + limits: + cpu: 100m + memory: 100Mi + telemetry: + enabled: true + loadshedding: + mode: disabled + resources: + requests: + cpu: 50m + memory: 100Mi + limits: + cpu: 100m + memory: 100Mi + adapters: + stdio: + enabled: true + +sidecarInjectorWebhook: + rewriteAppHTTPProbe: true diff --git a/istio-1.5.0/install/kubernetes/helm/istio/test-values/values-integ.yaml b/istio-1.5.0/install/kubernetes/helm/istio/test-values/values-integ.yaml new file mode 100644 index 0000000..40cc479 --- /dev/null +++ b/istio-1.5.0/install/kubernetes/helm/istio/test-values/values-integ.yaml @@ -0,0 +1,94 @@ +# This file overrides values for e2e testing. + +global: + proxy: + concurrency: 0 + resources: + requests: + cpu: 10m + memory: 40Mi + + accessLogFile: "/dev/stdout" + +prometheus: + scrapeInterval: 5s + +gateways: + istio-ingressgateway: + autoscaleMax: 1 + resources: + requests: + cpu: 10m + memory: 40Mi + limits: + cpu: 100m + memory: 128Mi + # Disable the specific nodePort mappings for testing + # These occasionally cause port conflict flakes (#14190) + # Lacking a good way to override just part of a list, this is copied from + # the prod values.yaml with nodePort omitted + ports: + - port: 15020 + targetPort: 15020 + name: status-port + - port: 80 + targetPort: 80 + name: http2 + - port: 443 + name: https + - port: 31400 + name: tcp + - port: 15029 + targetPort: 15029 + name: https-kiali + - port: 15030 + targetPort: 15030 + name: https-prometheus + - port: 15031 + targetPort: 15031 + name: https-grafana + - port: 15032 + targetPort: 15032 + name: https-tracing + - port: 15443 + targetPort: 15443 + name: tls + + istio-egressgateway: + enabled: false + autoscaleMax: 1 + resources: + requests: + cpu: 10m + memory: 40Mi + limits: + cpu: 100m + memory: 128Mi + +mixer: + policy: + replicaCount: 2 + autoscaleEnabled: false + resources: + requests: + cpu: 10m + memory: 100Mi + limits: + cpu: 100m + memory: 100Mi + telemetry: + loadshedding: + mode: disabled + resources: + requests: + cpu: 50m + memory: 100Mi + limits: + cpu: 100m + memory: 100Mi + adapters: + stdio: + enabled: true + +sidecarInjectorWebhook: + rewriteAppHTTPProbe: true diff --git a/istio-1.5.0/install/kubernetes/helm/istio/test-values/values-istio-auth-mcp.yaml b/istio-1.5.0/install/kubernetes/helm/istio/test-values/values-istio-auth-mcp.yaml new file mode 100644 index 0000000..fb284d9 --- /dev/null +++ b/istio-1.5.0/install/kubernetes/helm/istio/test-values/values-istio-auth-mcp.yaml @@ -0,0 +1,17 @@ +# This is used to generate istio-auth.yaml with MCP enabled +global: + # controlPlaneSecurityEnabled enabled. Will result in delays starting the pods while secrets are + # propagated, not recommended for tests. + controlPlaneSecurityEnabled: true + + mtls: + # Default setting for service-to-service mtls. Can be set explicitly using + # destination rules or service annotations. + enabled: true + + ## imagePullSecrets for all ServiceAccount. Must be set for any cluster configured with private docker registry. + # imagePullSecrets: + # - name: "private-registry-key" + + useMCP: true + diff --git a/istio-1.5.0/install/kubernetes/helm/istio/test-values/values-istio-auth-multicluster.yaml b/istio-1.5.0/install/kubernetes/helm/istio/test-values/values-istio-auth-multicluster.yaml new file mode 100644 index 0000000..af14798 --- /dev/null +++ b/istio-1.5.0/install/kubernetes/helm/istio/test-values/values-istio-auth-multicluster.yaml @@ -0,0 +1,21 @@ +# This is used to generate istio-auth-multicluster.yaml, used for CI/CD. +global: + # controlPlaneSecurityEnabled enabled. Will result in delays starting the pods while secrets are + # propagated, not recommended for tests. + controlPlaneSecurityEnabled: true + + mtls: + # Default setting for service-to-service mtls. Can be set explicitly using + # destination rules or service annotations. + enabled: true + + proxy: + accessLogFile: "/dev/stdout" + + ## imagePullSecrets for all ServiceAccount. Must be set for any cluster configured with private docker registry. + # imagePullSecrets: + # - name: "private-registry-key" + +# In a multiple cluster environment, citadel uses the same root certificate in all the clusters +security: + selfSigned: false diff --git a/istio-1.5.0/install/kubernetes/helm/istio/test-values/values-istio-auth-non-mcp.yaml b/istio-1.5.0/install/kubernetes/helm/istio/test-values/values-istio-auth-non-mcp.yaml new file mode 100644 index 0000000..eab07cd --- /dev/null +++ b/istio-1.5.0/install/kubernetes/helm/istio/test-values/values-istio-auth-non-mcp.yaml @@ -0,0 +1,7 @@ +global: + mtls: + enabled: true + + controlPlaneSecurityEnabled: true + + useMCP: false diff --git a/istio-1.5.0/install/kubernetes/helm/istio/test-values/values-istio-auth-sds.yaml b/istio-1.5.0/install/kubernetes/helm/istio/test-values/values-istio-auth-sds.yaml new file mode 100644 index 0000000..8438697 --- /dev/null +++ b/istio-1.5.0/install/kubernetes/helm/istio/test-values/values-istio-auth-sds.yaml @@ -0,0 +1,24 @@ +global: + controlPlaneSecurityEnabled: true + + mtls: + # Default setting for service-to-service mtls. Can be set explicitly using + # destination rules or service annotations. + enabled: true + + sds: + enabled: true + udsPath: "unix:/var/run/sds/uds_path" + token: + aud: "istio-ca" + + proxy: + enableCoreDump: true + +nodeagent: + enabled: true + image: node-agent-k8s + env: + CA_PROVIDER: "Citadel" + CA_ADDR: "istio-citadel:8060" + VALID_TOKEN: true diff --git a/istio-1.5.0/install/kubernetes/helm/istio/test-values/values-istio-auth.yaml b/istio-1.5.0/install/kubernetes/helm/istio/test-values/values-istio-auth.yaml new file mode 100644 index 0000000..4ec1d35 --- /dev/null +++ b/istio-1.5.0/install/kubernetes/helm/istio/test-values/values-istio-auth.yaml @@ -0,0 +1,14 @@ +# This is used to generate istio-auth.yaml for automated CI/CD test, using v1/alpha1 +# or v2/alpha3 with 'gradual migration' (using env variable at inject time). +global: + # controlPlaneSecurityEnabled enabled. Will result in delays starting the pods while secrets are + # propagated, not recommended for tests. + controlPlaneSecurityEnabled: true + + mtls: + # Default setting for service-to-service mtls. Can be set explicitly using + # destination rules or service annotations. + enabled: true + ## imagePullSecrets for all ServiceAccount. Must be set for any cluster configured with private docker registry. + # imagePullSecrets: + # - name: "private-registry-key" diff --git a/istio-1.5.0/install/kubernetes/helm/istio/test-values/values-istio-dns-cert.yaml b/istio-1.5.0/install/kubernetes/helm/istio/test-values/values-istio-dns-cert.yaml new file mode 100644 index 0000000..4069703 --- /dev/null +++ b/istio-1.5.0/install/kubernetes/helm/istio/test-values/values-istio-dns-cert.yaml @@ -0,0 +1,7 @@ +global: + certificates: + - dnsNames: [istio-pilot.istio-system.svc, istio-pilot.istio-system] + - secretName: dns.istio-galley-service-account + dnsNames: [istio-galley.istio-system.svc, istio-galley.istio-system] + - secretName: dns.istio-sidecar-injector-service-account + dnsNames: [istio-sidecar-injector.istio-system.svc, istio-sidecar-injector.istio-system] diff --git a/istio-1.5.0/install/kubernetes/helm/istio/test-values/values-istio-mcp.yaml b/istio-1.5.0/install/kubernetes/helm/istio/test-values/values-istio-mcp.yaml new file mode 100644 index 0000000..a6638ee --- /dev/null +++ b/istio-1.5.0/install/kubernetes/helm/istio/test-values/values-istio-mcp.yaml @@ -0,0 +1,18 @@ +# This is used to generate istio.yaml with MCP enabled +global: + # controlPlaneSecurityEnabled enabled. Will result in delays starting the pods while secrets are + # propagated, not recommended for tests. + controlPlaneSecurityEnabled: false + + mtls: + # Default setting for service-to-service mtls. Can be set explicitly using + # destination rules or service annotations. + enabled: false + + ## imagePullSecrets for all ServiceAccount. Must be set for any cluster configured with private docker registry. + # imagePullSecrets: + # - name: "private-registry-key" + + useMCP: true + + diff --git a/istio-1.5.0/install/kubernetes/helm/istio/test-values/values-istio-mesh-networks.yaml b/istio-1.5.0/install/kubernetes/helm/istio/test-values/values-istio-mesh-networks.yaml new file mode 100644 index 0000000..c713b8a --- /dev/null +++ b/istio-1.5.0/install/kubernetes/helm/istio/test-values/values-istio-mesh-networks.yaml @@ -0,0 +1,16 @@ +# overrides to test the meshNetworks. +global: + meshNetworks: + # NOTE: DO NOT CHANGE THIS! Its hardcoded in Pilot in different areas + Kubernetes: + endpoints: + - fromRegistry: Kubernetes + gateways: + - port: 15443 + address: 2.2.2.2 + vm: {} + + #This will cause ISTIO_META_NETWORK to be set on the pods and the + #kube controller code to match endpoints from kubernetes with the default + #cluster ID of "Kubernetes". Need to fix this code + network: "Kubernetes" diff --git a/istio-1.5.0/install/kubernetes/helm/istio/test-values/values-istio-multicluster-split-horizon.yaml b/istio-1.5.0/install/kubernetes/helm/istio/test-values/values-istio-multicluster-split-horizon.yaml new file mode 100644 index 0000000..e664dd5 --- /dev/null +++ b/istio-1.5.0/install/kubernetes/helm/istio/test-values/values-istio-multicluster-split-horizon.yaml @@ -0,0 +1,25 @@ +# This is used to generate istio-multicluster-split-horizon.yaml, used for CI/CD. +global: + controlPlaneSecurityEnabled: true + mtls: + enabled: true + proxy: + accessLogFile: "/dev/stdout" + outboundTrafficPolicy: + mode: ALLOW_ANY + meshExpansion: + enabled: true + meshNetworks: + network2: + endpoints: + - fromRegistry: N2_REGISTRY_TOKEN + gateways: + - address: 0.0.0.0 + port: 443 +security: + selfSigned: false +gateways: + istio-egressgateway: + enabled: false + + diff --git a/istio-1.5.0/install/kubernetes/helm/istio/test-values/values-istio-multicluster.yaml b/istio-1.5.0/install/kubernetes/helm/istio/test-values/values-istio-multicluster.yaml new file mode 100644 index 0000000..59b924a --- /dev/null +++ b/istio-1.5.0/install/kubernetes/helm/istio/test-values/values-istio-multicluster.yaml @@ -0,0 +1,21 @@ +# This is used to generate istio-multicluster.yaml, used for CI/CD. +global: + # controlPlaneSecurityEnabled enabled. Will result in delays starting the pods while secrets are + # propagated, not recommended for tests. + controlPlaneSecurityEnabled: false + + mtls: + # Default setting for service-to-service mtls. Can be set explicitly using + # destination rules or service annotations. + enabled: false + + proxy: + accessLogFile: "/dev/stdout" + + ## imagePullSecrets for all ServiceAccount. Must be set for any cluster configured with private docker registry. + # imagePullSecrets: + # - name: "private-registry-key" + +# In a multiple cluster environment, citadel uses the same root certificate in all the clusters +security: + selfSigned: false diff --git a/istio-1.5.0/install/kubernetes/helm/istio/test-values/values-istio-non-mcp.yaml b/istio-1.5.0/install/kubernetes/helm/istio/test-values/values-istio-non-mcp.yaml new file mode 100644 index 0000000..091681a --- /dev/null +++ b/istio-1.5.0/install/kubernetes/helm/istio/test-values/values-istio-non-mcp.yaml @@ -0,0 +1,2 @@ +global: + useMCP: false diff --git a/istio-1.5.0/install/kubernetes/helm/istio/test-values/values-istio-one-namespace-auth.yaml b/istio-1.5.0/install/kubernetes/helm/istio/test-values/values-istio-one-namespace-auth.yaml new file mode 100644 index 0000000..c49f402 --- /dev/null +++ b/istio-1.5.0/install/kubernetes/helm/istio/test-values/values-istio-one-namespace-auth.yaml @@ -0,0 +1,17 @@ +# This is used to generate istio.yaml used for deprecated CI/CD testing. +global: + # controlPlaneSecurityEnabled enabled. Will result in delays starting the pods while secrets are + # propagated, not recommended for tests. + controlPlaneSecurityEnabled: true + + mtls: + # Default setting for service-to-service mtls. Can be set explicitly using + # destination rules or service annotations. + enabled: true + + ## imagePullSecrets for all ServiceAccount. Must be set for any cluster configured with private docker registry. + # imagePullSecrets: + # - name: "private-registry-key" + + # Restrict the applications in one namespace the controller manages + oneNamespace: true diff --git a/istio-1.5.0/install/kubernetes/helm/istio/test-values/values-istio-one-namespace-trust-domain.yaml b/istio-1.5.0/install/kubernetes/helm/istio/test-values/values-istio-one-namespace-trust-domain.yaml new file mode 100644 index 0000000..1840ab3 --- /dev/null +++ b/istio-1.5.0/install/kubernetes/helm/istio/test-values/values-istio-one-namespace-trust-domain.yaml @@ -0,0 +1,19 @@ +# This is used to generate istio.yaml used for deprecated CI/CD testing. +global: + # controlPlaneSecurityEnabled enabled. Will result in delays starting the pods while secrets are + # propagated, not recommended for tests. + controlPlaneSecurityEnabled: true + + mtls: + # Default setting for service-to-service mtls. Can be set explicitly using + # destination rules or service annotations. + enabled: true + + # Default is 10s second + refreshInterval: 1s + + # The trust domain corresponds to the trust root of a system + trustDomain: test.local + + # Restrict the applications in one namespace the controller manages + oneNamespace: true diff --git a/istio-1.5.0/install/kubernetes/helm/istio/test-values/values-istio-one-namespace.yaml b/istio-1.5.0/install/kubernetes/helm/istio/test-values/values-istio-one-namespace.yaml new file mode 100644 index 0000000..14aa450 --- /dev/null +++ b/istio-1.5.0/install/kubernetes/helm/istio/test-values/values-istio-one-namespace.yaml @@ -0,0 +1,17 @@ +# This is used to generate istio.yaml used for deprecated CI/CD testing. +global: + # controlPlaneSecurityEnabled enabled. Will result in delays starting the pods while secrets are + # propagated, not recommended for tests. + controlPlaneSecurityEnabled: false + + mtls: + # Default setting for service-to-service mtls. Can be set explicitly using + # destination rules or service annotations. + enabled: false + + ## imagePullSecrets for all ServiceAccount. Must be set for any cluster configured with private docker registry. + # imagePullSecrets: + # - name: "private-registry-key" + + # Restrict the applications in one namespace the controller manages + oneNamespace: true diff --git a/istio-1.5.0/install/kubernetes/helm/istio/test-values/values-istio.yaml b/istio-1.5.0/install/kubernetes/helm/istio/test-values/values-istio.yaml new file mode 100644 index 0000000..c115103 --- /dev/null +++ b/istio-1.5.0/install/kubernetes/helm/istio/test-values/values-istio.yaml @@ -0,0 +1,7 @@ + +# This is used to generate istio.yaml for automated CI/CD test, using v1/alpha1 +# or v2/alpha3 with 'gradual migration' (using env variable at inject time). +# global: + ## imagePullSecrets for all ServiceAccount. Must be set for any clustser configured with private docker registry. + # imagePullSecrets: + # - name: "private-registry-key" diff --git a/istio-1.5.0/install/kubernetes/helm/istio/values-istio-demo.yaml b/istio-1.5.0/install/kubernetes/helm/istio/values-istio-demo.yaml new file mode 100644 index 0000000..d28dbaa --- /dev/null +++ b/istio-1.5.0/install/kubernetes/helm/istio/values-istio-demo.yaml @@ -0,0 +1,81 @@ +# This is used to generate istio.yaml for minimal, demo mode. +# It is shipped with the release, used for bookinfo or quick installation of istio. +# Includes components used in the demo, defaults to alpha3 rules. +global: + controlPlaneSecurityEnabled: false + + proxy: + accessLogFile: "/dev/stdout" + resources: + requests: + cpu: 10m + memory: 40Mi + + disablePolicyChecks: false + + mtls: + # Default setting for service-to-service mtls. Can be set explicitly using + # destination rules or service annotations. + enabled: false + +sidecarInjectorWebhook: + enabled: true + # If true, webhook or istioctl injector will rewrite PodSpec for liveness + # health check to redirect request to sidecar. This makes liveness check work + # even when mTLS is enabled. + rewriteAppHTTPProbe: false + +pilot: + autoscaleEnabled: false + traceSampling: 100.0 + resources: + requests: + cpu: 10m + memory: 100Mi + +mixer: + policy: + enabled: true + autoscaleEnabled: false + resources: + requests: + cpu: 10m + memory: 100Mi + + telemetry: + enabled: true + autoscaleEnabled: false + resources: + requests: + cpu: 50m + memory: 100Mi + + adapters: + stdio: + enabled: true + +grafana: + enabled: true + +tracing: + enabled: true + +kiali: + enabled: true + createDemoSecret: true + +gateways: + istio-ingressgateway: + autoscaleEnabled: false + resources: + requests: + cpu: 10m + memory: 40Mi + + istio-egressgateway: + enabled: true + autoscaleEnabled: false + resources: + requests: + cpu: 10m + memory: 40Mi diff --git a/istio-1.5.0/install/kubernetes/helm/istio/values-istio-minimal.yaml b/istio-1.5.0/install/kubernetes/helm/istio/values-istio-minimal.yaml new file mode 100644 index 0000000..18467d1 --- /dev/null +++ b/istio-1.5.0/install/kubernetes/helm/istio/values-istio-minimal.yaml @@ -0,0 +1,49 @@ +# +# Minimal Istio Configuration: https://istio.io/docs/setup/kubernetes/additional-setup/config-profiles/ +# +pilot: + enabled: true + sidecar: false + +gateways: + enabled: false + +security: + enabled: false + +sidecarInjectorWebhook: + enabled: false + +galley: + enabled: false + +mixer: + policy: + enabled: false + telemetry: + enabled: false + +prometheus: + enabled: false + + +# Common settings. +global: + + proxy: + # Sets the destination Statsd in envoy (the value of the "--statsdUdpAddress" proxy argument + # would be :). + # Disabled by default. + # The istio-statsd-prom-bridge is deprecated and should not be used moving forward. + envoyStatsd: + # If enabled is set to true, host and port must also be provided. Istio no longer provides a statsd collector. + enabled: false + host: # example: statsd-svc.istio-system + port: # example: 9125 + + useMCP: false + + mtls: + auto: false + + diff --git a/istio-1.5.0/install/kubernetes/helm/istio/values-istio-remote.yaml b/istio-1.5.0/install/kubernetes/helm/istio/values-istio-remote.yaml new file mode 100644 index 0000000..4ff03c3 --- /dev/null +++ b/istio-1.5.0/install/kubernetes/helm/istio/values-istio-remote.yaml @@ -0,0 +1,36 @@ +gateways: + enabled: false + +galley: + enabled: false + +mixer: + policy: + enabled: false + telemetry: + enabled: false + +pilot: + enabled: false + configSource: + subscribedResources: + +security: + enabled: true + createMeshPolicy: false + +prometheus: + enabled: false + +global: + istioRemote: true + + enableTracing: false + + # Sets an identifier for the remote network to be used for Split Horizon EDS. The network will be sent + # to the Pilot when connected by the sidecar and will affect the results returned in EDS requests. + # Based on the network identifier Pilot will return all local endpoints + endpoints of gateways to + # other networks. + # + # Must match the names in the meshNetworks section in the Istio local. + network: "" diff --git a/istio-1.5.0/install/kubernetes/helm/istio/values-istio-sds-auth-control-plane-auth-disabled.yaml b/istio-1.5.0/install/kubernetes/helm/istio/values-istio-sds-auth-control-plane-auth-disabled.yaml new file mode 100644 index 0000000..6144aff --- /dev/null +++ b/istio-1.5.0/install/kubernetes/helm/istio/values-istio-sds-auth-control-plane-auth-disabled.yaml @@ -0,0 +1,21 @@ +global: + controlPlaneSecurityEnabled: false + + mtls: + # Default setting for service-to-service mtls. Can be set explicitly using + # destination rules or service annotations. + enabled: true + + sds: + enabled: true + udsPath: "unix:/var/run/sds/uds_path" + token: + aud: "istio-ca" + +nodeagent: + enabled: true + image: node-agent-k8s + env: + CA_PROVIDER: "Citadel" + CA_ADDR: "istio-citadel:8060" + VALID_TOKEN: true diff --git a/istio-1.5.0/install/kubernetes/helm/istio/values-istio-sds-auth.yaml b/istio-1.5.0/install/kubernetes/helm/istio/values-istio-sds-auth.yaml new file mode 100644 index 0000000..83085df --- /dev/null +++ b/istio-1.5.0/install/kubernetes/helm/istio/values-istio-sds-auth.yaml @@ -0,0 +1,21 @@ +global: + controlPlaneSecurityEnabled: true + + mtls: + # Default setting for service-to-service mtls. Can be set explicitly using + # destination rules or service annotations. + enabled: true + + sds: + enabled: true + udsPath: "unix:/var/run/sds/uds_path" + token: + aud: "istio-ca" + +nodeagent: + enabled: true + image: node-agent-k8s + env: + CA_PROVIDER: "Citadel" + CA_ADDR: "istio-citadel:8060" + VALID_TOKEN: true diff --git a/istio-1.5.0/install/kubernetes/helm/istio/values.yaml b/istio-1.5.0/install/kubernetes/helm/istio/values.yaml new file mode 100644 index 0000000..cf79725 --- /dev/null +++ b/istio-1.5.0/install/kubernetes/helm/istio/values.yaml @@ -0,0 +1,622 @@ +# Top level istio values file has the following sections. +# +# global: This file is the authoritative and exhaustive source for the global section. +# +# chart sections: Every subdirectory inside the charts/ directory has a top level +# configuration key in this file. This file overrides the values specified +# by the charts/${chartname}/values.yaml. +# Check the chart level values file for exhaustive list of configuration options. + +# +# Gateways Configuration, refer to the charts/gateways/values.yaml +# for detailed configuration +# +gateways: + enabled: true + +# +# sidecar-injector webhook configuration, refer to the +# charts/sidecarInjectorWebhook/values.yaml for detailed configuration +# +sidecarInjectorWebhook: + enabled: true + +# +# galley configuration, refer to charts/galley/values.yaml +# for detailed configuration +# +galley: + enabled: true + +# +# mixer configuration +# +# @see charts/mixer/values.yaml for all values +mixer: + policy: + # if policy is enabled the global.disablePolicyChecks has affect. + enabled: true + + telemetry: + enabled: true +# +# pilot configuration +# +# @see charts/pilot/values.yaml +pilot: + enabled: true + +# +# security configuration +# +security: + enabled: true + +# +# nodeagent configuration +# +nodeagent: + enabled: false + +# +# addon grafana configuration +# +grafana: + enabled: false + +# +# addon prometheus configuration +# +prometheus: + enabled: true + +# +# addon jaeger tracing configuration +# +tracing: + enabled: false + +# +# addon kiali tracing configuration +# +kiali: + enabled: false + +# +# addon certmanager configuration +# +certmanager: + enabled: false + +# +# Istio CNI plugin enabled +# This must be enabled to use the CNI plugin in Istio. The CNI plugin is installed separately. +# If true, the privileged initContainer istio-init is not needed to perform the traffic redirect +# settings for the istio-proxy. +# +istio_cni: + enabled: false + +# addon Istio CoreDNS configuration +# +istiocoredns: + enabled: false + +# Common settings used among istio subcharts. +global: + # Default hub for Istio images. + # Releases are published to docker hub under 'istio' project. + # Dev builds from prow are on gcr.io + hub: docker.io/istio + + # Default tag for Istio images. + tag: 1.5.0 + + # Comma-separated minimum per-scope logging level of messages to output, in the form of :,: + # The control plane has different scopes depending on component, but can configure default log level across all components + # If empty, default scope and level will be used as configured in code + logging: + level: "default:info" + + # monitoring port used by mixer, pilot, galley and sidecar injector + monitoringPort: 15014 + + k8sIngress: + enabled: false + # Gateway used for k8s Ingress resources. By default it is + # using 'istio:ingressgateway' that will be installed by setting + # 'gateways.enabled' and 'gateways.istio-ingressgateway.enabled' + # flags to true. + gatewayName: ingressgateway + # enableHttps will add port 443 on the ingress. + # It REQUIRES that the certificates are installed in the + # expected secrets - enabling this option without certificates + # will result in LDS rejection and the ingress will not work. + enableHttps: false + + proxy: + # use fully qualified image names for alternate path to proxy. + image: proxyv2 + + # cluster domain. Default value is "cluster.local". + clusterDomain: "cluster.local" + + # Resources for the sidecar. + resources: + requests: + cpu: 100m + memory: 128Mi + limits: + cpu: 2000m + memory: 1024Mi + + # Controls number of Proxy worker threads. + # If set to 0, then start worker thread for each CPU thread/core. + concurrency: 2 + + # Configures the access log for each sidecar. + # Options: + # "" - disables access log + # "/dev/stdout" - enables access log + accessLogFile: "" + + # Configure how and what fields are displayed in sidecar access log. Setting to + # empty string will result in default log format + accessLogFormat: "" + + # Configure the access log for sidecar to JSON or TEXT. + accessLogEncoding: TEXT + + # Configure envoy gRPC access log service. + envoyAccessLogService: + enabled: false + host: # example: accesslog-service.istio-system + port: # example: 15000 + tlsSettings: + mode: DISABLE # DISABLE, SIMPLE, MUTUAL, ISTIO_MUTUAL + clientCertificate: # example: /etc/istio/als/cert-chain.pem + privateKey: # example: /etc/istio/als/key.pem + caCertificates: # example: /etc/istio/als/root-cert.pem + sni: # example: als.somedomain + subjectAltNames: [] + # - als.somedomain + tcpKeepalive: + probes: 3 + time: 10s + interval: 10s + + # Log level for proxy, applies to gateways and sidecars. If left empty, "warning" is used. + # Expected values are: trace|debug|info|warning|error|critical|off + logLevel: "" + + # Per Component log level for proxy, applies to gateways and sidecars. If a component level is + # not set, then the global "logLevel" will be used. If left empty, "misc:error" is used. + componentLogLevel: "" + + # Configure the DNS refresh rate for Envoy cluster of type STRICT_DNS + # This must be given it terms of seconds. For example, 300s is valid but 5m is invalid. + dnsRefreshRate: 300s + + # Specifies the path to the outlier event log. + outlierLogPath: # example: /dev/stdout + + # Automatic protocol detection uses a set of heuristics to + # determine whether the connection is using TLS or not (on the + # server side), as well as the application protocol being used + # (e.g., http vs tcp). These heuristics rely on the client sending + # the first bits of data. For server first protocols like MySQL, + # MongoDB, etc., Envoy will timeout on the protocol detection after + # the specified period, defaulting to non mTLS plain TCP + # traffic. Set this field to tweak the period that Envoy will wait + # for the client to send the first bits of data. (MUST BE >=1ms) + protocolDetectionTimeout: 100ms + + #If set to true, istio-proxy container will have privileged securityContext + privileged: false + + # If set, newly injected sidecars will have core dumps enabled. + enableCoreDump: false + + # Image used to enable core dumps. This is only used, when "enableCoreDump" is set to true. + enableCoreDumpImage: ubuntu:xenial + + # Default port for Pilot agent health checks. A value of 0 will disable health checking. + statusPort: 15020 + + # The initial delay for readiness probes in seconds. + readinessInitialDelaySeconds: 1 + + # The period between readiness probes. + readinessPeriodSeconds: 2 + + # The number of successive failed probes before indicating readiness failure. + readinessFailureThreshold: 30 + + # istio egress capture whitelist + # https://istio.io/docs/tasks/traffic-management/egress.html#calling-external-services-directly + # example: includeIPRanges: "172.30.0.0/16,172.20.0.0/16" + # would only capture egress traffic on those two IP Ranges, all other outbound traffic would + # be allowed by the sidecar + includeIPRanges: "*" + excludeIPRanges: "" + excludeOutboundPorts: "" + + # pod internal interfaces + kubevirtInterfaces: "" + + # istio ingress capture whitelist + # examples: + # Redirect no inbound traffic to Envoy: --includeInboundPorts="" + # Redirect all inbound traffic to Envoy: --includeInboundPorts="*" + # Redirect only selected ports: --includeInboundPorts="80,8080" + includeInboundPorts: "*" + excludeInboundPorts: "" + + # This controls the 'policy' in the sidecar injector. + autoInject: enabled + + # Sets the destination Statsd in envoy (the value of the "--statsdUdpAddress" proxy argument + # would be :). + # Disabled by default. + # The istio-statsd-prom-bridge is deprecated and should not be used moving forward. + envoyStatsd: + # If enabled is set to true, host and port must also be provided. Istio no longer provides a statsd collector. + enabled: false + host: # example: statsd-svc.istio-system + port: # example: 9125 + + # Sets the Envoy Metrics Service address, used to push Envoy metrics to an external collector + # via the Metrics Service gRPC API. This contains detailed stats information emitted directly + # by Envoy and should not be confused with the the Istio telemetry. The Envoy stats are also + # available to scrape via the Envoy admin port at either /stats or /stats/prometheus. + # + # See https://www.envoyproxy.io/docs/envoy/latest/api-v2/config/metrics/v2/metrics_service.proto + # for details about Envoy's Metrics Service API. + # + # Disabled by default. + envoyMetricsService: + enabled: false + host: # example: metrics-service.istio-system + port: # example: 15000 + tlsSettings: + mode: DISABLE # DISABLE, SIMPLE, MUTUAL, ISTIO_MUTUAL + clientCertificate: # example: /etc/istio/ms/cert-chain.pem + privateKey: # example: /etc/istio/ms/key.pem + caCertificates: # example: /etc/istio/ms/root-cert.pem + sni: # example: ms.somedomain + subjectAltNames: [] + # - ms.somedomain + tcpKeepalive: + probes: 3 + time: 10s + interval: 10s + + # Specify which tracer to use. One of: zipkin, lightstep, datadog, stackdriver. + # If using stackdriver tracer outside GCP, set env GOOGLE_APPLICATION_CREDENTIALS to the GCP credential file. + tracer: "zipkin" + + proxy_init: + # Base name for the istio-init container, used to configure iptables. + image: proxyv2 + resources: + limits: + cpu: 100m + memory: 50Mi + requests: + cpu: 10m + memory: 10Mi + + # imagePullPolicy is applied to istio control plane components. + # local tests require IfNotPresent, to avoid uploading to dockerhub. + # TODO: Switch to Always as default, and override in the local tests. + imagePullPolicy: IfNotPresent + + # controlPlaneSecurityEnabled enabled. Will result in delays starting the pods while secrets are + # propagated, not recommended for tests. + controlPlaneSecurityEnabled: false + + # disablePolicyChecks disables mixer policy checks. + # if mixer.policy.enabled==true then disablePolicyChecks has affect. + # Will set the value with same name in istio config map - pilot needs to be restarted to take effect. + disablePolicyChecks: true + + # policyCheckFailOpen allows traffic in cases when the mixer policy service cannot be reached. + # Default is false which means the traffic is denied when the client is unable to connect to Mixer. + policyCheckFailOpen: false + + # EnableTracing sets the value with same name in istio config map, requires pilot restart to take effect. + enableTracing: true + + # Configuration for each of the supported tracers + tracer: + # Configuration for envoy to send trace data to LightStep. + # Disabled by default. + # address: the : of the satellite pool + # accessToken: required for sending data to the pool + # secure: specifies whether data should be sent with TLS + # cacertPath: the path to the file containing the cacert to use when verifying TLS. If secure is true, this is + # required. If a value is specified then a secret called "lightstep.cacert" must be created in the destination + # namespace with the key matching the base of the provided cacertPath and the value being the cacert itself. + # + lightstep: + address: "" # example: lightstep-satellite:443 + accessToken: "" # example: abcdefg1234567 + secure: true # example: true|false + cacertPath: "" # example: /etc/lightstep/cacert.pem + zipkin: + # Host:Port for reporting trace data in zipkin format. If not specified, will default to + # zipkin service (port 9411) in the same namespace as the other istio components. + address: "" + datadog: + # Host:Port for submitting traces to the Datadog agent. + address: "$(HOST_IP):8126" + stackdriver: + # enables trace output to stdout. + debug: false + # The global default max number of attributes per span. + maxNumberOfAttributes: 200 + # The global default max number of annotation events per span. + maxNumberOfAnnotations: 200 + # The global default max number of message events per span. + maxNumberOfMessageEvents: 200 + + # Default mtls policy. If true, mtls between services will be enabled by default. + mtls: + # Default setting for service-to-service mtls. Can be set explicitly using + # destination rules or service annotations. + enabled: false + # If set to true, and a given service does not have a corresponding DestinationRule configured, + # or its DestinationRule does not have TLSSettings specified, Istio configures client side + # TLS configuration automatically, based on the server side mTLS authentication policy and the + # availibity of sidecars. + auto: true + + # Lists the secrets you need to use to pull Istio images from a private registry. + imagePullSecrets: [] + # - private-registry-key + + # Specify pod scheduling arch(amd64, ppc64le, s390x) and weight as follows: + # 0 - Never scheduled + # 1 - Least preferred + # 2 - No preference + # 3 - Most preferred + arch: + amd64: 2 + s390x: 2 + ppc64le: 2 + + # Whether to restrict the applications namespace the controller manages; + # If not set, controller watches all namespaces + oneNamespace: false + + # Default node selector to be applied to all deployments so that all pods can be + # constrained to run a particular nodes. Each component can overwrite these default + # values by adding its node selector block in the relevant section below and setting + # the desired values. + defaultNodeSelector: {} + + # Default node tolerations to be applied to all deployments so that all pods can be + # scheduled to a particular nodes with matching taints. Each component can overwrite + # these default values by adding its tolerations block in the relevant section below + # and setting the desired values. + # Configure this field in case that all pods of Istio control plane are expected to + # be scheduled to particular nodes with specified taints. + defaultTolerations: [] + + # Whether to perform server-side validation of configuration. + configValidation: true + + # Custom DNS config for the pod to resolve names of services in other + # clusters. Use this to add additional search domains, and other settings. + # see + # https://kubernetes.io/docs/concepts/services-networking/dns-pod-service/#dns-config + # This does not apply to gateway pods as they typically need a different + # set of DNS settings than the normal application pods (e.g., in + # multicluster scenarios). + # NOTE: If using templates, follow the pattern in the commented example below. + # podDNSSearchNamespaces: + # - global + # - "{{ valueOrDefault .DeploymentMeta.Namespace \"default\" }}.global" + + # If set to true, the pilot and citadel mtls will be exposed on the + # ingress gateway + meshExpansion: + enabled: false + # If set to true, the pilot and citadel mtls and the plaintext pilot ports + # will be exposed on an internal gateway + useILB: false + + multiCluster: + # Set to true to connect two kubernetes clusters via their respective + # ingressgateway services when pods in each cluster cannot directly + # talk to one another. All clusters should be using Istio mTLS and must + # have a shared root CA for this model to work. + enabled: false + + # Should be set to the name of the cluster this installation will run in. This is required for sidecar injection + # to properly label proxies + clusterName: "" + + # A minimal set of requested resources to applied to all deployments so that + # Horizontal Pod Autoscaler will be able to function (if set). + # Each component can overwrite these default values by adding its own resources + # block in the relevant section below and setting the desired resources values. + defaultResources: + requests: + cpu: 10m + # memory: 128Mi + # limits: + # cpu: 100m + # memory: 128Mi + + # enable pod distruption budget for the control plane, which is used to + # ensure Istio control plane components are gradually upgraded or recovered. + defaultPodDisruptionBudget: + enabled: true + # The values aren't mutable due to a current PodDisruptionBudget limitation + # minAvailable: 1 + + # Kubernetes >=v1.11.0 will create two PriorityClass, including system-cluster-critical and + # system-node-critical, it is better to configure this in order to make sure your Istio pods + # will not be killed because of low priority class. + # Refer to https://kubernetes.io/docs/concepts/configuration/pod-priority-preemption/#priorityclass + # for more detail. + priorityClassName: "" + + # Use the Mesh Control Protocol (MCP) for configuring Mixer and + # Pilot. Requires galley (`--set galley.enabled=true`). + useMCP: true + + # The trust domain corresponds to the trust root of a system + # Refer to https://github.com/spiffe/spiffe/blob/master/standards/SPIFFE-ID.md#21-trust-domain + # Indicate the domain used in SPIFFE identity URL + # The default depends on the environment. + # kubernetes: cluster.local + # else: default dns domain + trustDomain: "" + + # The trust domain aliases represent the aliases of trust_domain. + # For example, if we have + # trustDomain: td1 + # trustDomainAliases: [“td2”, "td3"] + # Any service with the identity "td1/ns/foo/sa/a-service-account", "td2/ns/foo/sa/a-service-account", + # or "td3/ns/foo/sa/a-service-account" will be treated the same in the Istio mesh. + trustDomainAliases: [] + + # Mesh ID means Mesh Identifier. It should be unique within the scope where + # meshes will interact with each other, but it is not required to be + # globally/universally unique. For example, if any of the following are true, + # then two meshes must have different Mesh IDs: + # - Meshes will have their telemetry aggregated in one place + # - Meshes will be federated together + # - Policy will be written referencing one mesh from the other + # + # If an administrator expects that any of these conditions may become true in + # the future, they should ensure their meshes have different Mesh IDs + # assigned. + # + # Within a multicluster mesh, each cluster must be (manually or auto) + # configured to have the same Mesh ID value. If an existing cluster 'joins' a + # multicluster mesh, it will need to be migrated to the new mesh ID. Details + # of migration TBD, and it may be a disruptive operation to change the Mesh + # ID post-install. + # + # If the mesh admin does not specify a value, Istio will use the value of the + # mesh's Trust Domain. The best practice is to select a proper Trust Domain + # value. + meshID: "" + + # Set the default behavior of the sidecar for handling outbound traffic from the application: + # ALLOW_ANY - outbound traffic to unknown destinations will be allowed, in case there are no + # services or ServiceEntries for the destination port + # REGISTRY_ONLY - restrict outbound traffic to services defined in the service registry as well + # as those defined through ServiceEntries + # ALLOW_ANY is the default in 1.1. This means each pod will be able to make outbound requests + # to services outside of the mesh without any ServiceEntry. + # REGISTRY_ONLY was the default in 1.0. If this behavior is desired, set the value below to REGISTRY_ONLY. + outboundTrafficPolicy: + mode: ALLOW_ANY + + # The namespace where globally shared configurations should be present. + # DestinationRules that apply to the entire mesh (e.g., enabling mTLS), + # default Sidecar configs, etc. should be added to this namespace. + # configRootNamespace: istio-config + + # set the default set of namespaces to which services, service entries, virtual services, destination + # rules should be exported to. Currently only one value can be provided in this list. This value + # should be one of the following two options: + # * implies these objects are visible to all namespaces, enabling any sidecar to talk to any other sidecar. + # . implies these objects are visible to only to sidecars in the same namespace, or if imported as a Sidecar.egress.host + # defaultConfigVisibilitySettings: + #- '*' + + sds: + # SDS enabled. IF set to true, mTLS certificates for the sidecars will be + # distributed through the SecretDiscoveryService instead of using K8S secrets to mount the certificates. + enabled: false + udsPath: "" + # The JWT token for SDS and the aud field of such JWT. See RFC 7519, section 4.1.3. + # When a CSR is sent from Citadel Agent to the CA (e.g. Citadel), this aud is to make sure the + # JWT is intended for the CA. + token: + aud: istio-ca + + # Configure the mesh networks to be used by the Split Horizon EDS. + # + # The following example defines two networks with different endpoints association methods. + # For `network1` all endpoints that their IP belongs to the provided CIDR range will be + # mapped to network1. The gateway for this network example is specified by its public IP + # address and port. + # The second network, `network2`, in this example is defined differently with all endpoints + # retrieved through the specified Multi-Cluster registry being mapped to network2. The + # gateway is also defined differently with the name of the gateway service on the remote + # cluster. The public IP for the gateway will be determined from that remote service (only + # LoadBalancer gateway service type is currently supported, for a NodePort type gateway service, + # it still need to be configured manually). + # + # meshNetworks: + # network1: + # endpoints: + # - fromCidr: "192.168.0.1/24" + # gateways: + # - address: 1.1.1.1 + # port: 80 + # network2: + # endpoints: + # - fromRegistry: reg1 + # gateways: + # - registryServiceName: istio-ingressgateway.istio-system.svc.cluster.local + # port: 443 + # + meshNetworks: {} + + # Network defines the network this cluster belong to. This name + # corresponds to the networks in the map of mesh networks. + network: "" + + # Specifies the global locality load balancing settings. + # Locality-weighted load balancing allows administrators to control the distribution of traffic to + # endpoints based on the localities of where the traffic originates and where it will terminate. + # Either failover or distribute configuration can be set, but not both. If neither are provided + # failover mode will be used. + # + # localityLbSetting: + # enabled: true + # distribute: + # - from: "us-central1/*" + # to: + # "us-central1/*": 80 + # "us-central2/*": 20 + # + # localityLbSetting: + # enabled: true + # failover: + # - from: us-east + # to: eu-west + # - from: us-west + # to: us-east + localityLbSetting: + enabled: true + + # Specifies whether helm test is enabled or not. + # This field is set to false by default, so 'helm template ...' + # will ignore the helm test yaml files when generating the template + enableHelmTest: false + + # Configures DNS certificates provisioned through Chiron linked into Pilot. + # The DNS names in this file are all hard-coded; please ensure the namespaces + # in dnsNames are consistent with those of your services. + # Example: + # certificates: + # - secretName: dns.istio-galley-service-account + # dnsNames: [istio-galley.istio-system.svc, istio-galley.istio-system] + # - secretName: dns.istio-sidecar-injector-service-account + # dnsNames: [istio-sidecar-injector.istio-system.svc, istio-sidecar-injector.istio-system] + certificates: [] + + # Configure whether Operator manages webhook configurations. The current behavior + # of Galley and Sidecar Injector is that they manage their own webhook configurations. + # When this option is set as true, Istio Operator, instead of webhooks, manages the + # webhook configurations. When this option is set as false, webhooks manage their + # own webhook configurations. + operatorManageWebhooks: false diff --git a/istio-1.5.0/install/kubernetes/istio-demo.yaml b/istio-1.5.0/install/kubernetes/istio-demo.yaml new file mode 100644 index 0000000..5f6c977 --- /dev/null +++ b/istio-1.5.0/install/kubernetes/istio-demo.yaml @@ -0,0 +1,26097 @@ +apiVersion: v1 +kind: Namespace +metadata: + name: istio-system + labels: + istio-injection: disabled +--- +# DO NOT EDIT - Generated by Cue OpenAPI generator based on Istio APIs. +apiVersion: apiextensions.k8s.io/v1beta1 +kind: CustomResourceDefinition +metadata: + annotations: + "helm.sh/resource-policy": keep + labels: + app: istio-citadel + chart: istio + heritage: Tiller + release: istio + name: meshpolicies.authentication.istio.io +spec: + group: authentication.istio.io + names: + categories: + - istio-io + - authentication-istio-io + kind: MeshPolicy + listKind: MeshPolicyList + plural: meshpolicies + singular: meshpolicy + scope: Cluster + subresources: + status: {} + validation: + openAPIV3Schema: + properties: + spec: + description: 'Authentication policy for Istio services. See more details + at: https://istio.io/docs/reference/config/security/istio.authentication.v1alpha1.html' + properties: + originIsOptional: + description: Deprecated. + type: boolean + origins: + description: Deprecated. + items: + properties: + jwt: + description: Jwt params for the method. + properties: + audiences: + items: + format: string + type: string + type: array + issuer: + description: Identifies the issuer that issued the JWT. + format: string + type: string + jwks: + description: JSON Web Key Set of public keys to validate signature + of the JWT. + format: string + type: string + jwks_uri: + format: string + type: string + jwksUri: + format: string + type: string + jwt_headers: + description: JWT is sent in a request header. + items: + format: string + type: string + type: array + jwtHeaders: + description: JWT is sent in a request header. + items: + format: string + type: string + type: array + jwtParams: + description: JWT is sent in a query parameter. + items: + format: string + type: string + type: array + trigger_rules: + items: + properties: + excluded_paths: + description: List of paths to be excluded from the request. + items: + oneOf: + - required: + - exact + - required: + - prefix + - required: + - suffix + - required: + - regex + properties: + exact: + description: exact string match. + format: string + type: string + prefix: + description: prefix-based match. + format: string + type: string + regex: + description: ECMAscript style regex-based match + as defined by [EDCA-262](http://en.cppreference.com/w/cpp/regex/ecmascript). + format: string + type: string + suffix: + description: suffix-based match. + format: string + type: string + type: object + type: array + excludedPaths: + description: List of paths to be excluded from the request. + items: + oneOf: + - required: + - exact + - required: + - prefix + - required: + - suffix + - required: + - regex + properties: + exact: + description: exact string match. + format: string + type: string + prefix: + description: prefix-based match. + format: string + type: string + regex: + description: ECMAscript style regex-based match + as defined by [EDCA-262](http://en.cppreference.com/w/cpp/regex/ecmascript). + format: string + type: string + suffix: + description: suffix-based match. + format: string + type: string + type: object + type: array + included_paths: + description: List of paths that the request must include. + items: + oneOf: + - required: + - exact + - required: + - prefix + - required: + - suffix + - required: + - regex + properties: + exact: + description: exact string match. + format: string + type: string + prefix: + description: prefix-based match. + format: string + type: string + regex: + description: ECMAscript style regex-based match + as defined by [EDCA-262](http://en.cppreference.com/w/cpp/regex/ecmascript). + format: string + type: string + suffix: + description: suffix-based match. + format: string + type: string + type: object + type: array + includedPaths: + description: List of paths that the request must include. + items: + oneOf: + - required: + - exact + - required: + - prefix + - required: + - suffix + - required: + - regex + properties: + exact: + description: exact string match. + format: string + type: string + prefix: + description: prefix-based match. + format: string + type: string + regex: + description: ECMAscript style regex-based match + as defined by [EDCA-262](http://en.cppreference.com/w/cpp/regex/ecmascript). + format: string + type: string + suffix: + description: suffix-based match. + format: string + type: string + type: object + type: array + type: object + type: array + triggerRules: + items: + properties: + excluded_paths: + description: List of paths to be excluded from the request. + items: + oneOf: + - required: + - exact + - required: + - prefix + - required: + - suffix + - required: + - regex + properties: + exact: + description: exact string match. + format: string + type: string + prefix: + description: prefix-based match. + format: string + type: string + regex: + description: ECMAscript style regex-based match + as defined by [EDCA-262](http://en.cppreference.com/w/cpp/regex/ecmascript). + format: string + type: string + suffix: + description: suffix-based match. + format: string + type: string + type: object + type: array + excludedPaths: + description: List of paths to be excluded from the request. + items: + oneOf: + - required: + - exact + - required: + - prefix + - required: + - suffix + - required: + - regex + properties: + exact: + description: exact string match. + format: string + type: string + prefix: + description: prefix-based match. + format: string + type: string + regex: + description: ECMAscript style regex-based match + as defined by [EDCA-262](http://en.cppreference.com/w/cpp/regex/ecmascript). + format: string + type: string + suffix: + description: suffix-based match. + format: string + type: string + type: object + type: array + included_paths: + description: List of paths that the request must include. + items: + oneOf: + - required: + - exact + - required: + - prefix + - required: + - suffix + - required: + - regex + properties: + exact: + description: exact string match. + format: string + type: string + prefix: + description: prefix-based match. + format: string + type: string + regex: + description: ECMAscript style regex-based match + as defined by [EDCA-262](http://en.cppreference.com/w/cpp/regex/ecmascript). + format: string + type: string + suffix: + description: suffix-based match. + format: string + type: string + type: object + type: array + includedPaths: + description: List of paths that the request must include. + items: + oneOf: + - required: + - exact + - required: + - prefix + - required: + - suffix + - required: + - regex + properties: + exact: + description: exact string match. + format: string + type: string + prefix: + description: prefix-based match. + format: string + type: string + regex: + description: ECMAscript style regex-based match + as defined by [EDCA-262](http://en.cppreference.com/w/cpp/regex/ecmascript). + format: string + type: string + suffix: + description: suffix-based match. + format: string + type: string + type: object + type: array + type: object + type: array + type: object + type: object + type: array + peerIsOptional: + description: Deprecated. + type: boolean + peers: + description: List of authentication methods that can be used for peer + authentication. + items: + oneOf: + - required: + - mtls + - properties: + jwt: {} + required: + - jwt + properties: + jwt: + properties: + audiences: + items: + format: string + type: string + type: array + issuer: + description: Identifies the issuer that issued the JWT. + format: string + type: string + jwks: + description: JSON Web Key Set of public keys to validate signature + of the JWT. + format: string + type: string + jwks_uri: + format: string + type: string + jwksUri: + format: string + type: string + jwt_headers: + description: JWT is sent in a request header. + items: + format: string + type: string + type: array + jwtHeaders: + description: JWT is sent in a request header. + items: + format: string + type: string + type: array + jwtParams: + description: JWT is sent in a query parameter. + items: + format: string + type: string + type: array + trigger_rules: + items: + properties: + excluded_paths: + description: List of paths to be excluded from the request. + items: + oneOf: + - required: + - exact + - required: + - prefix + - required: + - suffix + - required: + - regex + properties: + exact: + description: exact string match. + format: string + type: string + prefix: + description: prefix-based match. + format: string + type: string + regex: + description: ECMAscript style regex-based match + as defined by [EDCA-262](http://en.cppreference.com/w/cpp/regex/ecmascript). + format: string + type: string + suffix: + description: suffix-based match. + format: string + type: string + type: object + type: array + excludedPaths: + description: List of paths to be excluded from the request. + items: + oneOf: + - required: + - exact + - required: + - prefix + - required: + - suffix + - required: + - regex + properties: + exact: + description: exact string match. + format: string + type: string + prefix: + description: prefix-based match. + format: string + type: string + regex: + description: ECMAscript style regex-based match + as defined by [EDCA-262](http://en.cppreference.com/w/cpp/regex/ecmascript). + format: string + type: string + suffix: + description: suffix-based match. + format: string + type: string + type: object + type: array + included_paths: + description: List of paths that the request must include. + items: + oneOf: + - required: + - exact + - required: + - prefix + - required: + - suffix + - required: + - regex + properties: + exact: + description: exact string match. + format: string + type: string + prefix: + description: prefix-based match. + format: string + type: string + regex: + description: ECMAscript style regex-based match + as defined by [EDCA-262](http://en.cppreference.com/w/cpp/regex/ecmascript). + format: string + type: string + suffix: + description: suffix-based match. + format: string + type: string + type: object + type: array + includedPaths: + description: List of paths that the request must include. + items: + oneOf: + - required: + - exact + - required: + - prefix + - required: + - suffix + - required: + - regex + properties: + exact: + description: exact string match. + format: string + type: string + prefix: + description: prefix-based match. + format: string + type: string + regex: + description: ECMAscript style regex-based match + as defined by [EDCA-262](http://en.cppreference.com/w/cpp/regex/ecmascript). + format: string + type: string + suffix: + description: suffix-based match. + format: string + type: string + type: object + type: array + type: object + type: array + triggerRules: + items: + properties: + excluded_paths: + description: List of paths to be excluded from the request. + items: + oneOf: + - required: + - exact + - required: + - prefix + - required: + - suffix + - required: + - regex + properties: + exact: + description: exact string match. + format: string + type: string + prefix: + description: prefix-based match. + format: string + type: string + regex: + description: ECMAscript style regex-based match + as defined by [EDCA-262](http://en.cppreference.com/w/cpp/regex/ecmascript). + format: string + type: string + suffix: + description: suffix-based match. + format: string + type: string + type: object + type: array + excludedPaths: + description: List of paths to be excluded from the request. + items: + oneOf: + - required: + - exact + - required: + - prefix + - required: + - suffix + - required: + - regex + properties: + exact: + description: exact string match. + format: string + type: string + prefix: + description: prefix-based match. + format: string + type: string + regex: + description: ECMAscript style regex-based match + as defined by [EDCA-262](http://en.cppreference.com/w/cpp/regex/ecmascript). + format: string + type: string + suffix: + description: suffix-based match. + format: string + type: string + type: object + type: array + included_paths: + description: List of paths that the request must include. + items: + oneOf: + - required: + - exact + - required: + - prefix + - required: + - suffix + - required: + - regex + properties: + exact: + description: exact string match. + format: string + type: string + prefix: + description: prefix-based match. + format: string + type: string + regex: + description: ECMAscript style regex-based match + as defined by [EDCA-262](http://en.cppreference.com/w/cpp/regex/ecmascript). + format: string + type: string + suffix: + description: suffix-based match. + format: string + type: string + type: object + type: array + includedPaths: + description: List of paths that the request must include. + items: + oneOf: + - required: + - exact + - required: + - prefix + - required: + - suffix + - required: + - regex + properties: + exact: + description: exact string match. + format: string + type: string + prefix: + description: prefix-based match. + format: string + type: string + regex: + description: ECMAscript style regex-based match + as defined by [EDCA-262](http://en.cppreference.com/w/cpp/regex/ecmascript). + format: string + type: string + suffix: + description: suffix-based match. + format: string + type: string + type: object + type: array + type: object + type: array + type: object + mtls: + description: Set if mTLS is used. + properties: + allowTls: + description: Deprecated. + type: boolean + mode: + description: Defines the mode of mTLS authentication. + enum: + - STRICT + - PERMISSIVE + type: string + type: object + type: object + type: array + principalBinding: + description: Deprecated. + enum: + - USE_PEER + - USE_ORIGIN + type: string + targets: + description: Deprecated. + items: + properties: + name: + description: The name must be a short name from the service registry. + format: string + type: string + ports: + description: Specifies the ports. + items: + oneOf: + - required: + - number + - required: + - name + properties: + name: + format: string + type: string + number: + type: integer + type: object + type: array + type: object + type: array + type: object + type: object + versions: + - name: v1alpha1 + served: true + storage: true + +--- +apiVersion: apiextensions.k8s.io/v1beta1 +kind: CustomResourceDefinition +metadata: + annotations: + "helm.sh/resource-policy": keep + labels: + app: istio-citadel + chart: istio + heritage: Tiller + release: istio + name: policies.authentication.istio.io +spec: + group: authentication.istio.io + names: + categories: + - istio-io + - authentication-istio-io + kind: Policy + listKind: PolicyList + plural: policies + singular: policy + scope: Namespaced + subresources: + status: {} + validation: + openAPIV3Schema: + properties: + spec: + description: 'Authentication policy for Istio services. See more details + at: https://istio.io/docs/reference/config/security/istio.authentication.v1alpha1.html' + properties: + originIsOptional: + description: Deprecated. + type: boolean + origins: + description: Deprecated. + items: + properties: + jwt: + description: Jwt params for the method. + properties: + audiences: + items: + format: string + type: string + type: array + issuer: + description: Identifies the issuer that issued the JWT. + format: string + type: string + jwks: + description: JSON Web Key Set of public keys to validate signature + of the JWT. + format: string + type: string + jwks_uri: + format: string + type: string + jwksUri: + format: string + type: string + jwt_headers: + description: JWT is sent in a request header. + items: + format: string + type: string + type: array + jwtHeaders: + description: JWT is sent in a request header. + items: + format: string + type: string + type: array + jwtParams: + description: JWT is sent in a query parameter. + items: + format: string + type: string + type: array + trigger_rules: + items: + properties: + excluded_paths: + description: List of paths to be excluded from the request. + items: + oneOf: + - required: + - exact + - required: + - prefix + - required: + - suffix + - required: + - regex + properties: + exact: + description: exact string match. + format: string + type: string + prefix: + description: prefix-based match. + format: string + type: string + regex: + description: ECMAscript style regex-based match + as defined by [EDCA-262](http://en.cppreference.com/w/cpp/regex/ecmascript). + format: string + type: string + suffix: + description: suffix-based match. + format: string + type: string + type: object + type: array + excludedPaths: + description: List of paths to be excluded from the request. + items: + oneOf: + - required: + - exact + - required: + - prefix + - required: + - suffix + - required: + - regex + properties: + exact: + description: exact string match. + format: string + type: string + prefix: + description: prefix-based match. + format: string + type: string + regex: + description: ECMAscript style regex-based match + as defined by [EDCA-262](http://en.cppreference.com/w/cpp/regex/ecmascript). + format: string + type: string + suffix: + description: suffix-based match. + format: string + type: string + type: object + type: array + included_paths: + description: List of paths that the request must include. + items: + oneOf: + - required: + - exact + - required: + - prefix + - required: + - suffix + - required: + - regex + properties: + exact: + description: exact string match. + format: string + type: string + prefix: + description: prefix-based match. + format: string + type: string + regex: + description: ECMAscript style regex-based match + as defined by [EDCA-262](http://en.cppreference.com/w/cpp/regex/ecmascript). + format: string + type: string + suffix: + description: suffix-based match. + format: string + type: string + type: object + type: array + includedPaths: + description: List of paths that the request must include. + items: + oneOf: + - required: + - exact + - required: + - prefix + - required: + - suffix + - required: + - regex + properties: + exact: + description: exact string match. + format: string + type: string + prefix: + description: prefix-based match. + format: string + type: string + regex: + description: ECMAscript style regex-based match + as defined by [EDCA-262](http://en.cppreference.com/w/cpp/regex/ecmascript). + format: string + type: string + suffix: + description: suffix-based match. + format: string + type: string + type: object + type: array + type: object + type: array + triggerRules: + items: + properties: + excluded_paths: + description: List of paths to be excluded from the request. + items: + oneOf: + - required: + - exact + - required: + - prefix + - required: + - suffix + - required: + - regex + properties: + exact: + description: exact string match. + format: string + type: string + prefix: + description: prefix-based match. + format: string + type: string + regex: + description: ECMAscript style regex-based match + as defined by [EDCA-262](http://en.cppreference.com/w/cpp/regex/ecmascript). + format: string + type: string + suffix: + description: suffix-based match. + format: string + type: string + type: object + type: array + excludedPaths: + description: List of paths to be excluded from the request. + items: + oneOf: + - required: + - exact + - required: + - prefix + - required: + - suffix + - required: + - regex + properties: + exact: + description: exact string match. + format: string + type: string + prefix: + description: prefix-based match. + format: string + type: string + regex: + description: ECMAscript style regex-based match + as defined by [EDCA-262](http://en.cppreference.com/w/cpp/regex/ecmascript). + format: string + type: string + suffix: + description: suffix-based match. + format: string + type: string + type: object + type: array + included_paths: + description: List of paths that the request must include. + items: + oneOf: + - required: + - exact + - required: + - prefix + - required: + - suffix + - required: + - regex + properties: + exact: + description: exact string match. + format: string + type: string + prefix: + description: prefix-based match. + format: string + type: string + regex: + description: ECMAscript style regex-based match + as defined by [EDCA-262](http://en.cppreference.com/w/cpp/regex/ecmascript). + format: string + type: string + suffix: + description: suffix-based match. + format: string + type: string + type: object + type: array + includedPaths: + description: List of paths that the request must include. + items: + oneOf: + - required: + - exact + - required: + - prefix + - required: + - suffix + - required: + - regex + properties: + exact: + description: exact string match. + format: string + type: string + prefix: + description: prefix-based match. + format: string + type: string + regex: + description: ECMAscript style regex-based match + as defined by [EDCA-262](http://en.cppreference.com/w/cpp/regex/ecmascript). + format: string + type: string + suffix: + description: suffix-based match. + format: string + type: string + type: object + type: array + type: object + type: array + type: object + type: object + type: array + peerIsOptional: + description: Deprecated. + type: boolean + peers: + description: List of authentication methods that can be used for peer + authentication. + items: + oneOf: + - required: + - mtls + - properties: + jwt: {} + required: + - jwt + properties: + jwt: + properties: + audiences: + items: + format: string + type: string + type: array + issuer: + description: Identifies the issuer that issued the JWT. + format: string + type: string + jwks: + description: JSON Web Key Set of public keys to validate signature + of the JWT. + format: string + type: string + jwks_uri: + format: string + type: string + jwksUri: + format: string + type: string + jwt_headers: + description: JWT is sent in a request header. + items: + format: string + type: string + type: array + jwtHeaders: + description: JWT is sent in a request header. + items: + format: string + type: string + type: array + jwtParams: + description: JWT is sent in a query parameter. + items: + format: string + type: string + type: array + trigger_rules: + items: + properties: + excluded_paths: + description: List of paths to be excluded from the request. + items: + oneOf: + - required: + - exact + - required: + - prefix + - required: + - suffix + - required: + - regex + properties: + exact: + description: exact string match. + format: string + type: string + prefix: + description: prefix-based match. + format: string + type: string + regex: + description: ECMAscript style regex-based match + as defined by [EDCA-262](http://en.cppreference.com/w/cpp/regex/ecmascript). + format: string + type: string + suffix: + description: suffix-based match. + format: string + type: string + type: object + type: array + excludedPaths: + description: List of paths to be excluded from the request. + items: + oneOf: + - required: + - exact + - required: + - prefix + - required: + - suffix + - required: + - regex + properties: + exact: + description: exact string match. + format: string + type: string + prefix: + description: prefix-based match. + format: string + type: string + regex: + description: ECMAscript style regex-based match + as defined by [EDCA-262](http://en.cppreference.com/w/cpp/regex/ecmascript). + format: string + type: string + suffix: + description: suffix-based match. + format: string + type: string + type: object + type: array + included_paths: + description: List of paths that the request must include. + items: + oneOf: + - required: + - exact + - required: + - prefix + - required: + - suffix + - required: + - regex + properties: + exact: + description: exact string match. + format: string + type: string + prefix: + description: prefix-based match. + format: string + type: string + regex: + description: ECMAscript style regex-based match + as defined by [EDCA-262](http://en.cppreference.com/w/cpp/regex/ecmascript). + format: string + type: string + suffix: + description: suffix-based match. + format: string + type: string + type: object + type: array + includedPaths: + description: List of paths that the request must include. + items: + oneOf: + - required: + - exact + - required: + - prefix + - required: + - suffix + - required: + - regex + properties: + exact: + description: exact string match. + format: string + type: string + prefix: + description: prefix-based match. + format: string + type: string + regex: + description: ECMAscript style regex-based match + as defined by [EDCA-262](http://en.cppreference.com/w/cpp/regex/ecmascript). + format: string + type: string + suffix: + description: suffix-based match. + format: string + type: string + type: object + type: array + type: object + type: array + triggerRules: + items: + properties: + excluded_paths: + description: List of paths to be excluded from the request. + items: + oneOf: + - required: + - exact + - required: + - prefix + - required: + - suffix + - required: + - regex + properties: + exact: + description: exact string match. + format: string + type: string + prefix: + description: prefix-based match. + format: string + type: string + regex: + description: ECMAscript style regex-based match + as defined by [EDCA-262](http://en.cppreference.com/w/cpp/regex/ecmascript). + format: string + type: string + suffix: + description: suffix-based match. + format: string + type: string + type: object + type: array + excludedPaths: + description: List of paths to be excluded from the request. + items: + oneOf: + - required: + - exact + - required: + - prefix + - required: + - suffix + - required: + - regex + properties: + exact: + description: exact string match. + format: string + type: string + prefix: + description: prefix-based match. + format: string + type: string + regex: + description: ECMAscript style regex-based match + as defined by [EDCA-262](http://en.cppreference.com/w/cpp/regex/ecmascript). + format: string + type: string + suffix: + description: suffix-based match. + format: string + type: string + type: object + type: array + included_paths: + description: List of paths that the request must include. + items: + oneOf: + - required: + - exact + - required: + - prefix + - required: + - suffix + - required: + - regex + properties: + exact: + description: exact string match. + format: string + type: string + prefix: + description: prefix-based match. + format: string + type: string + regex: + description: ECMAscript style regex-based match + as defined by [EDCA-262](http://en.cppreference.com/w/cpp/regex/ecmascript). + format: string + type: string + suffix: + description: suffix-based match. + format: string + type: string + type: object + type: array + includedPaths: + description: List of paths that the request must include. + items: + oneOf: + - required: + - exact + - required: + - prefix + - required: + - suffix + - required: + - regex + properties: + exact: + description: exact string match. + format: string + type: string + prefix: + description: prefix-based match. + format: string + type: string + regex: + description: ECMAscript style regex-based match + as defined by [EDCA-262](http://en.cppreference.com/w/cpp/regex/ecmascript). + format: string + type: string + suffix: + description: suffix-based match. + format: string + type: string + type: object + type: array + type: object + type: array + type: object + mtls: + description: Set if mTLS is used. + properties: + allowTls: + description: Deprecated. + type: boolean + mode: + description: Defines the mode of mTLS authentication. + enum: + - STRICT + - PERMISSIVE + type: string + type: object + type: object + type: array + principalBinding: + description: Deprecated. + enum: + - USE_PEER + - USE_ORIGIN + type: string + targets: + description: Deprecated. + items: + properties: + name: + description: The name must be a short name from the service registry. + format: string + type: string + ports: + description: Specifies the ports. + items: + oneOf: + - required: + - number + - required: + - name + properties: + name: + format: string + type: string + number: + type: integer + type: object + type: array + type: object + type: array + type: object + type: object + versions: + - name: v1alpha1 + served: true + storage: true + +--- +apiVersion: apiextensions.k8s.io/v1beta1 +kind: CustomResourceDefinition +metadata: + annotations: + "helm.sh/resource-policy": keep + labels: + app: istio-mixer + chart: istio + heritage: Tiller + release: istio + name: httpapispecs.config.istio.io +spec: + group: config.istio.io + names: + categories: + - istio-io + - apim-istio-io + kind: HTTPAPISpec + listKind: HTTPAPISpecList + plural: httpapispecs + singular: httpapispec + scope: Namespaced + subresources: + status: {} + validation: + openAPIV3Schema: + properties: + spec: + properties: + api_keys: + items: + oneOf: + - required: + - query + - required: + - header + - required: + - cookie + properties: + cookie: + format: string + type: string + header: + description: API key is sent in a request header. + format: string + type: string + query: + description: API Key is sent as a query parameter. + format: string + type: string + type: object + type: array + apiKeys: + items: + oneOf: + - required: + - query + - required: + - header + - required: + - cookie + properties: + cookie: + format: string + type: string + header: + description: API key is sent in a request header. + format: string + type: string + query: + description: API Key is sent as a query parameter. + format: string + type: string + type: object + type: array + attributes: + properties: + attributes: + additionalProperties: + oneOf: + - required: + - stringValue + - required: + - int64Value + - required: + - doubleValue + - required: + - boolValue + - required: + - bytesValue + - required: + - timestampValue + - required: + - durationValue + - required: + - stringMapValue + properties: + boolValue: + type: boolean + bytesValue: + format: binary + type: string + doubleValue: + format: double + type: number + durationValue: + type: string + int64Value: + format: int64 + type: integer + stringMapValue: + properties: + entries: + additionalProperties: + format: string + type: string + description: Holds a set of name/value pairs. + type: object + type: object + stringValue: + format: string + type: string + timestampValue: + format: dateTime + type: string + type: object + description: A map of attribute name to its value. + type: object + type: object + patterns: + description: List of HTTP patterns to match. + items: + oneOf: + - required: + - uriTemplate + - required: + - regex + properties: + attributes: + properties: + attributes: + additionalProperties: + oneOf: + - required: + - stringValue + - required: + - int64Value + - required: + - doubleValue + - required: + - boolValue + - required: + - bytesValue + - required: + - timestampValue + - required: + - durationValue + - required: + - stringMapValue + properties: + boolValue: + type: boolean + bytesValue: + format: binary + type: string + doubleValue: + format: double + type: number + durationValue: + type: string + int64Value: + format: int64 + type: integer + stringMapValue: + properties: + entries: + additionalProperties: + format: string + type: string + description: Holds a set of name/value pairs. + type: object + type: object + stringValue: + format: string + type: string + timestampValue: + format: dateTime + type: string + type: object + description: A map of attribute name to its value. + type: object + type: object + httpMethod: + format: string + type: string + regex: + format: string + type: string + uriTemplate: + format: string + type: string + type: object + type: array + type: object + type: object + versions: + - name: v1alpha2 + served: true + storage: true + +--- +apiVersion: apiextensions.k8s.io/v1beta1 +kind: CustomResourceDefinition +metadata: + annotations: + "helm.sh/resource-policy": keep + labels: + app: istio-mixer + chart: istio + heritage: Tiller + release: istio + name: httpapispecbindings.config.istio.io +spec: + group: config.istio.io + names: + categories: + - istio-io + - apim-istio-io + kind: HTTPAPISpecBinding + listKind: HTTPAPISpecBindingList + plural: httpapispecbindings + singular: httpapispecbinding + scope: Namespaced + subresources: + status: {} + validation: + openAPIV3Schema: + properties: + spec: + properties: + api_specs: + items: + properties: + name: + description: The short name of the HTTPAPISpec. + format: string + type: string + namespace: + description: Optional namespace of the HTTPAPISpec. + format: string + type: string + type: object + type: array + apiSpecs: + items: + properties: + name: + description: The short name of the HTTPAPISpec. + format: string + type: string + namespace: + description: Optional namespace of the HTTPAPISpec. + format: string + type: string + type: object + type: array + services: + description: One or more services to map the listed HTTPAPISpec onto. + items: + properties: + domain: + description: Domain suffix used to construct the service FQDN + in implementations that support such specification. + format: string + type: string + labels: + additionalProperties: + format: string + type: string + description: Optional one or more labels that uniquely identify + the service version. + type: object + name: + description: The short name of the service such as "foo". + format: string + type: string + namespace: + description: Optional namespace of the service. + format: string + type: string + service: + description: The service FQDN. + format: string + type: string + type: object + type: array + type: object + type: object + versions: + - name: v1alpha2 + served: true + storage: true + +--- +apiVersion: apiextensions.k8s.io/v1beta1 +kind: CustomResourceDefinition +metadata: + annotations: + "helm.sh/resource-policy": keep + labels: + app: istio-mixer + chart: istio + heritage: Tiller + release: istio + name: quotaspecs.config.istio.io +spec: + group: config.istio.io + names: + categories: + - istio-io + - apim-istio-io + kind: QuotaSpec + listKind: QuotaSpecList + plural: quotaspecs + singular: quotaspec + scope: Namespaced + subresources: + status: {} + validation: + openAPIV3Schema: + properties: + spec: + description: Determines the quotas used for individual requests. + properties: + rules: + description: A list of Quota rules. + items: + properties: + match: + description: If empty, match all request. + items: + properties: + clause: + additionalProperties: + oneOf: + - required: + - exact + - required: + - prefix + - required: + - regex + properties: + exact: + format: string + type: string + prefix: + format: string + type: string + regex: + format: string + type: string + type: object + description: Map of attribute names to StringMatch type. + type: object + type: object + type: array + quotas: + description: The list of quotas to charge. + items: + properties: + charge: + format: int32 + type: integer + quota: + format: string + type: string + type: object + type: array + type: object + type: array + type: object + type: object + versions: + - name: v1alpha2 + served: true + storage: true + +--- +apiVersion: apiextensions.k8s.io/v1beta1 +kind: CustomResourceDefinition +metadata: + annotations: + "helm.sh/resource-policy": keep + labels: + app: istio-mixer + chart: istio + heritage: Tiller + release: istio + name: quotaspecbindings.config.istio.io +spec: + group: config.istio.io + names: + categories: + - istio-io + - apim-istio-io + kind: QuotaSpecBinding + listKind: QuotaSpecBindingList + plural: quotaspecbindings + singular: quotaspecbinding + scope: Namespaced + subresources: + status: {} + validation: + openAPIV3Schema: + properties: + spec: + properties: + quotaSpecs: + items: + properties: + name: + description: The short name of the QuotaSpec. + format: string + type: string + namespace: + description: Optional namespace of the QuotaSpec. + format: string + type: string + type: object + type: array + services: + description: One or more services to map the listed QuotaSpec onto. + items: + properties: + domain: + description: Domain suffix used to construct the service FQDN + in implementations that support such specification. + format: string + type: string + labels: + additionalProperties: + format: string + type: string + description: Optional one or more labels that uniquely identify + the service version. + type: object + name: + description: The short name of the service such as "foo". + format: string + type: string + namespace: + description: Optional namespace of the service. + format: string + type: string + service: + description: The service FQDN. + format: string + type: string + type: object + type: array + type: object + type: object + versions: + - name: v1alpha2 + served: true + storage: true + +--- +apiVersion: apiextensions.k8s.io/v1beta1 +kind: CustomResourceDefinition +metadata: + annotations: + "helm.sh/resource-policy": keep + labels: + app: istio-pilot + chart: istio + heritage: Tiller + release: istio + name: destinationrules.networking.istio.io +spec: + additionalPrinterColumns: + - JSONPath: .spec.host + description: The name of a service from the service registry + name: Host + type: string + - JSONPath: .metadata.creationTimestamp + description: 'CreationTimestamp is a timestamp representing the server time when + this object was created. It is not guaranteed to be set in happens-before order + across separate operations. Clients may not set this value. It is represented + in RFC3339 form and is in UTC. Populated by the system. Read-only. Null for + lists. More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#metadata' + name: Age + type: date + group: networking.istio.io + names: + categories: + - istio-io + - networking-istio-io + kind: DestinationRule + listKind: DestinationRuleList + plural: destinationrules + shortNames: + - dr + singular: destinationrule + scope: Namespaced + subresources: + status: {} + validation: + openAPIV3Schema: + properties: + spec: + description: 'Configuration affecting load balancing, outlier detection, + etc. See more details at: https://istio.io/docs/reference/config/networking/destination-rule.html' + properties: + exportTo: + description: A list of namespaces to which this destination rule is + exported. + items: + format: string + type: string + type: array + host: + description: The name of a service from the service registry. + format: string + type: string + subsets: + items: + properties: + labels: + additionalProperties: + format: string + type: string + type: object + name: + description: Name of the subset. + format: string + type: string + trafficPolicy: + description: Traffic policies that apply to this subset. + properties: + connectionPool: + properties: + http: + description: HTTP connection pool settings. + properties: + h2UpgradePolicy: + description: Specify if http1.1 connection should + be upgraded to http2 for the associated destination. + enum: + - DEFAULT + - DO_NOT_UPGRADE + - UPGRADE + type: string + http1MaxPendingRequests: + description: Maximum number of pending HTTP requests + to a destination. + format: int32 + type: integer + http2MaxRequests: + description: Maximum number of requests to a backend. + format: int32 + type: integer + idleTimeout: + description: The idle timeout for upstream connection + pool connections. + type: string + maxRequestsPerConnection: + description: Maximum number of requests per connection + to a backend. + format: int32 + type: integer + maxRetries: + format: int32 + type: integer + type: object + tcp: + description: Settings common to both HTTP and TCP upstream + connections. + properties: + connectTimeout: + description: TCP connection timeout. + type: string + maxConnections: + description: Maximum number of HTTP1 /TCP connections + to a destination host. + format: int32 + type: integer + tcpKeepalive: + description: If set then set SO_KEEPALIVE on the socket + to enable TCP Keepalives. + properties: + interval: + description: The time duration between keep-alive + probes. + type: string + probes: + type: integer + time: + type: string + type: object + type: object + type: object + loadBalancer: + description: Settings controlling the load balancer algorithms. + oneOf: + - required: + - simple + - properties: + consistentHash: + oneOf: + - required: + - httpHeaderName + - required: + - httpCookie + - required: + - useSourceIp + required: + - consistentHash + properties: + consistentHash: + properties: + httpCookie: + description: Hash based on HTTP cookie. + properties: + name: + description: Name of the cookie. + format: string + type: string + path: + description: Path to set for the cookie. + format: string + type: string + ttl: + description: Lifetime of the cookie. + type: string + type: object + httpHeaderName: + description: Hash based on a specific HTTP header. + format: string + type: string + minimumRingSize: + type: integer + useSourceIp: + description: Hash based on the source IP address. + type: boolean + type: object + localityLbSetting: + properties: + distribute: + description: 'Optional: only one of distribute or + failover can be set.' + items: + properties: + from: + description: Originating locality, '/' separated, + e.g. + format: string + type: string + to: + additionalProperties: + type: integer + description: Map of upstream localities to traffic + distribution weights. + type: object + type: object + type: array + enabled: + description: enable locality load balancing, this + is DestinationRule-level and will override mesh + wide settings in entirety. + type: boolean + failover: + description: 'Optional: only failover or distribute + can be set.' + items: + properties: + from: + description: Originating region. + format: string + type: string + to: + format: string + type: string + type: object + type: array + type: object + simple: + enum: + - ROUND_ROBIN + - LEAST_CONN + - RANDOM + - PASSTHROUGH + type: string + type: object + outlierDetection: + properties: + baseEjectionTime: + description: Minimum ejection duration. + type: string + consecutive5xxErrors: + description: Number of 5xx errors before a host is ejected + from the connection pool. + type: integer + consecutiveErrors: + format: int32 + type: integer + consecutiveGatewayErrors: + description: Number of gateway errors before a host is + ejected from the connection pool. + type: integer + interval: + description: Time interval between ejection sweep analysis. + type: string + maxEjectionPercent: + format: int32 + type: integer + minHealthPercent: + format: int32 + type: integer + type: object + portLevelSettings: + description: Traffic policies specific to individual ports. + items: + properties: + connectionPool: + properties: + http: + description: HTTP connection pool settings. + properties: + h2UpgradePolicy: + description: Specify if http1.1 connection should + be upgraded to http2 for the associated destination. + enum: + - DEFAULT + - DO_NOT_UPGRADE + - UPGRADE + type: string + http1MaxPendingRequests: + description: Maximum number of pending HTTP + requests to a destination. + format: int32 + type: integer + http2MaxRequests: + description: Maximum number of requests to a + backend. + format: int32 + type: integer + idleTimeout: + description: The idle timeout for upstream connection + pool connections. + type: string + maxRequestsPerConnection: + description: Maximum number of requests per + connection to a backend. + format: int32 + type: integer + maxRetries: + format: int32 + type: integer + type: object + tcp: + description: Settings common to both HTTP and TCP + upstream connections. + properties: + connectTimeout: + description: TCP connection timeout. + type: string + maxConnections: + description: Maximum number of HTTP1 /TCP connections + to a destination host. + format: int32 + type: integer + tcpKeepalive: + description: If set then set SO_KEEPALIVE on + the socket to enable TCP Keepalives. + properties: + interval: + description: The time duration between keep-alive + probes. + type: string + probes: + type: integer + time: + type: string + type: object + type: object + type: object + loadBalancer: + description: Settings controlling the load balancer + algorithms. + oneOf: + - required: + - simple + - properties: + consistentHash: + oneOf: + - required: + - httpHeaderName + - required: + - httpCookie + - required: + - useSourceIp + required: + - consistentHash + properties: + consistentHash: + properties: + httpCookie: + description: Hash based on HTTP cookie. + properties: + name: + description: Name of the cookie. + format: string + type: string + path: + description: Path to set for the cookie. + format: string + type: string + ttl: + description: Lifetime of the cookie. + type: string + type: object + httpHeaderName: + description: Hash based on a specific HTTP header. + format: string + type: string + minimumRingSize: + type: integer + useSourceIp: + description: Hash based on the source IP address. + type: boolean + type: object + localityLbSetting: + properties: + distribute: + description: 'Optional: only one of distribute + or failover can be set.' + items: + properties: + from: + description: Originating locality, '/' + separated, e.g. + format: string + type: string + to: + additionalProperties: + type: integer + description: Map of upstream localities + to traffic distribution weights. + type: object + type: object + type: array + enabled: + description: enable locality load balancing, + this is DestinationRule-level and will override + mesh wide settings in entirety. + type: boolean + failover: + description: 'Optional: only failover or distribute + can be set.' + items: + properties: + from: + description: Originating region. + format: string + type: string + to: + format: string + type: string + type: object + type: array + type: object + simple: + enum: + - ROUND_ROBIN + - LEAST_CONN + - RANDOM + - PASSTHROUGH + type: string + type: object + outlierDetection: + properties: + baseEjectionTime: + description: Minimum ejection duration. + type: string + consecutive5xxErrors: + description: Number of 5xx errors before a host + is ejected from the connection pool. + type: integer + consecutiveErrors: + format: int32 + type: integer + consecutiveGatewayErrors: + description: Number of gateway errors before a host + is ejected from the connection pool. + type: integer + interval: + description: Time interval between ejection sweep + analysis. + type: string + maxEjectionPercent: + format: int32 + type: integer + minHealthPercent: + format: int32 + type: integer + type: object + port: + properties: + number: + type: integer + type: object + tls: + description: TLS related settings for connections to + the upstream service. + properties: + caCertificates: + format: string + type: string + clientCertificate: + description: REQUIRED if mode is `MUTUAL`. + format: string + type: string + mode: + enum: + - DISABLE + - SIMPLE + - MUTUAL + - ISTIO_MUTUAL + type: string + privateKey: + description: REQUIRED if mode is `MUTUAL`. + format: string + type: string + sni: + description: SNI string to present to the server + during TLS handshake. + format: string + type: string + subjectAltNames: + items: + format: string + type: string + type: array + type: object + type: object + type: array + tls: + description: TLS related settings for connections to the upstream + service. + properties: + caCertificates: + format: string + type: string + clientCertificate: + description: REQUIRED if mode is `MUTUAL`. + format: string + type: string + mode: + enum: + - DISABLE + - SIMPLE + - MUTUAL + - ISTIO_MUTUAL + type: string + privateKey: + description: REQUIRED if mode is `MUTUAL`. + format: string + type: string + sni: + description: SNI string to present to the server during + TLS handshake. + format: string + type: string + subjectAltNames: + items: + format: string + type: string + type: array + type: object + type: object + type: object + type: array + trafficPolicy: + properties: + connectionPool: + properties: + http: + description: HTTP connection pool settings. + properties: + h2UpgradePolicy: + description: Specify if http1.1 connection should be upgraded + to http2 for the associated destination. + enum: + - DEFAULT + - DO_NOT_UPGRADE + - UPGRADE + type: string + http1MaxPendingRequests: + description: Maximum number of pending HTTP requests to + a destination. + format: int32 + type: integer + http2MaxRequests: + description: Maximum number of requests to a backend. + format: int32 + type: integer + idleTimeout: + description: The idle timeout for upstream connection pool + connections. + type: string + maxRequestsPerConnection: + description: Maximum number of requests per connection to + a backend. + format: int32 + type: integer + maxRetries: + format: int32 + type: integer + type: object + tcp: + description: Settings common to both HTTP and TCP upstream connections. + properties: + connectTimeout: + description: TCP connection timeout. + type: string + maxConnections: + description: Maximum number of HTTP1 /TCP connections to + a destination host. + format: int32 + type: integer + tcpKeepalive: + description: If set then set SO_KEEPALIVE on the socket + to enable TCP Keepalives. + properties: + interval: + description: The time duration between keep-alive probes. + type: string + probes: + type: integer + time: + type: string + type: object + type: object + type: object + loadBalancer: + description: Settings controlling the load balancer algorithms. + oneOf: + - required: + - simple + - properties: + consistentHash: + oneOf: + - required: + - httpHeaderName + - required: + - httpCookie + - required: + - useSourceIp + required: + - consistentHash + properties: + consistentHash: + properties: + httpCookie: + description: Hash based on HTTP cookie. + properties: + name: + description: Name of the cookie. + format: string + type: string + path: + description: Path to set for the cookie. + format: string + type: string + ttl: + description: Lifetime of the cookie. + type: string + type: object + httpHeaderName: + description: Hash based on a specific HTTP header. + format: string + type: string + minimumRingSize: + type: integer + useSourceIp: + description: Hash based on the source IP address. + type: boolean + type: object + localityLbSetting: + properties: + distribute: + description: 'Optional: only one of distribute or failover + can be set.' + items: + properties: + from: + description: Originating locality, '/' separated, + e.g. + format: string + type: string + to: + additionalProperties: + type: integer + description: Map of upstream localities to traffic + distribution weights. + type: object + type: object + type: array + enabled: + description: enable locality load balancing, this is DestinationRule-level + and will override mesh wide settings in entirety. + type: boolean + failover: + description: 'Optional: only failover or distribute can + be set.' + items: + properties: + from: + description: Originating region. + format: string + type: string + to: + format: string + type: string + type: object + type: array + type: object + simple: + enum: + - ROUND_ROBIN + - LEAST_CONN + - RANDOM + - PASSTHROUGH + type: string + type: object + outlierDetection: + properties: + baseEjectionTime: + description: Minimum ejection duration. + type: string + consecutive5xxErrors: + description: Number of 5xx errors before a host is ejected from + the connection pool. + type: integer + consecutiveErrors: + format: int32 + type: integer + consecutiveGatewayErrors: + description: Number of gateway errors before a host is ejected + from the connection pool. + type: integer + interval: + description: Time interval between ejection sweep analysis. + type: string + maxEjectionPercent: + format: int32 + type: integer + minHealthPercent: + format: int32 + type: integer + type: object + portLevelSettings: + description: Traffic policies specific to individual ports. + items: + properties: + connectionPool: + properties: + http: + description: HTTP connection pool settings. + properties: + h2UpgradePolicy: + description: Specify if http1.1 connection should + be upgraded to http2 for the associated destination. + enum: + - DEFAULT + - DO_NOT_UPGRADE + - UPGRADE + type: string + http1MaxPendingRequests: + description: Maximum number of pending HTTP requests + to a destination. + format: int32 + type: integer + http2MaxRequests: + description: Maximum number of requests to a backend. + format: int32 + type: integer + idleTimeout: + description: The idle timeout for upstream connection + pool connections. + type: string + maxRequestsPerConnection: + description: Maximum number of requests per connection + to a backend. + format: int32 + type: integer + maxRetries: + format: int32 + type: integer + type: object + tcp: + description: Settings common to both HTTP and TCP upstream + connections. + properties: + connectTimeout: + description: TCP connection timeout. + type: string + maxConnections: + description: Maximum number of HTTP1 /TCP connections + to a destination host. + format: int32 + type: integer + tcpKeepalive: + description: If set then set SO_KEEPALIVE on the socket + to enable TCP Keepalives. + properties: + interval: + description: The time duration between keep-alive + probes. + type: string + probes: + type: integer + time: + type: string + type: object + type: object + type: object + loadBalancer: + description: Settings controlling the load balancer algorithms. + oneOf: + - required: + - simple + - properties: + consistentHash: + oneOf: + - required: + - httpHeaderName + - required: + - httpCookie + - required: + - useSourceIp + required: + - consistentHash + properties: + consistentHash: + properties: + httpCookie: + description: Hash based on HTTP cookie. + properties: + name: + description: Name of the cookie. + format: string + type: string + path: + description: Path to set for the cookie. + format: string + type: string + ttl: + description: Lifetime of the cookie. + type: string + type: object + httpHeaderName: + description: Hash based on a specific HTTP header. + format: string + type: string + minimumRingSize: + type: integer + useSourceIp: + description: Hash based on the source IP address. + type: boolean + type: object + localityLbSetting: + properties: + distribute: + description: 'Optional: only one of distribute or + failover can be set.' + items: + properties: + from: + description: Originating locality, '/' separated, + e.g. + format: string + type: string + to: + additionalProperties: + type: integer + description: Map of upstream localities to traffic + distribution weights. + type: object + type: object + type: array + enabled: + description: enable locality load balancing, this + is DestinationRule-level and will override mesh + wide settings in entirety. + type: boolean + failover: + description: 'Optional: only failover or distribute + can be set.' + items: + properties: + from: + description: Originating region. + format: string + type: string + to: + format: string + type: string + type: object + type: array + type: object + simple: + enum: + - ROUND_ROBIN + - LEAST_CONN + - RANDOM + - PASSTHROUGH + type: string + type: object + outlierDetection: + properties: + baseEjectionTime: + description: Minimum ejection duration. + type: string + consecutive5xxErrors: + description: Number of 5xx errors before a host is ejected + from the connection pool. + type: integer + consecutiveErrors: + format: int32 + type: integer + consecutiveGatewayErrors: + description: Number of gateway errors before a host is + ejected from the connection pool. + type: integer + interval: + description: Time interval between ejection sweep analysis. + type: string + maxEjectionPercent: + format: int32 + type: integer + minHealthPercent: + format: int32 + type: integer + type: object + port: + properties: + number: + type: integer + type: object + tls: + description: TLS related settings for connections to the upstream + service. + properties: + caCertificates: + format: string + type: string + clientCertificate: + description: REQUIRED if mode is `MUTUAL`. + format: string + type: string + mode: + enum: + - DISABLE + - SIMPLE + - MUTUAL + - ISTIO_MUTUAL + type: string + privateKey: + description: REQUIRED if mode is `MUTUAL`. + format: string + type: string + sni: + description: SNI string to present to the server during + TLS handshake. + format: string + type: string + subjectAltNames: + items: + format: string + type: string + type: array + type: object + type: object + type: array + tls: + description: TLS related settings for connections to the upstream + service. + properties: + caCertificates: + format: string + type: string + clientCertificate: + description: REQUIRED if mode is `MUTUAL`. + format: string + type: string + mode: + enum: + - DISABLE + - SIMPLE + - MUTUAL + - ISTIO_MUTUAL + type: string + privateKey: + description: REQUIRED if mode is `MUTUAL`. + format: string + type: string + sni: + description: SNI string to present to the server during TLS + handshake. + format: string + type: string + subjectAltNames: + items: + format: string + type: string + type: array + type: object + type: object + type: object + type: object + versions: + - name: v1alpha3 + served: true + storage: true + - name: v1beta1 + served: true + storage: false + +--- +apiVersion: apiextensions.k8s.io/v1beta1 +kind: CustomResourceDefinition +metadata: + annotations: + "helm.sh/resource-policy": keep + labels: + app: istio-pilot + chart: istio + heritage: Tiller + release: istio + name: envoyfilters.networking.istio.io +spec: + group: networking.istio.io + names: + categories: + - istio-io + - networking-istio-io + kind: EnvoyFilter + listKind: EnvoyFilterList + plural: envoyfilters + singular: envoyfilter + scope: Namespaced + subresources: + status: {} + validation: + openAPIV3Schema: + properties: + spec: + description: 'Customizing Envoy configuration generated by Istio. See more + details at: https://istio.io/docs/reference/config/networking/envoy-filter.html' + properties: + configPatches: + description: One or more patches with match conditions. + items: + properties: + applyTo: + enum: + - INVALID + - LISTENER + - FILTER_CHAIN + - NETWORK_FILTER + - HTTP_FILTER + - ROUTE_CONFIGURATION + - VIRTUAL_HOST + - HTTP_ROUTE + - CLUSTER + type: string + match: + description: Match on listener/route configuration/cluster. + oneOf: + - required: + - listener + - required: + - routeConfiguration + - required: + - cluster + properties: + cluster: + description: Match on envoy cluster attributes. + properties: + name: + description: The exact name of the cluster to match. + format: string + type: string + portNumber: + description: The service port for which this cluster was + generated. + type: integer + service: + description: The fully qualified service name for this + cluster. + format: string + type: string + subset: + description: The subset associated with the service. + format: string + type: string + type: object + context: + description: The specific config generation context to match + on. + enum: + - ANY + - SIDECAR_INBOUND + - SIDECAR_OUTBOUND + - GATEWAY + type: string + listener: + description: Match on envoy listener attributes. + properties: + filterChain: + description: Match a specific filter chain in a listener. + properties: + applicationProtocols: + description: Applies only to sidecars. + format: string + type: string + filter: + description: The name of a specific filter to apply + the patch to. + properties: + name: + description: The filter name to match on. + format: string + type: string + subFilter: + properties: + name: + description: The filter name to match on. + format: string + type: string + type: object + type: object + name: + description: The name assigned to the filter chain. + format: string + type: string + sni: + description: The SNI value used by a filter chain's + match condition. + format: string + type: string + transportProtocol: + description: Applies only to SIDECAR_INBOUND context. + format: string + type: string + type: object + name: + description: Match a specific listener by its name. + format: string + type: string + portName: + format: string + type: string + portNumber: + type: integer + type: object + proxy: + description: Match on properties associated with a proxy. + properties: + metadata: + additionalProperties: + format: string + type: string + type: object + proxyVersion: + format: string + type: string + type: object + routeConfiguration: + description: Match on envoy HTTP route configuration attributes. + properties: + gateway: + format: string + type: string + name: + description: Route configuration name to match on. + format: string + type: string + portName: + description: Applicable only for GATEWAY context. + format: string + type: string + portNumber: + type: integer + vhost: + properties: + name: + format: string + type: string + route: + description: Match a specific route within the virtual + host. + properties: + action: + description: Match a route with specific action + type. + enum: + - ANY + - ROUTE + - REDIRECT + - DIRECT_RESPONSE + type: string + name: + format: string + type: string + type: object + type: object + type: object + type: object + patch: + description: The patch to apply along with the operation. + properties: + operation: + description: Determines how the patch should be applied. + enum: + - INVALID + - MERGE + - ADD + - REMOVE + - INSERT_BEFORE + - INSERT_AFTER + - INSERT_FIRST + type: string + value: + description: The JSON config of the object being patched. + type: object + type: object + type: object + type: array + filters: + items: + properties: + filterConfig: + type: object + filterName: + description: The name of the filter to instantiate. + format: string + type: string + filterType: + description: The type of filter to instantiate. + enum: + - INVALID + - HTTP + - NETWORK + type: string + insertPosition: + description: Insert position in the filter chain. + properties: + index: + description: Position of this filter in the filter chain. + enum: + - FIRST + - LAST + - BEFORE + - AFTER + type: string + relativeTo: + format: string + type: string + type: object + listenerMatch: + properties: + address: + description: One or more IP addresses to which the listener + is bound. + items: + format: string + type: string + type: array + listenerProtocol: + description: Selects a class of listeners for the same protocol. + enum: + - ALL + - HTTP + - TCP + type: string + listenerType: + description: Inbound vs outbound sidecar listener or gateway + listener. + enum: + - ANY + - SIDECAR_INBOUND + - SIDECAR_OUTBOUND + - GATEWAY + type: string + portNamePrefix: + format: string + type: string + portNumber: + type: integer + type: object + type: object + type: array + workloadLabels: + additionalProperties: + format: string + type: string + description: Deprecated. + type: object + workloadSelector: + properties: + labels: + additionalProperties: + format: string + type: string + type: object + type: object + type: object + type: object + versions: + - name: v1alpha3 + served: true + storage: true + +--- +apiVersion: apiextensions.k8s.io/v1beta1 +kind: CustomResourceDefinition +metadata: + annotations: + "helm.sh/resource-policy": keep + labels: + app: istio-pilot + chart: istio + heritage: Tiller + release: istio + name: gateways.networking.istio.io +spec: + group: networking.istio.io + names: + categories: + - istio-io + - networking-istio-io + kind: Gateway + listKind: GatewayList + plural: gateways + shortNames: + - gw + singular: gateway + scope: Namespaced + subresources: + status: {} + validation: + openAPIV3Schema: + properties: + spec: + description: 'Configuration affecting edge load balancer. See more details + at: https://istio.io/docs/reference/config/networking/gateway.html' + properties: + selector: + additionalProperties: + format: string + type: string + type: object + servers: + description: A list of server specifications. + items: + properties: + bind: + format: string + type: string + defaultEndpoint: + format: string + type: string + hosts: + description: One or more hosts exposed by this gateway. + items: + format: string + type: string + type: array + port: + properties: + name: + description: Label assigned to the port. + format: string + type: string + number: + description: A valid non-negative integer port number. + type: integer + protocol: + description: The protocol exposed on the port. + format: string + type: string + type: object + tls: + description: Set of TLS related options that govern the server's + behavior. + properties: + caCertificates: + description: REQUIRED if mode is `MUTUAL`. + format: string + type: string + cipherSuites: + description: 'Optional: If specified, only support the specified + cipher list.' + items: + format: string + type: string + type: array + credentialName: + format: string + type: string + httpsRedirect: + type: boolean + maxProtocolVersion: + description: 'Optional: Maximum TLS protocol version.' + enum: + - TLS_AUTO + - TLSV1_0 + - TLSV1_1 + - TLSV1_2 + - TLSV1_3 + type: string + minProtocolVersion: + description: 'Optional: Minimum TLS protocol version.' + enum: + - TLS_AUTO + - TLSV1_0 + - TLSV1_1 + - TLSV1_2 + - TLSV1_3 + type: string + mode: + enum: + - PASSTHROUGH + - SIMPLE + - MUTUAL + - AUTO_PASSTHROUGH + - ISTIO_MUTUAL + type: string + privateKey: + description: REQUIRED if mode is `SIMPLE` or `MUTUAL`. + format: string + type: string + serverCertificate: + description: REQUIRED if mode is `SIMPLE` or `MUTUAL`. + format: string + type: string + subjectAltNames: + items: + format: string + type: string + type: array + verifyCertificateHash: + items: + format: string + type: string + type: array + verifyCertificateSpki: + items: + format: string + type: string + type: array + type: object + type: object + type: array + type: object + type: object + versions: + - name: v1alpha3 + served: true + storage: true + - name: v1beta1 + served: true + storage: false + +--- +apiVersion: apiextensions.k8s.io/v1beta1 +kind: CustomResourceDefinition +metadata: + annotations: + "helm.sh/resource-policy": keep + labels: + app: istio-pilot + chart: istio + heritage: Tiller + release: istio + name: serviceentries.networking.istio.io +spec: + additionalPrinterColumns: + - JSONPath: .spec.hosts + description: The hosts associated with the ServiceEntry + name: Hosts + type: string + - JSONPath: .spec.location + description: Whether the service is external to the mesh or part of the mesh (MESH_EXTERNAL + or MESH_INTERNAL) + name: Location + type: string + - JSONPath: .spec.resolution + description: Service discovery mode for the hosts (NONE, STATIC, or DNS) + name: Resolution + type: string + - JSONPath: .metadata.creationTimestamp + description: 'CreationTimestamp is a timestamp representing the server time when + this object was created. It is not guaranteed to be set in happens-before order + across separate operations. Clients may not set this value. It is represented + in RFC3339 form and is in UTC. Populated by the system. Read-only. Null for + lists. More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#metadata' + name: Age + type: date + group: networking.istio.io + names: + categories: + - istio-io + - networking-istio-io + kind: ServiceEntry + listKind: ServiceEntryList + plural: serviceentries + shortNames: + - se + singular: serviceentry + scope: Namespaced + subresources: + status: {} + validation: + openAPIV3Schema: + properties: + spec: + description: 'Configuration affecting service registry. See more details + at: https://istio.io/docs/reference/config/networking/service-entry.html' + properties: + addresses: + description: The virtual IP addresses associated with the service. + items: + format: string + type: string + type: array + endpoints: + description: One or more endpoints associated with the service. + items: + properties: + address: + format: string + type: string + labels: + additionalProperties: + format: string + type: string + description: One or more labels associated with the endpoint. + type: object + locality: + description: The locality associated with the endpoint. + format: string + type: string + network: + format: string + type: string + ports: + additionalProperties: + type: integer + description: Set of ports associated with the endpoint. + type: object + weight: + description: The load balancing weight associated with the endpoint. + type: integer + type: object + type: array + exportTo: + description: A list of namespaces to which this service is exported. + items: + format: string + type: string + type: array + hosts: + description: The hosts associated with the ServiceEntry. + items: + format: string + type: string + type: array + location: + enum: + - MESH_EXTERNAL + - MESH_INTERNAL + type: string + ports: + description: The ports associated with the external service. + items: + properties: + name: + description: Label assigned to the port. + format: string + type: string + number: + description: A valid non-negative integer port number. + type: integer + protocol: + description: The protocol exposed on the port. + format: string + type: string + type: object + type: array + resolution: + description: Service discovery mode for the hosts. + enum: + - NONE + - STATIC + - DNS + type: string + subjectAltNames: + items: + format: string + type: string + type: array + type: object + type: object + versions: + - name: v1alpha3 + served: true + storage: true + - name: v1beta1 + served: true + storage: false + +--- +apiVersion: apiextensions.k8s.io/v1beta1 +kind: CustomResourceDefinition +metadata: + annotations: + "helm.sh/resource-policy": keep + labels: + app: istio-pilot + chart: istio + heritage: Tiller + release: istio + name: sidecars.networking.istio.io +spec: + group: networking.istio.io + names: + categories: + - istio-io + - networking-istio-io + kind: Sidecar + listKind: SidecarList + plural: sidecars + singular: sidecar + scope: Namespaced + subresources: + status: {} + validation: + openAPIV3Schema: + properties: + spec: + description: 'Configuration affecting network reachability of a sidecar. + See more details at: https://istio.io/docs/reference/config/networking/sidecar.html' + properties: + egress: + items: + properties: + bind: + format: string + type: string + captureMode: + enum: + - DEFAULT + - IPTABLES + - NONE + type: string + hosts: + items: + format: string + type: string + type: array + port: + description: The port associated with the listener. + properties: + name: + description: Label assigned to the port. + format: string + type: string + number: + description: A valid non-negative integer port number. + type: integer + protocol: + description: The protocol exposed on the port. + format: string + type: string + type: object + type: object + type: array + ingress: + items: + properties: + bind: + description: The IP to which the listener should be bound. + format: string + type: string + captureMode: + enum: + - DEFAULT + - IPTABLES + - NONE + type: string + defaultEndpoint: + format: string + type: string + port: + description: The port associated with the listener. + properties: + name: + description: Label assigned to the port. + format: string + type: string + number: + description: A valid non-negative integer port number. + type: integer + protocol: + description: The protocol exposed on the port. + format: string + type: string + type: object + type: object + type: array + outboundTrafficPolicy: + description: This allows to configure the outbound traffic policy. + properties: + mode: + enum: + - REGISTRY_ONLY + - ALLOW_ANY + type: string + type: object + workloadSelector: + properties: + labels: + additionalProperties: + format: string + type: string + type: object + type: object + type: object + type: object + versions: + - name: v1alpha3 + served: true + storage: true + - name: v1beta1 + served: true + storage: false + +--- +apiVersion: apiextensions.k8s.io/v1beta1 +kind: CustomResourceDefinition +metadata: + annotations: + "helm.sh/resource-policy": keep + labels: + app: istio-pilot + chart: istio + heritage: Tiller + release: istio + name: virtualservices.networking.istio.io +spec: + additionalPrinterColumns: + - JSONPath: .spec.gateways + description: The names of gateways and sidecars that should apply these routes + name: Gateways + type: string + - JSONPath: .spec.hosts + description: The destination hosts to which traffic is being sent + name: Hosts + type: string + - JSONPath: .metadata.creationTimestamp + description: 'CreationTimestamp is a timestamp representing the server time when + this object was created. It is not guaranteed to be set in happens-before order + across separate operations. Clients may not set this value. It is represented + in RFC3339 form and is in UTC. Populated by the system. Read-only. Null for + lists. More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#metadata' + name: Age + type: date + group: networking.istio.io + names: + categories: + - istio-io + - networking-istio-io + kind: VirtualService + listKind: VirtualServiceList + plural: virtualservices + shortNames: + - vs + singular: virtualservice + scope: Namespaced + subresources: + status: {} + validation: + openAPIV3Schema: + properties: + spec: + description: 'Configuration affecting label/content routing, sni routing, + etc. See more details at: https://istio.io/docs/reference/config/networking/virtual-service.html' + properties: + exportTo: + description: A list of namespaces to which this virtual service is exported. + items: + format: string + type: string + type: array + gateways: + description: The names of gateways and sidecars that should apply these + routes. + items: + format: string + type: string + type: array + hosts: + description: The destination hosts to which traffic is being sent. + items: + format: string + type: string + type: array + http: + description: An ordered list of route rules for HTTP traffic. + items: + properties: + corsPolicy: + description: Cross-Origin Resource Sharing policy (CORS). + properties: + allowCredentials: + type: boolean + allowHeaders: + items: + format: string + type: string + type: array + allowMethods: + description: List of HTTP methods allowed to access the resource. + items: + format: string + type: string + type: array + allowOrigin: + description: The list of origins that are allowed to perform + CORS requests. + items: + format: string + type: string + type: array + allowOrigins: + description: String patterns that match allowed origins. + items: + oneOf: + - required: + - exact + - required: + - prefix + - required: + - regex + properties: + exact: + format: string + type: string + prefix: + format: string + type: string + regex: + format: string + type: string + type: object + type: array + exposeHeaders: + items: + format: string + type: string + type: array + maxAge: + type: string + type: object + fault: + description: Fault injection policy to apply on HTTP traffic at + the client side. + properties: + abort: + oneOf: + - required: + - httpStatus + - required: + - grpcStatus + - required: + - http2Error + properties: + grpcStatus: + format: string + type: string + http2Error: + format: string + type: string + httpStatus: + description: HTTP status code to use to abort the Http + request. + format: int32 + type: integer + percentage: + description: Percentage of requests to be aborted with + the error code provided. + properties: + value: + format: double + type: number + type: object + type: object + delay: + oneOf: + - properties: + percent: {} + required: + - fixedDelay + - properties: + percent: {} + required: + - exponentialDelay + properties: + exponentialDelay: + type: string + fixedDelay: + description: Add a fixed delay before forwarding the request. + type: string + percent: + description: Percentage of requests on which the delay + will be injected (0-100). + format: int32 + type: integer + percentage: + description: Percentage of requests on which the delay + will be injected. + properties: + value: + format: double + type: number + type: object + type: object + type: object + headers: + properties: + request: + properties: + add: + additionalProperties: + format: string + type: string + type: object + remove: + items: + format: string + type: string + type: array + set: + additionalProperties: + format: string + type: string + type: object + type: object + response: + properties: + add: + additionalProperties: + format: string + type: string + type: object + remove: + items: + format: string + type: string + type: array + set: + additionalProperties: + format: string + type: string + type: object + type: object + type: object + match: + items: + properties: + authority: + oneOf: + - required: + - exact + - required: + - prefix + - required: + - regex + properties: + exact: + format: string + type: string + prefix: + format: string + type: string + regex: + format: string + type: string + type: object + gateways: + description: Names of gateways where the rule should be + applied. + items: + format: string + type: string + type: array + headers: + additionalProperties: + oneOf: + - required: + - exact + - required: + - prefix + - required: + - regex + properties: + exact: + format: string + type: string + prefix: + format: string + type: string + regex: + format: string + type: string + type: object + type: object + ignoreUriCase: + description: Flag to specify whether the URI matching should + be case-insensitive. + type: boolean + method: + oneOf: + - required: + - exact + - required: + - prefix + - required: + - regex + properties: + exact: + format: string + type: string + prefix: + format: string + type: string + regex: + format: string + type: string + type: object + name: + description: The name assigned to a match. + format: string + type: string + port: + description: Specifies the ports on the host that is being + addressed. + type: integer + queryParams: + additionalProperties: + oneOf: + - required: + - exact + - required: + - prefix + - required: + - regex + properties: + exact: + format: string + type: string + prefix: + format: string + type: string + regex: + format: string + type: string + type: object + description: Query parameters for matching. + type: object + scheme: + oneOf: + - required: + - exact + - required: + - prefix + - required: + - regex + properties: + exact: + format: string + type: string + prefix: + format: string + type: string + regex: + format: string + type: string + type: object + sourceLabels: + additionalProperties: + format: string + type: string + type: object + uri: + oneOf: + - required: + - exact + - required: + - prefix + - required: + - regex + properties: + exact: + format: string + type: string + prefix: + format: string + type: string + regex: + format: string + type: string + type: object + type: object + type: array + mirror: + properties: + host: + description: The name of a service from the service registry. + format: string + type: string + port: + description: Specifies the port on the host that is being + addressed. + properties: + number: + type: integer + type: object + subset: + description: The name of a subset within the service. + format: string + type: string + type: object + mirror_percent: + description: Percentage of the traffic to be mirrored by the `mirror` + field. + type: integer + mirrorPercent: + description: Percentage of the traffic to be mirrored by the `mirror` + field. + type: integer + mirrorPercentage: + description: Percentage of the traffic to be mirrored by the `mirror` + field. + properties: + value: + format: double + type: number + type: object + name: + description: The name assigned to the route for debugging purposes. + format: string + type: string + redirect: + description: A HTTP rule can either redirect or forward (default) + traffic. + properties: + authority: + format: string + type: string + redirectCode: + type: integer + uri: + format: string + type: string + type: object + retries: + description: Retry policy for HTTP requests. + properties: + attempts: + description: Number of retries for a given request. + format: int32 + type: integer + perTryTimeout: + description: Timeout per retry attempt for a given request. + type: string + retryOn: + description: Specifies the conditions under which retry takes + place. + format: string + type: string + type: object + rewrite: + description: Rewrite HTTP URIs and Authority headers. + properties: + authority: + description: rewrite the Authority/Host header with this value. + format: string + type: string + uri: + format: string + type: string + type: object + route: + description: A HTTP rule can either redirect or forward (default) + traffic. + items: + properties: + destination: + properties: + host: + description: The name of a service from the service + registry. + format: string + type: string + port: + description: Specifies the port on the host that is + being addressed. + properties: + number: + type: integer + type: object + subset: + description: The name of a subset within the service. + format: string + type: string + type: object + headers: + properties: + request: + properties: + add: + additionalProperties: + format: string + type: string + type: object + remove: + items: + format: string + type: string + type: array + set: + additionalProperties: + format: string + type: string + type: object + type: object + response: + properties: + add: + additionalProperties: + format: string + type: string + type: object + remove: + items: + format: string + type: string + type: array + set: + additionalProperties: + format: string + type: string + type: object + type: object + type: object + weight: + format: int32 + type: integer + type: object + type: array + timeout: + description: Timeout for HTTP requests. + type: string + type: object + type: array + tcp: + description: An ordered list of route rules for opaque TCP traffic. + items: + properties: + match: + items: + properties: + destinationSubnets: + description: IPv4 or IPv6 ip addresses of destination with + optional subnet. + items: + format: string + type: string + type: array + gateways: + description: Names of gateways where the rule should be + applied. + items: + format: string + type: string + type: array + port: + description: Specifies the port on the host that is being + addressed. + type: integer + sourceLabels: + additionalProperties: + format: string + type: string + type: object + sourceSubnet: + description: IPv4 or IPv6 ip address of source with optional + subnet. + format: string + type: string + type: object + type: array + route: + description: The destination to which the connection should be + forwarded to. + items: + properties: + destination: + properties: + host: + description: The name of a service from the service + registry. + format: string + type: string + port: + description: Specifies the port on the host that is + being addressed. + properties: + number: + type: integer + type: object + subset: + description: The name of a subset within the service. + format: string + type: string + type: object + weight: + format: int32 + type: integer + type: object + type: array + type: object + type: array + tls: + items: + properties: + match: + items: + properties: + destinationSubnets: + description: IPv4 or IPv6 ip addresses of destination with + optional subnet. + items: + format: string + type: string + type: array + gateways: + description: Names of gateways where the rule should be + applied. + items: + format: string + type: string + type: array + port: + description: Specifies the port on the host that is being + addressed. + type: integer + sniHosts: + description: SNI (server name indicator) to match on. + items: + format: string + type: string + type: array + sourceLabels: + additionalProperties: + format: string + type: string + type: object + type: object + type: array + route: + description: The destination to which the connection should be + forwarded to. + items: + properties: + destination: + properties: + host: + description: The name of a service from the service + registry. + format: string + type: string + port: + description: Specifies the port on the host that is + being addressed. + properties: + number: + type: integer + type: object + subset: + description: The name of a subset within the service. + format: string + type: string + type: object + weight: + format: int32 + type: integer + type: object + type: array + type: object + type: array + type: object + type: object + versions: + - name: v1alpha3 + served: true + storage: true + - name: v1beta1 + served: true + storage: false + +--- +apiVersion: apiextensions.k8s.io/v1beta1 +kind: CustomResourceDefinition +metadata: + annotations: + "helm.sh/resource-policy": keep + labels: + app: mixer + chart: istio + heritage: Tiller + istio: core + package: istio.io.mixer + release: istio + name: attributemanifests.config.istio.io +spec: + group: config.istio.io + names: + categories: + - istio-io + - policy-istio-io + kind: attributemanifest + listKind: attributemanifestList + plural: attributemanifests + singular: attributemanifest + scope: Namespaced + subresources: + status: {} + validation: + openAPIV3Schema: + properties: + spec: + description: 'Describes the rules used to configure Mixer''s policy and + telemetry features. See more details at: https://istio.io/docs/reference/config/policy-and-telemetry/istio.policy.v1beta1.html' + properties: + attributes: + additionalProperties: + properties: + description: + description: A human-readable description of the attribute's purpose. + format: string + type: string + valueType: + description: The type of data carried by this attribute. + enum: + - VALUE_TYPE_UNSPECIFIED + - STRING + - INT64 + - DOUBLE + - BOOL + - TIMESTAMP + - IP_ADDRESS + - EMAIL_ADDRESS + - URI + - DNS_NAME + - DURATION + - STRING_MAP + type: string + type: object + description: The set of attributes this Istio component will be responsible + for producing at runtime. + type: object + name: + description: Name of the component producing these attributes. + format: string + type: string + revision: + description: The revision of this document. + format: string + type: string + type: object + type: object + versions: + - name: v1alpha2 + served: true + storage: true + +--- +apiVersion: apiextensions.k8s.io/v1beta1 +kind: CustomResourceDefinition +metadata: + annotations: + "helm.sh/resource-policy": keep + labels: + app: mixer + chart: istio + heritage: Tiller + istio: mixer-handler + package: handler + release: istio + name: handlers.config.istio.io +spec: + group: config.istio.io + names: + categories: + - istio-io + - policy-istio-io + kind: handler + listKind: handlerList + plural: handlers + singular: handler + scope: Namespaced + subresources: + status: {} + validation: + openAPIV3Schema: + properties: + spec: + description: Handler allows the operator to configure a specific adapter + implementation. + properties: + adapter: + description: The name of a specific adapter implementation. + format: string + type: string + compiledAdapter: + description: The name of the compiled in adapter this handler instantiates. + format: string + type: string + connection: + description: Information on how to connect to the out-of-process adapter. + properties: + address: + description: The address of the backend. + format: string + type: string + authentication: + description: Auth config for the connection to the backend. + oneOf: + - properties: + tls: + allOf: + - oneOf: + - required: + - tokenPath + - required: + - oauth + - oneOf: + - required: + - authHeader + - required: + - customHeader + required: + - tls + - required: + - mutual + properties: + mutual: + properties: + caCertificates: + format: string + type: string + clientCertificate: + description: The path to the file holding client certificate + for mutual TLS. + format: string + type: string + privateKey: + description: The path to the file holding the private key + for mutual TLS. + format: string + type: string + serverName: + description: Used to configure mixer mutual TLS client to + supply server name for SNI. + format: string + type: string + type: object + tls: + properties: + authHeader: + description: Access token is passed as authorization header. + enum: + - PLAIN + - BEARER + type: string + caCertificates: + format: string + type: string + customHeader: + description: Customized header key to hold access token, + e.g. + format: string + type: string + oauth: + description: Oauth config to fetch access token from auth + provider. + properties: + clientId: + description: OAuth client id for mixer. + format: string + type: string + clientSecret: + description: The path to the file holding the client + secret for oauth. + format: string + type: string + endpointParams: + additionalProperties: + format: string + type: string + description: Additional parameters for requests to the + token endpoint. + type: object + scopes: + description: List of requested permissions. + items: + format: string + type: string + type: array + tokenUrl: + description: The Resource server's token endpoint URL. + format: string + type: string + type: object + serverName: + format: string + type: string + tokenPath: + format: string + type: string + type: object + type: object + timeout: + description: Timeout for remote calls to the backend. + type: string + type: object + name: + description: Must be unique in the entire Mixer configuration. + format: string + type: string + params: + description: Depends on adapter implementation. + type: object + type: object + type: object + versions: + - name: v1alpha2 + served: true + storage: true + +--- +apiVersion: apiextensions.k8s.io/v1beta1 +kind: CustomResourceDefinition +metadata: + annotations: + "helm.sh/resource-policy": keep + labels: + app: mixer + chart: istio + heritage: Tiller + istio: mixer-instance + package: instance + release: istio + name: instances.config.istio.io +spec: + group: config.istio.io + names: + categories: + - istio-io + - policy-istio-io + kind: instance + listKind: instanceList + plural: instances + singular: instance + scope: Namespaced + subresources: + status: {} + validation: + openAPIV3Schema: + properties: + spec: + description: An Instance tells Mixer how to create instances for particular + template. + properties: + attributeBindings: + additionalProperties: + format: string + type: string + type: object + compiledTemplate: + description: The name of the compiled in template this instance creates + instances for. + format: string + type: string + name: + format: string + type: string + params: + description: Depends on referenced template. + type: object + template: + description: The name of the template this instance creates instances + for. + format: string + type: string + type: object + type: object + versions: + - name: v1alpha2 + served: true + storage: true + +--- +apiVersion: apiextensions.k8s.io/v1beta1 +kind: CustomResourceDefinition +metadata: + annotations: + "helm.sh/resource-policy": keep + labels: + app: mixer + chart: istio + heritage: Tiller + istio: core + package: istio.io.mixer + release: istio + name: rules.config.istio.io +spec: + group: config.istio.io + names: + categories: + - istio-io + - policy-istio-io + kind: rule + listKind: ruleList + plural: rules + singular: rule + scope: Namespaced + subresources: + status: {} + validation: + openAPIV3Schema: + properties: + spec: + description: 'Describes the rules used to configure Mixer''s policy and + telemetry features. See more details at: https://istio.io/docs/reference/config/policy-and-telemetry/istio.policy.v1beta1.html' + properties: + actions: + description: The actions that will be executed when match evaluates + to `true`. + items: + properties: + handler: + description: Fully qualified name of the handler to invoke. + format: string + type: string + instances: + items: + format: string + type: string + type: array + name: + description: A handle to refer to the results of the action. + format: string + type: string + type: object + type: array + match: + description: Match is an attribute based predicate. + format: string + type: string + requestHeaderOperations: + items: + properties: + name: + description: Header name literal value. + format: string + type: string + operation: + description: Header operation type. + enum: + - REPLACE + - REMOVE + - APPEND + type: string + values: + description: Header value expressions. + items: + format: string + type: string + type: array + type: object + type: array + responseHeaderOperations: + items: + properties: + name: + description: Header name literal value. + format: string + type: string + operation: + description: Header operation type. + enum: + - REPLACE + - REMOVE + - APPEND + type: string + values: + description: Header value expressions. + items: + format: string + type: string + type: array + type: object + type: array + sampling: + properties: + random: + description: Provides filtering of actions based on random selection + per request. + properties: + attributeExpression: + description: Specifies an attribute expression to use to override + the numerator in the `percent_sampled` field. + format: string + type: string + percentSampled: + description: The default sampling rate, expressed as a percentage. + properties: + denominator: + description: Specifies the denominator. + enum: + - HUNDRED + - TEN_THOUSAND + type: string + numerator: + description: Specifies the numerator. + type: integer + type: object + useIndependentRandomness: + description: By default sampling will be based on the value + of the request header `x-request-id`. + type: boolean + type: object + rateLimit: + properties: + maxUnsampledEntries: + description: Number of entries to allow during the `sampling_duration` + before sampling is enforced. + format: int64 + type: integer + samplingDuration: + description: Window in which to enforce the sampling rate. + type: string + samplingRate: + description: The rate at which to sample entries once the unsampled + limit has been reached. + format: int64 + type: integer + type: object + type: object + type: object + type: object + versions: + - name: v1alpha2 + served: true + storage: true + +--- +apiVersion: apiextensions.k8s.io/v1beta1 +kind: CustomResourceDefinition +metadata: + annotations: + "helm.sh/resource-policy": keep + labels: + app: istio-pilot + chart: istio + heritage: Tiller + istio: rbac + release: istio + name: clusterrbacconfigs.rbac.istio.io +spec: + group: rbac.istio.io + names: + categories: + - istio-io + - rbac-istio-io + kind: ClusterRbacConfig + listKind: ClusterRbacConfigList + plural: clusterrbacconfigs + singular: clusterrbacconfig + scope: Cluster + subresources: + status: {} + validation: + openAPIV3Schema: + properties: + spec: + description: 'Configuration for Role Based Access Control. See more details + at: https://istio.io/docs/reference/config/security/istio.rbac.v1alpha1.html' + properties: + enforcementMode: + enum: + - ENFORCED + - PERMISSIVE + type: string + exclusion: + description: A list of services or namespaces that should not be enforced + by Istio RBAC policies. + properties: + namespaces: + description: A list of namespaces. + items: + format: string + type: string + type: array + services: + description: A list of services. + items: + format: string + type: string + type: array + type: object + inclusion: + description: A list of services or namespaces that should be enforced + by Istio RBAC policies. + properties: + namespaces: + description: A list of namespaces. + items: + format: string + type: string + type: array + services: + description: A list of services. + items: + format: string + type: string + type: array + type: object + mode: + description: Istio RBAC mode. + enum: + - "OFF" + - "ON" + - ON_WITH_INCLUSION + - ON_WITH_EXCLUSION + type: string + type: object + type: object + versions: + - name: v1alpha1 + served: true + storage: true + +--- +apiVersion: apiextensions.k8s.io/v1beta1 +kind: CustomResourceDefinition +metadata: + annotations: + "helm.sh/resource-policy": keep + labels: + app: mixer + chart: istio + heritage: Tiller + istio: rbac + package: istio.io.mixer + release: istio + name: rbacconfigs.rbac.istio.io +spec: + group: rbac.istio.io + names: + categories: + - istio-io + - rbac-istio-io + kind: RbacConfig + listKind: RbacConfigList + plural: rbacconfigs + singular: rbacconfig + scope: Namespaced + subresources: + status: {} + validation: + openAPIV3Schema: + properties: + spec: + description: 'Configuration for Role Based Access Control. See more details + at: https://istio.io/docs/reference/config/security/istio.rbac.v1alpha1.html' + properties: + enforcementMode: + enum: + - ENFORCED + - PERMISSIVE + type: string + exclusion: + description: A list of services or namespaces that should not be enforced + by Istio RBAC policies. + properties: + namespaces: + description: A list of namespaces. + items: + format: string + type: string + type: array + services: + description: A list of services. + items: + format: string + type: string + type: array + type: object + inclusion: + description: A list of services or namespaces that should be enforced + by Istio RBAC policies. + properties: + namespaces: + description: A list of namespaces. + items: + format: string + type: string + type: array + services: + description: A list of services. + items: + format: string + type: string + type: array + type: object + mode: + description: Istio RBAC mode. + enum: + - "OFF" + - "ON" + - ON_WITH_INCLUSION + - ON_WITH_EXCLUSION + type: string + type: object + type: object + versions: + - name: v1alpha1 + served: true + storage: true + +--- +apiVersion: apiextensions.k8s.io/v1beta1 +kind: CustomResourceDefinition +metadata: + annotations: + "helm.sh/resource-policy": keep + labels: + app: mixer + chart: istio + heritage: Tiller + istio: rbac + package: istio.io.mixer + release: istio + name: serviceroles.rbac.istio.io +spec: + group: rbac.istio.io + names: + categories: + - istio-io + - rbac-istio-io + kind: ServiceRole + listKind: ServiceRoleList + plural: serviceroles + singular: servicerole + scope: Namespaced + subresources: + status: {} + validation: + openAPIV3Schema: + properties: + spec: + description: 'Configuration for Role Based Access Control. See more details + at: https://istio.io/docs/reference/config/security/istio.rbac.v1alpha1.html' + properties: + rules: + description: The set of access rules (permissions) that the role has. + items: + properties: + constraints: + description: Optional. + items: + properties: + key: + description: Key of the constraint. + format: string + type: string + values: + description: List of valid values for the constraint. + items: + format: string + type: string + type: array + type: object + type: array + hosts: + items: + format: string + type: string + type: array + methods: + description: Optional. + items: + format: string + type: string + type: array + notHosts: + items: + format: string + type: string + type: array + notMethods: + items: + format: string + type: string + type: array + notPaths: + items: + format: string + type: string + type: array + notPorts: + items: + format: int32 + type: integer + type: array + paths: + description: Optional. + items: + format: string + type: string + type: array + ports: + items: + format: int32 + type: integer + type: array + services: + description: A list of service names. + items: + format: string + type: string + type: array + type: object + type: array + type: object + type: object + versions: + - name: v1alpha1 + served: true + storage: true + +--- +apiVersion: apiextensions.k8s.io/v1beta1 +kind: CustomResourceDefinition +metadata: + annotations: + "helm.sh/resource-policy": keep + labels: + app: mixer + chart: istio + heritage: Tiller + istio: rbac + package: istio.io.mixer + release: istio + name: servicerolebindings.rbac.istio.io +spec: + additionalPrinterColumns: + - JSONPath: .spec.roleRef.name + description: The name of the ServiceRole object being referenced + name: Reference + type: string + - JSONPath: .metadata.creationTimestamp + description: 'CreationTimestamp is a timestamp representing the server time when + this object was created. It is not guaranteed to be set in happens-before order + across separate operations. Clients may not set this value. It is represented + in RFC3339 form and is in UTC. Populated by the system. Read-only. Null for + lists. More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#metadata' + name: Age + type: date + group: rbac.istio.io + names: + categories: + - istio-io + - rbac-istio-io + kind: ServiceRoleBinding + listKind: ServiceRoleBindingList + plural: servicerolebindings + singular: servicerolebinding + scope: Namespaced + subresources: + status: {} + validation: + openAPIV3Schema: + properties: + spec: + description: 'Configuration for Role Based Access Control. See more details + at: https://istio.io/docs/reference/config/security/istio.rbac.v1alpha1.html' + properties: + actions: + items: + properties: + constraints: + description: Optional. + items: + properties: + key: + description: Key of the constraint. + format: string + type: string + values: + description: List of valid values for the constraint. + items: + format: string + type: string + type: array + type: object + type: array + hosts: + items: + format: string + type: string + type: array + methods: + description: Optional. + items: + format: string + type: string + type: array + notHosts: + items: + format: string + type: string + type: array + notMethods: + items: + format: string + type: string + type: array + notPaths: + items: + format: string + type: string + type: array + notPorts: + items: + format: int32 + type: integer + type: array + paths: + description: Optional. + items: + format: string + type: string + type: array + ports: + items: + format: int32 + type: integer + type: array + services: + description: A list of service names. + items: + format: string + type: string + type: array + type: object + type: array + mode: + enum: + - ENFORCED + - PERMISSIVE + type: string + role: + format: string + type: string + roleRef: + description: Reference to the ServiceRole object. + properties: + kind: + description: The type of the role being referenced. + format: string + type: string + name: + description: The name of the ServiceRole object being referenced. + format: string + type: string + type: object + subjects: + description: List of subjects that are assigned the ServiceRole object. + items: + properties: + group: + format: string + type: string + groups: + items: + format: string + type: string + type: array + ips: + items: + format: string + type: string + type: array + names: + items: + format: string + type: string + type: array + namespaces: + items: + format: string + type: string + type: array + notGroups: + items: + format: string + type: string + type: array + notIps: + items: + format: string + type: string + type: array + notNames: + items: + format: string + type: string + type: array + notNamespaces: + items: + format: string + type: string + type: array + properties: + additionalProperties: + format: string + type: string + description: Optional. + type: object + user: + description: Optional. + format: string + type: string + type: object + type: array + type: object + type: object + versions: + - name: v1alpha1 + served: true + storage: true + +--- +apiVersion: apiextensions.k8s.io/v1beta1 +kind: CustomResourceDefinition +metadata: + annotations: + "helm.sh/resource-policy": keep + labels: + app: istio-pilot + chart: istio + heritage: Tiller + istio: security + release: istio + name: authorizationpolicies.security.istio.io +spec: + group: security.istio.io + names: + categories: + - istio-io + - security-istio-io + kind: AuthorizationPolicy + listKind: AuthorizationPolicyList + plural: authorizationpolicies + singular: authorizationpolicy + scope: Namespaced + subresources: + status: {} + validation: + openAPIV3Schema: + properties: + spec: + description: 'Configuration for access control on workloads. See more details + at: https://istio.io/docs/reference/config/security/authorization-policy.html' + properties: + action: + description: Optional. + enum: + - ALLOW + - DENY + type: string + rules: + description: Optional. + items: + properties: + from: + description: Optional. + items: + properties: + source: + description: Source specifies the source of a request. + properties: + ipBlocks: + description: Optional. + items: + format: string + type: string + type: array + namespaces: + description: Optional. + items: + format: string + type: string + type: array + notIpBlocks: + description: Optional. + items: + format: string + type: string + type: array + notNamespaces: + description: Optional. + items: + format: string + type: string + type: array + notPrincipals: + description: Optional. + items: + format: string + type: string + type: array + notRequestPrincipals: + description: Optional. + items: + format: string + type: string + type: array + principals: + description: Optional. + items: + format: string + type: string + type: array + requestPrincipals: + description: Optional. + items: + format: string + type: string + type: array + type: object + type: object + type: array + to: + description: Optional. + items: + properties: + operation: + description: Operation specifies the operation of a request. + properties: + hosts: + description: Optional. + items: + format: string + type: string + type: array + methods: + description: Optional. + items: + format: string + type: string + type: array + notHosts: + description: Optional. + items: + format: string + type: string + type: array + notMethods: + description: Optional. + items: + format: string + type: string + type: array + notPaths: + description: Optional. + items: + format: string + type: string + type: array + notPorts: + description: Optional. + items: + format: string + type: string + type: array + paths: + description: Optional. + items: + format: string + type: string + type: array + ports: + description: Optional. + items: + format: string + type: string + type: array + type: object + type: object + type: array + when: + description: Optional. + items: + properties: + key: + description: The name of an Istio attribute. + format: string + type: string + notValues: + description: Optional. + items: + format: string + type: string + type: array + values: + description: Optional. + items: + format: string + type: string + type: array + type: object + type: array + type: object + type: array + selector: + description: Optional. + properties: + matchLabels: + additionalProperties: + format: string + type: string + type: object + type: object + type: object + type: object + versions: + - name: v1beta1 + served: true + storage: true + +--- +apiVersion: apiextensions.k8s.io/v1beta1 +kind: CustomResourceDefinition +metadata: + annotations: + "helm.sh/resource-policy": keep + labels: + app: istio-pilot + chart: istio + heritage: Tiller + istio: security + release: istio + name: peerauthentications.security.istio.io +spec: + group: security.istio.io + names: + categories: + - istio-io + - security-istio-io + kind: PeerAuthentication + listKind: PeerAuthenticationList + plural: peerauthentications + singular: peerauthentication + scope: Namespaced + subresources: + status: {} + validation: + openAPIV3Schema: + properties: + spec: + description: PeerAuthentication defines how traffic will be tunneled (or + not) to the sidecar. + properties: + mtls: + description: Mutual TLS settings for workload. + properties: + mode: + description: Defines the mTLS mode used for peer authentication. + enum: + - UNSET + - DISABLE + - PERMISSIVE + - STRICT + type: string + type: object + portLevelMtls: + additionalProperties: + properties: + mode: + description: Defines the mTLS mode used for peer authentication. + enum: + - UNSET + - DISABLE + - PERMISSIVE + - STRICT + type: string + type: object + description: Port specific mutual TLS settings. + type: object + selector: + description: The selector determines the workloads to apply the ChannelAuthentication + on. + properties: + matchLabels: + additionalProperties: + format: string + type: string + type: object + type: object + type: object + type: object + versions: + - name: v1beta1 + served: true + storage: true + +--- +apiVersion: apiextensions.k8s.io/v1beta1 +kind: CustomResourceDefinition +metadata: + annotations: + "helm.sh/resource-policy": keep + labels: + app: istio-pilot + chart: istio + heritage: Tiller + istio: security + release: istio + name: requestauthentications.security.istio.io +spec: + group: security.istio.io + names: + categories: + - istio-io + - security-istio-io + kind: RequestAuthentication + listKind: RequestAuthenticationList + plural: requestauthentications + singular: requestauthentication + scope: Namespaced + subresources: + status: {} + validation: + openAPIV3Schema: + properties: + spec: + description: RequestAuthentication defines what request authentication methods + are supported by a workload. + properties: + jwtRules: + description: Define the list of JWTs that can be validated at the selected + workloads' proxy. + items: + properties: + audiences: + items: + format: string + type: string + type: array + forwardOriginalToken: + description: If set to true, the orginal token will be kept for + the ustream request. + type: boolean + fromHeaders: + description: List of header locations from which JWT is expected. + items: + properties: + name: + description: The HTTP header name. + format: string + type: string + prefix: + description: The prefix that should be stripped before decoding + the token. + format: string + type: string + type: object + type: array + fromParams: + description: List of query parameters from which JWT is expected. + items: + format: string + type: string + type: array + issuer: + description: Identifies the issuer that issued the JWT. + format: string + type: string + jwks: + description: JSON Web Key Set of public keys to validate signature + of the JWT. + format: string + type: string + jwks_uri: + format: string + type: string + jwksUri: + format: string + type: string + outputPayloadToHeader: + format: string + type: string + type: object + type: array + selector: + description: The selector determines the workloads to apply the RequestAuthentication + on. + properties: + matchLabels: + additionalProperties: + format: string + type: string + type: object + type: object + type: object + type: object + versions: + - name: v1beta1 + served: true + storage: true + +--- +apiVersion: apiextensions.k8s.io/v1beta1 +kind: CustomResourceDefinition +metadata: + name: clusterissuers.certmanager.k8s.io + labels: + app: certmanager + chart: certmanager + heritage: Tiller + release: istio + annotations: + "helm.sh/resource-policy": keep +spec: + group: certmanager.k8s.io + versions: + - name: v1alpha1 + served: true + storage: true + names: + kind: ClusterIssuer + plural: clusterissuers + scope: Cluster +--- +apiVersion: apiextensions.k8s.io/v1beta1 +kind: CustomResourceDefinition +metadata: + name: issuers.certmanager.k8s.io + labels: + app: certmanager + chart: certmanager + heritage: Tiller + release: istio + annotations: + "helm.sh/resource-policy": keep +spec: + group: certmanager.k8s.io + versions: + - name: v1alpha1 + served: true + storage: true + names: + kind: Issuer + plural: issuers + scope: Namespaced +--- +apiVersion: apiextensions.k8s.io/v1beta1 +kind: CustomResourceDefinition +metadata: + name: certificates.certmanager.k8s.io + labels: + app: certmanager + chart: certmanager + heritage: Tiller + release: istio + annotations: + "helm.sh/resource-policy": keep +spec: + additionalPrinterColumns: + - JSONPath: .status.conditions[?(@.type=="Ready")].status + name: Ready + type: string + - JSONPath: .spec.secretName + name: Secret + type: string + - JSONPath: .spec.issuerRef.name + name: Issuer + type: string + priority: 1 + - JSONPath: .status.conditions[?(@.type=="Ready")].message + name: Status + type: string + priority: 1 + - JSONPath: .metadata.creationTimestamp + description: |- + CreationTimestamp is a timestamp representing the server time when this object was created. It is not guaranteed to be set in happens-before order across separate operations. Clients may not set this value. It is represented in RFC3339 form and is in UTC. + + Populated by the system. Read-only. Null for lists. More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#metadata + name: Age + type: date + group: certmanager.k8s.io + versions: + - name: v1alpha1 + served: true + storage: true + scope: Namespaced + names: + kind: Certificate + plural: certificates + shortNames: + - cert + - certs +--- +apiVersion: apiextensions.k8s.io/v1beta1 +kind: CustomResourceDefinition +metadata: + name: orders.certmanager.k8s.io + labels: + app: certmanager + chart: certmanager + heritage: Tiller + release: istio + annotations: + "helm.sh/resource-policy": keep +spec: + additionalPrinterColumns: + - JSONPath: .status.state + name: State + type: string + - JSONPath: .spec.issuerRef.name + name: Issuer + type: string + priority: 1 + - JSONPath: .status.reason + name: Reason + type: string + priority: 1 + - JSONPath: .metadata.creationTimestamp + description: |- + CreationTimestamp is a timestamp representing the server time when this object was created. It is not guaranteed to be set in happens-before order across separate operations. Clients may not set this value. It is represented in RFC3339 form and is in UTC. + + Populated by the system. Read-only. Null for lists. More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#metadata + name: Age + type: date + group: certmanager.k8s.io + versions: + - name: v1alpha1 + served: true + storage: true + names: + kind: Order + plural: orders + scope: Namespaced +--- +apiVersion: apiextensions.k8s.io/v1beta1 +kind: CustomResourceDefinition +metadata: + name: challenges.certmanager.k8s.io + labels: + app: certmanager + chart: certmanager + heritage: Tiller + release: istio + annotations: + "helm.sh/resource-policy": keep +spec: + additionalPrinterColumns: + - JSONPath: .status.state + name: State + type: string + - JSONPath: .spec.dnsName + name: Domain + type: string + - JSONPath: .status.reason + name: Reason + type: string + - JSONPath: .metadata.creationTimestamp + description: |- + CreationTimestamp is a timestamp representing the server time when this object was created. It is not guaranteed to be set in happens-before order across separate operations. Clients may not set this value. It is represented in RFC3339 form and is in UTC. + + Populated by the system. Read-only. Null for lists. More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#metadata + name: Age + type: date + group: certmanager.k8s.io + versions: + - name: v1alpha1 + served: true + storage: true + names: + kind: Challenge + plural: challenges + scope: Namespaced +--- +kind: CustomResourceDefinition +apiVersion: apiextensions.k8s.io/v1beta1 +metadata: + name: adapters.config.istio.io + labels: + app: mixer + package: adapter + istio: mixer-adapter + chart: istio + heritage: Tiller + release: istio + annotations: + "helm.sh/resource-policy": keep +spec: + group: config.istio.io + names: + kind: adapter + plural: adapters + singular: adapter + categories: + - istio-io + - policy-istio-io + scope: Namespaced + subresources: + status: {} + versions: + - name: v1alpha2 + served: true + storage: true +--- +kind: CustomResourceDefinition +apiVersion: apiextensions.k8s.io/v1beta1 +metadata: + name: templates.config.istio.io + labels: + app: mixer + package: template + istio: mixer-template + chart: istio + heritage: Tiller + release: istio + annotations: + "helm.sh/resource-policy": keep +spec: + group: config.istio.io + names: + kind: template + plural: templates + singular: template + categories: + - istio-io + - policy-istio-io + scope: Namespaced + subresources: + status: {} + versions: + - name: v1alpha2 + served: true + storage: true +--- +# Source: istio/charts/galley/templates/poddisruptionbudget.yaml + +apiVersion: policy/v1beta1 +kind: PodDisruptionBudget +metadata: + name: istio-galley + namespace: istio-system + labels: + app: galley + chart: galley + heritage: Tiller + release: istio + istio: galley +spec: + + minAvailable: 1 + selector: + matchLabels: + app: galley + release: istio + istio: galley + +--- +# Source: istio/charts/gateways/templates/poddisruptionbudget.yaml + +apiVersion: policy/v1beta1 +kind: PodDisruptionBudget +metadata: + name: istio-egressgateway + namespace: istio-system + labels: + chart: gateways + heritage: Tiller + release: istio + app: istio-egressgateway + istio: egressgateway +spec: + + minAvailable: 1 + selector: + matchLabels: + release: istio + app: istio-egressgateway + istio: egressgateway +--- +apiVersion: policy/v1beta1 +kind: PodDisruptionBudget +metadata: + name: istio-ingressgateway + namespace: istio-system + labels: + chart: gateways + heritage: Tiller + release: istio + app: istio-ingressgateway + istio: ingressgateway +spec: + + minAvailable: 1 + selector: + matchLabels: + release: istio + app: istio-ingressgateway + istio: ingressgateway +--- + +--- +# Source: istio/charts/mixer/templates/poddisruptionbudget.yaml + +apiVersion: policy/v1beta1 +kind: PodDisruptionBudget +metadata: + name: istio-policy + namespace: istio-system + labels: + app: policy + chart: mixer + heritage: Tiller + release: istio + version: 1.5.0 + istio: mixer + istio-mixer-type: policy +spec: + + minAvailable: 1 + selector: + matchLabels: + app: policy + release: istio + istio: mixer + istio-mixer-type: policy +--- +apiVersion: policy/v1beta1 +kind: PodDisruptionBudget +metadata: + name: istio-telemetry + namespace: istio-system + labels: + app: telemetry + chart: mixer + heritage: Tiller + release: istio + version: 1.5.0 + istio: mixer + istio-mixer-type: telemetry +spec: + + minAvailable: 1 + selector: + matchLabels: + app: telemetry + release: istio + istio: mixer + istio-mixer-type: telemetry +--- + +--- +# Source: istio/charts/pilot/templates/poddisruptionbudget.yaml + +apiVersion: policy/v1beta1 +kind: PodDisruptionBudget +metadata: + name: istio-pilot + namespace: istio-system + labels: + app: pilot + chart: pilot + heritage: Tiller + release: istio + istio: pilot +spec: + + minAvailable: 1 + selector: + matchLabels: + app: pilot + release: istio + istio: pilot + +--- +# Source: istio/charts/security/templates/poddisruptionbudget.yaml + +apiVersion: policy/v1beta1 +kind: PodDisruptionBudget +metadata: + name: istio-citadel + namespace: istio-system + labels: + app: security + chart: security + heritage: Tiller + release: istio + istio: citadel +spec: + + minAvailable: 1 + selector: + matchLabels: + app: security + release: istio + istio: citadel + +--- +# Source: istio/charts/sidecarInjectorWebhook/templates/poddisruptionbudget.yaml + +apiVersion: policy/v1beta1 +kind: PodDisruptionBudget +metadata: + name: istio-sidecar-injector + namespace: istio-system + labels: + app: sidecarInjectorWebhook + release: istio + istio: sidecar-injector +spec: + + minAvailable: 1 + selector: + matchLabels: + app: sidecarInjectorWebhook + release: istio + istio: sidecar-injector + +--- +# Source: istio/charts/kiali/templates/demosecret.yaml + +apiVersion: v1 +kind: Secret +metadata: + name: kiali + namespace: istio-system + labels: + app: kiali + chart: kiali + heritage: Tiller + release: istio +type: Opaque +data: + username: YWRtaW4= # admin + passphrase: YWRtaW4= # admin + +--- +# Source: istio/charts/galley/templates/configmap.yaml +apiVersion: v1 +kind: ConfigMap +metadata: + name: istio-galley-configuration + namespace: istio-system + labels: + app: galley + chart: galley + heritage: Tiller + release: istio + istio: galley +data: + validatingwebhookconfiguration.yaml: |- + apiVersion: admissionregistration.k8s.io/v1beta1 + kind: ValidatingWebhookConfiguration + metadata: + name: istio-galley + labels: + app: galley + chart: galley + heritage: Tiller + release: istio + istio: galley + webhooks: + - name: pilot.validation.istio.io + clientConfig: + service: + name: istio-galley + namespace: istio-system + path: "/admitpilot" + caBundle: "" + rules: + - operations: + - CREATE + - UPDATE + apiGroups: + - config.istio.io + apiVersions: + - v1alpha2 + resources: + - httpapispecs + - httpapispecbindings + - quotaspecs + - quotaspecbindings + - operations: + - CREATE + - UPDATE + apiGroups: + - rbac.istio.io + apiVersions: + - "*" + resources: + - "*" + - operations: + - CREATE + - UPDATE + apiGroups: + - security.istio.io + apiVersions: + - "*" + resources: + - "*" + - operations: + - CREATE + - UPDATE + apiGroups: + - authentication.istio.io + apiVersions: + - "*" + resources: + - "*" + - operations: + - CREATE + - UPDATE + apiGroups: + - networking.istio.io + apiVersions: + - "*" + resources: + - destinationrules + - envoyfilters + - gateways + - serviceentries + - sidecars + - virtualservices + # Fail open until the validation webhook is ready. The webhook controller + # will update this to `Fail` and patch in the `caBundle` when the webhook + # endpoint is ready. + failurePolicy: Ignore + sideEffects: None + - name: mixer.validation.istio.io + clientConfig: + service: + name: istio-galley + namespace: istio-system + path: "/admitmixer" + caBundle: "" + rules: + - operations: + - CREATE + - UPDATE + apiGroups: + - config.istio.io + apiVersions: + - v1alpha2 + resources: + - rules + - attributemanifests + - adapters + - handlers + - instances + - templates + # Fail open until the validation webhook is ready. The webhook controller + # will update this to `Fail` and patch in the `caBundle` when the webhook + # endpoint is ready. + failurePolicy: Ignore + sideEffects: None + +--- +# Source: istio/charts/grafana/templates/configmap-custom-resources.yaml +apiVersion: v1 +kind: ConfigMap +metadata: + name: istio-grafana-custom-resources + namespace: istio-system + labels: + app: grafana + chart: grafana + heritage: Tiller + release: istio + istio: grafana +data: + custom-resources.yaml: |- + apiVersion: authentication.istio.io/v1alpha1 + kind: Policy + metadata: + name: grafana-ports-mtls-disabled + namespace: istio-system + labels: + app: grafana + chart: grafana + heritage: Tiller + release: istio + spec: + targets: + - name: grafana + ports: + - number: 3000 + run.sh: |- + #!/bin/sh + + set -x + + if [ "$#" -ne "1" ]; then + echo "first argument should be path to custom resource yaml" + exit 1 + fi + + pathToResourceYAML=${1} + + kubectl get validatingwebhookconfiguration istio-galley 2>/dev/null + if [ "$?" -eq 0 ]; then + echo "istio-galley validatingwebhookconfiguration found - waiting for istio-galley deployment to be ready" + while true; do + kubectl -n istio-system get deployment istio-galley 2>/dev/null + if [ "$?" -eq 0 ]; then + break + fi + sleep 1 + done + kubectl -n istio-system rollout status deployment istio-galley + if [ "$?" -ne 0 ]; then + echo "istio-galley deployment rollout status check failed" + exit 1 + fi + echo "istio-galley deployment ready for configuration validation" + fi + sleep 5 + kubectl apply -f ${pathToResourceYAML} + + +--- +# Source: istio/charts/grafana/templates/configmap-dashboards.yaml + +apiVersion: v1 +kind: ConfigMap +metadata: + name: istio-grafana-configuration-dashboards-citadel-dashboard + namespace: istio-system + labels: + app: grafana + chart: grafana + heritage: Tiller + release: istio + istio: grafana +data: + citadel-dashboard.json: '{ + "annotations": { + "list": [ + { + "builtIn": 1, + "datasource": "-- Grafana --", + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations & Alerts", + "type": "dashboard" + } + ] + }, + "description": "", + "editable": true, + "gnetId": null, + "graphTooltip": 0, + "links": [], + "panels": [ + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 0 + }, + "id": 8, + "panels": [], + "title": "Performance", + "type": "row" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "description": "CPU usage across Citadel instances.", + "fill": 1, + "gridPos": { + "h": 6, + "w": 8, + "x": 0, + "y": 1 + }, + "id": 10, + "legend": { + "alignAsTable": false, + "avg": false, + "current": false, + "max": false, + "min": false, + "rightSide": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(rate(container_cpu_usage_seconds_total{job=\"kubernetes-cadvisor\",container=~\"citadel\", pod=~\"istio-citadel-.*\"}[1m]))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Citadel CPU usage rate", + "refId": "A" + }, + { + "expr": "irate(process_cpu_seconds_total{job=\"citadel\"}[1m])", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Citadel CPU usage irate", + "refId": "C" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "CPU", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": "", + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "description": "Citadel process memory statistics.", + "fill": 1, + "gridPos": { + "h": 6, + "w": 8, + "x": 8, + "y": 1 + }, + "id": 12, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "process_virtual_memory_bytes{job=\"citadel\"}", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Virtual Memory", + "refId": "A" + }, + { + "expr": "process_resident_memory_bytes{job=\"citadel\"}", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Resident Memory", + "refId": "B" + }, + { + "expr": "go_memstats_heap_sys_bytes{job=\"citadel\"}", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Heap Memory Total", + "refId": "C" + }, + { + "expr": "go_memstats_alloc_bytes{job=\"citadel\"}", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Heap Memory Allocated", + "refId": "E" + }, + { + "expr": "go_memstats_heap_inuse_bytes{job=\"citadel\"}", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Heap Inuse", + "refId": "F" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Memory", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "fill": 1, + "gridPos": { + "h": 6, + "w": 8, + "x": 16, + "y": 1 + }, + "id": 14, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "go_goroutines{job=\"citadel\"}", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Goroutines", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Goroutines", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 7 + }, + "id": 28, + "panels": [], + "title": "General", + "type": "row" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "description": "Total number of CSR requests made to Citadel.", + "fill": 1, + "gridPos": { + "h": 5, + "w": 12, + "x": 0, + "y": 8 + }, + "id": 30, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "citadel_server_csr_count{job=\"citadel\"}", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "CSR Request Count", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "CSR Requests", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "description": "The number of certificates issuances that have succeeded.", + "fill": 1, + "gridPos": { + "h": 5, + "w": 12, + "x": 12, + "y": 8 + }, + "id": 32, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "citadel_server_success_cert_issuance_count{job=\"citadel\"}", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Certificates Issued", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Certificates Issued", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 13 + }, + "id": 23, + "panels": [], + "title": "Errors", + "type": "row" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "description": "The number of errors occurred when creating the CSR.", + "fill": 1, + "gridPos": { + "h": 5, + "w": 8, + "x": 0, + "y": 14 + }, + "id": 20, + "legend": { + "alignAsTable": false, + "avg": false, + "current": false, + "max": false, + "min": false, + "rightSide": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "citadel_secret_controller_csr_err_count{job=\"citadel\"}", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "CSR Creation Error Count", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "CSR Creation Errors", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": "", + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "fill": 1, + "gridPos": { + "h": 5, + "w": 8, + "x": 8, + "y": 14 + }, + "id": 24, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "citadel_server_csr_parsing_err_count{job=\"citadel\"}", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "CSR Parse Error Count", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "CSR Parse Errors", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "description": "The number of authentication failures.", + "fill": 1, + "gridPos": { + "h": 5, + "w": 8, + "x": 16, + "y": 14 + }, + "id": 26, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "citadel_server_authentication_failure_count{job=\"citadel\"}", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Authentication Failure Count", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Authentication Failures", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 19 + }, + "id": 4, + "panels": [], + "title": "Secret Controller", + "type": "row" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "description": "The number of certificates created due to service account creation.", + "fill": 1, + "gridPos": { + "h": 5, + "w": 8, + "x": 0, + "y": 20 + }, + "id": 2, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": true, + "targets": [ + { + "expr": "citadel_secret_controller_svc_acc_created_cert_count{job=\"citadel\"}", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "SA Secrets Created", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Service Account Secrets Created (due to SA creation)", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "decimals": null, + "format": "short", + "label": "Certs Created", + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "description": "The number of certificates deleted due to service account deletion.", + "fill": 1, + "gridPos": { + "h": 5, + "w": 8, + "x": 8, + "y": 20 + }, + "id": 16, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": true, + "targets": [ + { + "expr": "citadel_secret_controller_svc_acc_deleted_cert_count{job=\"citadel\"}", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "SA Secrets Deleted", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Service Account Secrets Deleted (due to SA deletion)", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "decimals": null, + "format": "short", + "label": "Certs Created", + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "description": "The number of certificates recreated due to secret deletion (service account still exists).", + "fill": 1, + "gridPos": { + "h": 5, + "w": 8, + "x": 16, + "y": 20 + }, + "id": 6, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": true, + "targets": [ + { + "expr": "citadel_secret_controller_secret_deleted_cert_count{job=\"citadel\"}", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "SA Secrets Recreated", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Service Account Secrets Recreated (due to errant deletion)", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "decimals": null, + "format": "short", + "label": "Certs Created", + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + } + ], + "refresh": "5s", + "schemaVersion": 18, + "style": "dark", + "tags": [], + "templating": { + "list": [] + }, + "time": { + "from": "now-5m", + "to": "now" + }, + "timepicker": { + "refresh_intervals": [ + "5s", + "10s", + "30s", + "1m", + "5m", + "15m", + "30m", + "1h", + "2h", + "1d" + ], + "time_options": [ + "5m", + "15m", + "1h", + "6h", + "12h", + "24h", + "2d", + "7d", + "30d" + ] + }, + "timezone": "", + "title": "Istio Citadel Dashboard", + "uid": "OOyOqb4Wz", + "version": 1 +}' +--- +apiVersion: v1 +kind: ConfigMap +metadata: + name: istio-grafana-configuration-dashboards-galley-dashboard + namespace: istio-system + labels: + app: grafana + chart: grafana + heritage: Tiller + release: istio + istio: grafana +data: + galley-dashboard.json: '{ + "__inputs": [ + { + "name": "DS_PROMETHEUS", + "label": "Prometheus", + "description": "", + "type": "datasource", + "pluginId": "prometheus", + "pluginName": "Prometheus" + } + ], + "annotations": { + "list": [ + { + "builtIn": 1, + "datasource": "-- Grafana --", + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations & Alerts", + "type": "dashboard" + } + ] + }, + "editable": false, + "gnetId": null, + "graphTooltip": 0, + "links": [], + "panels": [ + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 5, + "w": 24, + "x": 0, + "y": 0 + }, + "id": 46, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(istio_build{component=\"galley\"}) by (tag)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{ tag }}", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Galley Versions", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 5 + }, + "id": 40, + "panels": [], + "title": "Resource Usage", + "type": "row" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 8, + "w": 6, + "x": 0, + "y": 6 + }, + "id": 36, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "process_virtual_memory_bytes{job=\"galley\"}", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "Virtual Memory", + "refId": "A" + }, + { + "expr": "process_resident_memory_bytes{job=\"galley\"}", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "Resident Memory", + "refId": "B" + }, + { + "expr": "go_memstats_heap_sys_bytes{job=\"galley\"}", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "heap sys", + "refId": "C" + }, + { + "expr": "go_memstats_heap_alloc_bytes{job=\"galley\"}", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "heap alloc", + "refId": "D" + }, + { + "expr": "go_memstats_alloc_bytes{job=\"galley\"}", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "Alloc", + "refId": "F" + }, + { + "expr": "go_memstats_heap_inuse_bytes{job=\"galley\"}", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "Heap in-use", + "refId": "G" + }, + { + "expr": "go_memstats_stack_inuse_bytes{job=\"galley\"}", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "Stack in-use", + "refId": "H" + }, + { + "expr": "sum(container_memory_usage_bytes{job=\"kubernetes-cadvisor\",container=~\"galley\", pod=~\"istio-galley-.*\"})", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Total (kis)", + "refId": "E" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Memory", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 8, + "w": 6, + "x": 6, + "y": 6 + }, + "id": 38, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(rate(container_cpu_usage_seconds_total{job=\"kubernetes-cadvisor\",container=~\"galley\", pod=~\"istio-galley-.*\"}[1m]))", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "Total (k8s)", + "refId": "A" + }, + { + "expr": "sum(rate(container_cpu_usage_seconds_total{job=\"kubernetes-cadvisor\",container=~\"galley\", pod=~\"istio-galley-.*\"}[1m])) by (container)", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "{{ container }} (k8s)", + "refId": "B" + }, + { + "expr": "irate(process_cpu_seconds_total{job=\"galley\"}[1m])", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "galley (self-reported)", + "refId": "C" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "CPU", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 8, + "w": 6, + "x": 12, + "y": 6 + }, + "id": 42, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "process_open_fds{job=\"galley\"}", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "Open FDs (galley)", + "refId": "A" + }, + { + "expr": "container_fs_usage_bytes{job=\"kubernetes-cadvisor\",container=~\"galley\", pod=~\"istio-galley-.*\"}", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "{{ container }} ", + "refId": "B" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Disk", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 8, + "w": 6, + "x": 18, + "y": 6 + }, + "id": 44, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "go_goroutines{job=\"galley\"}", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "goroutines_total", + "refId": "A" + }, + { + "expr": "istio_mcp_clients_total{component=\"galley\"}", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "clients_total", + "refId": "B" + }, + { + "expr": "go_goroutines{job=\"galley\"}/sum(istio_mcp_clients_total{component=\"galley\"}) without (component)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "avg_goroutines_per_client", + "refId": "C" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Goroutines", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 14 + }, + "id": 10, + "panels": [], + "title": "Runtime", + "type": "row" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 6, + "w": 8, + "x": 0, + "y": 15 + }, + "id": 2, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(rate(galley_runtime_strategy_on_change_total[1m])) * 60", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Strategy Change Events", + "refId": "A" + }, + { + "expr": "sum(rate(galley_runtime_processor_events_processed_total[1m])) * 60", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Processed Events", + "refId": "B" + }, + { + "expr": "sum(rate(galley_runtime_processor_snapshots_published_total[1m])) * 60", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Snapshot Published", + "refId": "C" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Event Rates", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": "Events/min", + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": "", + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 6, + "w": 8, + "x": 8, + "y": 15 + }, + "id": 4, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(rate(galley_runtime_strategy_timer_max_time_reached_total[1m])) * 60", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Max Time Reached", + "refId": "A" + }, + { + "expr": "sum(rate(galley_runtime_strategy_timer_quiesce_reached_total[1m])) * 60", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Quiesce Reached", + "refId": "B" + }, + { + "expr": "sum(rate(galley_runtime_strategy_timer_resets_total[1m])) * 60", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Timer Resets", + "refId": "C" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Timer Rates", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": "Events/min", + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 6, + "w": 8, + "x": 16, + "y": 15 + }, + "id": 8, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 3, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": true, + "steppedLine": false, + "targets": [ + { + "expr": "histogram_quantile(0.50, sum by (le) (galley_runtime_processor_snapshot_events_total_bucket))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "P50", + "refId": "A" + }, + { + "expr": "histogram_quantile(0.90, sum by (le) (galley_runtime_processor_snapshot_events_total_bucket))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "P90", + "refId": "B" + }, + { + "expr": "histogram_quantile(0.95, sum by (le) (galley_runtime_processor_snapshot_events_total_bucket))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "P95", + "refId": "C" + }, + { + "expr": "histogram_quantile(0.99, sum by (le) (galley_runtime_processor_snapshot_events_total_bucket))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "P99", + "refId": "D" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Events Per Snapshot", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 6, + "w": 8, + "x": 8, + "y": 21 + }, + "id": 6, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum by (collection) (galley_runtime_state_type_instances_total)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{ collection }}", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "State Type Instances", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": "Count", + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 27 + }, + "id": 34, + "panels": [], + "title": "Validation", + "type": "row" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 6, + "w": 8, + "x": 0, + "y": 28 + }, + "id": 28, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "galley_validation_cert_key_updates{job=\"galley\"}", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Key Updates", + "refId": "A" + }, + { + "expr": "galley_validation_cert_key_update_errors{job=\"galley\"}", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Key Update Errors: {{ error }}", + "refId": "B" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Validation Webhook Certificate", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 6, + "w": 8, + "x": 8, + "y": 28 + }, + "id": 30, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(galley_validation_passed{job=\"galley\"}) by (group, version, resource)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Passed: {{ group }}/{{ version }}/{{resource}}", + "refId": "A" + }, + { + "expr": "sum(galley_validation_failed{job=\"galley\"}) by (group, version, resource, reason)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Failed: {{ group }}/{{ version }}/{{resource}} ({{ reason}})", + "refId": "B" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Resource Validation", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 6, + "w": 8, + "x": 16, + "y": 28 + }, + "id": 32, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(galley_validation_http_error{job=\"galley\"}) by (status)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{ status }}", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Validation HTTP Errors", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 34 + }, + "id": 12, + "panels": [], + "title": "Kubernetes Source", + "type": "row" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 6, + "w": 8, + "x": 0, + "y": 35 + }, + "id": 14, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "rate(galley_source_kube_event_success_total[1m]) * 60", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Success", + "refId": "A" + }, + { + "expr": "rate(galley_source_kube_event_error_total[1m]) * 60", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Error", + "refId": "B" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Source Event Rate", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": "Events/min", + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 6, + "w": 8, + "x": 16, + "y": 35 + }, + "id": 24, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "rate(galley_source_kube_dynamic_converter_failure_total[1m]) * 60", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Error", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Kubernetes Object Conversion Failures", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": "Failures/min", + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 41 + }, + "id": 18, + "panels": [], + "title": "Mesh Configuration Protocol", + "type": "row" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 6, + "w": 8, + "x": 0, + "y": 42 + }, + "id": 20, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(istio_mcp_clients_total{component=\"galley\"})", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Clients", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Connected Clients", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 6, + "w": 8, + "x": 8, + "y": 42 + }, + "id": 22, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum by(collection)(irate(istio_mcp_request_acks_total{component=\"galley\"}[1m]) * 60)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Request ACKs", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": "ACKs/min", + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 6, + "w": 8, + "x": 16, + "y": 42 + }, + "id": 26, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "rate(istio_mcp_request_nacks_total{component=\"galley\"}[1m]) * 60", + "format": "time_series", + "intervalFactor": 1, + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Request NACKs", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": "NACKs/min", + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + } + ], + "refresh": "5s", + "schemaVersion": 16, + "style": "dark", + "tags": [], + "templating": { + "list": [] + }, + "time": { + "from": "now-5m", + "to": "now" + }, + "timepicker": { + "refresh_intervals": [ + "5s", + "10s", + "30s", + "1m", + "5m", + "15m", + "30m", + "1h", + "2h", + "1d" + ], + "time_options": [ + "5m", + "15m", + "1h", + "6h", + "12h", + "24h", + "2d", + "7d", + "30d" + ] + }, + "timezone": "", + "title": "Istio Galley Dashboard", + "uid": "TSEY6jLmk", + "version": 1 +} +' +--- +apiVersion: v1 +kind: ConfigMap +metadata: + name: istio-grafana-configuration-dashboards-istio-mesh-dashboard + namespace: istio-system + labels: + app: grafana + chart: grafana + heritage: Tiller + release: istio + istio: grafana +data: + istio-mesh-dashboard.json: '{ + "annotations": { + "list": [ + { + "builtIn": 1, + "datasource": "-- Grafana --", + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations & Alerts", + "type": "dashboard" + } + ] + }, + "editable": false, + "gnetId": null, + "graphTooltip": 0, + "id": null, + "links": [], + "panels": [ + { + "content": "
\n
\n Istio\n
\n
\n Istio is an open platform that provides a uniform way to connect,\n manage, and \n secure microservices.\n
\n Need help? Join the Istio community.\n
\n
", + "gridPos": { + "h": 3, + "w": 24, + "x": 0, + "y": 0 + }, + "height": "50px", + "id": 13, + "links": [], + "mode": "html", + "style": { + "font-size": "18pt" + }, + "title": "", + "transparent": true, + "type": "text" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "datasource": "Prometheus", + "format": "ops", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "gridPos": { + "h": 3, + "w": 6, + "x": 0, + "y": 3 + }, + "id": 20, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": true, + "lineColor": "rgb(31, 120, 193)", + "show": true + }, + "tableColumn": "", + "targets": [ + { + "expr": "round(sum(irate(istio_requests_total{reporter=\"destination\"}[1m])), 0.001)", + "intervalFactor": 1, + "refId": "A", + "step": 4 + } + ], + "thresholds": "", + "title": "Global Request Volume", + "type": "singlestat", + "valueFontSize": "80%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "avg" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "datasource": "Prometheus", + "format": "percentunit", + "gauge": { + "maxValue": 100, + "minValue": 80, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": false + }, + "gridPos": { + "h": 3, + "w": 6, + "x": 6, + "y": 3 + }, + "id": 21, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": true, + "lineColor": "rgb(31, 120, 193)", + "show": true + }, + "tableColumn": "", + "targets": [ + { + "expr": "sum(rate(istio_requests_total{reporter=\"destination\", response_code!~\"5.*\"}[1m])) / sum(rate(istio_requests_total{reporter=\"destination\"}[1m]))", + "format": "time_series", + "intervalFactor": 1, + "refId": "A", + "step": 4 + } + ], + "thresholds": "95, 99, 99.5", + "title": "Global Success Rate (non-5xx responses)", + "type": "singlestat", + "valueFontSize": "80%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "avg" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "datasource": "Prometheus", + "format": "ops", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "gridPos": { + "h": 3, + "w": 6, + "x": 12, + "y": 3 + }, + "id": 22, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": true, + "lineColor": "rgb(31, 120, 193)", + "show": true + }, + "tableColumn": "", + "targets": [ + { + "expr": "sum(irate(istio_requests_total{reporter=\"destination\", response_code=~\"4.*\"}[1m])) ", + "format": "time_series", + "intervalFactor": 1, + "refId": "A", + "step": 4 + } + ], + "thresholds": "", + "title": "4xxs", + "type": "singlestat", + "valueFontSize": "80%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "avg" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "datasource": "Prometheus", + "format": "ops", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "gridPos": { + "h": 3, + "w": 6, + "x": 18, + "y": 3 + }, + "id": 23, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": true, + "lineColor": "rgb(31, 120, 193)", + "show": true + }, + "tableColumn": "", + "targets": [ + { + "expr": "sum(irate(istio_requests_total{reporter=\"destination\", response_code=~\"5.*\"}[1m])) ", + "format": "time_series", + "intervalFactor": 1, + "refId": "A", + "step": 4 + } + ], + "thresholds": "", + "title": "5xxs", + "type": "singlestat", + "valueFontSize": "80%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "avg" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "#299c46", + "rgba(237, 129, 40, 0.89)", + "#d44a3a" + ], + "format": "none", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "gridPos": { + "h": 3, + "w": 6, + "x": 0, + "y": 6 + }, + "id": 113, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": false, + "lineColor": "rgb(31, 120, 193)", + "show": true + }, + "tableColumn": "", + "targets": [ + { + "expr": "sum(galley_istio_networking_virtualservices) / count(up{job=\"galley\"})", + "format": "time_series", + "intervalFactor": 1, + "refId": "A" + } + ], + "thresholds": "", + "timeFrom": null, + "timeShift": null, + "title": "Virtual Services", + "type": "singlestat", + "valueFontSize": "80%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "current" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "#299c46", + "rgba(237, 129, 40, 0.89)", + "#d44a3a" + ], + "format": "none", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "gridPos": { + "h": 3, + "w": 6, + "x": 6, + "y": 6 + }, + "id": 114, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": false, + "lineColor": "rgb(31, 120, 193)", + "show": true + }, + "tableColumn": "", + "targets": [ + { + "expr": "sum(galley_istio_networking_destinationrules) / count(up{job=\"galley\"})", + "format": "time_series", + "intervalFactor": 1, + "refId": "A" + } + ], + "thresholds": "", + "timeFrom": null, + "timeShift": null, + "title": "Destination Rules", + "type": "singlestat", + "valueFontSize": "80%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "current" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "#299c46", + "rgba(237, 129, 40, 0.89)", + "#d44a3a" + ], + "format": "none", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "gridPos": { + "h": 3, + "w": 6, + "x": 12, + "y": 6 + }, + "id": 115, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": false, + "lineColor": "rgb(31, 120, 193)", + "show": true + }, + "tableColumn": "", + "targets": [ + { + "expr": "sum(galley_istio_networking_gateways) / count(up{job=\"galley\"})", + "format": "time_series", + "intervalFactor": 1, + "refId": "A" + } + ], + "thresholds": "", + "timeFrom": null, + "timeShift": null, + "title": "Gateways", + "type": "singlestat", + "valueFontSize": "80%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "current" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "#299c46", + "rgba(237, 129, 40, 0.89)", + "#d44a3a" + ], + "format": "none", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "gridPos": { + "h": 3, + "w": 6, + "x": 18, + "y": 6 + }, + "id": 116, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": false, + "lineColor": "rgb(31, 120, 193)", + "show": true + }, + "tableColumn": "", + "targets": [ + { + "expr": "sum(galley_istio_authentication_meshpolicies) / count(up{job=\"galley\"})", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "refId": "A" + } + ], + "thresholds": "", + "timeFrom": null, + "timeShift": null, + "title": "Authentication Mesh Policies", + "type": "singlestat", + "valueFontSize": "80%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "current" + }, + { + "columns": [], + "datasource": "Prometheus", + "fontSize": "100%", + "gridPos": { + "h": 21, + "w": 24, + "x": 0, + "y": 9 + }, + "hideTimeOverride": false, + "id": 73, + "links": [], + "pageSize": null, + "repeat": null, + "repeatDirection": "v", + "scroll": true, + "showHeader": true, + "sort": { + "col": 4, + "desc": true + }, + "styles": [ + { + "alias": "Workload", + "colorMode": null, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "link": false, + "linkTargetBlank": false, + "linkTooltip": "Workload dashboard", + "linkUrl": "/dashboard/db/istio-workload-dashboard?var-namespace=$__cell_2&var-workload=$__cell_", + "pattern": "destination_workload", + "preserveFormat": false, + "sanitize": false, + "thresholds": [], + "type": "hidden", + "unit": "short" + }, + { + "alias": "", + "colorMode": null, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "pattern": "Time", + "thresholds": [], + "type": "hidden", + "unit": "short" + }, + { + "alias": "Requests", + "colorMode": null, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "pattern": "Value #A", + "thresholds": [], + "type": "number", + "unit": "ops" + }, + { + "alias": "P50 Latency", + "colorMode": null, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "pattern": "Value #B", + "thresholds": [], + "type": "number", + "unit": "s" + }, + { + "alias": "P90 Latency", + "colorMode": null, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "pattern": "Value #D", + "thresholds": [], + "type": "number", + "unit": "s" + }, + { + "alias": "P99 Latency", + "colorMode": null, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "pattern": "Value #E", + "thresholds": [], + "type": "number", + "unit": "s" + }, + { + "alias": "Success Rate", + "colorMode": "cell", + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "pattern": "Value #F", + "thresholds": [ + ".95", + " 1.00" + ], + "type": "number", + "unit": "percentunit" + }, + { + "alias": "Workload", + "colorMode": null, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "link": true, + "linkTooltip": "$__cell dashboard", + "linkUrl": "/dashboard/db/istio-workload-dashboard?var-workload=$__cell_2&var-namespace=$__cell_3", + "pattern": "destination_workload_var", + "thresholds": [], + "type": "number", + "unit": "short" + }, + { + "alias": "Service", + "colorMode": null, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "link": true, + "linkTooltip": "$__cell dashboard", + "linkUrl": "/dashboard/db/istio-service-dashboard?var-service=$__cell", + "pattern": "destination_service", + "thresholds": [], + "type": "string", + "unit": "short" + }, + { + "alias": "", + "colorMode": null, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "pattern": "destination_workload_namespace", + "thresholds": [], + "type": "hidden", + "unit": "short" + } + ], + "targets": [ + { + "expr": "label_join(sum(rate(istio_requests_total{reporter=\"destination\", response_code=\"200\"}[1m])) by (destination_workload, destination_workload_namespace, destination_service), \"destination_workload_var\", \".\", \"destination_workload\", \"destination_workload_namespace\")", + "format": "table", + "hide": false, + "instant": true, + "intervalFactor": 1, + "legendFormat": "{{ destination_workload}}.{{ destination_workload_namespace }}", + "refId": "A" + }, + { + "expr": "label_join((histogram_quantile(0.50, sum(rate(istio_request_duration_milliseconds_bucket{reporter=\"destination\"}[1m])) by (le, destination_workload, destination_workload_namespace)) / 1000) or histogram_quantile(0.50, sum(rate(istio_request_duration_seconds_bucket{reporter=\"destination\"}[1m])) by (le, destination_workload, destination_workload_namespace)), \"destination_workload_var\", \".\", \"destination_workload\", \"destination_workload_namespace\")", + "format": "table", + "hide": false, + "instant": true, + "intervalFactor": 1, + "legendFormat": "{{ destination_workload}}.{{ destination_workload_namespace }}", + "refId": "B" + }, + { + "expr": "label_join((histogram_quantile(0.90, sum(rate(istio_request_duration_milliseconds_bucket{reporter=\"destination\"}[1m])) by (le, destination_workload, destination_workload_namespace)) / 1000) or histogram_quantile(0.90, sum(rate(istio_request_duration_seconds_bucket{reporter=\"destination\"}[1m])) by (le, destination_workload, destination_workload_namespace)), \"destination_workload_var\", \".\", \"destination_workload\", \"destination_workload_namespace\")", + "format": "table", + "hide": false, + "instant": true, + "intervalFactor": 1, + "legendFormat": "{{ destination_workload }}.{{ destination_workload_namespace }}", + "refId": "D" + }, + { + "expr": "label_join((histogram_quantile(0.99, sum(rate(istio_request_duration_milliseconds_bucket{reporter=\"destination\"}[1m])) by (le, destination_workload, destination_workload_namespace)) / 1000) or histogram_quantile(0.99, sum(rate(istio_request_duration_seconds_bucket{reporter=\"destination\"}[1m])) by (le, destination_workload, destination_workload_namespace)), \"destination_workload_var\", \".\", \"destination_workload\", \"destination_workload_namespace\")", + "format": "table", + "hide": false, + "instant": true, + "intervalFactor": 1, + "legendFormat": "{{ destination_workload }}.{{ destination_workload_namespace }}", + "refId": "E" + }, + { + "expr": "label_join((sum(rate(istio_requests_total{reporter=\"destination\", response_code!~\"5.*\"}[1m])) by (destination_workload, destination_workload_namespace) / sum(rate(istio_requests_total{reporter=\"destination\"}[1m])) by (destination_workload, destination_workload_namespace)), \"destination_workload_var\", \".\", \"destination_workload\", \"destination_workload_namespace\")", + "format": "table", + "hide": false, + "instant": true, + "interval": "", + "intervalFactor": 1, + "legendFormat": "{{ destination_workload }}.{{ destination_workload_namespace }}", + "refId": "F" + } + ], + "timeFrom": null, + "title": "HTTP/GRPC Workloads", + "transform": "table", + "type": "table" + }, + { + "columns": [], + "datasource": "Prometheus", + "fontSize": "100%", + "gridPos": { + "h": 18, + "w": 24, + "x": 0, + "y": 30 + }, + "hideTimeOverride": false, + "id": 109, + "links": [], + "pageSize": null, + "repeatDirection": "v", + "scroll": true, + "showHeader": true, + "sort": { + "col": 2, + "desc": true + }, + "styles": [ + { + "alias": "Workload", + "colorMode": null, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "link": false, + "linkTargetBlank": false, + "linkTooltip": "$__cell dashboard", + "linkUrl": "/dashboard/db/istio-tcp-workload-dashboard?var-namespace=$__cell_2&&var-workload=$__cell", + "pattern": "destination_workload", + "preserveFormat": false, + "sanitize": false, + "thresholds": [], + "type": "hidden", + "unit": "short" + }, + { + "alias": "Bytes Sent", + "colorMode": null, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "pattern": "Value #A", + "thresholds": [ + "" + ], + "type": "number", + "unit": "Bps" + }, + { + "alias": "Bytes Received", + "colorMode": null, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "pattern": "Value #C", + "thresholds": [], + "type": "number", + "unit": "Bps" + }, + { + "alias": "", + "colorMode": null, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "pattern": "Time", + "thresholds": [], + "type": "hidden", + "unit": "short" + }, + { + "alias": "Workload", + "colorMode": null, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "link": true, + "linkTooltip": "$__cell dashboard", + "linkUrl": "/dashboard/db/istio-workload-dashboard?var-namespace=$__cell_3&var-workload=$__cell_2", + "pattern": "destination_workload_var", + "thresholds": [], + "type": "string", + "unit": "short" + }, + { + "alias": "", + "colorMode": null, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "pattern": "destination_workload_namespace", + "thresholds": [], + "type": "hidden", + "unit": "short" + }, + { + "alias": "Service", + "colorMode": null, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "link": true, + "linkTooltip": "$__cell dashboard", + "linkUrl": "/dashboard/db/istio-service-dashboard?var-service=$__cell", + "pattern": "destination_service", + "thresholds": [], + "type": "number", + "unit": "short" + } + ], + "targets": [ + { + "expr": "label_join(sum(rate(istio_tcp_received_bytes_total{reporter=\"source\"}[1m])) by (destination_workload, destination_workload_namespace, destination_service), \"destination_workload_var\", \".\", \"destination_workload\", \"destination_workload_namespace\")", + "format": "table", + "hide": false, + "instant": true, + "intervalFactor": 1, + "legendFormat": "{{ destination_workload }}", + "refId": "C" + }, + { + "expr": "label_join(sum(rate(istio_tcp_sent_bytes_total{reporter=\"source\"}[1m])) by (destination_workload, destination_workload_namespace, destination_service), \"destination_workload_var\", \".\", \"destination_workload\", \"destination_workload_namespace\")", + "format": "table", + "hide": false, + "instant": true, + "intervalFactor": 1, + "legendFormat": "{{ destination_workload }}", + "refId": "A" + } + ], + "timeFrom": null, + "title": "TCP Workloads", + "transform": "table", + "type": "table" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 9, + "w": 24, + "x": 0, + "y": 48 + }, + "id": 111, + "legend": { + "alignAsTable": false, + "avg": false, + "current": false, + "max": false, + "min": false, + "rightSide": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(istio_build) by (component, tag)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{ component }}: {{ tag }}", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Istio Components by Version", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + } + ], + "refresh": "5s", + "schemaVersion": 18, + "style": "dark", + "tags": [], + "templating": { + "list": [] + }, + "time": { + "from": "now-5m", + "to": "now" + }, + "timepicker": { + "refresh_intervals": [ + "5s", + "10s", + "30s", + "1m", + "5m", + "15m", + "30m", + "1h", + "2h", + "1d" + ], + "time_options": [ + "5m", + "15m", + "1h", + "6h", + "12h", + "24h", + "2d", + "7d", + "30d" + ] + }, + "timezone": "browser", + "title": "Istio Mesh Dashboard", + "uid": "G8wLrJIZk", + "version": 5 +} +' +--- +apiVersion: v1 +kind: ConfigMap +metadata: + name: istio-grafana-configuration-dashboards-istio-performance-dashboard + namespace: istio-system + labels: + app: grafana + chart: grafana + heritage: Tiller + release: istio + istio: grafana +data: + istio-performance-dashboard.json: '{ + "annotations": { + "list": [ + { + "builtIn": 1, + "datasource": "-- Grafana --", + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations & Alerts", + "type": "dashboard" + } + ] + }, + "editable": false, + "gnetId": null, + "graphTooltip": 0, + "id": 9, + "links": [], + "panels": [ + { + "collapsed": true, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 0 + }, + "id": 21, + "panels": [ + { + "content": "The charts on this dashboard are intended to show Istio main components cost in terms resources utilization under steady load.\n\n- **vCPU/1k rps:** shows vCPU utilization by the main Istio components normalized by 1000 requests/second. When idle or low traffic, this chart will be blank. The curve for istio-proxy refers to the services sidecars only.\n- **vCPU:** vCPU utilization by Istio components, not normalized.\n- **Memory:** memory footprint for the components. Telemetry and policy are normalized by 1k rps, and no data is shown when there is no traffic. For ingress and istio-proxy, the data is per instance.\n- **Bytes transferred/ sec:** shows the number of bytes flowing through each Istio component.\n\n\n", + "gridPos": { + "h": 6, + "w": 24, + "x": 0, + "y": 1 + }, + "id": 19, + "links": [], + "mode": "markdown", + "timeFrom": null, + "timeShift": null, + "title": "Performance Dashboard README", + "transparent": true, + "type": "text" + } + ], + "title": "Performance Dashboard Notes", + "type": "row" + }, + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 1 + }, + "id": 6, + "panels": [], + "title": "vCPU Usage", + "type": "row" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "fill": 1, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 2 + }, + "id": 4, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "(sum(irate(container_cpu_usage_seconds_total{job=\"kubernetes-cadvisor\",pod=~\"istio-telemetry-.*\",container=~\"mixer|istio-proxy\"}[1m]))/ (round(sum(irate(istio_requests_total[1m])), 0.001)/1000))/ (sum(irate(istio_requests_total{source_workload=\"istio-ingressgateway\"}[1m])) >bool 10)", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "istio-telemetry", + "refId": "A" + }, + { + "expr": "(sum(irate(container_cpu_usage_seconds_total{job=\"kubernetes-cadvisor\",pod=~\"istio-ingressgateway-.*\",container=\"istio-proxy\"}[1m])) / (round(sum(irate(istio_requests_total{source_workload=\"istio-ingressgateway\", reporter=\"source\"}[1m])), 0.001)/1000))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "istio-ingressgateway", + "refId": "B" + }, + { + "expr": "(sum(irate(container_cpu_usage_seconds_total{job=\"kubernetes-cadvisor\",namespace!=\"istio-system\",container=\"istio-proxy\"}[1m]))/ (round(sum(irate(istio_requests_total[1m])), 0.001)/1000))/ (sum(irate(istio_requests_total{source_workload=\"istio-ingressgateway\"}[1m])) >bool 10)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "istio-proxy", + "refId": "C" + }, + { + "expr": "(sum(irate(container_cpu_usage_seconds_total{job=\"kubernetes-cadvisor\",pod=~\"istio-policy-.*\",container=~\"mixer|istio-proxy\"}[1m]))/ (round(sum(irate(istio_requests_total[1m])), 0.001)/1000))/ (sum(irate(istio_requests_total{source_workload=\"istio-ingressgateway\"}[1m])) >bool 10)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "istio-policy", + "refId": "D" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "vCPU / 1k rps", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "fill": 1, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 2 + }, + "id": 7, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(rate(container_cpu_usage_seconds_total{job=\"kubernetes-cadvisor\",pod=~\"istio-telemetry-.*\",container=~\"mixer|istio-proxy\"}[1m]))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "istio-telemetry", + "refId": "A" + }, + { + "expr": "sum(rate(container_cpu_usage_seconds_total{job=\"kubernetes-cadvisor\",pod=~\"istio-ingressgateway-.*\",container=\"istio-proxy\"}[1m]))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "istio-ingressgateway", + "refId": "B" + }, + { + "expr": "sum(rate(container_cpu_usage_seconds_total{job=\"kubernetes-cadvisor\",namespace!=\"istio-system\",container=\"istio-proxy\"}[1m]))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "istio-proxy", + "refId": "C" + }, + { + "expr": "sum(rate(container_cpu_usage_seconds_total{job=\"kubernetes-cadvisor\",pod=~\"istio-policy-.*\",container=~\"mixer|istio-proxy\"}[1m]))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "istio-policy", + "refId": "D" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "vCPU", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 10 + }, + "id": 13, + "panels": [], + "title": "Memory and Data Rates", + "type": "row" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "fill": 1, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 11 + }, + "id": 902, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "(sum(container_memory_usage_bytes{job=\"kubernetes-cadvisor\",pod=~\"istio-telemetry-.*\"}) / (sum(irate(istio_requests_total[1m])) / 1000)) / (sum(irate(istio_requests_total{source_workload=\"istio-ingressgateway\"}[1m])) >bool 10)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "istio-telemetry / 1k rps", + "refId": "A" + }, + { + "expr": "sum(container_memory_usage_bytes{job=\"kubernetes-cadvisor\",pod=~\"istio-ingressgateway-.*\"}) / count(container_memory_usage_bytes{job=\"kubernetes-cadvisor\",pod=~\"istio-ingressgateway-.*\",container!=\"POD\"})", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "per istio-ingressgateway", + "refId": "B" + }, + { + "expr": "sum(container_memory_usage_bytes{job=\"kubernetes-cadvisor\",namespace!=\"istio-system\",container=\"istio-proxy\"}) / count(container_memory_usage_bytes{job=\"kubernetes-cadvisor\",namespace!=\"istio-system\",container=\"istio-proxy\"})", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "per istio proxy", + "refId": "C" + }, + { + "expr": "(sum(container_memory_usage_bytes{job=\"kubernetes-cadvisor\",pod=~\"istio-policy-.*\"}) / (sum(irate(istio_requests_total[1m])) / 1000))/ (sum(irate(istio_requests_total{source_workload=\"istio-ingressgateway\"}[1m])) >bool 10)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "istio-policy / 1k rps", + "refId": "D" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Memory Usage", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "bytes", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "fill": 1, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 11 + }, + "id": 11, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(irate(istio_response_bytes_sum{destination_workload=\"istio-telemetry\"}[1m])) + sum(irate(istio_request_bytes_sum{destination_workload=\"istio-telemetry\"}[1m]))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "istio-telemetry", + "refId": "A" + }, + { + "expr": "sum(irate(istio_response_bytes_sum{source_workload=\"istio-ingressgateway\", reporter=\"source\"}[1m]))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "istio-ingressgateway", + "refId": "B" + }, + { + "expr": "sum(irate(istio_response_bytes_sum{source_workload_namespace!=\"istio-system\", reporter=\"source\"}[1m])) + sum(irate(istio_response_bytes_sum{destination_workload_namespace!=\"istio-system\", reporter=\"destination\"}[1m])) + sum(irate(istio_request_bytes_sum{source_workload_namespace!=\"istio-system\", reporter=\"source\"}[1m])) + sum(irate(istio_request_bytes_sum{destination_workload_namespace!=\"istio-system\", reporter=\"destination\"}[1m]))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "istio-proxy", + "refId": "C" + }, + { + "expr": "sum(irate(istio_response_bytes_sum{destination_workload=\"istio-policy\"}[1m])) + sum(irate(istio_request_bytes_sum{destination_workload=\"istio-policy\"}[1m]))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "istio_policy", + "refId": "D" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Bytes transferred / sec", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "Bps", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 19 + }, + "id": 17, + "panels": [], + "title": "Istio Component Versions", + "type": "row" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "fill": 1, + "gridPos": { + "h": 8, + "w": 24, + "x": 0, + "y": 20 + }, + "id": 15, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(istio_build) by (component, tag)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{ component }}: {{ tag }}", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Istio Components by Version", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 31 + }, + "id": 71, + "panels": [], + "title": "Proxy Resource Usage", + "type": "row" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 7, + "w": 6, + "x": 0, + "y": 32 + }, + "id": 72, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(container_memory_usage_bytes{job=\"kubernetes-cadvisor\",container=\"istio-proxy\"})", + "format": "time_series", + "hide": false, + "intervalFactor": 2, + "legendFormat": "{{ container }} (k8s)", + "refId": "B", + "step": 2 + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Memory", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "bytes", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 7, + "w": 6, + "x": 6, + "y": 32 + }, + "id": 73, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(rate(container_cpu_usage_seconds_total{job=\"kubernetes-cadvisor\",container=\"istio-proxy\"}[1m]))", + "format": "time_series", + "hide": false, + "intervalFactor": 2, + "legendFormat": "Total (k8s)", + "refId": "A", + "step": 2 + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "vCPU", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 7, + "w": 6, + "x": 12, + "y": 32 + }, + "id": 702, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(container_fs_usage_bytes{job=\"kubernetes-cadvisor\", container=\"istio-proxy\"})", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "{{ container }}", + "refId": "B", + "step": 2 + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Disk", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "bytes", + "label": "", + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "decimals": null, + "format": "none", + "label": "", + "logBase": 1024, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 39 + }, + "id": 69, + "panels": [], + "title": "Pilot Resource Usage", + "type": "row" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 7, + "w": 6, + "x": 0, + "y": 40 + }, + "id": 5, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "process_virtual_memory_bytes{job=\"pilot\"}", + "format": "time_series", + "instant": false, + "intervalFactor": 2, + "legendFormat": "Virtual Memory", + "refId": "I", + "step": 2 + }, + { + "expr": "process_resident_memory_bytes{job=\"pilot\"}", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "Resident Memory", + "refId": "H", + "step": 2 + }, + { + "expr": "go_memstats_heap_sys_bytes{job=\"pilot\"}", + "format": "time_series", + "hide": true, + "intervalFactor": 2, + "legendFormat": "heap sys", + "refId": "A" + }, + { + "expr": "go_memstats_heap_alloc_bytes{job=\"pilot\"}", + "format": "time_series", + "hide": true, + "intervalFactor": 2, + "legendFormat": "heap alloc", + "refId": "D" + }, + { + "expr": "go_memstats_alloc_bytes{job=\"pilot\"}", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "Alloc", + "refId": "F", + "step": 2 + }, + { + "expr": "go_memstats_heap_inuse_bytes{job=\"pilot\"}", + "format": "time_series", + "hide": false, + "intervalFactor": 2, + "legendFormat": "Heap in-use", + "refId": "E", + "step": 2 + }, + { + "expr": "go_memstats_stack_inuse_bytes{job=\"pilot\"}", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "Stack in-use", + "refId": "G", + "step": 2 + }, + { + "expr": "sum(container_memory_usage_bytes{job=\"kubernetes-cadvisor\",container=~\"discovery|istio-proxy\", pod=~\"istio-pilot-.*\"})", + "format": "time_series", + "hide": false, + "intervalFactor": 2, + "legendFormat": "Total (k8s)", + "refId": "C", + "step": 2 + }, + { + "expr": "container_memory_usage_bytes{job=\"kubernetes-cadvisor\",container=~\"discovery|istio-proxy\", pod=~\"istio-pilot-.*\"}", + "format": "time_series", + "hide": false, + "intervalFactor": 2, + "legendFormat": "{{ container }} (k8s)", + "refId": "B", + "step": 2 + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Memory", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "bytes", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 7, + "w": 6, + "x": 6, + "y": 40 + }, + "id": 602, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(rate(container_cpu_usage_seconds_total{job=\"kubernetes-cadvisor\",container=~\"discovery|istio-proxy\", pod=~\"istio-pilot-.*\"}[1m]))", + "format": "time_series", + "hide": false, + "intervalFactor": 2, + "legendFormat": "Total (k8s)", + "refId": "A", + "step": 2 + }, + { + "expr": "sum(rate(container_cpu_usage_seconds_total{job=\"kubernetes-cadvisor\",container=~\"discovery|istio-proxy\", pod=~\"istio-pilot-.*\"}[1m])) by (container)", + "format": "time_series", + "hide": false, + "intervalFactor": 2, + "legendFormat": "{{ container }} (k8s)", + "refId": "B", + "step": 2 + }, + { + "expr": "irate(process_cpu_seconds_total{job=\"pilot\"}[1m])", + "format": "time_series", + "hide": false, + "intervalFactor": 2, + "legendFormat": "pilot (self-reported)", + "refId": "C", + "step": 2 + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "vCPU", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 7, + "w": 6, + "x": 12, + "y": 40 + }, + "id": 74, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "process_open_fds{job=\"pilot\"}", + "format": "time_series", + "hide": true, + "instant": false, + "interval": "", + "intervalFactor": 2, + "legendFormat": "Open FDs (pilot)", + "refId": "A" + }, + { + "expr": "container_fs_usage_bytes{job=\"kubernetes-cadvisor\", container=~\"discovery|istio-proxy\", pod=~\"istio-pilot-.*\"}", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "{{ container }}", + "refId": "B", + "step": 2 + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Disk", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "bytes", + "label": "", + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "decimals": null, + "format": "none", + "label": "", + "logBase": 1024, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 7, + "w": 6, + "x": 18, + "y": 40 + }, + "id": 402, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": false, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "go_goroutines{job=\"pilot\"}", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "Number of Goroutines", + "refId": "A", + "step": 2 + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Goroutines", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": "", + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 47 + }, + "id": 93, + "panels": [], + "title": "Mixer Resource Usage", + "type": "row" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 7, + "w": 6, + "x": 0, + "y": 48 + }, + "id": 94, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "process_virtual_memory_bytes{job=~\"istio-telemetry|istio-policy\"}", + "format": "time_series", + "instant": false, + "intervalFactor": 2, + "legendFormat": "Virtual Memory", + "refId": "I", + "step": 2 + }, + { + "expr": "process_resident_memory_bytes{job=~\"istio-telemetry|istio-policy\"}", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "Resident Memory", + "refId": "H", + "step": 2 + }, + { + "expr": "go_memstats_heap_sys_bytes{job=~\"istio-telemetry|istio-policy\"}", + "format": "time_series", + "hide": true, + "intervalFactor": 2, + "legendFormat": "heap sys", + "refId": "A" + }, + { + "expr": "go_memstats_heap_alloc_bytes{job=~\"istio-telemetry|istio-policy\"}", + "format": "time_series", + "hide": true, + "intervalFactor": 2, + "legendFormat": "heap alloc", + "refId": "D" + }, + { + "expr": "go_memstats_alloc_bytes{job=~\"istio-telemetry|istio-policy\"}", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "Alloc", + "refId": "F", + "step": 2 + }, + { + "expr": "go_memstats_heap_inuse_bytes{job=~\"istio-telemetry|istio-policy\"}", + "format": "time_series", + "hide": false, + "intervalFactor": 2, + "legendFormat": "Heap in-use", + "refId": "E", + "step": 2 + }, + { + "expr": "go_memstats_stack_inuse_bytes{job=~\"istio-policy|istio-telemetry\"}", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "Stack in-use", + "refId": "G", + "step": 2 + }, + { + "expr": "sum(container_memory_usage_bytes{job=\"kubernetes-cadvisor\",container=~\"mixer|istio-proxy\", pod=~\"istio-telemetry-.*\"})", + "format": "time_series", + "hide": false, + "intervalFactor": 2, + "legendFormat": "Total (k8s)", + "refId": "C", + "step": 2 + }, + { + "expr": "container_memory_usage_bytes{job=\"kubernetes-cadvisor\",container=~\"mixer|istio-proxy\", pod=~\"istio-telemetry-.*\"}", + "format": "time_series", + "hide": false, + "intervalFactor": 2, + "legendFormat": "{{ container }} (k8s)", + "refId": "B", + "step": 2 + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Memory", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "bytes", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 7, + "w": 6, + "x": 6, + "y": 48 + }, + "id": 95, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(rate(container_cpu_usage_seconds_total{job=\"kubernetes-cadvisor\",container=~\"mixer|istio-proxy\", pod=~\"istio-telemetry-.*\"}[1m]))", + "format": "time_series", + "hide": false, + "intervalFactor": 2, + "legendFormat": "Total (k8s)", + "refId": "A", + "step": 2 + }, + { + "expr": "sum(rate(container_cpu_usage_seconds_total{job=\"kubernetes-cadvisor\",container=~\"mixer|istio-proxy\", pod=~\"istio-telemetry-.*\"}[1m])) by (container)", + "format": "time_series", + "hide": false, + "intervalFactor": 2, + "legendFormat": "{{ container }} (k8s)", + "refId": "B", + "step": 2 + }, + { + "expr": "irate(process_cpu_seconds_total{job=~\"istio-policy|istio-telemetry\"}[1m])", + "format": "time_series", + "hide": false, + "intervalFactor": 2, + "legendFormat": "mixer (self-reported)", + "refId": "C", + "step": 2 + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "vCPU", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 7, + "w": 6, + "x": 12, + "y": 48 + }, + "id": 96, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "process_open_fds{job=~\"istio-policy|istio-telemetry\"}", + "format": "time_series", + "hide": true, + "instant": false, + "interval": "", + "intervalFactor": 2, + "legendFormat": "Open FDs (pilot)", + "refId": "A" + }, + { + "expr": "container_fs_usage_bytes{job=\"kubernetes-cadvisor\", container=~\"mixer|istio-proxy\", pod=~\"istio-telemetry-.*\"}", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "{{ container }}", + "refId": "B", + "step": 2 + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Disk", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "bytes", + "label": "", + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "decimals": null, + "format": "none", + "label": "", + "logBase": 1024, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 7, + "w": 6, + "x": 18, + "y": 48 + }, + "id": 97, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": false, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "go_goroutines{job=\"istio-telemetry\"}", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "Number of Goroutines", + "refId": "A", + "step": 2 + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Goroutines", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": "", + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + } + ], + "refresh": "10s", + "schemaVersion": 18, + "style": "dark", + "tags": [], + "templating": { + "list": [] + }, + "time": { + "from": "now-5m", + "to": "now" + }, + "timepicker": { + "refresh_intervals": [ + "5s", + "10s", + "30s", + "1m", + "5m", + "15m", + "30m", + "1h", + "2h", + "1d" + ], + "time_options": [ + "5m", + "15m", + "1h", + "6h", + "12h", + "24h", + "2d", + "7d", + "30d" + ] + }, + "timezone": "", + "title": "Istio Performance Dashboard", + "uid": "vu8e0VWZk", + "version": 22 +} +' +--- +apiVersion: v1 +kind: ConfigMap +metadata: + name: istio-grafana-configuration-dashboards-istio-service-dashboard + namespace: istio-system + labels: + app: grafana + chart: grafana + heritage: Tiller + release: istio + istio: grafana +data: + istio-service-dashboard.json: '{ + "annotations": { + "list": [ + { + "builtIn": 1, + "datasource": "-- Grafana --", + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations & Alerts", + "type": "dashboard" + } + ] + }, + "editable": false, + "gnetId": null, + "graphTooltip": 0, + "iteration": 1536442501501, + "links": [], + "panels": [ + { + "content": "
\nSERVICE: $service\n
", + "gridPos": { + "h": 3, + "w": 24, + "x": 0, + "y": 0 + }, + "id": 89, + "links": [], + "mode": "html", + "title": "", + "transparent": true, + "type": "text" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "datasource": "Prometheus", + "format": "ops", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "gridPos": { + "h": 4, + "w": 6, + "x": 0, + "y": 3 + }, + "id": 12, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": true, + "lineColor": "rgb(31, 120, 193)", + "show": true + }, + "tableColumn": "", + "targets": [ + { + "expr": "round(sum(irate(istio_requests_total{reporter=\"source\",destination_service=~\"$service\"}[5m])), 0.001)", + "format": "time_series", + "intervalFactor": 1, + "refId": "A", + "step": 4 + } + ], + "thresholds": "", + "title": "Client Request Volume", + "transparent": false, + "type": "singlestat", + "valueFontSize": "80%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "current" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "rgba(50, 172, 45, 0.97)", + "rgba(237, 129, 40, 0.89)", + "rgba(245, 54, 54, 0.9)" + ], + "datasource": "Prometheus", + "decimals": null, + "format": "percentunit", + "gauge": { + "maxValue": 100, + "minValue": 80, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": false + }, + "gridPos": { + "h": 4, + "w": 6, + "x": 6, + "y": 3 + }, + "id": 14, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": true, + "lineColor": "rgb(31, 120, 193)", + "show": true + }, + "tableColumn": "", + "targets": [ + { + "expr": "sum(irate(istio_requests_total{reporter=\"source\",destination_service=~\"$service\",response_code!~\"5.*\"}[5m])) / sum(irate(istio_requests_total{reporter=\"source\",destination_service=~\"$service\"}[5m]))", + "format": "time_series", + "intervalFactor": 1, + "refId": "B" + } + ], + "thresholds": "95, 99, 99.5", + "title": "Client Success Rate (non-5xx responses)", + "transparent": false, + "type": "singlestat", + "valueFontSize": "80%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "avg" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 4, + "w": 6, + "x": 12, + "y": 3 + }, + "id": 87, + "legend": { + "alignAsTable": false, + "avg": false, + "current": false, + "hideEmpty": false, + "hideZero": false, + "max": false, + "min": false, + "rightSide": true, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "(histogram_quantile(0.50, sum(irate(istio_request_duration_milliseconds_bucket{reporter=\"source\",destination_service=~\"$service\"}[1m])) by (le)) / 1000) or histogram_quantile(0.50, sum(irate(istio_request_duration_seconds_bucket{reporter=\"source\",destination_service=~\"$service\"}[1m])) by (le))", + "format": "time_series", + "interval": "", + "intervalFactor": 1, + "legendFormat": "P50", + "refId": "A" + }, + { + "expr": "(histogram_quantile(0.90, sum(irate(istio_request_duration_milliseconds_bucket{reporter=\"source\",destination_service=~\"$service\"}[1m])) by (le)) / 1000) or histogram_quantile(0.90, sum(irate(istio_request_duration_seconds_bucket{reporter=\"source\",destination_service=~\"$service\"}[1m])) by (le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "P90", + "refId": "B" + }, + { + "expr": "(histogram_quantile(0.99, sum(irate(istio_request_duration_milliseconds_bucket{reporter=\"source\",destination_service=~\"$service\"}[1m])) by (le)) / 1000) or histogram_quantile(0.99, sum(irate(istio_request_duration_seconds_bucket{reporter=\"source\",destination_service=~\"$service\"}[1m])) by (le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "P99", + "refId": "C" + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Client Request Duration", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "s", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "#299c46", + "rgba(237, 129, 40, 0.89)", + "#d44a3a" + ], + "datasource": "Prometheus", + "format": "Bps", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "gridPos": { + "h": 4, + "w": 6, + "x": 18, + "y": 3 + }, + "id": 84, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": true, + "lineColor": "rgb(31, 120, 193)", + "show": true + }, + "tableColumn": "", + "targets": [ + { + "expr": "sum(irate(istio_tcp_received_bytes_total{reporter=\"source\", destination_service=~\"$service\"}[1m]))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "", + "refId": "A" + } + ], + "thresholds": "", + "title": "TCP Received Bytes", + "transparent": false, + "type": "singlestat", + "valueFontSize": "80%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "avg" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "datasource": "Prometheus", + "format": "ops", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "gridPos": { + "h": 4, + "w": 6, + "x": 0, + "y": 7 + }, + "id": 97, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": true, + "lineColor": "rgb(31, 120, 193)", + "show": true + }, + "tableColumn": "", + "targets": [ + { + "expr": "round(sum(irate(istio_requests_total{reporter=\"destination\",destination_service=~\"$service\"}[5m])), 0.001)", + "format": "time_series", + "intervalFactor": 1, + "refId": "A", + "step": 4 + } + ], + "thresholds": "", + "title": "Server Request Volume", + "transparent": false, + "type": "singlestat", + "valueFontSize": "80%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "current" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "rgba(50, 172, 45, 0.97)", + "rgba(237, 129, 40, 0.89)", + "rgba(245, 54, 54, 0.9)" + ], + "datasource": "Prometheus", + "decimals": null, + "format": "percentunit", + "gauge": { + "maxValue": 100, + "minValue": 80, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": false + }, + "gridPos": { + "h": 4, + "w": 6, + "x": 6, + "y": 7 + }, + "id": 98, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": true, + "lineColor": "rgb(31, 120, 193)", + "show": true + }, + "tableColumn": "", + "targets": [ + { + "expr": "sum(irate(istio_requests_total{reporter=\"destination\",destination_service=~\"$service\",response_code!~\"5.*\"}[5m])) / sum(irate(istio_requests_total{reporter=\"destination\",destination_service=~\"$service\"}[5m]))", + "format": "time_series", + "intervalFactor": 1, + "refId": "B" + } + ], + "thresholds": "95, 99, 99.5", + "title": "Server Success Rate (non-5xx responses)", + "transparent": false, + "type": "singlestat", + "valueFontSize": "80%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "avg" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 4, + "w": 6, + "x": 12, + "y": 7 + }, + "id": 99, + "legend": { + "alignAsTable": false, + "avg": false, + "current": false, + "hideEmpty": false, + "hideZero": false, + "max": false, + "min": false, + "rightSide": true, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "(histogram_quantile(0.50, sum(irate(istio_request_duration_milliseconds_bucket{reporter=\"destination\",destination_service=~\"$service\"}[1m])) by (le)) / 1000) or histogram_quantile(0.50, sum(irate(istio_request_duration_seconds_bucket{reporter=\"destination\",destination_service=~\"$service\"}[1m])) by (le))", + "format": "time_series", + "interval": "", + "intervalFactor": 1, + "legendFormat": "P50", + "refId": "A" + }, + { + "expr": "(histogram_quantile(0.90, sum(irate(istio_request_duration_milliseconds_bucket{reporter=\"destination\",destination_service=~\"$service\"}[1m])) by (le)) / 1000) or histogram_quantile(0.90, sum(irate(istio_request_duration_seconds_bucket{reporter=\"destination\",destination_service=~\"$service\"}[1m])) by (le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "P90", + "refId": "B" + }, + { + "expr": "(histogram_quantile(0.99, sum(irate(istio_request_duration_milliseconds_bucket{reporter=\"destination\",destination_service=~\"$service\"}[1m])) by (le)) / 1000) or histogram_quantile(0.99, sum(irate(istio_request_duration_seconds_bucket{reporter=\"destination\",destination_service=~\"$service\"}[1m])) by (le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "P99", + "refId": "C" + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Server Request Duration", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "s", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "#299c46", + "rgba(237, 129, 40, 0.89)", + "#d44a3a" + ], + "datasource": "Prometheus", + "format": "Bps", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "gridPos": { + "h": 4, + "w": 6, + "x": 18, + "y": 7 + }, + "id": 100, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": true, + "lineColor": "rgb(31, 120, 193)", + "show": true + }, + "tableColumn": "", + "targets": [ + { + "expr": "sum(irate(istio_tcp_sent_bytes_total{reporter=\"source\", destination_service=~\"$service\"}[1m])) ", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "", + "refId": "A" + } + ], + "thresholds": "", + "title": "TCP Sent Bytes", + "transparent": false, + "type": "singlestat", + "valueFontSize": "80%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "avg" + }, + { + "content": "
\nCLIENT WORKLOADS\n
", + "gridPos": { + "h": 3, + "w": 24, + "x": 0, + "y": 11 + }, + "id": 45, + "links": [], + "mode": "html", + "title": "", + "transparent": true, + "type": "text" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 0, + "gridPos": { + "h": 6, + "w": 12, + "x": 0, + "y": 14 + }, + "id": 25, + "legend": { + "avg": false, + "current": false, + "hideEmpty": true, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null as zero", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "round(sum(irate(istio_requests_total{connection_security_policy=\"mutual_tls\",destination_service=~\"$service\",reporter=\"source\",source_workload=~\"$srcwl\",source_workload_namespace=~\"$srcns\"}[5m])) by (source_workload, source_workload_namespace, response_code), 0.001)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{ source_workload }}.{{ source_workload_namespace }} : {{ response_code }} (🔐mTLS)", + "refId": "B", + "step": 2 + }, + { + "expr": "round(sum(irate(istio_requests_total{connection_security_policy!=\"mutual_tls\", destination_service=~\"$service\", reporter=\"source\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[5m])) by (source_workload, source_workload_namespace, response_code), 0.001)", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ source_workload }}.{{ source_workload_namespace }} : {{ response_code }}", + "refId": "A", + "step": 2 + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Incoming Requests by Source And Response Code", + "tooltip": { + "shared": false, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [ + "total" + ] + }, + "yaxes": [ + { + "format": "ops", + "label": null, + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 6, + "w": 12, + "x": 12, + "y": 14 + }, + "id": 26, + "legend": { + "avg": false, + "current": false, + "hideEmpty": true, + "hideZero": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(irate(istio_requests_total{reporter=\"source\", connection_security_policy=\"mutual_tls\", destination_service=~\"$service\",response_code!~\"5.*\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[5m])) by (source_workload, source_workload_namespace) / sum(irate(istio_requests_total{reporter=\"source\", connection_security_policy=\"mutual_tls\", destination_service=~\"$service\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[5m])) by (source_workload, source_workload_namespace)", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ source_workload }}.{{ source_workload_namespace }} (🔐mTLS)", + "refId": "A", + "step": 2 + }, + { + "expr": "sum(irate(istio_requests_total{reporter=\"source\", connection_security_policy!=\"mutual_tls\", destination_service=~\"$service\",response_code!~\"5.*\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[5m])) by (source_workload, source_workload_namespace) / sum(irate(istio_requests_total{reporter=\"source\", connection_security_policy!=\"mutual_tls\", destination_service=~\"$service\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[5m])) by (source_workload, source_workload_namespace)", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ source_workload }}.{{ source_workload_namespace }}", + "refId": "B", + "step": 2 + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Incoming Success Rate (non-5xx responses) By Source", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "percentunit", + "label": null, + "logBase": 1, + "max": "1.01", + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "description": "", + "fill": 1, + "gridPos": { + "h": 6, + "w": 8, + "x": 0, + "y": 20 + }, + "id": 27, + "legend": { + "alignAsTable": false, + "avg": false, + "current": false, + "hideEmpty": true, + "hideZero": false, + "max": false, + "min": false, + "rightSide": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "(histogram_quantile(0.50, sum(irate(istio_request_duration_milliseconds_bucket{reporter=\"source\", connection_security_policy=\"mutual_tls\", destination_service=~\"$service\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le)) / 1000) or histogram_quantile(0.50, sum(irate(istio_request_duration_seconds_bucket{reporter=\"source\", connection_security_policy=\"mutual_tls\", destination_service=~\"$service\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{source_workload}}.{{source_workload_namespace}} P50 (🔐mTLS)", + "refId": "D", + "step": 2 + }, + { + "expr": "(histogram_quantile(0.90, sum(irate(istio_request_duration_milliseconds_bucket{reporter=\"source\", connection_security_policy=\"mutual_tls\", destination_service=~\"$service\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le)) / 1000) or histogram_quantile(0.90, sum(irate(istio_request_duration_seconds_bucket{reporter=\"source\", connection_security_policy=\"mutual_tls\", destination_service=~\"$service\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{source_workload}}.{{source_workload_namespace}} P90 (🔐mTLS)", + "refId": "A", + "step": 2 + }, + { + "expr": "(histogram_quantile(0.95, sum(irate(istio_request_duration_milliseconds_bucket{reporter=\"source\", connection_security_policy=\"mutual_tls\", destination_service=~\"$service\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le)) / 1000) or histogram_quantile(0.95, sum(irate(istio_request_duration_seconds_bucket{reporter=\"source\", connection_security_policy=\"mutual_tls\", destination_service=~\"$service\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{source_workload}}.{{source_workload_namespace}} P95 (🔐mTLS)", + "refId": "B", + "step": 2 + }, + { + "expr": "(histogram_quantile(0.99, sum(irate(istio_request_duration_milliseconds_bucket{reporter=\"source\", connection_security_policy=\"mutual_tls\", destination_service=~\"$service\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le)) / 1000) or histogram_quantile(0.99, sum(irate(istio_request_duration_seconds_bucket{reporter=\"source\", connection_security_policy=\"mutual_tls\", destination_service=~\"$service\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{source_workload}}.{{source_workload_namespace}} P99 (🔐mTLS)", + "refId": "C", + "step": 2 + }, + { + "expr": "(histogram_quantile(0.50, sum(irate(istio_request_duration_milliseconds_bucket{reporter=\"source\", connection_security_policy!=\"mutual_tls\", destination_service=~\"$service\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le)) / 1000) or histogram_quantile(0.50, sum(irate(istio_request_duration_seconds_bucket{reporter=\"source\", connection_security_policy!=\"mutual_tls\", destination_service=~\"$service\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{source_workload}}.{{source_workload_namespace}} P50", + "refId": "E", + "step": 2 + }, + { + "expr": "(histogram_quantile(0.90, sum(irate(istio_request_duration_milliseconds_bucket{reporter=\"source\", connection_security_policy!=\"mutual_tls\", destination_service=~\"$service\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le)) / 1000) or histogram_quantile(0.90, sum(irate(istio_request_duration_seconds_bucket{reporter=\"source\", connection_security_policy!=\"mutual_tls\", destination_service=~\"$service\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{source_workload}}.{{source_workload_namespace}} P90", + "refId": "F", + "step": 2 + }, + { + "expr": "(histogram_quantile(0.95, sum(irate(istio_request_duration_milliseconds_bucket{reporter=\"source\", connection_security_policy!=\"mutual_tls\", destination_service=~\"$service\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le)) / 1000) or histogram_quantile(0.95, sum(irate(istio_request_duration_seconds_bucket{reporter=\"source\", connection_security_policy!=\"mutual_tls\", destination_service=~\"$service\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{source_workload}}.{{source_workload_namespace}} P95", + "refId": "G", + "step": 2 + }, + { + "expr": "(histogram_quantile(0.99, sum(irate(istio_request_duration_milliseconds_bucket{reporter=\"source\", connection_security_policy!=\"mutual_tls\", destination_service=~\"$service\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le)) / 1000) or histogram_quantile(0.99, sum(irate(istio_request_duration_seconds_bucket{reporter=\"source\", connection_security_policy!=\"mutual_tls\", destination_service=~\"$service\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{source_workload}}.{{source_workload_namespace}} P99", + "refId": "H", + "step": 2 + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Incoming Request Duration by Source", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "s", + "label": null, + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 6, + "w": 8, + "x": 8, + "y": 20 + }, + "id": 28, + "legend": { + "alignAsTable": false, + "avg": false, + "current": false, + "hideEmpty": true, + "max": false, + "min": false, + "rightSide": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "histogram_quantile(0.50, sum(irate(istio_request_bytes_bucket{reporter=\"source\", connection_security_policy=\"mutual_tls\", destination_service=~\"$service\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{source_workload}}.{{source_workload_namespace}} P50 (🔐mTLS)", + "refId": "D", + "step": 2 + }, + { + "expr": "histogram_quantile(0.90, sum(irate(istio_request_bytes_bucket{reporter=\"source\", connection_security_policy=\"mutual_tls\", destination_service=~\"$service\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{source_workload}}.{{source_workload_namespace}} P90 (🔐mTLS)", + "refId": "A", + "step": 2 + }, + { + "expr": "histogram_quantile(0.95, sum(irate(istio_request_bytes_bucket{reporter=\"source\", connection_security_policy=\"mutual_tls\", destination_service=~\"$service\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{source_workload}}.{{source_workload_namespace}} P95 (🔐mTLS)", + "refId": "B", + "step": 2 + }, + { + "expr": "histogram_quantile(0.99, sum(irate(istio_request_bytes_bucket{reporter=\"source\", connection_security_policy=\"mutual_tls\", destination_service=~\"$service\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{source_workload}}.{{source_workload_namespace}} P99 (🔐mTLS)", + "refId": "C", + "step": 2 + }, + { + "expr": "histogram_quantile(0.50, sum(irate(istio_request_bytes_bucket{reporter=\"source\", connection_security_policy!=\"mutual_tls\", destination_service=~\"$service\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{source_workload}}.{{source_workload_namespace}} P50", + "refId": "E", + "step": 2 + }, + { + "expr": "histogram_quantile(0.90, sum(irate(istio_request_bytes_bucket{reporter=\"source\", connection_security_policy!=\"mutual_tls\", destination_service=~\"$service\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{source_workload}}.{{source_workload_namespace}} P90", + "refId": "F", + "step": 2 + }, + { + "expr": "histogram_quantile(0.95, sum(irate(istio_request_bytes_bucket{reporter=\"source\", connection_security_policy!=\"mutual_tls\", destination_service=~\"$service\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{source_workload}}.{{source_workload_namespace}} P95", + "refId": "G", + "step": 2 + }, + { + "expr": "histogram_quantile(0.99, sum(irate(istio_request_bytes_bucket{reporter=\"source\", connection_security_policy!=\"mutual_tls\", destination_service=~\"$service\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{source_workload}}.{{source_workload_namespace}} P99", + "refId": "H", + "step": 2 + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Incoming Request Size By Source", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "decbytes", + "label": null, + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 6, + "w": 8, + "x": 16, + "y": 20 + }, + "id": 68, + "legend": { + "alignAsTable": false, + "avg": false, + "current": false, + "hideEmpty": true, + "max": false, + "min": false, + "rightSide": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "histogram_quantile(0.50, sum(irate(istio_response_bytes_bucket{reporter=\"source\", connection_security_policy=\"mutual_tls\", destination_service=~\"$service\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{source_workload}}.{{source_workload_namespace}} P50 (🔐mTLS)", + "refId": "D", + "step": 2 + }, + { + "expr": "histogram_quantile(0.90, sum(irate(istio_response_bytes_bucket{reporter=\"source\", connection_security_policy=\"mutual_tls\", destination_service=~\"$service\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{source_workload}}.{{source_workload_namespace}} P90 (🔐mTLS)", + "refId": "A", + "step": 2 + }, + { + "expr": "histogram_quantile(0.95, sum(irate(istio_response_bytes_bucket{reporter=\"source\", connection_security_policy=\"mutual_tls\", destination_service=~\"$service\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{source_workload}}.{{source_workload_namespace}} P95 (🔐mTLS)", + "refId": "B", + "step": 2 + }, + { + "expr": "histogram_quantile(0.99, sum(irate(istio_response_bytes_bucket{reporter=\"source\", connection_security_policy=\"mutual_tls\", destination_service=~\"$service\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{source_workload}}.{{source_workload_namespace}} P99 (🔐mTLS)", + "refId": "C", + "step": 2 + }, + { + "expr": "histogram_quantile(0.50, sum(irate(istio_response_bytes_bucket{reporter=\"source\", connection_security_policy!=\"mutual_tls\", destination_service=~\"$service\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{source_workload}}.{{source_workload_namespace}} P50", + "refId": "E", + "step": 2 + }, + { + "expr": "histogram_quantile(0.90, sum(irate(istio_response_bytes_bucket{reporter=\"source\", connection_security_policy!=\"mutual_tls\", destination_service=~\"$service\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{source_workload}}.{{source_workload_namespace}} P90", + "refId": "F", + "step": 2 + }, + { + "expr": "histogram_quantile(0.95, sum(irate(istio_response_bytes_bucket{reporter=\"source\", connection_security_policy!=\"mutual_tls\", destination_service=~\"$service\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{source_workload}}.{{source_workload_namespace}} P95", + "refId": "G", + "step": 2 + }, + { + "expr": "histogram_quantile(0.99, sum(irate(istio_response_bytes_bucket{reporter=\"source\", connection_security_policy!=\"mutual_tls\", destination_service=~\"$service\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{source_workload}}.{{source_workload_namespace}} P99", + "refId": "H", + "step": 2 + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Response Size By Source", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "decbytes", + "label": null, + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 6, + "w": 12, + "x": 0, + "y": 26 + }, + "id": 80, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "round(sum(irate(istio_tcp_received_bytes_total{reporter=\"source\", connection_security_policy=\"mutual_tls\", destination_service=~\"$service\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace), 0.001)", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ source_workload }}.{{ source_workload_namespace}} (🔐mTLS)", + "refId": "A", + "step": 2 + }, + { + "expr": "round(sum(irate(istio_tcp_received_bytes_total{reporter=\"source\", connection_security_policy!=\"mutual_tls\", destination_service=~\"$service\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace), 0.001)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{ source_workload }}.{{ source_workload_namespace}}", + "refId": "B", + "step": 2 + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Bytes Received from Incoming TCP Connection", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "Bps", + "label": null, + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 6, + "w": 12, + "x": 12, + "y": 26 + }, + "id": 82, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "round(sum(irate(istio_tcp_sent_bytes_total{connection_security_policy=\"mutual_tls\", reporter=\"source\", destination_service=~\"$service\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace), 0.001)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{ source_workload }}.{{ source_workload_namespace}} (🔐mTLS)", + "refId": "A", + "step": 2 + }, + { + "expr": "round(sum(irate(istio_tcp_sent_bytes_total{connection_security_policy!=\"mutual_tls\", reporter=\"source\", destination_service=~\"$service\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace), 0.001)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{ source_workload }}.{{ source_workload_namespace}}", + "refId": "B", + "step": 2 + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Bytes Sent to Incoming TCP Connection", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "Bps", + "label": null, + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "content": "
\nSERVICE WORKLOADS\n
", + "gridPos": { + "h": 3, + "w": 24, + "x": 0, + "y": 32 + }, + "id": 69, + "links": [], + "mode": "html", + "title": "", + "transparent": true, + "type": "text" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 0, + "gridPos": { + "h": 6, + "w": 12, + "x": 0, + "y": 35 + }, + "id": 90, + "legend": { + "avg": false, + "current": false, + "hideEmpty": true, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null as zero", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "round(sum(irate(istio_requests_total{connection_security_policy=\"mutual_tls\",destination_service=~\"$service\",reporter=\"destination\",destination_workload=~\"$dstwl\",destination_workload_namespace=~\"$dstns\"}[5m])) by (destination_workload, destination_workload_namespace, response_code), 0.001)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{ destination_workload }}.{{ destination_workload_namespace }} : {{ response_code }} (🔐mTLS)", + "refId": "B", + "step": 2 + }, + { + "expr": "round(sum(irate(istio_requests_total{connection_security_policy!=\"mutual_tls\", destination_service=~\"$service\", reporter=\"destination\", destination_workload=~\"$dstwl\", destination_workload_namespace=~\"$dstns\"}[5m])) by (destination_workload, destination_workload_namespace, response_code), 0.001)", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_workload }}.{{ destination_workload_namespace }} : {{ response_code }}", + "refId": "A", + "step": 2 + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Incoming Requests by Destination And Response Code", + "tooltip": { + "shared": false, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [ + "total" + ] + }, + "yaxes": [ + { + "format": "ops", + "label": null, + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 6, + "w": 12, + "x": 12, + "y": 35 + }, + "id": 91, + "legend": { + "avg": false, + "current": false, + "hideEmpty": true, + "hideZero": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(irate(istio_requests_total{reporter=\"destination\", connection_security_policy=\"mutual_tls\", destination_service=~\"$service\",response_code!~\"5.*\", destination_workload=~\"$dstwl\", destination_workload_namespace=~\"$dstns\"}[5m])) by (destination_workload, destination_workload_namespace) / sum(irate(istio_requests_total{reporter=\"destination\", connection_security_policy=\"mutual_tls\", destination_service=~\"$service\", destination_workload=~\"$dstwl\", destination_workload_namespace=~\"$dstns\"}[5m])) by (destination_workload, destination_workload_namespace)", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_workload }}.{{ destination_workload_namespace }} (🔐mTLS)", + "refId": "A", + "step": 2 + }, + { + "expr": "sum(irate(istio_requests_total{reporter=\"destination\", connection_security_policy!=\"mutual_tls\", destination_service=~\"$service\",response_code!~\"5.*\", destination_workload=~\"$dstwl\", destination_workload_namespace=~\"$dstns\"}[5m])) by (destination_workload, destination_workload_namespace) / sum(irate(istio_requests_total{reporter=\"destination\", connection_security_policy!=\"mutual_tls\", destination_service=~\"$service\", destination_workload=~\"$dstwl\", destination_workload_namespace=~\"$dstns\"}[5m])) by (destination_workload, destination_workload_namespace)", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_workload }}.{{ destination_workload_namespace }}", + "refId": "B", + "step": 2 + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Incoming Success Rate (non-5xx responses) By Source", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "percentunit", + "label": null, + "logBase": 1, + "max": "1.01", + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "description": "", + "fill": 1, + "gridPos": { + "h": 6, + "w": 8, + "x": 0, + "y": 41 + }, + "id": 94, + "legend": { + "alignAsTable": false, + "avg": false, + "current": false, + "hideEmpty": true, + "hideZero": false, + "max": false, + "min": false, + "rightSide": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "(histogram_quantile(0.50, sum(irate(istio_request_duration_milliseconds_bucket{reporter=\"destination\", connection_security_policy=\"mutual_tls\", destination_service=~\"$service\", destination_workload=~\"$dstwl\", destination_workload_namespace=~\"$dstns\"}[1m])) by (destination_workload, destination_workload_namespace, le)) / 1000) or histogram_quantile(0.50, sum(irate(istio_request_duration_seconds_bucket{reporter=\"destination\", connection_security_policy=\"mutual_tls\", destination_service=~\"$service\", destination_workload=~\"$dstwl\", destination_workload_namespace=~\"$dstns\"}[1m])) by (destination_workload, destination_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_workload }}.{{ destination_workload_namespace }} P50 (🔐mTLS)", + "refId": "D", + "step": 2 + }, + { + "expr": "(histogram_quantile(0.90, sum(irate(istio_request_duration_milliseconds_bucket{reporter=\"destination\", connection_security_policy=\"mutual_tls\", destination_service=~\"$service\", destination_workload=~\"$dstwl\", destination_workload_namespace=~\"$dstns\"}[1m])) by (destination_workload, destination_workload_namespace, le)) / 1000) or histogram_quantile(0.90, sum(irate(istio_request_duration_seconds_bucket{reporter=\"destination\", connection_security_policy=\"mutual_tls\", destination_service=~\"$service\", destination_workload=~\"$dstwl\", destination_workload_namespace=~\"$dstns\"}[1m])) by (destination_workload, destination_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_workload }}.{{ destination_workload_namespace }} P90 (🔐mTLS)", + "refId": "A", + "step": 2 + }, + { + "expr": "(histogram_quantile(0.95, sum(irate(istio_request_duration_milliseconds_bucket{reporter=\"destination\", connection_security_policy=\"mutual_tls\", destination_service=~\"$service\", destination_workload=~\"$dstwl\", destination_workload_namespace=~\"$dstns\"}[1m])) by (destination_workload, destination_workload_namespace, le)) / 1000) or histogram_quantile(0.95, sum(irate(istio_request_duration_seconds_bucket{reporter=\"destination\", connection_security_policy=\"mutual_tls\", destination_service=~\"$service\", destination_workload=~\"$dstwl\", destination_workload_namespace=~\"$dstns\"}[1m])) by (destination_workload, destination_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_workload }}.{{ destination_workload_namespace }} P95 (🔐mTLS)", + "refId": "B", + "step": 2 + }, + { + "expr": "(histogram_quantile(0.99, sum(irate(istio_request_duration_milliseconds_bucket{reporter=\"destination\", connection_security_policy=\"mutual_tls\", destination_service=~\"$service\", destination_workload=~\"$dstwl\", destination_workload_namespace=~\"$dstns\"}[1m])) by (destination_workload, destination_workload_namespace, le)) / 1000) or histogram_quantile(0.99, sum(irate(istio_request_duration_seconds_bucket{reporter=\"destination\", connection_security_policy=\"mutual_tls\", destination_service=~\"$service\", destination_workload=~\"$dstwl\", destination_workload_namespace=~\"$dstns\"}[1m])) by (destination_workload, destination_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_workload }}.{{ destination_workload_namespace }} P99 (🔐mTLS)", + "refId": "C", + "step": 2 + }, + { + "expr": "(histogram_quantile(0.50, sum(irate(istio_request_duration_milliseconds_bucket{reporter=\"destination\", connection_security_policy!=\"mutual_tls\", destination_service=~\"$service\", destination_workload=~\"$dstwl\", destination_workload_namespace=~\"$dstns\"}[1m])) by (destination_workload, destination_workload_namespace, le)) / 1000) or histogram_quantile(0.50, sum(irate(istio_request_duration_seconds_bucket{reporter=\"destination\", connection_security_policy!=\"mutual_tls\", destination_service=~\"$service\", destination_workload=~\"$dstwl\", destination_workload_namespace=~\"$dstns\"}[1m])) by (destination_workload, destination_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_workload }}.{{ destination_workload_namespace }} P50", + "refId": "E", + "step": 2 + }, + { + "expr": "(histogram_quantile(0.90, sum(irate(istio_request_duration_milliseconds_bucket{reporter=\"destination\", connection_security_policy!=\"mutual_tls\", destination_service=~\"$service\", destination_workload=~\"$dstwl\", destination_workload_namespace=~\"$dstns\"}[1m])) by (destination_workload, destination_workload_namespace, le)) / 1000) or histogram_quantile(0.90, sum(irate(istio_request_duration_seconds_bucket{reporter=\"destination\", connection_security_policy!=\"mutual_tls\", destination_service=~\"$service\", destination_workload=~\"$dstwl\", destination_workload_namespace=~\"$dstns\"}[1m])) by (destination_workload, destination_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_workload }}.{{ destination_workload_namespace }} P90", + "refId": "F", + "step": 2 + }, + { + "expr": "(histogram_quantile(0.95, sum(irate(istio_request_duration_milliseconds_bucket{reporter=\"destination\", connection_security_policy!=\"mutual_tls\", destination_service=~\"$service\", destination_workload=~\"$dstwl\", destination_workload_namespace=~\"$dstns\"}[1m])) by (destination_workload, destination_workload_namespace, le)) / 1000) or histogram_quantile(0.95, sum(irate(istio_request_duration_seconds_bucket{reporter=\"destination\", connection_security_policy!=\"mutual_tls\", destination_service=~\"$service\", destination_workload=~\"$dstwl\", destination_workload_namespace=~\"$dstns\"}[1m])) by (destination_workload, destination_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_workload }}.{{ destination_workload_namespace }} P95", + "refId": "G", + "step": 2 + }, + { + "expr": "(histogram_quantile(0.99, sum(irate(istio_request_duration_milliseconds_bucket{reporter=\"destination\", connection_security_policy!=\"mutual_tls\", destination_service=~\"$service\", destination_workload=~\"$dstwl\", destination_workload_namespace=~\"$dstns\"}[1m])) by (destination_workload, destination_workload_namespace, le)) / 1000) or histogram_quantile(0.99, sum(irate(istio_request_duration_seconds_bucket{reporter=\"destination\", connection_security_policy!=\"mutual_tls\", destination_service=~\"$service\", destination_workload=~\"$dstwl\", destination_workload_namespace=~\"$dstns\"}[1m])) by (destination_workload, destination_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_workload }}.{{ destination_workload_namespace }} P99", + "refId": "H", + "step": 2 + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Incoming Request Duration by Source", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "s", + "label": null, + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 6, + "w": 8, + "x": 8, + "y": 41 + }, + "id": 95, + "legend": { + "alignAsTable": false, + "avg": false, + "current": false, + "hideEmpty": true, + "max": false, + "min": false, + "rightSide": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "histogram_quantile(0.50, sum(irate(istio_request_bytes_bucket{reporter=\"destination\", connection_security_policy=\"mutual_tls\", destination_service=~\"$service\", destination_workload=~\"$dstwl\", destination_workload_namespace=~\"$dstns\"}[1m])) by (destination_workload, destination_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_workload }}.{{ destination_workload_namespace }} P50 (🔐mTLS)", + "refId": "D", + "step": 2 + }, + { + "expr": "histogram_quantile(0.90, sum(irate(istio_request_bytes_bucket{reporter=\"destination\", connection_security_policy=\"mutual_tls\", destination_service=~\"$service\", destination_workload=~\"$dstwl\", destination_workload_namespace=~\"$dstns\"}[1m])) by (destination_workload, destination_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_workload }}.{{ destination_workload_namespace }} P90 (🔐mTLS)", + "refId": "A", + "step": 2 + }, + { + "expr": "histogram_quantile(0.95, sum(irate(istio_request_bytes_bucket{reporter=\"destination\", connection_security_policy=\"mutual_tls\", destination_service=~\"$service\", destination_workload=~\"$dstwl\", destination_workload_namespace=~\"$dstns\"}[1m])) by (destination_workload, destination_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_workload }}.{{ destination_workload_namespace }} P95 (🔐mTLS)", + "refId": "B", + "step": 2 + }, + { + "expr": "histogram_quantile(0.99, sum(irate(istio_request_bytes_bucket{reporter=\"destination\", connection_security_policy=\"mutual_tls\", destination_service=~\"$service\", destination_workload=~\"$dstwl\", destination_workload_namespace=~\"$dstns\"}[1m])) by (destination_workload, destination_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_workload }}.{{ destination_workload_namespace }} P99 (🔐mTLS)", + "refId": "C", + "step": 2 + }, + { + "expr": "histogram_quantile(0.50, sum(irate(istio_request_bytes_bucket{reporter=\"destination\", connection_security_policy!=\"mutual_tls\", destination_service=~\"$service\", destination_workload=~\"$dstwl\", destination_workload_namespace=~\"$dstns\"}[1m])) by (destination_workload, destination_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_workload }}.{{ destination_workload_namespace }} P50", + "refId": "E", + "step": 2 + }, + { + "expr": "histogram_quantile(0.90, sum(irate(istio_request_bytes_bucket{reporter=\"destination\", connection_security_policy!=\"mutual_tls\", destination_service=~\"$service\", destination_workload=~\"$dstwl\", destination_workload_namespace=~\"$dstns\"}[1m])) by (destination_workload, destination_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_workload }}.{{ destination_workload_namespace }} P90", + "refId": "F", + "step": 2 + }, + { + "expr": "histogram_quantile(0.95, sum(irate(istio_request_bytes_bucket{reporter=\"destination\", connection_security_policy!=\"mutual_tls\", destination_service=~\"$service\", destination_workload=~\"$dstwl\", destination_workload_namespace=~\"$dstns\"}[1m])) by (destination_workload, destination_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_workload }}.{{ destination_workload_namespace }} P95", + "refId": "G", + "step": 2 + }, + { + "expr": "histogram_quantile(0.99, sum(irate(istio_request_bytes_bucket{reporter=\"destination\", connection_security_policy!=\"mutual_tls\", destination_service=~\"$service\", destination_workload=~\"$dstwl\", destination_workload_namespace=~\"$dstns\"}[1m])) by (destination_workload, destination_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_workload }}.{{ destination_workload_namespace }} P99", + "refId": "H", + "step": 2 + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Incoming Request Size By Source", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "decbytes", + "label": null, + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 6, + "w": 8, + "x": 16, + "y": 41 + }, + "id": 96, + "legend": { + "alignAsTable": false, + "avg": false, + "current": false, + "hideEmpty": true, + "max": false, + "min": false, + "rightSide": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "histogram_quantile(0.50, sum(irate(istio_response_bytes_bucket{reporter=\"destination\", connection_security_policy=\"mutual_tls\", destination_service=~\"$service\", destination_workload=~\"$dstwl\", destination_workload_namespace=~\"$dstns\"}[1m])) by (destination_workload, destination_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_workload }}.{{ destination_workload_namespace }} P50 (🔐mTLS)", + "refId": "D", + "step": 2 + }, + { + "expr": "histogram_quantile(0.90, sum(irate(istio_response_bytes_bucket{reporter=\"destination\", connection_security_policy=\"mutual_tls\", destination_service=~\"$service\", destination_workload=~\"$dstwl\", destination_workload_namespace=~\"$dstns\"}[1m])) by (destination_workload, destination_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_workload }}.{{ destination_workload_namespace }} P90 (🔐mTLS)", + "refId": "A", + "step": 2 + }, + { + "expr": "histogram_quantile(0.95, sum(irate(istio_response_bytes_bucket{reporter=\"destination\", connection_security_policy=\"mutual_tls\", destination_service=~\"$service\", destination_workload=~\"$dstwl\", destination_workload_namespace=~\"$dstns\"}[1m])) by (destination_workload, destination_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_workload }}.{{ destination_workload_namespace }} P95 (🔐mTLS)", + "refId": "B", + "step": 2 + }, + { + "expr": "histogram_quantile(0.99, sum(irate(istio_response_bytes_bucket{reporter=\"destination\", connection_security_policy=\"mutual_tls\", destination_service=~\"$service\", destination_workload=~\"$dstwl\", destination_workload_namespace=~\"$dstns\"}[1m])) by (destination_workload, destination_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_workload }}.{{ destination_workload_namespace }} P99 (🔐mTLS)", + "refId": "C", + "step": 2 + }, + { + "expr": "histogram_quantile(0.50, sum(irate(istio_response_bytes_bucket{reporter=\"destination\", connection_security_policy!=\"mutual_tls\", destination_service=~\"$service\", destination_workload=~\"$dstwl\", destination_workload_namespace=~\"$dstns\"}[1m])) by (destination_workload, destination_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_workload }}.{{ destination_workload_namespace }} P50", + "refId": "E", + "step": 2 + }, + { + "expr": "histogram_quantile(0.90, sum(irate(istio_response_bytes_bucket{reporter=\"destination\", connection_security_policy!=\"mutual_tls\", destination_service=~\"$service\", destination_workload=~\"$dstwl\", destination_workload_namespace=~\"$dstns\"}[1m])) by (destination_workload, destination_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_workload }}.{{ destination_workload_namespace }} P90", + "refId": "F", + "step": 2 + }, + { + "expr": "histogram_quantile(0.95, sum(irate(istio_response_bytes_bucket{reporter=\"destination\", connection_security_policy!=\"mutual_tls\", destination_service=~\"$service\", destination_workload=~\"$dstwl\", destination_workload_namespace=~\"$dstns\"}[1m])) by (destination_workload, destination_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_workload }}.{{ destination_workload_namespace }} P95", + "refId": "G", + "step": 2 + }, + { + "expr": "histogram_quantile(0.99, sum(irate(istio_response_bytes_bucket{reporter=\"destination\", connection_security_policy!=\"mutual_tls\", destination_service=~\"$service\", destination_workload=~\"$dstwl\", destination_workload_namespace=~\"$dstns\"}[1m])) by (destination_workload, destination_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_workload }}.{{ destination_workload_namespace }} P99", + "refId": "H", + "step": 2 + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Response Size By Source", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "decbytes", + "label": null, + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 6, + "w": 12, + "x": 0, + "y": 47 + }, + "id": 92, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "round(sum(irate(istio_tcp_received_bytes_total{reporter=\"source\", connection_security_policy=\"mutual_tls\", destination_service=~\"$service\", destination_workload=~\"$dstwl\", destination_workload_namespace=~\"$dstns\"}[1m])) by (destination_workload, destination_workload_namespace), 0.001)", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_workload }}.{{ destination_workload_namespace}} (🔐mTLS)", + "refId": "A", + "step": 2 + }, + { + "expr": "round(sum(irate(istio_tcp_received_bytes_total{reporter=\"source\", connection_security_policy!=\"mutual_tls\", destination_service=~\"$service\", destination_workload=~\"$dstwl\", destination_workload_namespace=~\"$dstns\"}[1m])) by (destination_workload, destination_workload_namespace), 0.001)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{ destination_workload }}.{{ destination_workload_namespace}}", + "refId": "B", + "step": 2 + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Bytes Received from Incoming TCP Connection", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "Bps", + "label": null, + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 6, + "w": 12, + "x": 12, + "y": 47 + }, + "id": 93, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "round(sum(irate(istio_tcp_sent_bytes_total{connection_security_policy=\"mutual_tls\", reporter=\"source\", destination_service=~\"$service\", destination_workload=~\"$dstwl\", destination_workload_namespace=~\"$dstns\"}[1m])) by (destination_workload, destination_workload_namespace), 0.001)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{ destination_workload }}.{{destination_workload_namespace }} (🔐mTLS)", + "refId": "A", + "step": 2 + }, + { + "expr": "round(sum(irate(istio_tcp_sent_bytes_total{connection_security_policy!=\"mutual_tls\", reporter=\"source\", destination_service=~\"$service\", destination_workload=~\"$dstwl\", destination_workload_namespace=~\"$dstns\"}[1m])) by (destination_workload, destination_workload_namespace), 0.001)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{ destination_workload }}.{{destination_workload_namespace }}", + "refId": "B", + "step": 2 + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Bytes Sent to Incoming TCP Connection", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "Bps", + "label": null, + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + } + ], + "refresh": "10s", + "schemaVersion": 16, + "style": "dark", + "tags": [], + "templating": { + "list": [ + { + "allValue": null, + "datasource": "Prometheus", + "hide": 0, + "includeAll": false, + "label": "Service", + "multi": false, + "name": "service", + "options": [], + "query": "label_values(destination_service)", + "refresh": 1, + "regex": "", + "sort": 0, + "tagValuesQuery": "", + "tags": [], + "tagsQuery": "", + "type": "query", + "useTags": false + }, + { + "allValue": null, + "current": { + "text": "All", + "value": "$__all" + }, + "datasource": "Prometheus", + "hide": 0, + "includeAll": true, + "label": "Client Workload Namespace", + "multi": true, + "name": "srcns", + "options": [], + "query": "query_result( sum(istio_requests_total{reporter=\"destination\", destination_service=\"$service\"}) by (source_workload_namespace) or sum(istio_tcp_sent_bytes_total{reporter=\"destination\", destination_service=~\"$service\"}) by (source_workload_namespace))", + "refresh": 1, + "regex": "/.*namespace=\"([^\"]*).*/", + "sort": 2, + "tagValuesQuery": "", + "tags": [], + "tagsQuery": "", + "type": "query", + "useTags": false + }, + { + "allValue": null, + "current": { + "text": "All", + "value": "$__all" + }, + "datasource": "Prometheus", + "hide": 0, + "includeAll": true, + "label": "Client Workload", + "multi": true, + "name": "srcwl", + "options": [], + "query": "query_result( sum(istio_requests_total{reporter=\"destination\", destination_service=~\"$service\", source_workload_namespace=~\"$srcns\"}) by (source_workload) or sum(istio_tcp_sent_bytes_total{reporter=\"destination\", destination_service=~\"$service\", source_workload_namespace=~\"$srcns\"}) by (source_workload))", + "refresh": 1, + "regex": "/.*workload=\"([^\"]*).*/", + "sort": 3, + "tagValuesQuery": "", + "tags": [], + "tagsQuery": "", + "type": "query", + "useTags": false + }, + { + "allValue": null, + "current": { + "text": "All", + "value": "$__all" + }, + "datasource": "Prometheus", + "hide": 0, + "includeAll": true, + "label": "Service Workload Namespace", + "multi": true, + "name": "dstns", + "options": [], + "query": "query_result( sum(istio_requests_total{reporter=\"destination\", destination_service=\"$service\"}) by (destination_workload_namespace) or sum(istio_tcp_sent_bytes_total{reporter=\"destination\", destination_service=~\"$service\"}) by (destination_workload_namespace))", + "refresh": 1, + "regex": "/.*namespace=\"([^\"]*).*/", + "sort": 2, + "tagValuesQuery": "", + "tags": [], + "tagsQuery": "", + "type": "query", + "useTags": false + }, + { + "allValue": null, + "current": { + "text": "All", + "value": "$__all" + }, + "datasource": "Prometheus", + "hide": 0, + "includeAll": true, + "label": "Service Workload", + "multi": true, + "name": "dstwl", + "options": [], + "query": "query_result( sum(istio_requests_total{reporter=\"destination\", destination_service=~\"$service\", destination_workload_namespace=~\"$dstns\"}) by (destination_workload) or sum(istio_tcp_sent_bytes_total{reporter=\"destination\", destination_service=~\"$service\", destination_workload_namespace=~\"$dstns\"}) by (destination_workload))", + "refresh": 1, + "regex": "/.*workload=\"([^\"]*).*/", + "sort": 3, + "tagValuesQuery": "", + "tags": [], + "tagsQuery": "", + "type": "query", + "useTags": false + } + ] + }, + "time": { + "from": "now-5m", + "to": "now" + }, + "timepicker": { + "refresh_intervals": [ + "5s", + "10s", + "30s", + "1m", + "5m", + "15m", + "30m", + "1h", + "2h", + "1d" + ], + "time_options": [ + "5m", + "15m", + "1h", + "6h", + "12h", + "24h", + "2d", + "7d", + "30d" + ] + }, + "timezone": "", + "title": "Istio Service Dashboard", + "uid": "LJ_uJAvmk", + "version": 1 +} +' +--- +apiVersion: v1 +kind: ConfigMap +metadata: + name: istio-grafana-configuration-dashboards-istio-workload-dashboard + namespace: istio-system + labels: + app: grafana + chart: grafana + heritage: Tiller + release: istio + istio: grafana +data: + istio-workload-dashboard.json: '{ + "__inputs": [ + { + "name": "DS_PROMETHEUS", + "label": "Prometheus", + "description": "", + "type": "datasource", + "pluginId": "prometheus", + "pluginName": "Prometheus" + } + ], + "__requires": [ + { + "type": "grafana", + "id": "grafana", + "name": "Grafana", + "version": "5.0.4" + }, + { + "type": "panel", + "id": "graph", + "name": "Graph", + "version": "5.0.0" + }, + { + "type": "datasource", + "id": "prometheus", + "name": "Prometheus", + "version": "5.0.0" + }, + { + "type": "panel", + "id": "singlestat", + "name": "Singlestat", + "version": "5.0.0" + }, + { + "type": "panel", + "id": "text", + "name": "Text", + "version": "5.0.0" + } + ], + "annotations": { + "list": [ + { + "builtIn": 1, + "datasource": "-- Grafana --", + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations & Alerts", + "type": "dashboard" + } + ] + }, + "editable": false, + "gnetId": null, + "graphTooltip": 0, + "id": null, + "iteration": 1531345461465, + "links": [], + "panels": [ + { + "content": "
\nWORKLOAD: $workload.$namespace\n
", + "gridPos": { + "h": 3, + "w": 24, + "x": 0, + "y": 0 + }, + "id": 89, + "links": [], + "mode": "html", + "title": "", + "transparent": true, + "type": "text" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "datasource": "Prometheus", + "format": "ops", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "gridPos": { + "h": 4, + "w": 8, + "x": 0, + "y": 3 + }, + "id": 12, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": true, + "lineColor": "rgb(31, 120, 193)", + "show": true + }, + "tableColumn": "", + "targets": [ + { + "expr": "round(sum(irate(istio_requests_total{reporter=\"destination\",destination_workload_namespace=~\"$namespace\",destination_workload=~\"$workload\"}[5m])), 0.001)", + "format": "time_series", + "intervalFactor": 1, + "refId": "A", + "step": 4 + } + ], + "thresholds": "", + "title": "Incoming Request Volume", + "transparent": false, + "type": "singlestat", + "valueFontSize": "80%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "current" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "rgba(50, 172, 45, 0.97)", + "rgba(237, 129, 40, 0.89)", + "rgba(245, 54, 54, 0.9)" + ], + "datasource": "Prometheus", + "decimals": null, + "format": "percentunit", + "gauge": { + "maxValue": 100, + "minValue": 80, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": false + }, + "gridPos": { + "h": 4, + "w": 8, + "x": 8, + "y": 3 + }, + "id": 14, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": true, + "lineColor": "rgb(31, 120, 193)", + "show": true + }, + "tableColumn": "", + "targets": [ + { + "expr": "sum(irate(istio_requests_total{reporter=\"destination\",destination_workload_namespace=~\"$namespace\",destination_workload=~\"$workload\",response_code!~\"5.*\"}[5m])) / sum(irate(istio_requests_total{reporter=\"destination\",destination_workload_namespace=~\"$namespace\",destination_workload=~\"$workload\"}[5m]))", + "format": "time_series", + "intervalFactor": 1, + "refId": "B" + } + ], + "thresholds": "95, 99, 99.5", + "title": "Incoming Success Rate (non-5xx responses)", + "transparent": false, + "type": "singlestat", + "valueFontSize": "80%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "avg" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 4, + "w": 8, + "x": 16, + "y": 3 + }, + "id": 87, + "legend": { + "alignAsTable": false, + "avg": false, + "current": false, + "hideEmpty": false, + "hideZero": false, + "max": false, + "min": false, + "rightSide": true, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "(histogram_quantile(0.50, sum(irate(istio_request_duration_milliseconds_bucket{reporter=\"destination\",destination_workload=~\"$workload\", destination_workload_namespace=~\"$namespace\"}[1m])) by (le)) / 1000) or histogram_quantile(0.50, sum(irate(istio_request_duration_seconds_bucket{reporter=\"destination\",destination_workload=~\"$workload\", destination_workload_namespace=~\"$namespace\"}[1m])) by (le))", + "format": "time_series", + "interval": "", + "intervalFactor": 1, + "legendFormat": "P50", + "refId": "A" + }, + { + "expr": "(histogram_quantile(0.50, sum(irate(istio_request_duration_milliseconds_bucket{reporter=\"destination\",destination_workload=~\"$workload\", destination_workload_namespace=~\"$namespace\"}[1m])) by (le)) / 1000) or histogram_quantile(0.90, sum(irate(istio_request_duration_seconds_bucket{reporter=\"destination\",destination_workload=~\"$workload\", destination_workload_namespace=~\"$namespace\"}[1m])) by (le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "P90", + "refId": "B" + }, + { + "expr": "(histogram_quantile(0.50, sum(irate(istio_request_duration_milliseconds_bucket{reporter=\"destination\",destination_workload=~\"$workload\", destination_workload_namespace=~\"$namespace\"}[1m])) by (le)) / 1000) or histogram_quantile(0.99, sum(irate(istio_request_duration_seconds_bucket{reporter=\"destination\",destination_workload=~\"$workload\", destination_workload_namespace=~\"$namespace\"}[1m])) by (le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "P99", + "refId": "C" + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Request Duration", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "s", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ] + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "#299c46", + "rgba(237, 129, 40, 0.89)", + "#d44a3a" + ], + "datasource": "Prometheus", + "format": "Bps", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "gridPos": { + "h": 4, + "w": 12, + "x": 0, + "y": 7 + }, + "id": 84, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": true, + "lineColor": "rgb(31, 120, 193)", + "show": true + }, + "tableColumn": "", + "targets": [ + { + "expr": "sum(irate(istio_tcp_sent_bytes_total{reporter=\"destination\", destination_workload_namespace=~\"$namespace\", destination_workload=~\"$workload\"}[1m])) + sum(irate(istio_tcp_received_bytes_total{reporter=\"destination\", destination_workload_namespace=~\"$namespace\", destination_workload=~\"$workload\"}[1m]))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "", + "refId": "A" + } + ], + "thresholds": "", + "title": "TCP Server Traffic", + "transparent": false, + "type": "singlestat", + "valueFontSize": "80%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "avg" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "#299c46", + "rgba(237, 129, 40, 0.89)", + "#d44a3a" + ], + "datasource": "Prometheus", + "format": "Bps", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "gridPos": { + "h": 4, + "w": 12, + "x": 12, + "y": 7 + }, + "id": 85, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": true, + "lineColor": "rgb(31, 120, 193)", + "show": true + }, + "tableColumn": "", + "targets": [ + { + "expr": "sum(irate(istio_tcp_sent_bytes_total{reporter=\"source\", source_workload_namespace=~\"$namespace\", source_workload=~\"$workload\"}[1m])) + sum(irate(istio_tcp_received_bytes_total{reporter=\"source\", source_workload_namespace=~\"$namespace\", source_workload=~\"$workload\"}[1m]))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "", + "refId": "A" + } + ], + "thresholds": "", + "title": "TCP Client Traffic", + "transparent": false, + "type": "singlestat", + "valueFontSize": "80%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "avg" + }, + { + "content": "
\nINBOUND WORKLOADS\n
", + "gridPos": { + "h": 3, + "w": 24, + "x": 0, + "y": 11 + }, + "id": 45, + "links": [], + "mode": "html", + "title": "", + "transparent": true, + "type": "text" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 0, + "gridPos": { + "h": 6, + "w": 12, + "x": 0, + "y": 14 + }, + "id": 25, + "legend": { + "avg": false, + "current": false, + "hideEmpty": true, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null as zero", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "round(sum(irate(istio_requests_total{connection_security_policy=\"mutual_tls\", destination_workload_namespace=~\"$namespace\", destination_workload=~\"$workload\", reporter=\"destination\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[5m])) by (source_workload, source_workload_namespace, response_code), 0.001)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{ source_workload }}.{{ source_workload_namespace }} : {{ response_code }} (🔐mTLS)", + "refId": "B", + "step": 2 + }, + { + "expr": "round(sum(irate(istio_requests_total{connection_security_policy!=\"mutual_tls\", destination_workload_namespace=~\"$namespace\", destination_workload=~\"$workload\", reporter=\"destination\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[5m])) by (source_workload, source_workload_namespace, response_code), 0.001)", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ source_workload }}.{{ source_workload_namespace }} : {{ response_code }}", + "refId": "A", + "step": 2 + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Incoming Requests by Source And Response Code", + "tooltip": { + "shared": false, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [ + "total" + ] + }, + "yaxes": [ + { + "format": "ops", + "label": null, + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ] + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 6, + "w": 12, + "x": 12, + "y": 14 + }, + "id": 26, + "legend": { + "avg": false, + "current": false, + "hideEmpty": true, + "hideZero": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(irate(istio_requests_total{reporter=\"destination\", connection_security_policy=\"mutual_tls\", destination_workload_namespace=~\"$namespace\", destination_workload=~\"$workload\",response_code!~\"5.*\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[5m])) by (source_workload, source_workload_namespace) / sum(irate(istio_requests_total{reporter=\"destination\", connection_security_policy=\"mutual_tls\", destination_workload_namespace=~\"$namespace\", destination_workload=~\"$workload\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[5m])) by (source_workload, source_workload_namespace)", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ source_workload }}.{{ source_workload_namespace }} (🔐mTLS)", + "refId": "A", + "step": 2 + }, + { + "expr": "sum(irate(istio_requests_total{reporter=\"destination\", connection_security_policy!=\"mutual_tls\", destination_workload_namespace=~\"$namespace\", destination_workload=~\"$workload\",response_code!~\"5.*\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[5m])) by (source_workload, source_workload_namespace) / sum(irate(istio_requests_total{reporter=\"destination\", connection_security_policy!=\"mutual_tls\", destination_workload_namespace=~\"$namespace\", destination_workload=~\"$workload\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[5m])) by (source_workload, source_workload_namespace)", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ source_workload }}.{{ source_workload_namespace }}", + "refId": "B", + "step": 2 + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Incoming Success Rate (non-5xx responses) By Source", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "percentunit", + "label": null, + "logBase": 1, + "max": "1.01", + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ] + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "description": "", + "fill": 1, + "gridPos": { + "h": 6, + "w": 8, + "x": 0, + "y": 20 + }, + "id": 27, + "legend": { + "alignAsTable": false, + "avg": false, + "current": false, + "hideEmpty": true, + "hideZero": false, + "max": false, + "min": false, + "rightSide": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "(histogram_quantile(0.50, sum(irate(istio_request_duration_milliseconds_bucket{reporter=\"destination\", connection_security_policy=\"mutual_tls\", destination_workload=~\"$workload\", destination_workload_namespace=~\"$namespace\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le)) / 1000) or histogram_quantile(0.50, sum(irate(istio_request_duration_seconds_bucket{reporter=\"destination\", connection_security_policy=\"mutual_tls\", destination_workload=~\"$workload\", destination_workload_namespace=~\"$namespace\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{source_workload}}.{{source_workload_namespace}} P50 (🔐mTLS)", + "refId": "D", + "step": 2 + }, + { + "expr": "(histogram_quantile(0.90, sum(irate(istio_request_duration_milliseconds_bucket{reporter=\"destination\", connection_security_policy=\"mutual_tls\", destination_workload=~\"$workload\", destination_workload_namespace=~\"$namespace\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le)) / 1000) or histogram_quantile(0.90, sum(irate(istio_request_duration_seconds_bucket{reporter=\"destination\", connection_security_policy=\"mutual_tls\", destination_workload=~\"$workload\", destination_workload_namespace=~\"$namespace\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{source_workload}}.{{source_workload_namespace}} P90 (🔐mTLS)", + "refId": "A", + "step": 2 + }, + { + "expr": "(histogram_quantile(0.95, sum(irate(istio_request_duration_milliseconds_bucket{reporter=\"destination\", connection_security_policy=\"mutual_tls\", destination_workload=~\"$workload\", destination_workload_namespace=~\"$namespace\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le)) / 1000) or histogram_quantile(0.95, sum(irate(istio_request_duration_seconds_bucket{reporter=\"destination\", connection_security_policy=\"mutual_tls\", destination_workload=~\"$workload\", destination_workload_namespace=~\"$namespace\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{source_workload}}.{{source_workload_namespace}} P95 (🔐mTLS)", + "refId": "B", + "step": 2 + }, + { + "expr": "(histogram_quantile(0.99, sum(irate(istio_request_duration_milliseconds_bucket{reporter=\"destination\", connection_security_policy=\"mutual_tls\", destination_workload=~\"$workload\", destination_workload_namespace=~\"$namespace\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le)) / 1000) or histogram_quantile(0.99, sum(irate(istio_request_duration_seconds_bucket{reporter=\"destination\", connection_security_policy=\"mutual_tls\", destination_workload=~\"$workload\", destination_workload_namespace=~\"$namespace\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{source_workload}}.{{source_workload_namespace}} P99 (🔐mTLS)", + "refId": "C", + "step": 2 + }, + { + "expr": "(histogram_quantile(0.50, sum(irate(istio_request_duration_milliseconds_bucket{reporter=\"destination\", connection_security_policy!=\"mutual_tls\", destination_workload=~\"$workload\", destination_workload_namespace=~\"$namespace\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le)) / 1000) or histogram_quantile(0.50, sum(irate(istio_request_duration_seconds_bucket{reporter=\"destination\", connection_security_policy!=\"mutual_tls\", destination_workload=~\"$workload\", destination_workload_namespace=~\"$namespace\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{source_workload}}.{{source_workload_namespace}} P50", + "refId": "E", + "step": 2 + }, + { + "expr": "(histogram_quantile(0.90, sum(irate(istio_request_duration_milliseconds_bucket{reporter=\"destination\", connection_security_policy!=\"mutual_tls\", destination_workload=~\"$workload\", destination_workload_namespace=~\"$namespace\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le)) / 1000) or histogram_quantile(0.90, sum(irate(istio_request_duration_seconds_bucket{reporter=\"destination\", connection_security_policy!=\"mutual_tls\", destination_workload=~\"$workload\", destination_workload_namespace=~\"$namespace\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{source_workload}}.{{source_workload_namespace}} P90", + "refId": "F", + "step": 2 + }, + { + "expr": "(histogram_quantile(0.95, sum(irate(istio_request_duration_milliseconds_bucket{reporter=\"destination\", connection_security_policy!=\"mutual_tls\", destination_workload=~\"$workload\", destination_workload_namespace=~\"$namespace\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le)) / 1000) or histogram_quantile(0.95, sum(irate(istio_request_duration_seconds_bucket{reporter=\"destination\", connection_security_policy!=\"mutual_tls\", destination_workload=~\"$workload\", destination_workload_namespace=~\"$namespace\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{source_workload}}.{{source_workload_namespace}} P95", + "refId": "G", + "step": 2 + }, + { + "expr": "(histogram_quantile(0.99, sum(irate(istio_request_duration_milliseconds_bucket{reporter=\"destination\", connection_security_policy!=\"mutual_tls\", destination_workload=~\"$workload\", destination_workload_namespace=~\"$namespace\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le)) / 1000) or histogram_quantile(0.99, sum(irate(istio_request_duration_seconds_bucket{reporter=\"destination\", connection_security_policy!=\"mutual_tls\", destination_workload=~\"$workload\", destination_workload_namespace=~\"$namespace\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{source_workload}}.{{source_workload_namespace}} P99", + "refId": "H", + "step": 2 + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Incoming Request Duration by Source", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "s", + "label": null, + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ] + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 6, + "w": 8, + "x": 8, + "y": 20 + }, + "id": 28, + "legend": { + "alignAsTable": false, + "avg": false, + "current": false, + "hideEmpty": true, + "max": false, + "min": false, + "rightSide": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "histogram_quantile(0.50, sum(irate(istio_request_bytes_bucket{reporter=\"destination\", connection_security_policy=\"mutual_tls\", destination_workload=~\"$workload\", destination_workload_namespace=~\"$namespace\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{source_workload}}.{{source_workload_namespace}} P50 (🔐mTLS)", + "refId": "D", + "step": 2 + }, + { + "expr": "histogram_quantile(0.90, sum(irate(istio_request_bytes_bucket{reporter=\"destination\", connection_security_policy=\"mutual_tls\", destination_workload=~\"$workload\", destination_workload_namespace=~\"$namespace\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{source_workload}}.{{source_workload_namespace}} P90 (🔐mTLS)", + "refId": "A", + "step": 2 + }, + { + "expr": "histogram_quantile(0.95, sum(irate(istio_request_bytes_bucket{reporter=\"destination\", connection_security_policy=\"mutual_tls\", destination_workload=~\"$workload\", destination_workload_namespace=~\"$namespace\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{source_workload}}.{{source_workload_namespace}} P95 (🔐mTLS)", + "refId": "B", + "step": 2 + }, + { + "expr": "histogram_quantile(0.99, sum(irate(istio_request_bytes_bucket{reporter=\"destination\", connection_security_policy=\"mutual_tls\", destination_workload=~\"$workload\", destination_workload_namespace=~\"$namespace\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{source_workload}}.{{source_workload_namespace}} P99 (🔐mTLS)", + "refId": "C", + "step": 2 + }, + { + "expr": "histogram_quantile(0.50, sum(irate(istio_request_bytes_bucket{reporter=\"destination\", connection_security_policy!=\"mutual_tls\", destination_workload=~\"$workload\", destination_workload_namespace=~\"$namespace\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{source_workload}}.{{source_workload_namespace}} P50", + "refId": "E", + "step": 2 + }, + { + "expr": "histogram_quantile(0.90, sum(irate(istio_request_bytes_bucket{reporter=\"destination\", connection_security_policy!=\"mutual_tls\", destination_workload=~\"$workload\", destination_workload_namespace=~\"$namespace\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{source_workload}}.{{source_workload_namespace}} P90", + "refId": "F", + "step": 2 + }, + { + "expr": "histogram_quantile(0.95, sum(irate(istio_request_bytes_bucket{reporter=\"destination\", connection_security_policy!=\"mutual_tls\", destination_workload=~\"$workload\", destination_workload_namespace=~\"$namespace\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{source_workload}}.{{source_workload_namespace}} P95", + "refId": "G", + "step": 2 + }, + { + "expr": "histogram_quantile(0.99, sum(irate(istio_request_bytes_bucket{reporter=\"destination\", connection_security_policy!=\"mutual_tls\", destination_workload=~\"$workload\", destination_workload_namespace=~\"$namespace\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{source_workload}}.{{source_workload_namespace}} P99", + "refId": "H", + "step": 2 + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Incoming Request Size By Source", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "decbytes", + "label": null, + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ] + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 6, + "w": 8, + "x": 16, + "y": 20 + }, + "id": 68, + "legend": { + "alignAsTable": false, + "avg": false, + "current": false, + "hideEmpty": true, + "max": false, + "min": false, + "rightSide": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "histogram_quantile(0.50, sum(irate(istio_response_bytes_bucket{reporter=\"destination\", connection_security_policy=\"mutual_tls\", destination_workload=~\"$workload\", destination_workload_namespace=~\"$namespace\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{source_workload}}.{{source_workload_namespace}} P50 (🔐mTLS)", + "refId": "D", + "step": 2 + }, + { + "expr": "histogram_quantile(0.90, sum(irate(istio_response_bytes_bucket{reporter=\"destination\", connection_security_policy=\"mutual_tls\", destination_workload=~\"$workload\", destination_workload_namespace=~\"$namespace\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{source_workload}}.{{source_workload_namespace}} P90 (🔐mTLS)", + "refId": "A", + "step": 2 + }, + { + "expr": "histogram_quantile(0.95, sum(irate(istio_response_bytes_bucket{reporter=\"destination\", connection_security_policy=\"mutual_tls\", destination_workload=~\"$workload\", destination_workload_namespace=~\"$namespace\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{source_workload}}.{{source_workload_namespace}} P95 (🔐mTLS)", + "refId": "B", + "step": 2 + }, + { + "expr": "histogram_quantile(0.99, sum(irate(istio_response_bytes_bucket{reporter=\"destination\", connection_security_policy=\"mutual_tls\", destination_workload=~\"$workload\", destination_workload_namespace=~\"$namespace\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{source_workload}}.{{source_workload_namespace}} P99 (🔐mTLS)", + "refId": "C", + "step": 2 + }, + { + "expr": "histogram_quantile(0.50, sum(irate(istio_response_bytes_bucket{reporter=\"destination\", connection_security_policy!=\"mutual_tls\", destination_workload=~\"$workload\", destination_workload_namespace=~\"$namespace\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{source_workload}}.{{source_workload_namespace}} P50", + "refId": "E", + "step": 2 + }, + { + "expr": "histogram_quantile(0.90, sum(irate(istio_response_bytes_bucket{reporter=\"destination\", connection_security_policy!=\"mutual_tls\", destination_workload=~\"$workload\", destination_workload_namespace=~\"$namespace\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{source_workload}}.{{source_workload_namespace}} P90", + "refId": "F", + "step": 2 + }, + { + "expr": "histogram_quantile(0.95, sum(irate(istio_response_bytes_bucket{reporter=\"destination\", connection_security_policy!=\"mutual_tls\", destination_workload=~\"$workload\", destination_workload_namespace=~\"$namespace\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{source_workload}}.{{source_workload_namespace}} P95", + "refId": "G", + "step": 2 + }, + { + "expr": "histogram_quantile(0.99, sum(irate(istio_response_bytes_bucket{reporter=\"destination\", connection_security_policy!=\"mutual_tls\", destination_workload=~\"$workload\", destination_workload_namespace=~\"$namespace\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{source_workload}}.{{source_workload_namespace}} P99", + "refId": "H", + "step": 2 + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Response Size By Source", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "decbytes", + "label": null, + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ] + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 6, + "w": 12, + "x": 0, + "y": 26 + }, + "id": 80, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "round(sum(irate(istio_tcp_received_bytes_total{reporter=\"destination\", connection_security_policy=\"mutual_tls\", destination_workload_namespace=~\"$namespace\", destination_workload=~\"$workload\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace), 0.001)", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ source_workload }}.{{ source_workload_namespace}} (🔐mTLS)", + "refId": "A", + "step": 2 + }, + { + "expr": "round(sum(irate(istio_tcp_received_bytes_total{reporter=\"destination\", connection_security_policy!=\"mutual_tls\", destination_workload_namespace=~\"$namespace\", destination_workload=~\"$workload\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace), 0.001)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{ source_workload }}.{{ source_workload_namespace}}", + "refId": "B", + "step": 2 + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Bytes Received from Incoming TCP Connection", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "Bps", + "label": null, + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ] + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 6, + "w": 12, + "x": 12, + "y": 26 + }, + "id": 82, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "round(sum(irate(istio_tcp_sent_bytes_total{connection_security_policy=\"mutual_tls\", reporter=\"destination\", destination_workload_namespace=~\"$namespace\", destination_workload=~\"$workload\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace), 0.001)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{ source_workload }}.{{ source_workload_namespace}} (🔐mTLS)", + "refId": "A", + "step": 2 + }, + { + "expr": "round(sum(irate(istio_tcp_sent_bytes_total{connection_security_policy!=\"mutual_tls\", reporter=\"destination\", destination_workload_namespace=~\"$namespace\", destination_workload=~\"$workload\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace), 0.001)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{ source_workload }}.{{ source_workload_namespace}}", + "refId": "B", + "step": 2 + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Bytes Sent to Incoming TCP Connection", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "Bps", + "label": null, + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ] + }, + { + "content": "
\nOUTBOUND SERVICES\n
", + "gridPos": { + "h": 3, + "w": 24, + "x": 0, + "y": 32 + }, + "id": 69, + "links": [], + "mode": "html", + "title": "", + "transparent": true, + "type": "text" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 0, + "gridPos": { + "h": 6, + "w": 12, + "x": 0, + "y": 35 + }, + "id": 70, + "legend": { + "avg": false, + "current": false, + "hideEmpty": true, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null as zero", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "round(sum(irate(istio_requests_total{connection_security_policy=\"mutual_tls\", source_workload_namespace=~\"$namespace\", source_workload=~\"$workload\", reporter=\"source\", destination_service=~\"$dstsvc\"}[5m])) by (destination_service, response_code), 0.001)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{ destination_service }} : {{ response_code }} (🔐mTLS)", + "refId": "B", + "step": 2 + }, + { + "expr": "round(sum(irate(istio_requests_total{connection_security_policy!=\"mutual_tls\", source_workload_namespace=~\"$namespace\", source_workload=~\"$workload\", reporter=\"source\", destination_service=~\"$dstsvc\"}[5m])) by (destination_service, response_code), 0.001)", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_service }} : {{ response_code }}", + "refId": "A", + "step": 2 + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Outgoing Requests by Destination And Response Code", + "tooltip": { + "shared": false, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [ + "total" + ] + }, + "yaxes": [ + { + "format": "ops", + "label": null, + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ] + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 6, + "w": 12, + "x": 12, + "y": 35 + }, + "id": 71, + "legend": { + "avg": false, + "current": false, + "hideEmpty": true, + "hideZero": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(irate(istio_requests_total{reporter=\"source\", connection_security_policy=\"mutual_tls\", source_workload_namespace=~\"$namespace\", source_workload=~\"$workload\",response_code!~\"5.*\", destination_service=~\"$dstsvc\"}[5m])) by (destination_service) / sum(irate(istio_requests_total{reporter=\"source\", connection_security_policy=\"mutual_tls\", source_workload_namespace=~\"$namespace\", source_workload=~\"$workload\", destination_service=~\"$dstsvc\"}[5m])) by (destination_service)", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_service }} (🔐mTLS)", + "refId": "A", + "step": 2 + }, + { + "expr": "sum(irate(istio_requests_total{reporter=\"source\", connection_security_policy!=\"mutual_tls\", source_workload_namespace=~\"$namespace\", source_workload=~\"$workload\",response_code!~\"5.*\", destination_service=~\"$dstsvc\"}[5m])) by (destination_service) / sum(irate(istio_requests_total{reporter=\"source\", connection_security_policy!=\"mutual_tls\", source_workload_namespace=~\"$namespace\", source_workload=~\"$workload\", destination_service=~\"$dstsvc\"}[5m])) by (destination_service)", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{destination_service }}", + "refId": "B", + "step": 2 + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Outgoing Success Rate (non-5xx responses) By Destination", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "percentunit", + "label": null, + "logBase": 1, + "max": "1.01", + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ] + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "description": "", + "fill": 1, + "gridPos": { + "h": 6, + "w": 8, + "x": 0, + "y": 41 + }, + "id": 72, + "legend": { + "alignAsTable": false, + "avg": false, + "current": false, + "hideEmpty": true, + "hideZero": false, + "max": false, + "min": false, + "rightSide": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "(histogram_quantile(0.50, sum(irate(istio_request_duration_milliseconds_bucket{reporter=\"source\", connection_security_policy=\"mutual_tls\", source_workload=~\"$workload\", source_workload_namespace=~\"$namespace\", destination_service=~\"$dstsvc\"}[1m])) by (destination_service, le)) / 1000) or histogram_quantile(0.50, sum(irate(istio_request_duration_seconds_bucket{reporter=\"source\", connection_security_policy=\"mutual_tls\", source_workload=~\"$workload\", source_workload_namespace=~\"$namespace\", destination_service=~\"$dstsvc\"}[1m])) by (destination_service, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_service }} P50 (🔐mTLS)", + "refId": "D", + "step": 2 + }, + { + "expr": "(histogram_quantile(0.90, sum(irate(istio_request_duration_milliseconds_bucket{reporter=\"source\", connection_security_policy=\"mutual_tls\", source_workload=~\"$workload\", source_workload_namespace=~\"$namespace\", destination_service=~\"$dstsvc\"}[1m])) by (destination_service, le)) / 1000) or histogram_quantile(0.90, sum(irate(istio_request_duration_seconds_bucket{reporter=\"source\", connection_security_policy=\"mutual_tls\", source_workload=~\"$workload\", source_workload_namespace=~\"$namespace\", destination_service=~\"$dstsvc\"}[1m])) by (destination_service, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_service }} P90 (🔐mTLS)", + "refId": "A", + "step": 2 + }, + { + "expr": "(histogram_quantile(0.95, sum(irate(istio_request_duration_milliseconds_bucket{reporter=\"source\", connection_security_policy=\"mutual_tls\", source_workload=~\"$workload\", source_workload_namespace=~\"$namespace\", destination_service=~\"$dstsvc\"}[1m])) by (destination_service, le)) / 1000) or histogram_quantile(0.95, sum(irate(istio_request_duration_seconds_bucket{reporter=\"source\", connection_security_policy=\"mutual_tls\", source_workload=~\"$workload\", source_workload_namespace=~\"$namespace\", destination_service=~\"$dstsvc\"}[1m])) by (destination_service, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_service }} P95 (🔐mTLS)", + "refId": "B", + "step": 2 + }, + { + "expr": "(histogram_quantile(0.99, sum(irate(istio_request_duration_milliseconds_bucket{reporter=\"source\", connection_security_policy=\"mutual_tls\", source_workload=~\"$workload\", source_workload_namespace=~\"$namespace\", destination_service=~\"$dstsvc\"}[1m])) by (destination_service, le)) / 1000) or histogram_quantile(0.99, sum(irate(istio_request_duration_seconds_bucket{reporter=\"source\", connection_security_policy=\"mutual_tls\", source_workload=~\"$workload\", source_workload_namespace=~\"$namespace\", destination_service=~\"$dstsvc\"}[1m])) by (destination_service, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_service }} P99 (🔐mTLS)", + "refId": "C", + "step": 2 + }, + { + "expr": "(histogram_quantile(0.50, sum(irate(istio_request_duration_milliseconds_bucket{reporter=\"source\", connection_security_policy!=\"mutual_tls\", source_workload=~\"$workload\", source_workload_namespace=~\"$namespace\", destination_service=~\"$dstsvc\"}[1m])) by (destination_service, le)) / 1000) or histogram_quantile(0.50, sum(irate(istio_request_duration_seconds_bucket{reporter=\"source\", connection_security_policy!=\"mutual_tls\", source_workload=~\"$workload\", source_workload_namespace=~\"$namespace\", destination_service=~\"$dstsvc\"}[1m])) by (destination_service, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_service }} P50", + "refId": "E", + "step": 2 + }, + { + "expr": "(histogram_quantile(0.90, sum(irate(istio_request_duration_milliseconds_bucket{reporter=\"source\", connection_security_policy!=\"mutual_tls\", source_workload=~\"$workload\", source_workload_namespace=~\"$namespace\", destination_service=~\"$dstsvc\"}[1m])) by (destination_service, le)) / 1000) or histogram_quantile(0.90, sum(irate(istio_request_duration_seconds_bucket{reporter=\"source\", connection_security_policy!=\"mutual_tls\", source_workload=~\"$workload\", source_workload_namespace=~\"$namespace\", destination_service=~\"$dstsvc\"}[1m])) by (destination_service, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_service }} P90", + "refId": "F", + "step": 2 + }, + { + "expr": "(histogram_quantile(0.95, sum(irate(istio_request_duration_milliseconds_bucket{reporter=\"source\", connection_security_policy!=\"mutual_tls\", source_workload=~\"$workload\", source_workload_namespace=~\"$namespace\", destination_service=~\"$dstsvc\"}[1m])) by (destination_service, le)) / 1000) or histogram_quantile(0.95, sum(irate(istio_request_duration_seconds_bucket{reporter=\"source\", connection_security_policy!=\"mutual_tls\", source_workload=~\"$workload\", source_workload_namespace=~\"$namespace\", destination_service=~\"$dstsvc\"}[1m])) by (destination_service, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_service }} P95", + "refId": "G", + "step": 2 + }, + { + "expr": "(histogram_quantile(0.99, sum(irate(istio_request_duration_milliseconds_bucket{reporter=\"source\", connection_security_policy!=\"mutual_tls\", source_workload=~\"$workload\", source_workload_namespace=~\"$namespace\", destination_service=~\"$dstsvc\"}[1m])) by (destination_service, le)) / 1000) or histogram_quantile(0.99, sum(irate(istio_request_duration_seconds_bucket{reporter=\"source\", connection_security_policy!=\"mutual_tls\", source_workload=~\"$workload\", source_workload_namespace=~\"$namespace\", destination_service=~\"$dstsvc\"}[1m])) by (destination_service, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_service }} P99", + "refId": "H", + "step": 2 + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Outgoing Request Duration by Destination", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "s", + "label": null, + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ] + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 6, + "w": 8, + "x": 8, + "y": 41 + }, + "id": 73, + "legend": { + "alignAsTable": false, + "avg": false, + "current": false, + "hideEmpty": true, + "max": false, + "min": false, + "rightSide": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "histogram_quantile(0.50, sum(irate(istio_request_bytes_bucket{reporter=\"source\", connection_security_policy=\"mutual_tls\", source_workload=~\"$workload\", source_workload_namespace=~\"$namespace\", destination_service=~\"$dstsvc\"}[1m])) by (destination_service, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_service }} P50 (🔐mTLS)", + "refId": "D", + "step": 2 + }, + { + "expr": "histogram_quantile(0.90, sum(irate(istio_request_bytes_bucket{reporter=\"source\", connection_security_policy=\"mutual_tls\", source_workload=~\"$workload\", source_workload_namespace=~\"$namespace\", destination_service=~\"$dstsvc\"}[1m])) by (destination_service, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_service }} P90 (🔐mTLS)", + "refId": "A", + "step": 2 + }, + { + "expr": "histogram_quantile(0.95, sum(irate(istio_request_bytes_bucket{reporter=\"source\", connection_security_policy=\"mutual_tls\", source_workload=~\"$workload\", source_workload_namespace=~\"$namespace\", destination_service=~\"$dstsvc\"}[1m])) by (destination_service, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_service }} P95 (🔐mTLS)", + "refId": "B", + "step": 2 + }, + { + "expr": "histogram_quantile(0.99, sum(irate(istio_request_bytes_bucket{reporter=\"source\", connection_security_policy=\"mutual_tls\", source_workload=~\"$workload\", source_workload_namespace=~\"$namespace\", destination_service=~\"$dstsvc\"}[1m])) by (destination_service, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_service }} P99 (🔐mTLS)", + "refId": "C", + "step": 2 + }, + { + "expr": "histogram_quantile(0.50, sum(irate(istio_request_bytes_bucket{reporter=\"source\", connection_security_policy!=\"mutual_tls\", source_workload=~\"$workload\", source_workload_namespace=~\"$namespace\", destination_service=~\"$dstsvc\"}[1m])) by (destination_service, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_service }} P50", + "refId": "E", + "step": 2 + }, + { + "expr": "histogram_quantile(0.90, sum(irate(istio_request_bytes_bucket{reporter=\"source\", connection_security_policy!=\"mutual_tls\", source_workload=~\"$workload\", source_workload_namespace=~\"$namespace\", destination_service=~\"$dstsvc\"}[1m])) by (destination_service, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_service }} P90", + "refId": "F", + "step": 2 + }, + { + "expr": "histogram_quantile(0.95, sum(irate(istio_request_bytes_bucket{reporter=\"source\", connection_security_policy!=\"mutual_tls\", source_workload=~\"$workload\", source_workload_namespace=~\"$namespace\", destination_service=~\"$dstsvc\"}[1m])) by (destination_service, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_service }} P95", + "refId": "G", + "step": 2 + }, + { + "expr": "histogram_quantile(0.99, sum(irate(istio_request_bytes_bucket{reporter=\"source\", connection_security_policy!=\"mutual_tls\", source_workload=~\"$workload\", source_workload_namespace=~\"$namespace\", destination_service=~\"$dstsvc\"}[1m])) by (destination_service, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_service }} P99", + "refId": "H", + "step": 2 + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Outgoing Request Size By Destination", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "decbytes", + "label": null, + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ] + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 6, + "w": 8, + "x": 16, + "y": 41 + }, + "id": 74, + "legend": { + "alignAsTable": false, + "avg": false, + "current": false, + "hideEmpty": true, + "max": false, + "min": false, + "rightSide": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "histogram_quantile(0.50, sum(irate(istio_response_bytes_bucket{reporter=\"source\", connection_security_policy=\"mutual_tls\", source_workload=~\"$workload\", source_workload_namespace=~\"$namespace\", destination_service=~\"$dstsvc\"}[1m])) by (destination_service, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_service }} P50 (🔐mTLS)", + "refId": "D", + "step": 2 + }, + { + "expr": "histogram_quantile(0.90, sum(irate(istio_response_bytes_bucket{reporter=\"source\", connection_security_policy=\"mutual_tls\", source_workload=~\"$workload\", source_workload_namespace=~\"$namespace\", destination_service=~\"$dstsvc\"}[1m])) by (destination_service, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_service }} P90 (🔐mTLS)", + "refId": "A", + "step": 2 + }, + { + "expr": "histogram_quantile(0.95, sum(irate(istio_response_bytes_bucket{reporter=\"source\", connection_security_policy=\"mutual_tls\", source_workload=~\"$workload\", source_workload_namespace=~\"$namespace\", destination_service=~\"$dstsvc\"}[1m])) by (destination_service, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_service }} P95 (🔐mTLS)", + "refId": "B", + "step": 2 + }, + { + "expr": "histogram_quantile(0.99, sum(irate(istio_response_bytes_bucket{reporter=\"source\", connection_security_policy=\"mutual_tls\", source_workload=~\"$workload\", source_workload_namespace=~\"$namespace\", destination_service=~\"$dstsvc\"}[1m])) by (destination_service, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_service }} P99 (🔐mTLS)", + "refId": "C", + "step": 2 + }, + { + "expr": "histogram_quantile(0.50, sum(irate(istio_response_bytes_bucket{reporter=\"source\", connection_security_policy!=\"mutual_tls\", source_workload=~\"$workload\", source_workload_namespace=~\"$namespace\", destination_service=~\"$dstsvc\"}[1m])) by (destination_service, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_service }} P50", + "refId": "E", + "step": 2 + }, + { + "expr": "histogram_quantile(0.90, sum(irate(istio_response_bytes_bucket{reporter=\"source\", connection_security_policy!=\"mutual_tls\", source_workload=~\"$workload\", source_workload_namespace=~\"$namespace\", destination_service=~\"$dstsvc\"}[1m])) by (destination_service, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_service }} P90", + "refId": "F", + "step": 2 + }, + { + "expr": "histogram_quantile(0.95, sum(irate(istio_response_bytes_bucket{reporter=\"source\", connection_security_policy!=\"mutual_tls\", source_workload=~\"$workload\", source_workload_namespace=~\"$namespace\", destination_service=~\"$dstsvc\"}[1m])) by (destination_service, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_service }} P95", + "refId": "G", + "step": 2 + }, + { + "expr": "histogram_quantile(0.99, sum(irate(istio_response_bytes_bucket{reporter=\"source\", connection_security_policy!=\"mutual_tls\", source_workload=~\"$workload\", source_workload_namespace=~\"$namespace\", destination_service=~\"$dstsvc\"}[1m])) by (destination_service, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_service }} P99", + "refId": "H", + "step": 2 + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Response Size By Destination", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "decbytes", + "label": null, + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ] + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 6, + "w": 12, + "x": 0, + "y": 47 + }, + "id": 76, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "round(sum(irate(istio_tcp_sent_bytes_total{connection_security_policy=\"mutual_tls\", reporter=\"source\", source_workload_namespace=~\"$namespace\", source_workload=~\"$workload\", destination_service=~\"$dstsvc\"}[1m])) by (destination_service), 0.001)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{ destination_service }} (🔐mTLS)", + "refId": "A", + "step": 2 + }, + { + "expr": "round(sum(irate(istio_tcp_sent_bytes_total{connection_security_policy!=\"mutual_tls\", reporter=\"source\", source_workload_namespace=~\"$namespace\", source_workload=~\"$workload\", destination_service=~\"$dstsvc\"}[1m])) by (destination_service), 0.001)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{ destination_service }}", + "refId": "B", + "step": 2 + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Bytes Sent on Outgoing TCP Connection", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "Bps", + "label": null, + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ] + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 6, + "w": 12, + "x": 12, + "y": 47 + }, + "id": 78, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "round(sum(irate(istio_tcp_received_bytes_total{reporter=\"source\", connection_security_policy=\"mutual_tls\", source_workload_namespace=~\"$namespace\", source_workload=~\"$workload\", destination_service=~\"$dstsvc\"}[1m])) by (destination_service), 0.001)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{ destination_service }} (🔐mTLS)", + "refId": "A", + "step": 2 + }, + { + "expr": "round(sum(irate(istio_tcp_received_bytes_total{reporter=\"source\", connection_security_policy!=\"mutual_tls\", source_workload_namespace=~\"$namespace\", source_workload=~\"$workload\", destination_service=~\"$dstsvc\"}[1m])) by (destination_service), 0.001)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{ destination_service }}", + "refId": "B", + "step": 2 + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Bytes Received from Outgoing TCP Connection", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "Bps", + "label": null, + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ] + } + ], + "refresh": "10s", + "schemaVersion": 16, + "style": "dark", + "tags": [], + "templating": { + "list": [ + { + "allValue": null, + "current": {}, + "datasource": "Prometheus", + "hide": 0, + "includeAll": false, + "label": "Namespace", + "multi": false, + "name": "namespace", + "options": [], + "query": "query_result(sum(istio_requests_total) by (destination_workload_namespace) or sum(istio_tcp_sent_bytes_total) by (destination_workload_namespace))", + "refresh": 1, + "regex": "/.*_namespace=\"([^\"]*).*/", + "sort": 0, + "tagValuesQuery": "", + "tags": [], + "tagsQuery": "", + "type": "query", + "useTags": false + }, + { + "allValue": null, + "current": {}, + "datasource": "Prometheus", + "hide": 0, + "includeAll": false, + "label": "Workload", + "multi": false, + "name": "workload", + "options": [], + "query": "query_result((sum(istio_requests_total{destination_workload_namespace=~\"$namespace\"}) by (destination_workload) or sum(istio_requests_total{source_workload_namespace=~\"$namespace\"}) by (source_workload)) or (sum(istio_tcp_sent_bytes_total{destination_workload_namespace=~\"$namespace\"}) by (destination_workload) or sum(istio_tcp_sent_bytes_total{source_workload_namespace=~\"$namespace\"}) by (source_workload)))", + "refresh": 1, + "regex": "/.*workload=\"([^\"]*).*/", + "sort": 1, + "tagValuesQuery": "", + "tags": [], + "tagsQuery": "", + "type": "query", + "useTags": false + }, + { + "allValue": null, + "current": {}, + "datasource": "Prometheus", + "hide": 0, + "includeAll": true, + "label": "Inbound Workload Namespace", + "multi": true, + "name": "srcns", + "options": [], + "query": "query_result( sum(istio_requests_total{reporter=\"destination\", destination_workload=\"$workload\", destination_workload_namespace=~\"$namespace\"}) by (source_workload_namespace) or sum(istio_tcp_sent_bytes_total{reporter=\"destination\", destination_workload=\"$workload\", destination_workload_namespace=~\"$namespace\"}) by (source_workload_namespace))", + "refresh": 1, + "regex": "/.*namespace=\"([^\"]*).*/", + "sort": 2, + "tagValuesQuery": "", + "tags": [], + "tagsQuery": "", + "type": "query", + "useTags": false + }, + { + "allValue": null, + "current": {}, + "datasource": "Prometheus", + "hide": 0, + "includeAll": true, + "label": "Inbound Workload", + "multi": true, + "name": "srcwl", + "options": [], + "query": "query_result( sum(istio_requests_total{reporter=\"destination\", destination_workload=\"$workload\", destination_workload_namespace=~\"$namespace\", source_workload_namespace=~\"$srcns\"}) by (source_workload) or sum(istio_tcp_sent_bytes_total{reporter=\"destination\", destination_workload=\"$workload\", destination_workload_namespace=~\"$namespace\", source_workload_namespace=~\"$srcns\"}) by (source_workload))", + "refresh": 1, + "regex": "/.*workload=\"([^\"]*).*/", + "sort": 3, + "tagValuesQuery": "", + "tags": [], + "tagsQuery": "", + "type": "query", + "useTags": false + }, + { + "allValue": null, + "current": {}, + "datasource": "Prometheus", + "hide": 0, + "includeAll": true, + "label": "Destination Service", + "multi": true, + "name": "dstsvc", + "options": [], + "query": "query_result( sum(istio_requests_total{reporter=\"source\", source_workload=~\"$workload\", source_workload_namespace=~\"$namespace\"}) by (destination_service) or sum(istio_tcp_sent_bytes_total{reporter=\"source\", source_workload=~\"$workload\", source_workload_namespace=~\"$namespace\"}) by (destination_service))", + "refresh": 1, + "regex": "/.*destination_service=\"([^\"]*).*/", + "sort": 4, + "tagValuesQuery": "", + "tags": [], + "tagsQuery": "", + "type": "query", + "useTags": false + } + ] + }, + "time": { + "from": "now-5m", + "to": "now" + }, + "timepicker": { + "refresh_intervals": [ + "5s", + "10s", + "30s", + "1m", + "5m", + "15m", + "30m", + "1h", + "2h", + "1d" + ], + "time_options": [ + "5m", + "15m", + "1h", + "6h", + "12h", + "24h", + "2d", + "7d", + "30d" + ] + }, + "timezone": "", + "title": "Istio Workload Dashboard", + "uid": "UbsSZTDik", + "version": 1 +} +' +--- +apiVersion: v1 +kind: ConfigMap +metadata: + name: istio-grafana-configuration-dashboards-mixer-dashboard + namespace: istio-system + labels: + app: grafana + chart: grafana + heritage: Tiller + release: istio + istio: grafana +data: + mixer-dashboard.json: '{ + "__inputs": [ + { + "name": "DS_PROMETHEUS", + "label": "Prometheus", + "description": "", + "type": "datasource", + "pluginId": "prometheus", + "pluginName": "Prometheus" + } + ], + "__requires": [ + { + "type": "grafana", + "id": "grafana", + "name": "Grafana", + "version": "5.2.3" + }, + { + "type": "panel", + "id": "graph", + "name": "Graph", + "version": "5.0.0" + }, + { + "type": "datasource", + "id": "prometheus", + "name": "Prometheus", + "version": "5.0.0" + }, + { + "type": "panel", + "id": "text", + "name": "Text", + "version": "5.0.0" + } + ], + "annotations": { + "list": [ + { + "builtIn": 1, + "datasource": "-- Grafana --", + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "limit": 100, + "name": "Annotations & Alerts", + "showIn": 0, + "type": "dashboard" + } + ] + }, + "editable": false, + "gnetId": null, + "graphTooltip": 1, + "id": null, + "iteration": 1543881232533, + "links": [], + "panels": [ + { + "content": "

Deployed Versions

", + "gridPos": { + "h": 3, + "w": 24, + "x": 0, + "y": 0 + }, + "height": "40", + "id": 62, + "links": [], + "mode": "html", + "title": "", + "transparent": true, + "type": "text" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 5, + "w": 24, + "x": 0, + "y": 3 + }, + "id": 64, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(istio_build{component=\"mixer\"}) by (tag)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{ tag }}", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Mixer Versions", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "content": "

Resource Usage

", + "gridPos": { + "h": 3, + "w": 24, + "x": 0, + "y": 8 + }, + "height": "40", + "id": 29, + "links": [], + "mode": "html", + "title": "", + "transparent": true, + "type": "text" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 7, + "w": 6, + "x": 0, + "y": 11 + }, + "id": 5, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(process_virtual_memory_bytes{job=~\"istio-telemetry|istio-policy\"}) by (job)", + "format": "time_series", + "instant": false, + "intervalFactor": 2, + "legendFormat": "Virtual Memory ({{ job }})", + "refId": "I" + }, + { + "expr": "sum(process_resident_memory_bytes{job=~\"istio-telemetry|istio-policy\"}) by (job)", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "Resident Memory ({{ job }})", + "refId": "H" + }, + { + "expr": "sum(go_memstats_heap_sys_bytes{job=~\"istio-telemetry|istio-policy\"}) by (job)", + "format": "time_series", + "hide": true, + "intervalFactor": 2, + "legendFormat": "heap sys ({{ job }})", + "refId": "A" + }, + { + "expr": "sum(go_memstats_heap_alloc_bytes{job=~\"istio-telemetry|istio-policy\"}) by (job)", + "format": "time_series", + "hide": true, + "intervalFactor": 2, + "legendFormat": "heap alloc ({{ job }})", + "refId": "D" + }, + { + "expr": "sum(go_memstats_alloc_bytes{job=~\"istio-telemetry|istio-policy\"}) by (job)", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "Alloc ({{ job }})", + "refId": "F" + }, + { + "expr": "sum(go_memstats_heap_inuse_bytes{job=~\"istio-telemetry|istio-policy\"}) by (job)", + "format": "time_series", + "hide": false, + "intervalFactor": 2, + "legendFormat": "Heap in-use ({{ job }})", + "refId": "E" + }, + { + "expr": "sum(go_memstats_stack_inuse_bytes{job=~\"istio-telemetry|istio-policy\"}) by (job)", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "Stack in-use ({{ job }})", + "refId": "G" + }, + { + "expr": "sum(label_replace(container_memory_usage_bytes{job=\"kubernetes-cadvisor\", container=~\"mixer|istio-proxy\", pod=~\"istio-telemetry-.*|istio-policy-.*\"}, \"service\", \"$1\" , \"pod\", \"(istio-telemetry|istio-policy)-.*\")) by (service)", + "format": "time_series", + "hide": false, + "intervalFactor": 2, + "legendFormat": "{{ service }} total (k8s)", + "refId": "C" + }, + { + "expr": "sum(label_replace(container_memory_usage_bytes{job=\"kubernetes-cadvisor\", container=~\"mixer|istio-proxy\", pod=~\"istio-telemetry-.*|istio-policy-.*\"}, \"service\", \"$1\" , \"pod\", \"(istio-telemetry|istio-policy)-.*\")) by (container, service)", + "format": "time_series", + "hide": false, + "intervalFactor": 2, + "legendFormat": "{{ service }} - {{ container }} (k8s)", + "refId": "B" + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Memory", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "bytes", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 7, + "w": 6, + "x": 6, + "y": 11 + }, + "id": 6, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "label_replace(sum(rate(container_cpu_usage_seconds_total{job=\"kubernetes-cadvisor\",container=~\"mixer|istio-proxy\", pod=~\"istio-telemetry-.*|istio-policy-.*\"}[1m])) by (pod), \"service\", \"$1\" , \"pod\", \"(istio-telemetry|istio-policy)-.*\")", + "format": "time_series", + "hide": false, + "intervalFactor": 2, + "legendFormat": "{{ service }} total (k8s)", + "refId": "A" + }, + { + "expr": "label_replace(sum(rate(container_cpu_usage_seconds_total{job=\"kubernetes-cadvisor\",container=~\"mixer|istio-proxy\", pod=~\"istio-telemetry-.*|istio-policy-.*\"}[1m])) by (container, pod), \"service\", \"$1\" , \"pod\", \"(istio-telemetry|istio-policy)-.*\")", + "format": "time_series", + "hide": false, + "intervalFactor": 2, + "legendFormat": "{{ service }} - {{ container }} (k8s)", + "refId": "B" + }, + { + "expr": "sum(irate(process_cpu_seconds_total{job=~\"istio-telemetry|istio-policy\"}[1m])) by (job)", + "format": "time_series", + "hide": false, + "intervalFactor": 2, + "legendFormat": "{{ job }} (self-reported)", + "refId": "C" + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "CPU", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 7, + "w": 6, + "x": 12, + "y": 11 + }, + "id": 7, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(process_open_fds{job=~\"istio-telemetry|istio-policy\"}) by (job)", + "format": "time_series", + "hide": true, + "instant": false, + "interval": "", + "intervalFactor": 2, + "legendFormat": "Open FDs ({{ job }})", + "refId": "A" + }, + { + "expr": "sum(label_replace(container_fs_usage_bytes{job=\"kubernetes-cadvisor\", container=~\"mixer|istio-proxy\", pod=~\"istio-telemetry-.*|istio-policy-.*\"}, \"service\", \"$1\" , \"pod\", \"(istio-telemetry|istio-policy)-.*\")) by (container, service)", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "{{ service }} - {{ container }}", + "refId": "B" + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Disk", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "bytes", + "label": "", + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "decimals": null, + "format": "none", + "label": "", + "logBase": 1024, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 7, + "w": 6, + "x": 18, + "y": 11 + }, + "id": 4, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": false, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(go_goroutines{job=~\"istio-telemetry|istio-policy\"}) by (job)", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "Number of Goroutines ({{ job }})", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Goroutines", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": "", + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "content": "

Mixer Overview

", + "gridPos": { + "h": 3, + "w": 24, + "x": 0, + "y": 18 + }, + "height": "40px", + "id": 30, + "links": [], + "mode": "html", + "title": "", + "transparent": true, + "type": "text" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 6, + "w": 6, + "x": 0, + "y": 21 + }, + "id": 9, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(rate(grpc_io_server_completed_rpcs[1m]))", + "format": "time_series", + "hide": false, + "intervalFactor": 2, + "legendFormat": "mixer (Total)", + "refId": "B" + }, + { + "expr": "sum(rate(grpc_io_server_completed_rpcs[1m])) by (grpc_server_method)", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "mixer ({{ grpc_server_method }})", + "refId": "C" + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Incoming Requests", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "ops", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 6, + "w": 6, + "x": 6, + "y": 21 + }, + "id": 8, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [ + { + "alias": "{}", + "yaxis": 1 + } + ], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "histogram_quantile(0.5, sum(rate(grpc_io_server_server_latency_bucket{}[1m])) by (grpc_server_method, le))", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "{{ grpc_server_method }} 0.5", + "refId": "B" + }, + { + "expr": "histogram_quantile(0.9, sum(rate(grpc_io_server_server_latency_bucket{}[1m])) by (grpc_server_method, le))", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "{{ grpc_server_method }} 0.9", + "refId": "C" + }, + { + "expr": "histogram_quantile(0.99, sum(rate(grpc_io_server_server_latency_bucket{}[1m])) by (grpc_server_method, le))", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "{{ grpc_server_method }} 0.99", + "refId": "D" + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Response Durations", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "ms", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 6, + "w": 6, + "x": 12, + "y": 21 + }, + "id": 11, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(rate(grpc_server_handled_total{grpc_code=~\"Unknown|Unimplemented|Internal|DataLoss\"}[1m])) by (grpc_method)", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "Mixer {{ grpc_method }}", + "refId": "B" + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Server Error Rate (5xx responses)", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 6, + "w": 6, + "x": 18, + "y": 21 + }, + "id": 12, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(irate(grpc_server_handled_total{grpc_code!=\"OK\",grpc_service=~\".*Mixer\"}[1m])) by (grpc_method)", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "Mixer {{ grpc_method }}", + "refId": "B" + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Non-successes (4xxs)", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "content": "

Adapters and Config

", + "gridPos": { + "h": 3, + "w": 24, + "x": 0, + "y": 27 + }, + "id": 28, + "links": [], + "mode": "html", + "title": "", + "transparent": true, + "type": "text" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 7, + "w": 12, + "x": 0, + "y": 30 + }, + "id": 13, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(irate(mixer_runtime_dispatches_total{adapter=~\"$adapter\"}[1m])) by (adapter)", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "{{ adapter }}", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Adapter Dispatch Count", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 7, + "w": 12, + "x": 12, + "y": 30 + }, + "id": 14, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "histogram_quantile(0.5, sum(irate(mixer_runtime_dispatch_duration_seconds_bucket{adapter=~\"$adapter\"}[1m])) by (adapter, le))", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "{{ adapter }} - p50", + "refId": "A" + }, + { + "expr": "histogram_quantile(0.9, sum(irate(mixer_runtime_dispatch_duration_seconds_bucket{adapter=~\"$adapter\"}[1m])) by (adapter, le))", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "{{ adapter }} - p90 ", + "refId": "B" + }, + { + "expr": "histogram_quantile(0.99, sum(irate(mixer_runtime_dispatch_duration_seconds_bucket{adapter=~\"$adapter\"}[1m])) by (adapter, le))", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "{{ adapter }} - p99", + "refId": "C" + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Adapter Dispatch Duration", + "tooltip": { + "shared": true, + "sort": 1, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "s", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 7, + "w": 6, + "x": 0, + "y": 37 + }, + "id": 60, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "scalar(topk(1, max(mixer_config_rule_config_count) by (configID)))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Rules", + "refId": "A" + }, + { + "expr": "scalar(topk(1, max(mixer_config_rule_config_error_count) by (configID)))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Config Errors", + "refId": "B" + }, + { + "expr": "scalar(topk(1, max(mixer_config_rule_config_match_error_count) by (configID)))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Match Errors", + "refId": "C" + }, + { + "expr": "scalar(topk(1, max(mixer_config_unsatisfied_action_handler_count) by (configID)))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Unsatisfied Actions", + "refId": "D" + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Rules", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 7, + "w": 6, + "x": 6, + "y": 37 + }, + "id": 56, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "scalar(topk(1, max(mixer_config_instance_config_count) by (configID)))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Instances", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Instances in Latest Config", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 7, + "w": 6, + "x": 12, + "y": 37 + }, + "id": 54, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "scalar(topk(1, max(mixer_config_handler_config_count) by (configID)))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Handlers", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Handlers in Latest Config", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 7, + "w": 6, + "x": 18, + "y": 37 + }, + "id": 58, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "scalar(topk(1, max(mixer_config_attribute_count) by (configID)))", + "format": "time_series", + "instant": false, + "intervalFactor": 1, + "legendFormat": "Attributes", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Attributes in Latest Config", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "content": "

Individual Adapters

", + "gridPos": { + "h": 3, + "w": 24, + "x": 0, + "y": 44 + }, + "id": 23, + "links": [], + "mode": "html", + "title": "", + "transparent": true, + "type": "text" + }, + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 47 + }, + "id": 46, + "panels": [], + "repeat": "adapter", + "title": "$adapter Adapter", + "type": "row" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 7, + "w": 12, + "x": 0, + "y": 48 + }, + "id": 17, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "label_replace(irate(mixer_runtime_dispatches_total{adapter=~\"$adapter\"}[1m]),\"handler\", \"$1 ($3)\", \"handler\", \"(.*)\\\\.(.*)\\\\.(.*)\")", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "{{ handler }} (error: {{ error }})", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Dispatch Count By Handler", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 7, + "w": 12, + "x": 12, + "y": 48 + }, + "id": 18, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "label_replace(histogram_quantile(0.5, sum(rate(mixer_runtime_dispatch_duration_seconds_bucket{adapter=~\"$adapter\"}[1m])) by (handler, error, le)), \"handler_short\", \"$1 ($3)\", \"handler\", \"(.*)\\\\.(.*)\\\\.(.*)\")", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "p50 - {{ handler_short }} (error: {{ error }})", + "refId": "A" + }, + { + "expr": "label_replace(histogram_quantile(0.9, sum(irate(mixer_runtime_dispatch_duration_seconds_bucket{adapter=~\"$adapter\"}[1m])) by (handler, error, le)), \"handler_short\", \"$1 ($3)\", \"handler\", \"(.*)\\\\.(.*)\\\\.(.*)\")", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "p90 - {{ handler_short }} (error: {{ error }})", + "refId": "D" + }, + { + "expr": "label_replace(histogram_quantile(0.99, sum(irate(mixer_runtime_dispatch_duration_seconds_bucket{adapter=~\"$adapter\"}[1m])) by (handler, error, le)), \"handler_short\", \"$1 ($3)\", \"handler\", \"(.*)\\\\.(.*)\\\\.(.*)\")", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "p99 - {{ handler_short }} (error: {{ error }})", + "refId": "E" + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Dispatch Duration By Handler", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "s", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + } + ], + "refresh": "5s", + "schemaVersion": 16, + "style": "dark", + "tags": [], + "templating": { + "list": [ + { + "allValue": null, + "current": {}, + "datasource": "Prometheus", + "hide": 0, + "includeAll": true, + "label": "Adapter", + "multi": true, + "name": "adapter", + "options": [], + "query": "label_values(adapter)", + "refresh": 2, + "regex": "", + "sort": 1, + "tagValuesQuery": "", + "tags": [], + "tagsQuery": "", + "type": "query", + "useTags": false + } + ] + }, + "time": { + "from": "now-5m", + "to": "now" + }, + "timepicker": { + "refresh_intervals": [ + "5s", + "10s", + "30s", + "1m", + "5m", + "15m", + "30m", + "1h", + "2h", + "1d" + ], + "time_options": [ + "5m", + "15m", + "1h", + "6h", + "12h", + "24h", + "2d", + "7d", + "30d" + ] + }, + "timezone": "", + "title": "Istio Mixer Dashboard", + "version": 4 +} +' +--- +apiVersion: v1 +kind: ConfigMap +metadata: + name: istio-grafana-configuration-dashboards-pilot-dashboard + namespace: istio-system + labels: + app: grafana + chart: grafana + heritage: Tiller + release: istio + istio: grafana +data: + pilot-dashboard.json: '{ + "annotations": { + "list": [ + { + "builtIn": 1, + "datasource": "-- Grafana --", + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations & Alerts", + "type": "dashboard" + } + ] + }, + "editable": false, + "gnetId": null, + "graphTooltip": 1, + "id": 11, + "links": [], + "panels": [ + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 0 + }, + "id": 60, + "panels": [], + "title": "Deployed Versions", + "type": "row" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 5, + "w": 24, + "x": 0, + "y": 1 + }, + "id": 56, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(istio_build{component=\"pilot\"}) by (tag)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{ tag }}", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Pilot Versions", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 6 + }, + "id": 62, + "panels": [], + "title": "Resource Usage", + "type": "row" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 7, + "w": 6, + "x": 0, + "y": 7 + }, + "id": 5, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "process_virtual_memory_bytes{job=\"pilot\"}", + "format": "time_series", + "instant": false, + "intervalFactor": 2, + "legendFormat": "Virtual Memory", + "refId": "I", + "step": 2 + }, + { + "expr": "process_resident_memory_bytes{job=\"pilot\"}", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "Resident Memory", + "refId": "H", + "step": 2 + }, + { + "expr": "go_memstats_heap_sys_bytes{job=\"pilot\"}", + "format": "time_series", + "hide": true, + "intervalFactor": 2, + "legendFormat": "heap sys", + "refId": "A" + }, + { + "expr": "go_memstats_heap_alloc_bytes{job=\"pilot\"}", + "format": "time_series", + "hide": true, + "intervalFactor": 2, + "legendFormat": "heap alloc", + "refId": "D" + }, + { + "expr": "go_memstats_alloc_bytes{job=\"pilot\"}", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "Alloc", + "refId": "F", + "step": 2 + }, + { + "expr": "go_memstats_heap_inuse_bytes{job=\"pilot\"}", + "format": "time_series", + "hide": false, + "intervalFactor": 2, + "legendFormat": "Heap in-use", + "refId": "E", + "step": 2 + }, + { + "expr": "go_memstats_stack_inuse_bytes{job=\"pilot\"}", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "Stack in-use", + "refId": "G", + "step": 2 + }, + { + "expr": "container_memory_usage_bytes{job=\"kubernetes-cadvisor\", container=~\"discovery\", pod=~\"istio-pilot-.*\"}", + "format": "time_series", + "hide": false, + "intervalFactor": 2, + "legendFormat": "Discovery (container)", + "refId": "B", + "step": 2 + }, + { + "expr": "container_memory_usage_bytes{job=\"kubernetes-cadvisor\", container=~\"istio-proxy\", pod=~\"istio-pilot-.*\"}", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Sidecar (container)", + "refId": "C" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Memory", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "bytes", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 7, + "w": 6, + "x": 6, + "y": 7 + }, + "id": 6, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(irate(container_cpu_usage_seconds_total{job=\"kubernetes-cadvisor\",container=\"discovery\", pod=~\"istio-pilot-.*\"}[1m]))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Discovery (container)", + "refId": "A" + }, + { + "expr": "irate(process_cpu_seconds_total{job=\"pilot\"}[1m])", + "format": "time_series", + "hide": false, + "intervalFactor": 2, + "legendFormat": "Discovery (process)", + "refId": "C", + "step": 2 + }, + { + "expr": "sum(irate(container_cpu_usage_seconds_total{job=\"kubernetes-cadvisor\",container=\"istio-proxy\", pod=~\"istio-pilot-.*\"}[1m]))", + "format": "time_series", + "hide": false, + "intervalFactor": 2, + "legendFormat": "Sidecar (container)", + "refId": "B", + "step": 2 + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "CPU", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 7, + "w": 6, + "x": 12, + "y": 7 + }, + "id": 7, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "container_fs_usage_bytes{job=\"kubernetes-cadvisor\", container=\"discovery\", pod=~\"istio-pilot-.*\"}", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "Discovery", + "refId": "B", + "step": 2 + }, + { + "expr": "container_fs_usage_bytes{job=\"kubernetes-cadvisor\", container=\"istio-proxy\", pod=~\"istio-pilot-.*\"}", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Sidecar", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Disk", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "bytes", + "label": "", + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "decimals": null, + "format": "none", + "label": "", + "logBase": 1024, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 7, + "w": 6, + "x": 18, + "y": 7 + }, + "id": 4, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": false, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "go_goroutines{job=\"pilot\"}", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "Number of Goroutines", + "refId": "A", + "step": 2 + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Goroutines", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": "", + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 14 + }, + "id": 58, + "panels": [], + "title": "Pilot Push Information", + "type": "row" + }, + { + "aliasColors": {}, + "bars": true, + "dashLength": 10, + "dashes": false, + "description": "Shows the rate of pilot pushes", + "fill": 1, + "gridPos": { + "h": 8, + "w": 8, + "x": 0, + "y": 15 + }, + "id": 622, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": false, + "linewidth": 1, + "links": [], + "nullPointMode": "null as zero", + "paceLength": 10, + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": true, + "steppedLine": false, + "targets": [ + { + "expr": "sum(irate(pilot_xds_pushes{type=\"cds\"}[1m]))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Cluster", + "refId": "C" + }, + { + "expr": "sum(irate(pilot_xds_pushes{type=\"eds\"}[1m]))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Endpoints", + "refId": "D" + }, + { + "expr": "sum(irate(pilot_xds_pushes{type=\"lds\"}[1m]))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Listeners", + "refId": "A" + }, + { + "expr": "sum(irate(pilot_xds_pushes{type=\"rds\"}[1m]))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Routes", + "refId": "E" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Pilot Pushes", + "tooltip": { + "shared": false, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [ + "total" + ] + }, + "yaxes": [ + { + "format": "ops", + "label": null, + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "description": "Captures a variety of pilot errors", + "fill": 1, + "gridPos": { + "h": 8, + "w": 8, + "x": 8, + "y": 15 + }, + "id": 67, + "legend": { + "avg": false, + "current": false, + "hideEmpty": true, + "hideZero": true, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(pilot_xds_cds_reject{job=\"pilot\"}) or (absent(pilot_xds_cds_reject{job=\"pilot\"}) - 1)", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "Rejected CDS Configs", + "refId": "C" + }, + { + "expr": "sum(pilot_xds_eds_reject{job=\"pilot\"}) or (absent(pilot_xds_eds_reject{job=\"pilot\"}) - 1)", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "Rejected EDS Configs", + "refId": "D" + }, + { + "expr": "sum(pilot_xds_rds_reject{job=\"pilot\"}) or (absent(pilot_xds_rds_reject{job=\"pilot\"}) - 1)", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "Rejected RDS Configs", + "refId": "A" + }, + { + "expr": "sum(pilot_xds_lds_reject{job=\"pilot\"}) or (absent(pilot_xds_lds_reject{job=\"pilot\"}) - 1)", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "Rejected LDS Configs", + "refId": "B" + }, + { + "expr": "sum(rate(pilot_xds_write_timeout{job=\"pilot\"}[1m]))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Write Timeouts", + "refId": "F" + }, + { + "expr": "sum(rate(pilot_total_xds_internal_errors{job=\"pilot\"}[1m]))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "Internal Errors", + "refId": "H" + }, + { + "expr": "sum(rate(pilot_total_xds_rejects{job=\"pilot\"}[1m]))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "Config Rejection Rate", + "refId": "E" + }, + { + "expr": "sum(rate(pilot_xds_push_context_errors{job=\"pilot\"}[1m]))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "Push Context Errors", + "refId": "K" + }, + { + "expr": "sum(rate(pilot_xds_pushes{type!~\"lds|cds|rds|eds\"}[1m])) by (type)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Push Errors ({{ type }})", + "refId": "L" + }, + { + "expr": "sum(rate(pilot_xds_push_errors{job=\"pilot\"}[1m])) by (type)", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "Push Errors ({{ type }})", + "refId": "I" + }, + { + "expr": "sum(rate(pilot_xds_push_timeout{job=\"pilot\"}[1m]))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Push Timeouts", + "refId": "G" + }, + { + "expr": "sum(rate(pilot_xds_push_timeout_failures{job=\"pilot\"}[1m]))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Push Timeouts Failures", + "refId": "J" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Pilot Errors", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "description": "Shows the total time it takes to push a config update to a proxy", + "fill": 1, + "gridPos": { + "h": 8, + "w": 8, + "x": 16, + "y": 15 + }, + "id": 624, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "histogram_quantile(0.5, sum(rate(pilot_proxy_convergence_time_bucket[1m])) by (le))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "p50 ", + "refId": "A" + }, + { + "expr": "histogram_quantile(0.9, sum(rate(pilot_proxy_convergence_time_bucket[1m])) by (le))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "p90", + "refId": "B" + }, + { + "expr": "histogram_quantile(0.99, sum(rate(pilot_proxy_convergence_time_bucket[1m])) by (le))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "p99", + "refId": "C" + }, + { + "expr": "histogram_quantile(0.999, sum(rate(pilot_proxy_convergence_time_bucket[1m])) by (le))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "p99.9", + "refId": "D" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Proxy Push Time", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "s", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 8, + "w": 8, + "x": 0, + "y": 23 + }, + "id": 45, + "legend": { + "avg": false, + "current": false, + "hideEmpty": true, + "hideZero": true, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null as zero", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "pilot_conflict_inbound_listener{job=\"pilot\"}", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "Inbound Listeners", + "refId": "B" + }, + { + "expr": "pilot_conflict_outbound_listener_http_over_current_tcp{job=\"pilot\"}", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "Outbound Listeners (http over current tcp)", + "refId": "A" + }, + { + "expr": "pilot_conflict_outbound_listener_tcp_over_current_tcp{job=\"pilot\"}", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "Outbound Listeners (tcp over current tcp)", + "refId": "C" + }, + { + "expr": "pilot_conflict_outbound_listener_tcp_over_current_http{job=\"pilot\"}", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "Outbound Listeners (tcp over current http)", + "refId": "D" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Conflicts", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 8, + "w": 8, + "x": 8, + "y": 23 + }, + "id": 47, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "pilot_virt_services{job=\"pilot\"}", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Virtual Services", + "refId": "A" + }, + { + "expr": "pilot_services{job=\"pilot\"}", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Services", + "refId": "B" + }, + { + "expr": "pilot_xds{job=\"pilot\"}", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Connected Endpoints", + "refId": "E" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "ADS Monitoring", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "columns": [], + "datasource": "Prometheus", + "description": "Clusters in this table do not have any endpoints known to pilot. This could be from referencing subsets that do not have any instances, or pods marked as NotReady", + "fontSize": "100%", + "gridPos": { + "h": 8, + "w": 8, + "x": 16, + "y": 23 + }, + "id": 51, + "links": [], + "pageSize": null, + "scroll": true, + "showHeader": true, + "sort": { + "col": null, + "desc": false + }, + "styles": [ + { + "alias": "Time", + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "pattern": "Time", + "type": "date" + }, + { + "alias": "Clusters", + "colorMode": null, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "decimals": 2, + "pattern": "/.*/", + "thresholds": [], + "type": "number", + "unit": "short" + } + ], + "targets": [ + { + "expr": "sum(pilot_xds_eds_instances{job=\"pilot\", cluster=~\".+\\\\|.+\"}) by (cluster) < 1", + "format": "time_series", + "hide": false, + "instant": true, + "intervalFactor": 1, + "legendFormat": "{{cluster}}", + "refId": "B" + } + ], + "timeFrom": null, + "timeShift": null, + "title": "Clusters with no known endpoints", + "transform": "timeseries_aggregations", + "type": "table" + }, + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 31 + }, + "id": 64, + "panels": [], + "title": "Envoy Information", + "type": "row" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "description": "Shows details about Envoy proxies in the mesh", + "fill": 1, + "gridPos": { + "h": 8, + "w": 8, + "x": 0, + "y": 32 + }, + "id": 40, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(irate(envoy_cluster_upstream_cx_total{cluster_name=\"xds-grpc\"}[1m]))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "XDS Connections", + "refId": "C" + }, + { + "expr": "sum(irate(envoy_cluster_upstream_cx_connect_fail{cluster_name=\"xds-grpc\"}[1m]))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "XDS Connection Failures", + "refId": "A" + }, + { + "expr": "sum(increase(envoy_server_hot_restart_epoch[1m]))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Envoy Restarts", + "refId": "B" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Envoy Details", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "ops", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "ops", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 8, + "w": 8, + "x": 8, + "y": 32 + }, + "id": 41, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(envoy_cluster_upstream_cx_active{cluster_name=\"xds-grpc\"})", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "XDS Active Connections", + "refId": "C", + "step": 2 + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "XDS Active Connections", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "description": "Shows the size of XDS requests and responses", + "fill": 1, + "gridPos": { + "h": 8, + "w": 8, + "x": 16, + "y": 32 + }, + "id": 42, + "legend": { + "avg": false, + "current": false, + "hideEmpty": false, + "hideZero": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "max(rate(envoy_cluster_upstream_cx_rx_bytes_total{cluster_name=\"xds-grpc\"}[1m]))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "XDS Response Bytes Max", + "refId": "D" + }, + { + "expr": "quantile(0.5, rate(envoy_cluster_upstream_cx_rx_bytes_total{cluster_name=\"xds-grpc\"}[1m]))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "XDS Response Bytes Average", + "refId": "B" + }, + { + "expr": "max(rate(envoy_cluster_upstream_cx_tx_bytes_total{cluster_name=\"xds-grpc\"}[1m]))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "XDS Request Bytes Max", + "refId": "A" + }, + { + "expr": "quantile(.5, rate(envoy_cluster_upstream_cx_tx_bytes_total{cluster_name=\"xds-grpc\"}[1m]))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "XDS Request Bytes Average", + "refId": "C" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "XDS Requests Size", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "Bps", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "ops", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + } + ], + "refresh": "5s", + "schemaVersion": 18, + "style": "dark", + "tags": [], + "templating": { + "list": [] + }, + "time": { + "from": "now-5m", + "to": "now" + }, + "timepicker": { + "refresh_intervals": [ + "5s", + "10s", + "30s", + "1m", + "5m", + "15m", + "30m", + "1h", + "2h", + "1d" + ], + "time_options": [ + "5m", + "15m", + "1h", + "6h", + "12h", + "24h", + "2d", + "7d", + "30d" + ] + }, + "timezone": "browser", + "title": "Istio Pilot Dashboard", + "uid": "3--MLVZZk", + "version": 11 +}' +--- + +--- +# Source: istio/charts/grafana/templates/configmap.yaml +apiVersion: v1 +kind: ConfigMap +metadata: + name: istio-grafana + namespace: istio-system + labels: + app: grafana + chart: grafana + heritage: Tiller + release: istio + istio: grafana +data: + datasources.yaml: | + apiVersion: 1 + datasources: + - access: proxy + editable: true + isDefault: true + jsonData: + timeInterval: 5s + name: Prometheus + orgId: 1 + type: prometheus + url: http://prometheus:9090 + + dashboardproviders.yaml: | + apiVersion: 1 + providers: + - disableDeletion: false + folder: istio + name: istio + options: + path: /var/lib/grafana/dashboards/istio + orgId: 1 + type: file + +--- +# Source: istio/charts/kiali/templates/configmap.yaml +apiVersion: v1 +kind: ConfigMap +metadata: + name: kiali + namespace: istio-system + labels: + app: kiali + chart: kiali + heritage: Tiller + release: istio +data: + config.yaml: | + istio_namespace: istio-system + deployment: + accessible_namespaces: ['**'] + auth: + strategy: login + server: + port: 20001 + web_root: /kiali + external_services: + tracing: + url: + in_cluster_url: http://tracing/jaeger + grafana: + url: + in_cluster_url: http://grafana:3000 + prometheus: + url: http://prometheus:9090 + +--- +# Source: istio/charts/prometheus/templates/configmap.yaml +apiVersion: v1 +kind: ConfigMap +metadata: + name: prometheus + namespace: istio-system + labels: + app: prometheus + chart: prometheus + heritage: Tiller + release: istio +data: + prometheus.yml: |- + global: + scrape_interval: 15s + scrape_configs: + + - job_name: 'istio-mesh' + kubernetes_sd_configs: + - role: endpoints + namespaces: + names: + - istio-system + + relabel_configs: + - source_labels: [__meta_kubernetes_service_name, __meta_kubernetes_endpoint_port_name] + action: keep + regex: istio-telemetry;prometheus + + # Scrape config for envoy stats + - job_name: 'envoy-stats' + metrics_path: /stats/prometheus + kubernetes_sd_configs: + - role: pod + + relabel_configs: + - source_labels: [__meta_kubernetes_pod_container_port_name] + action: keep + regex: '.*-envoy-prom' + - source_labels: [__address__, __meta_kubernetes_pod_annotation_prometheus_io_port] + action: replace + regex: ([^:]+)(?::\d+)?;(\d+) + replacement: $1:15090 + target_label: __address__ + - action: labelmap + regex: __meta_kubernetes_pod_label_(.+) + - source_labels: [__meta_kubernetes_namespace] + action: replace + target_label: namespace + - source_labels: [__meta_kubernetes_pod_name] + action: replace + target_label: pod_name + + - job_name: 'istio-policy' + kubernetes_sd_configs: + - role: endpoints + namespaces: + names: + - istio-system + + + relabel_configs: + - source_labels: [__meta_kubernetes_service_name, __meta_kubernetes_endpoint_port_name] + action: keep + regex: istio-policy;http-monitoring + + - job_name: 'istio-telemetry' + kubernetes_sd_configs: + - role: endpoints + namespaces: + names: + - istio-system + + relabel_configs: + - source_labels: [__meta_kubernetes_service_name, __meta_kubernetes_endpoint_port_name] + action: keep + regex: istio-telemetry;http-monitoring + + - job_name: 'pilot' + kubernetes_sd_configs: + - role: endpoints + namespaces: + names: + - istio-system + + relabel_configs: + - source_labels: [__meta_kubernetes_service_name, __meta_kubernetes_endpoint_port_name] + action: keep + regex: istio-pilot;http-monitoring + + - job_name: 'galley' + kubernetes_sd_configs: + - role: endpoints + namespaces: + names: + - istio-system + + relabel_configs: + - source_labels: [__meta_kubernetes_service_name, __meta_kubernetes_endpoint_port_name] + action: keep + regex: istio-galley;http-monitoring + + - job_name: 'citadel' + kubernetes_sd_configs: + - role: endpoints + namespaces: + names: + - istio-system + + relabel_configs: + - source_labels: [__meta_kubernetes_service_name, __meta_kubernetes_endpoint_port_name] + action: keep + regex: istio-citadel;http-monitoring + + - job_name: 'sidecar-injector' + + kubernetes_sd_configs: + - role: endpoints + namespaces: + names: + - istio-system + + relabel_configs: + - source_labels: [__meta_kubernetes_service_name, __meta_kubernetes_endpoint_port_name] + action: keep + regex: istio-sidecar-injector;http-monitoring + + # scrape config for API servers + - job_name: 'kubernetes-apiservers' + kubernetes_sd_configs: + - role: endpoints + namespaces: + names: + - default + scheme: https + tls_config: + ca_file: /var/run/secrets/kubernetes.io/serviceaccount/ca.crt + bearer_token_file: /var/run/secrets/kubernetes.io/serviceaccount/token + relabel_configs: + - source_labels: [__meta_kubernetes_service_name, __meta_kubernetes_endpoint_port_name] + action: keep + regex: kubernetes;https + + # scrape config for nodes (kubelet) + - job_name: 'kubernetes-nodes' + scheme: https + tls_config: + ca_file: /var/run/secrets/kubernetes.io/serviceaccount/ca.crt + bearer_token_file: /var/run/secrets/kubernetes.io/serviceaccount/token + kubernetes_sd_configs: + - role: node + relabel_configs: + - action: labelmap + regex: __meta_kubernetes_node_label_(.+) + - target_label: __address__ + replacement: kubernetes.default.svc:443 + - source_labels: [__meta_kubernetes_node_name] + regex: (.+) + target_label: __metrics_path__ + replacement: /api/v1/nodes/${1}/proxy/metrics + + # Scrape config for Kubelet cAdvisor. + # + # This is required for Kubernetes 1.7.3 and later, where cAdvisor metrics + # (those whose names begin with 'container_') have been removed from the + # Kubelet metrics endpoint. This job scrapes the cAdvisor endpoint to + # retrieve those metrics. + # + # In Kubernetes 1.7.0-1.7.2, these metrics are only exposed on the cAdvisor + # HTTP endpoint; use "replacement: /api/v1/nodes/${1}:4194/proxy/metrics" + # in that case (and ensure cAdvisor's HTTP server hasn't been disabled with + # the --cadvisor-port=0 Kubelet flag). + # + # This job is not necessary and should be removed in Kubernetes 1.6 and + # earlier versions, or it will cause the metrics to be scraped twice. + - job_name: 'kubernetes-cadvisor' + scheme: https + tls_config: + ca_file: /var/run/secrets/kubernetes.io/serviceaccount/ca.crt + bearer_token_file: /var/run/secrets/kubernetes.io/serviceaccount/token + kubernetes_sd_configs: + - role: node + relabel_configs: + - action: labelmap + regex: __meta_kubernetes_node_label_(.+) + - target_label: __address__ + replacement: kubernetes.default.svc:443 + - source_labels: [__meta_kubernetes_node_name] + regex: (.+) + target_label: __metrics_path__ + replacement: /api/v1/nodes/${1}/proxy/metrics/cadvisor + + # scrape config for service endpoints. + - job_name: 'kubernetes-service-endpoints' + kubernetes_sd_configs: + - role: endpoints + relabel_configs: + - source_labels: [__meta_kubernetes_service_annotation_prometheus_io_scrape] + action: keep + regex: true + - source_labels: [__meta_kubernetes_service_annotation_prometheus_io_scheme] + action: replace + target_label: __scheme__ + regex: (https?) + - source_labels: [__meta_kubernetes_service_annotation_prometheus_io_path] + action: replace + target_label: __metrics_path__ + regex: (.+) + - source_labels: [__address__, __meta_kubernetes_service_annotation_prometheus_io_port] + action: replace + target_label: __address__ + regex: ([^:]+)(?::\d+)?;(\d+) + replacement: $1:$2 + - action: labelmap + regex: __meta_kubernetes_service_label_(.+) + - source_labels: [__meta_kubernetes_namespace] + action: replace + target_label: kubernetes_namespace + - source_labels: [__meta_kubernetes_service_name] + action: replace + target_label: kubernetes_name + + - job_name: 'kubernetes-pods' + kubernetes_sd_configs: + - role: pod + relabel_configs: # If first two labels are present, pod should be scraped by the istio-secure job. + - source_labels: [__meta_kubernetes_pod_annotation_prometheus_io_scrape] + action: keep + regex: true + # Keep target if there's no sidecar or if prometheus.io/scheme is explicitly set to "http" + - source_labels: [__meta_kubernetes_pod_annotation_sidecar_istio_io_status, __meta_kubernetes_pod_annotation_prometheus_io_scheme] + action: keep + regex: ((;.*)|(.*;http)) + - source_labels: [__meta_kubernetes_pod_annotation_istio_mtls] + action: drop + regex: (true) + - source_labels: [__meta_kubernetes_pod_annotation_prometheus_io_path] + action: replace + target_label: __metrics_path__ + regex: (.+) + - source_labels: [__address__, __meta_kubernetes_pod_annotation_prometheus_io_port] + action: replace + regex: ([^:]+)(?::\d+)?;(\d+) + replacement: $1:$2 + target_label: __address__ + - action: labelmap + regex: __meta_kubernetes_pod_label_(.+) + - source_labels: [__meta_kubernetes_namespace] + action: replace + target_label: namespace + - source_labels: [__meta_kubernetes_pod_name] + action: replace + target_label: pod_name + + - job_name: 'kubernetes-pods-istio-secure' + scheme: https + tls_config: + ca_file: /etc/istio-certs/root-cert.pem + cert_file: /etc/istio-certs/cert-chain.pem + key_file: /etc/istio-certs/key.pem + insecure_skip_verify: true # prometheus does not support secure naming. + kubernetes_sd_configs: + - role: pod + relabel_configs: + - source_labels: [__meta_kubernetes_pod_annotation_prometheus_io_scrape] + action: keep + regex: true + # sidecar status annotation is added by sidecar injector and + # istio_workload_mtls_ability can be specifically placed on a pod to indicate its ability to receive mtls traffic. + - source_labels: [__meta_kubernetes_pod_annotation_sidecar_istio_io_status, __meta_kubernetes_pod_annotation_istio_mtls] + action: keep + regex: (([^;]+);([^;]*))|(([^;]*);(true)) + - source_labels: [__meta_kubernetes_pod_annotation_prometheus_io_scheme] + action: drop + regex: (http) + - source_labels: [__meta_kubernetes_pod_annotation_prometheus_io_path] + action: replace + target_label: __metrics_path__ + regex: (.+) + - source_labels: [__address__] # Only keep address that is host:port + action: keep # otherwise an extra target with ':443' is added for https scheme + regex: ([^:]+):(\d+) + - source_labels: [__address__, __meta_kubernetes_pod_annotation_prometheus_io_port] + action: replace + regex: ([^:]+)(?::\d+)?;(\d+) + replacement: $1:$2 + target_label: __address__ + - action: labelmap + regex: __meta_kubernetes_pod_label_(.+) + - source_labels: [__meta_kubernetes_namespace] + action: replace + target_label: namespace + - source_labels: [__meta_kubernetes_pod_name] + action: replace + target_label: pod_name + +--- +# Source: istio/charts/security/templates/configmap.yaml +apiVersion: v1 +kind: ConfigMap +metadata: + name: istio-security-custom-resources + namespace: istio-system + labels: + app: security + chart: security + heritage: Tiller + release: istio + istio: citadel +data: + custom-resources.yaml: |- + # Authentication policy to enable permissive mode for all services (that have sidecar) in the mesh. + apiVersion: "authentication.istio.io/v1alpha1" + kind: "MeshPolicy" + metadata: + name: "default" + labels: + app: security + chart: security + heritage: Tiller + release: istio + spec: + peers: + - mtls: + mode: PERMISSIVE + run.sh: |- + #!/bin/sh + + set -x + + if [ "$#" -ne "1" ]; then + echo "first argument should be path to custom resource yaml" + exit 1 + fi + + pathToResourceYAML=${1} + + kubectl get validatingwebhookconfiguration istio-galley 2>/dev/null + if [ "$?" -eq 0 ]; then + echo "istio-galley validatingwebhookconfiguration found - waiting for istio-galley deployment to be ready" + while true; do + kubectl -n istio-system get deployment istio-galley 2>/dev/null + if [ "$?" -eq 0 ]; then + break + fi + sleep 1 + done + kubectl -n istio-system rollout status deployment istio-galley + if [ "$?" -ne 0 ]; then + echo "istio-galley deployment rollout status check failed" + exit 1 + fi + echo "istio-galley deployment ready for configuration validation" + fi + sleep 5 + kubectl apply -f ${pathToResourceYAML} + + +--- +# Source: istio/templates/configmap.yaml + +apiVersion: v1 +kind: ConfigMap +metadata: + name: istio + namespace: istio-system + labels: + app: istio + chart: istio + heritage: Tiller + release: istio +data: + mesh: |- + # Set the following variable to true to disable policy checks by Mixer. + # Note that metrics will still be reported to Mixer. + disablePolicyChecks: false + + disableMixerHttpReports: false + # reportBatchMaxEntries is the number of requests that are batched before telemetry data is sent to the mixer server + reportBatchMaxEntries: 100 + # reportBatchMaxTime is the max waiting time before the telemetry data of a request is sent to the mixer server + reportBatchMaxTime: 1s + + # Set enableTracing to false to disable request tracing. + enableTracing: true + + # Set accessLogFile to empty string to disable access log. + accessLogFile: "/dev/stdout" + + # If accessLogEncoding is TEXT, value will be used directly as the log format + # example: "[%START_TIME%] %REQ(:METHOD)% %REQ(X-ENVOY-ORIGINAL-PATH?:PATH)% %PROTOCOL%\n" + # If AccessLogEncoding is JSON, value will be parsed as map[string]string + # example: '{"start_time": "%START_TIME%", "req_method": "%REQ(:METHOD)%"}' + # Leave empty to use default log format + accessLogFormat: "" + + # Set accessLogEncoding to JSON or TEXT to configure sidecar access log + accessLogEncoding: 'TEXT' + + enableEnvoyAccessLogService: false + mixerCheckServer: istio-policy.istio-system.svc.cluster.local:9091 + mixerReportServer: istio-telemetry.istio-system.svc.cluster.local:9091 + # policyCheckFailOpen allows traffic in cases when the mixer policy service cannot be reached. + # Default is false which means the traffic is denied when the client is unable to connect to Mixer. + policyCheckFailOpen: false + # Let Pilot give ingresses the public IP of the Istio ingressgateway + ingressService: istio-ingressgateway + + # Default connect timeout for dynamic clusters generated by Pilot and returned via XDS + connectTimeout: 10s + + # Automatic protocol detection uses a set of heuristics to + # determine whether the connection is using TLS or not (on the + # server side), as well as the application protocol being used + # (e.g., http vs tcp). These heuristics rely on the client sending + # the first bits of data. For server first protocols like MySQL, + # MongoDB, etc., Envoy will timeout on the protocol detection after + # the specified period, defaulting to non mTLS plain TCP + # traffic. Set this field to tweak the period that Envoy will wait + # for the client to send the first bits of data. (MUST BE >=1ms) + protocolDetectionTimeout: 100ms + + # DNS refresh rate for Envoy clusters of type STRICT_DNS + dnsRefreshRate: 300s + + # Unix Domain Socket through which envoy communicates with NodeAgent SDS to get + # key/cert for mTLS. Use secret-mount files instead of SDS if set to empty. + sdsUdsPath: "" + + # The trust domain corresponds to the trust root of a system. + # Refer to https://github.com/spiffe/spiffe/blob/master/standards/SPIFFE-ID.md#21-trust-domain + trustDomain: "" + + # The trust domain aliases represent the aliases of trust_domain. + # For example, if we have + # trustDomain: td1 + # trustDomainAliases: [“td2”, "td3"] + # Any service with the identity "td1/ns/foo/sa/a-service-account", "td2/ns/foo/sa/a-service-account", + # or "td3/ns/foo/sa/a-service-account" will be treated the same in the Istio mesh. + trustDomainAliases: + + # If true, automatically configure client side mTLS settings to match the corresponding service's + # server side mTLS authentication policy, when destination rule for that service does not specify + # TLS settings. + enableAutoMtls: true + + # Set the default behavior of the sidecar for handling outbound traffic from the application: + # ALLOW_ANY - outbound traffic to unknown destinations will be allowed, in case there are no + # services or ServiceEntries for the destination port + # REGISTRY_ONLY - restrict outbound traffic to services defined in the service registry as well + # as those defined through ServiceEntries + outboundTrafficPolicy: + mode: ALLOW_ANY + localityLbSetting: + enabled: true + # The namespace to treat as the administrative root namespace for istio + # configuration. + rootNamespace: istio-system + + # Configures DNS certificates provisioned through Chiron linked into Pilot. + certificates: + [] + configSources: + - address: istio-galley.istio-system.svc:9901 + + defaultConfig: + # + # TCP connection timeout between Envoy & the application, and between Envoys. Used for static clusters + # defined in Envoy's configuration file + connectTimeout: 10s + # + ### ADVANCED SETTINGS ############# + # Where should envoy's configuration be stored in the istio-proxy container + configPath: "/etc/istio/proxy" + binaryPath: "/usr/local/bin/envoy" + # The pseudo service name used for Envoy. + serviceCluster: istio-proxy + # These settings that determine how long an old Envoy + # process should be kept alive after an occasional reload. + drainDuration: 45s + parentShutdownDuration: 1m0s + # + # The mode used to redirect inbound connections to Envoy. This setting + # has no effect on outbound traffic: iptables REDIRECT is always used for + # outbound connections. + # If "REDIRECT", use iptables REDIRECT to NAT and redirect to Envoy. + # The "REDIRECT" mode loses source addresses during redirection. + # If "TPROXY", use iptables TPROXY to redirect to Envoy. + # The "TPROXY" mode preserves both the source and destination IP + # addresses and ports, so that they can be used for advanced filtering + # and manipulation. + # The "TPROXY" mode also configures the sidecar to run with the + # CAP_NET_ADMIN capability, which is required to use TPROXY. + #interceptionMode: REDIRECT + # + # Port where Envoy listens (on local host) for admin commands + # You can exec into the istio-proxy container in a pod and + # curl the admin port (curl http://localhost:15000/) to obtain + # diagnostic information from Envoy. See + # https://lyft.github.io/envoy/docs/operations/admin.html + # for more details + proxyAdminPort: 15000 + # + # Set concurrency to a specific number to control the number of Proxy worker threads. + # If set to 0 (default), then start worker thread for each CPU thread/core. + concurrency: 2 + # + tracing: + zipkin: + # Address of the Zipkin collector + address: zipkin.istio-system:9411 + # + # Mutual TLS authentication between sidecars and istio control plane. + controlPlaneAuthPolicy: NONE + # + # Address where istio Pilot service is running + discoveryAddress: istio-pilot.istio-system:15010 + + # Configuration file for the mesh networks to be used by the Split Horizon EDS. + meshNetworks: |- + networks: {} + +--- +# Source: istio/templates/sidecar-injector-configmap.yaml + +apiVersion: v1 +kind: ConfigMap +metadata: + name: istio-sidecar-injector + namespace: istio-system + labels: + app: istio + chart: istio + heritage: Tiller + release: istio + istio: sidecar-injector +data: + values: |- + {"certmanager":{"enabled":false},"galley":{"enableAnalysis":false,"enableServiceDiscovery":false,"enabled":true,"global":{"arch":{"amd64":2,"ppc64le":2,"s390x":2},"certificates":[],"configValidation":true,"controlPlaneSecurityEnabled":false,"defaultNodeSelector":{},"defaultPodDisruptionBudget":{"enabled":true},"defaultResources":{"requests":{"cpu":"10m"}},"defaultTolerations":[],"disablePolicyChecks":false,"enableHelmTest":false,"enableTracing":true,"hub":"docker.io/istio","imagePullPolicy":"IfNotPresent","imagePullSecrets":[],"k8sIngress":{"enableHttps":false,"enabled":false,"gatewayName":"ingressgateway"},"localityLbSetting":{"enabled":true},"logging":{"level":"default:info"},"meshExpansion":{"enabled":false,"useILB":false},"meshID":"","meshNetworks":{},"monitoringPort":15014,"mtls":{"auto":true,"enabled":false},"multiCluster":{"clusterName":"","enabled":false},"network":"","oneNamespace":false,"operatorManageWebhooks":false,"outboundTrafficPolicy":{"mode":"ALLOW_ANY"},"policyCheckFailOpen":false,"priorityClassName":"","proxy":{"accessLogEncoding":"TEXT","accessLogFile":"/dev/stdout","accessLogFormat":"","autoInject":"enabled","clusterDomain":"cluster.local","componentLogLevel":"","concurrency":2,"dnsRefreshRate":"300s","enableCoreDump":false,"enableCoreDumpImage":"ubuntu:xenial","envoyAccessLogService":{"enabled":false,"tcpKeepalive":{"interval":"10s","probes":3,"time":"10s"},"tlsSettings":{"mode":"DISABLE","subjectAltNames":[]}},"envoyMetricsService":{"enabled":false,"tcpKeepalive":{"interval":"10s","probes":3,"time":"10s"},"tlsSettings":{"mode":"DISABLE","subjectAltNames":[]}},"envoyStatsd":{"enabled":false},"excludeIPRanges":"","excludeInboundPorts":"","excludeOutboundPorts":"","image":"proxyv2","includeIPRanges":"*","includeInboundPorts":"*","kubevirtInterfaces":"","logLevel":"","privileged":false,"protocolDetectionTimeout":"100ms","readinessFailureThreshold":30,"readinessInitialDelaySeconds":1,"readinessPeriodSeconds":2,"resources":{"limits":{"cpu":"2000m","memory":"1024Mi"},"requests":{"cpu":"10m","memory":"40Mi"}},"statusPort":15020,"tracer":"zipkin"},"proxy_init":{"image":"proxyv2","resources":{"limits":{"cpu":"100m","memory":"50Mi"},"requests":{"cpu":"10m","memory":"10Mi"}}},"sds":{"enabled":false,"token":{"aud":"istio-ca"},"udsPath":""},"tag":"1.5.0","tracer":{"datadog":{"address":"$(HOST_IP):8126"},"lightstep":{"accessToken":"","address":"","cacertPath":"","secure":true},"stackdriver":{"debug":false,"maxNumberOfAnnotations":200,"maxNumberOfAttributes":200,"maxNumberOfMessageEvents":200},"zipkin":{"address":""}},"trustDomain":"","trustDomainAliases":[],"useMCP":true},"image":"galley","nodeSelector":{},"podAnnotations":{},"podAntiAffinityLabelSelector":[],"podAntiAffinityTermLabelSelector":[],"replicaCount":1,"rollingMaxSurge":"100%","rollingMaxUnavailable":"25%","tolerations":[]},"gateways":{"enabled":true,"global":{"arch":{"amd64":2,"ppc64le":2,"s390x":2},"certificates":[],"configValidation":true,"controlPlaneSecurityEnabled":false,"defaultNodeSelector":{},"defaultPodDisruptionBudget":{"enabled":true},"defaultResources":{"requests":{"cpu":"10m"}},"defaultTolerations":[],"disablePolicyChecks":false,"enableHelmTest":false,"enableTracing":true,"hub":"docker.io/istio","imagePullPolicy":"IfNotPresent","imagePullSecrets":[],"k8sIngress":{"enableHttps":false,"enabled":false,"gatewayName":"ingressgateway"},"localityLbSetting":{"enabled":true},"logging":{"level":"default:info"},"meshExpansion":{"enabled":false,"useILB":false},"meshID":"","meshNetworks":{},"monitoringPort":15014,"mtls":{"auto":true,"enabled":false},"multiCluster":{"clusterName":"","enabled":false},"network":"","oneNamespace":false,"operatorManageWebhooks":false,"outboundTrafficPolicy":{"mode":"ALLOW_ANY"},"policyCheckFailOpen":false,"priorityClassName":"","proxy":{"accessLogEncoding":"TEXT","accessLogFile":"/dev/stdout","accessLogFormat":"","autoInject":"enabled","clusterDomain":"cluster.local","componentLogLevel":"","concurrency":2,"dnsRefreshRate":"300s","enableCoreDump":false,"enableCoreDumpImage":"ubuntu:xenial","envoyAccessLogService":{"enabled":false,"tcpKeepalive":{"interval":"10s","probes":3,"time":"10s"},"tlsSettings":{"mode":"DISABLE","subjectAltNames":[]}},"envoyMetricsService":{"enabled":false,"tcpKeepalive":{"interval":"10s","probes":3,"time":"10s"},"tlsSettings":{"mode":"DISABLE","subjectAltNames":[]}},"envoyStatsd":{"enabled":false},"excludeIPRanges":"","excludeInboundPorts":"","excludeOutboundPorts":"","image":"proxyv2","includeIPRanges":"*","includeInboundPorts":"*","kubevirtInterfaces":"","logLevel":"","privileged":false,"protocolDetectionTimeout":"100ms","readinessFailureThreshold":30,"readinessInitialDelaySeconds":1,"readinessPeriodSeconds":2,"resources":{"limits":{"cpu":"2000m","memory":"1024Mi"},"requests":{"cpu":"10m","memory":"40Mi"}},"statusPort":15020,"tracer":"zipkin"},"proxy_init":{"image":"proxyv2","resources":{"limits":{"cpu":"100m","memory":"50Mi"},"requests":{"cpu":"10m","memory":"10Mi"}}},"sds":{"enabled":false,"token":{"aud":"istio-ca"},"udsPath":""},"tag":"1.5.0","tracer":{"datadog":{"address":"$(HOST_IP):8126"},"lightstep":{"accessToken":"","address":"","cacertPath":"","secure":true},"stackdriver":{"debug":false,"maxNumberOfAnnotations":200,"maxNumberOfAttributes":200,"maxNumberOfMessageEvents":200},"zipkin":{"address":""}},"trustDomain":"","trustDomainAliases":[],"useMCP":true},"istio-egressgateway":{"autoscaleEnabled":false,"autoscaleMax":5,"autoscaleMin":1,"cpu":{"targetAverageUtilization":80},"enabled":true,"env":{"ISTIO_META_ROUTER_MODE":"standard"},"labels":{"app":"istio-egressgateway","istio":"egressgateway"},"nodeSelector":{},"podAnnotations":{},"podAntiAffinityLabelSelector":[],"podAntiAffinityTermLabelSelector":[],"ports":[{"name":"http2","port":80},{"name":"https","port":443},{"name":"tls","port":15443,"targetPort":15443}],"resources":{"limits":{"cpu":"2000m","memory":"1024Mi"},"requests":{"cpu":"10m","memory":"40Mi"}},"rollingMaxSurge":"100%","rollingMaxUnavailable":"25%","secretVolumes":[{"mountPath":"/etc/istio/egressgateway-certs","name":"egressgateway-certs","secretName":"istio-egressgateway-certs"},{"mountPath":"/etc/istio/egressgateway-ca-certs","name":"egressgateway-ca-certs","secretName":"istio-egressgateway-ca-certs"}],"serviceAnnotations":{},"tolerations":[],"type":"ClusterIP"},"istio-ilbgateway":{"autoscaleEnabled":true,"autoscaleMax":5,"autoscaleMin":1,"cpu":{"targetAverageUtilization":80},"enabled":false,"labels":{"app":"istio-ilbgateway","istio":"ilbgateway"},"loadBalancerIP":"","nodeSelector":{},"podAnnotations":{},"ports":[{"name":"grpc-pilot-mtls","port":15011},{"name":"grpc-pilot","port":15010},{"name":"tcp-citadel-grpc-tls","port":8060,"targetPort":8060},{"name":"tcp-dns","port":5353}],"resources":{"requests":{"cpu":"800m","memory":"512Mi"}},"rollingMaxSurge":"100%","rollingMaxUnavailable":"25%","secretVolumes":[{"mountPath":"/etc/istio/ilbgateway-certs","name":"ilbgateway-certs","secretName":"istio-ilbgateway-certs"},{"mountPath":"/etc/istio/ilbgateway-ca-certs","name":"ilbgateway-ca-certs","secretName":"istio-ilbgateway-ca-certs"}],"serviceAnnotations":{"cloud.google.com/load-balancer-type":"internal"},"tolerations":[],"type":"LoadBalancer"},"istio-ingressgateway":{"autoscaleEnabled":false,"autoscaleMax":5,"autoscaleMin":1,"cpu":{"targetAverageUtilization":80},"enabled":true,"env":{"ISTIO_META_ROUTER_MODE":"standard"},"externalIPs":[],"labels":{"app":"istio-ingressgateway","istio":"ingressgateway"},"loadBalancerIP":"","loadBalancerSourceRanges":[],"meshExpansionPorts":[{"name":"tcp-pilot-grpc-tls","port":15011,"targetPort":15011},{"name":"tcp-mixer-grpc-tls","port":15004,"targetPort":15004},{"name":"tcp-citadel-grpc-tls","port":8060,"targetPort":8060},{"name":"tcp-dns-tls","port":853,"targetPort":853}],"nodeSelector":{},"podAnnotations":{},"podAntiAffinityLabelSelector":[],"podAntiAffinityTermLabelSelector":[],"ports":[{"name":"status-port","port":15020,"targetPort":15020},{"name":"http2","nodePort":31380,"port":80,"targetPort":80},{"name":"https","nodePort":31390,"port":443},{"name":"tcp","nodePort":31400,"port":31400},{"name":"https-kiali","port":15029,"targetPort":15029},{"name":"https-prometheus","port":15030,"targetPort":15030},{"name":"https-grafana","port":15031,"targetPort":15031},{"name":"https-tracing","port":15032,"targetPort":15032},{"name":"tls","port":15443,"targetPort":15443}],"resources":{"limits":{"cpu":"2000m","memory":"1024Mi"},"requests":{"cpu":"10m","memory":"40Mi"}},"rollingMaxSurge":"100%","rollingMaxUnavailable":"25%","sds":{"enabled":false,"image":"node-agent-k8s","resources":{"limits":{"cpu":"2000m","memory":"1024Mi"},"requests":{"cpu":"100m","memory":"128Mi"}}},"secretVolumes":[{"mountPath":"/etc/istio/ingressgateway-certs","name":"ingressgateway-certs","secretName":"istio-ingressgateway-certs"},{"mountPath":"/etc/istio/ingressgateway-ca-certs","name":"ingressgateway-ca-certs","secretName":"istio-ingressgateway-ca-certs"}],"serviceAnnotations":{},"tolerations":[],"type":"LoadBalancer"}},"global":{"arch":{"amd64":2,"ppc64le":2,"s390x":2},"certificates":[],"configValidation":true,"controlPlaneSecurityEnabled":false,"defaultNodeSelector":{},"defaultPodDisruptionBudget":{"enabled":true},"defaultResources":{"requests":{"cpu":"10m"}},"defaultTolerations":[],"disablePolicyChecks":false,"enableHelmTest":false,"enableTracing":true,"hub":"docker.io/istio","imagePullPolicy":"IfNotPresent","imagePullSecrets":[],"k8sIngress":{"enableHttps":false,"enabled":false,"gatewayName":"ingressgateway"},"localityLbSetting":{"enabled":true},"logging":{"level":"default:info"},"meshExpansion":{"enabled":false,"useILB":false},"meshID":"","meshNetworks":{},"monitoringPort":15014,"mtls":{"auto":true,"enabled":false},"multiCluster":{"clusterName":"","enabled":false},"network":"","oneNamespace":false,"operatorManageWebhooks":false,"outboundTrafficPolicy":{"mode":"ALLOW_ANY"},"policyCheckFailOpen":false,"priorityClassName":"","proxy":{"accessLogEncoding":"TEXT","accessLogFile":"/dev/stdout","accessLogFormat":"","autoInject":"enabled","clusterDomain":"cluster.local","componentLogLevel":"","concurrency":2,"dnsRefreshRate":"300s","enableCoreDump":false,"enableCoreDumpImage":"ubuntu:xenial","envoyAccessLogService":{"enabled":false,"host":null,"port":null,"tcpKeepalive":{"interval":"10s","probes":3,"time":"10s"},"tlsSettings":{"caCertificates":null,"clientCertificate":null,"mode":"DISABLE","privateKey":null,"sni":null,"subjectAltNames":[]}},"envoyMetricsService":{"enabled":false,"host":null,"port":null,"tcpKeepalive":{"interval":"10s","probes":3,"time":"10s"},"tlsSettings":{"caCertificates":null,"clientCertificate":null,"mode":"DISABLE","privateKey":null,"sni":null,"subjectAltNames":[]}},"envoyStatsd":{"enabled":false,"host":null,"port":null},"excludeIPRanges":"","excludeInboundPorts":"","excludeOutboundPorts":"","image":"proxyv2","includeIPRanges":"*","includeInboundPorts":"*","kubevirtInterfaces":"","logLevel":"","outlierLogPath":null,"privileged":false,"protocolDetectionTimeout":"100ms","readinessFailureThreshold":30,"readinessInitialDelaySeconds":1,"readinessPeriodSeconds":2,"resources":{"limits":{"cpu":"2000m","memory":"1024Mi"},"requests":{"cpu":"10m","memory":"40Mi"}},"statusPort":15020,"tracer":"zipkin"},"proxy_init":{"image":"proxyv2","resources":{"limits":{"cpu":"100m","memory":"50Mi"},"requests":{"cpu":"10m","memory":"10Mi"}}},"sds":{"enabled":false,"token":{"aud":"istio-ca"},"udsPath":""},"tag":"1.5.0","tracer":{"datadog":{"address":"$(HOST_IP):8126"},"lightstep":{"accessToken":"","address":"","cacertPath":"","secure":true},"stackdriver":{"debug":false,"maxNumberOfAnnotations":200,"maxNumberOfAttributes":200,"maxNumberOfMessageEvents":200},"zipkin":{"address":""}},"trustDomain":"","trustDomainAliases":[],"useMCP":true},"grafana":{"accessMode":"ReadWriteMany","contextPath":"/grafana","dashboardProviders":{"dashboardproviders.yaml":{"apiVersion":1,"providers":[{"disableDeletion":false,"folder":"istio","name":"istio","options":{"path":"/var/lib/grafana/dashboards/istio"},"orgId":1,"type":"file"}]}},"datasources":{"datasources.yaml":{"apiVersion":1,"datasources":[{"access":"proxy","editable":true,"isDefault":true,"jsonData":{"timeInterval":"5s"},"name":"Prometheus","orgId":1,"type":"prometheus","url":"http://prometheus:9090"}]}},"enabled":true,"env":{},"envSecrets":{},"global":{"arch":{"amd64":2,"ppc64le":2,"s390x":2},"certificates":[],"configValidation":true,"controlPlaneSecurityEnabled":false,"defaultNodeSelector":{},"defaultPodDisruptionBudget":{"enabled":true},"defaultResources":{"requests":{"cpu":"10m"}},"defaultTolerations":[],"disablePolicyChecks":false,"enableHelmTest":false,"enableTracing":true,"hub":"docker.io/istio","imagePullPolicy":"IfNotPresent","imagePullSecrets":[],"k8sIngress":{"enableHttps":false,"enabled":false,"gatewayName":"ingressgateway"},"localityLbSetting":{"enabled":true},"logging":{"level":"default:info"},"meshExpansion":{"enabled":false,"useILB":false},"meshID":"","meshNetworks":{},"monitoringPort":15014,"mtls":{"auto":true,"enabled":false},"multiCluster":{"clusterName":"","enabled":false},"network":"","oneNamespace":false,"operatorManageWebhooks":false,"outboundTrafficPolicy":{"mode":"ALLOW_ANY"},"policyCheckFailOpen":false,"priorityClassName":"","proxy":{"accessLogEncoding":"TEXT","accessLogFile":"/dev/stdout","accessLogFormat":"","autoInject":"enabled","clusterDomain":"cluster.local","componentLogLevel":"","concurrency":2,"dnsRefreshRate":"300s","enableCoreDump":false,"enableCoreDumpImage":"ubuntu:xenial","envoyAccessLogService":{"enabled":false,"tcpKeepalive":{"interval":"10s","probes":3,"time":"10s"},"tlsSettings":{"mode":"DISABLE","subjectAltNames":[]}},"envoyMetricsService":{"enabled":false,"tcpKeepalive":{"interval":"10s","probes":3,"time":"10s"},"tlsSettings":{"mode":"DISABLE","subjectAltNames":[]}},"envoyStatsd":{"enabled":false},"excludeIPRanges":"","excludeInboundPorts":"","excludeOutboundPorts":"","image":"proxyv2","includeIPRanges":"*","includeInboundPorts":"*","kubevirtInterfaces":"","logLevel":"","privileged":false,"protocolDetectionTimeout":"100ms","readinessFailureThreshold":30,"readinessInitialDelaySeconds":1,"readinessPeriodSeconds":2,"resources":{"limits":{"cpu":"2000m","memory":"1024Mi"},"requests":{"cpu":"10m","memory":"40Mi"}},"statusPort":15020,"tracer":"zipkin"},"proxy_init":{"image":"proxyv2","resources":{"limits":{"cpu":"100m","memory":"50Mi"},"requests":{"cpu":"10m","memory":"10Mi"}}},"sds":{"enabled":false,"token":{"aud":"istio-ca"},"udsPath":""},"tag":"1.5.0","tracer":{"datadog":{"address":"$(HOST_IP):8126"},"lightstep":{"accessToken":"","address":"","cacertPath":"","secure":true},"stackdriver":{"debug":false,"maxNumberOfAnnotations":200,"maxNumberOfAttributes":200,"maxNumberOfMessageEvents":200},"zipkin":{"address":""}},"trustDomain":"","trustDomainAliases":[],"useMCP":true},"image":{"repository":"grafana/grafana","tag":"6.4.3"},"ingress":{"annotations":{},"enabled":false,"hosts":["grafana.local"],"tls":[]},"nodeSelector":{},"persist":false,"podAntiAffinityLabelSelector":[],"podAntiAffinityTermLabelSelector":[],"replicaCount":1,"security":{"enabled":false,"passphraseKey":"passphrase","secretName":"grafana","usernameKey":"username"},"service":{"annotations":{},"externalPort":3000,"loadBalancerSourceRanges":[],"name":"http","type":"ClusterIP"},"storageClassName":"","tolerations":[]},"istio_cni":{"enabled":false},"istiocoredns":{"enabled":false},"kiali":{"contextPath":"/kiali","createDemoSecret":true,"dashboard":{"auth":{"strategy":"login"},"grafanaInClusterURL":"http://grafana:3000","jaegerInClusterURL":"http://tracing/jaeger","secretName":"kiali","viewOnlyMode":false},"enabled":true,"global":{"arch":{"amd64":2,"ppc64le":2,"s390x":2},"certificates":[],"configValidation":true,"controlPlaneSecurityEnabled":false,"defaultNodeSelector":{},"defaultPodDisruptionBudget":{"enabled":true},"defaultResources":{"requests":{"cpu":"10m"}},"defaultTolerations":[],"disablePolicyChecks":false,"enableHelmTest":false,"enableTracing":true,"hub":"docker.io/istio","imagePullPolicy":"IfNotPresent","imagePullSecrets":[],"k8sIngress":{"enableHttps":false,"enabled":false,"gatewayName":"ingressgateway"},"localityLbSetting":{"enabled":true},"logging":{"level":"default:info"},"meshExpansion":{"enabled":false,"useILB":false},"meshID":"","meshNetworks":{},"monitoringPort":15014,"mtls":{"auto":true,"enabled":false},"multiCluster":{"clusterName":"","enabled":false},"network":"","oneNamespace":false,"operatorManageWebhooks":false,"outboundTrafficPolicy":{"mode":"ALLOW_ANY"},"policyCheckFailOpen":false,"priorityClassName":"","proxy":{"accessLogEncoding":"TEXT","accessLogFile":"/dev/stdout","accessLogFormat":"","autoInject":"enabled","clusterDomain":"cluster.local","componentLogLevel":"","concurrency":2,"dnsRefreshRate":"300s","enableCoreDump":false,"enableCoreDumpImage":"ubuntu:xenial","envoyAccessLogService":{"enabled":false,"tcpKeepalive":{"interval":"10s","probes":3,"time":"10s"},"tlsSettings":{"mode":"DISABLE","subjectAltNames":[]}},"envoyMetricsService":{"enabled":false,"tcpKeepalive":{"interval":"10s","probes":3,"time":"10s"},"tlsSettings":{"mode":"DISABLE","subjectAltNames":[]}},"envoyStatsd":{"enabled":false},"excludeIPRanges":"","excludeInboundPorts":"","excludeOutboundPorts":"","image":"proxyv2","includeIPRanges":"*","includeInboundPorts":"*","kubevirtInterfaces":"","logLevel":"","privileged":false,"protocolDetectionTimeout":"100ms","readinessFailureThreshold":30,"readinessInitialDelaySeconds":1,"readinessPeriodSeconds":2,"resources":{"limits":{"cpu":"2000m","memory":"1024Mi"},"requests":{"cpu":"10m","memory":"40Mi"}},"statusPort":15020,"tracer":"zipkin"},"proxy_init":{"image":"proxyv2","resources":{"limits":{"cpu":"100m","memory":"50Mi"},"requests":{"cpu":"10m","memory":"10Mi"}}},"sds":{"enabled":false,"token":{"aud":"istio-ca"},"udsPath":""},"tag":"1.5.0","tracer":{"datadog":{"address":"$(HOST_IP):8126"},"lightstep":{"accessToken":"","address":"","cacertPath":"","secure":true},"stackdriver":{"debug":false,"maxNumberOfAnnotations":200,"maxNumberOfAttributes":200,"maxNumberOfMessageEvents":200},"zipkin":{"address":""}},"trustDomain":"","trustDomainAliases":[],"useMCP":true},"hub":"quay.io/kiali","image":"kiali","ingress":{"annotations":{},"enabled":false,"hosts":["kiali.local"]},"nodeSelector":{},"podAnnotations":{},"podAntiAffinityLabelSelector":[],"podAntiAffinityTermLabelSelector":[],"prometheusAddr":"http://prometheus:9090","replicaCount":1,"security":{"cert_file":"/kiali-cert/cert-chain.pem","enabled":false,"private_key_file":"/kiali-cert/key.pem"},"tag":"v1.9","tolerations":[]},"mixer":{"adapters":{"kubernetesenv":{"enabled":true},"prometheus":{"enabled":true,"metricsExpiryDuration":"10m"},"stdio":{"enabled":true,"outputAsJson":true},"useAdapterCRDs":false},"env":{"GOMAXPROCS":"6"},"global":{"arch":{"amd64":2,"ppc64le":2,"s390x":2},"certificates":[],"configValidation":true,"controlPlaneSecurityEnabled":false,"defaultNodeSelector":{},"defaultPodDisruptionBudget":{"enabled":true},"defaultResources":{"requests":{"cpu":"10m"}},"defaultTolerations":[],"disablePolicyChecks":false,"enableHelmTest":false,"enableTracing":true,"hub":"docker.io/istio","imagePullPolicy":"IfNotPresent","imagePullSecrets":[],"k8sIngress":{"enableHttps":false,"enabled":false,"gatewayName":"ingressgateway"},"localityLbSetting":{"enabled":true},"logging":{"level":"default:info"},"meshExpansion":{"enabled":false,"useILB":false},"meshID":"","meshNetworks":{},"monitoringPort":15014,"mtls":{"auto":true,"enabled":false},"multiCluster":{"clusterName":"","enabled":false},"network":"","oneNamespace":false,"operatorManageWebhooks":false,"outboundTrafficPolicy":{"mode":"ALLOW_ANY"},"policyCheckFailOpen":false,"priorityClassName":"","proxy":{"accessLogEncoding":"TEXT","accessLogFile":"/dev/stdout","accessLogFormat":"","autoInject":"enabled","clusterDomain":"cluster.local","componentLogLevel":"","concurrency":2,"dnsRefreshRate":"300s","enableCoreDump":false,"enableCoreDumpImage":"ubuntu:xenial","envoyAccessLogService":{"enabled":false,"tcpKeepalive":{"interval":"10s","probes":3,"time":"10s"},"tlsSettings":{"mode":"DISABLE","subjectAltNames":[]}},"envoyMetricsService":{"enabled":false,"tcpKeepalive":{"interval":"10s","probes":3,"time":"10s"},"tlsSettings":{"mode":"DISABLE","subjectAltNames":[]}},"envoyStatsd":{"enabled":false},"excludeIPRanges":"","excludeInboundPorts":"","excludeOutboundPorts":"","image":"proxyv2","includeIPRanges":"*","includeInboundPorts":"*","kubevirtInterfaces":"","logLevel":"","privileged":false,"protocolDetectionTimeout":"100ms","readinessFailureThreshold":30,"readinessInitialDelaySeconds":1,"readinessPeriodSeconds":2,"resources":{"limits":{"cpu":"2000m","memory":"1024Mi"},"requests":{"cpu":"10m","memory":"40Mi"}},"statusPort":15020,"tracer":"zipkin"},"proxy_init":{"image":"proxyv2","resources":{"limits":{"cpu":"100m","memory":"50Mi"},"requests":{"cpu":"10m","memory":"10Mi"}}},"sds":{"enabled":false,"token":{"aud":"istio-ca"},"udsPath":""},"tag":"1.5.0","tracer":{"datadog":{"address":"$(HOST_IP):8126"},"lightstep":{"accessToken":"","address":"","cacertPath":"","secure":true},"stackdriver":{"debug":false,"maxNumberOfAnnotations":200,"maxNumberOfAttributes":200,"maxNumberOfMessageEvents":200},"zipkin":{"address":""}},"trustDomain":"","trustDomainAliases":[],"useMCP":true},"image":"mixer","nodeSelector":{},"podAnnotations":{},"podAntiAffinityLabelSelector":[],"podAntiAffinityTermLabelSelector":[],"policy":{"autoscaleEnabled":false,"autoscaleMax":5,"autoscaleMin":1,"cpu":{"targetAverageUtilization":80},"enabled":true,"replicaCount":1,"resources":{"requests":{"cpu":"10m","memory":"100Mi"}},"rollingMaxSurge":"100%","rollingMaxUnavailable":"25%"},"telemetry":{"autoscaleEnabled":false,"autoscaleMax":5,"autoscaleMin":1,"cpu":{"targetAverageUtilization":80},"enabled":true,"loadshedding":{"latencyThreshold":"100ms","mode":"enforce"},"replicaCount":1,"reportBatchMaxEntries":100,"reportBatchMaxTime":"1s","resources":{"limits":{"cpu":"4800m","memory":"4G"},"requests":{"cpu":"50m","memory":"100Mi"}},"rollingMaxSurge":"100%","rollingMaxUnavailable":"25%","sessionAffinityEnabled":false},"tolerations":[]},"nodeagent":{"enabled":false},"pilot":{"autoscaleEnabled":false,"autoscaleMax":5,"autoscaleMin":1,"configSource":{},"cpu":{"targetAverageUtilization":80},"enableProtocolSniffingForInbound":false,"enableProtocolSniffingForOutbound":true,"enabled":true,"env":{"PILOT_PUSH_THROTTLE":100},"global":{"arch":{"amd64":2,"ppc64le":2,"s390x":2},"certificates":[],"configValidation":true,"controlPlaneSecurityEnabled":false,"defaultNodeSelector":{},"defaultPodDisruptionBudget":{"enabled":true},"defaultResources":{"requests":{"cpu":"10m"}},"defaultTolerations":[],"disablePolicyChecks":false,"enableHelmTest":false,"enableTracing":true,"hub":"docker.io/istio","imagePullPolicy":"IfNotPresent","imagePullSecrets":[],"k8sIngress":{"enableHttps":false,"enabled":false,"gatewayName":"ingressgateway"},"localityLbSetting":{"enabled":true},"logging":{"level":"default:info"},"meshExpansion":{"enabled":false,"useILB":false},"meshID":"","meshNetworks":{},"monitoringPort":15014,"mtls":{"auto":true,"enabled":false},"multiCluster":{"clusterName":"","enabled":false},"network":"","oneNamespace":false,"operatorManageWebhooks":false,"outboundTrafficPolicy":{"mode":"ALLOW_ANY"},"policyCheckFailOpen":false,"priorityClassName":"","proxy":{"accessLogEncoding":"TEXT","accessLogFile":"/dev/stdout","accessLogFormat":"","autoInject":"enabled","clusterDomain":"cluster.local","componentLogLevel":"","concurrency":2,"dnsRefreshRate":"300s","enableCoreDump":false,"enableCoreDumpImage":"ubuntu:xenial","envoyAccessLogService":{"enabled":false,"tcpKeepalive":{"interval":"10s","probes":3,"time":"10s"},"tlsSettings":{"mode":"DISABLE","subjectAltNames":[]}},"envoyMetricsService":{"enabled":false,"tcpKeepalive":{"interval":"10s","probes":3,"time":"10s"},"tlsSettings":{"mode":"DISABLE","subjectAltNames":[]}},"envoyStatsd":{"enabled":false},"excludeIPRanges":"","excludeInboundPorts":"","excludeOutboundPorts":"","image":"proxyv2","includeIPRanges":"*","includeInboundPorts":"*","kubevirtInterfaces":"","logLevel":"","privileged":false,"protocolDetectionTimeout":"100ms","readinessFailureThreshold":30,"readinessInitialDelaySeconds":1,"readinessPeriodSeconds":2,"resources":{"limits":{"cpu":"2000m","memory":"1024Mi"},"requests":{"cpu":"10m","memory":"40Mi"}},"statusPort":15020,"tracer":"zipkin"},"proxy_init":{"image":"proxyv2","resources":{"limits":{"cpu":"100m","memory":"50Mi"},"requests":{"cpu":"10m","memory":"10Mi"}}},"sds":{"enabled":false,"token":{"aud":"istio-ca"},"udsPath":""},"tag":"1.5.0","tracer":{"datadog":{"address":"$(HOST_IP):8126"},"lightstep":{"accessToken":"","address":"","cacertPath":"","secure":true},"stackdriver":{"debug":false,"maxNumberOfAnnotations":200,"maxNumberOfAttributes":200,"maxNumberOfMessageEvents":200},"zipkin":{"address":""}},"trustDomain":"","trustDomainAliases":[],"useMCP":true},"image":"pilot","keepaliveMaxServerConnectionAge":"30m","nodeSelector":{},"podAnnotations":{},"podAntiAffinityLabelSelector":[],"podAntiAffinityTermLabelSelector":[],"resources":{"requests":{"cpu":"10m","memory":"100Mi"}},"rollingMaxSurge":"100%","rollingMaxUnavailable":"25%","sidecar":true,"tolerations":[],"traceSampling":100},"prometheus":{"contextPath":"/prometheus","enabled":true,"global":{"arch":{"amd64":2,"ppc64le":2,"s390x":2},"certificates":[],"configValidation":true,"controlPlaneSecurityEnabled":false,"defaultNodeSelector":{},"defaultPodDisruptionBudget":{"enabled":true},"defaultResources":{"requests":{"cpu":"10m"}},"defaultTolerations":[],"disablePolicyChecks":false,"enableHelmTest":false,"enableTracing":true,"hub":"docker.io/istio","imagePullPolicy":"IfNotPresent","imagePullSecrets":[],"k8sIngress":{"enableHttps":false,"enabled":false,"gatewayName":"ingressgateway"},"localityLbSetting":{"enabled":true},"logging":{"level":"default:info"},"meshExpansion":{"enabled":false,"useILB":false},"meshID":"","meshNetworks":{},"monitoringPort":15014,"mtls":{"auto":true,"enabled":false},"multiCluster":{"clusterName":"","enabled":false},"network":"","oneNamespace":false,"operatorManageWebhooks":false,"outboundTrafficPolicy":{"mode":"ALLOW_ANY"},"policyCheckFailOpen":false,"priorityClassName":"","proxy":{"accessLogEncoding":"TEXT","accessLogFile":"/dev/stdout","accessLogFormat":"","autoInject":"enabled","clusterDomain":"cluster.local","componentLogLevel":"","concurrency":2,"dnsRefreshRate":"300s","enableCoreDump":false,"enableCoreDumpImage":"ubuntu:xenial","envoyAccessLogService":{"enabled":false,"tcpKeepalive":{"interval":"10s","probes":3,"time":"10s"},"tlsSettings":{"mode":"DISABLE","subjectAltNames":[]}},"envoyMetricsService":{"enabled":false,"tcpKeepalive":{"interval":"10s","probes":3,"time":"10s"},"tlsSettings":{"mode":"DISABLE","subjectAltNames":[]}},"envoyStatsd":{"enabled":false},"excludeIPRanges":"","excludeInboundPorts":"","excludeOutboundPorts":"","image":"proxyv2","includeIPRanges":"*","includeInboundPorts":"*","kubevirtInterfaces":"","logLevel":"","privileged":false,"protocolDetectionTimeout":"100ms","readinessFailureThreshold":30,"readinessInitialDelaySeconds":1,"readinessPeriodSeconds":2,"resources":{"limits":{"cpu":"2000m","memory":"1024Mi"},"requests":{"cpu":"10m","memory":"40Mi"}},"statusPort":15020,"tracer":"zipkin"},"proxy_init":{"image":"proxyv2","resources":{"limits":{"cpu":"100m","memory":"50Mi"},"requests":{"cpu":"10m","memory":"10Mi"}}},"sds":{"enabled":false,"token":{"aud":"istio-ca"},"udsPath":""},"tag":"1.5.0","tracer":{"datadog":{"address":"$(HOST_IP):8126"},"lightstep":{"accessToken":"","address":"","cacertPath":"","secure":true},"stackdriver":{"debug":false,"maxNumberOfAnnotations":200,"maxNumberOfAttributes":200,"maxNumberOfMessageEvents":200},"zipkin":{"address":""}},"trustDomain":"","trustDomainAliases":[],"useMCP":true},"hub":"docker.io/prom","image":"prometheus","ingress":{"enabled":false,"hosts":["prometheus.local"]},"nodeSelector":{},"podAntiAffinityLabelSelector":[],"podAntiAffinityTermLabelSelector":[],"replicaCount":1,"retention":"6h","scrapeInterval":"15s","security":{"enabled":true},"service":{"annotations":{},"nodePort":{"enabled":false,"port":32090}},"tag":"v2.12.0","tolerations":[]},"security":{"citadelHealthCheck":false,"createMeshPolicy":true,"enableNamespacesByDefault":true,"enabled":true,"env":{},"global":{"arch":{"amd64":2,"ppc64le":2,"s390x":2},"certificates":[],"configValidation":true,"controlPlaneSecurityEnabled":false,"defaultNodeSelector":{},"defaultPodDisruptionBudget":{"enabled":true},"defaultResources":{"requests":{"cpu":"10m"}},"defaultTolerations":[],"disablePolicyChecks":false,"enableHelmTest":false,"enableTracing":true,"hub":"docker.io/istio","imagePullPolicy":"IfNotPresent","imagePullSecrets":[],"k8sIngress":{"enableHttps":false,"enabled":false,"gatewayName":"ingressgateway"},"localityLbSetting":{"enabled":true},"logging":{"level":"default:info"},"meshExpansion":{"enabled":false,"useILB":false},"meshID":"","meshNetworks":{},"monitoringPort":15014,"mtls":{"auto":true,"enabled":false},"multiCluster":{"clusterName":"","enabled":false},"network":"","oneNamespace":false,"operatorManageWebhooks":false,"outboundTrafficPolicy":{"mode":"ALLOW_ANY"},"policyCheckFailOpen":false,"priorityClassName":"","proxy":{"accessLogEncoding":"TEXT","accessLogFile":"/dev/stdout","accessLogFormat":"","autoInject":"enabled","clusterDomain":"cluster.local","componentLogLevel":"","concurrency":2,"dnsRefreshRate":"300s","enableCoreDump":false,"enableCoreDumpImage":"ubuntu:xenial","envoyAccessLogService":{"enabled":false,"tcpKeepalive":{"interval":"10s","probes":3,"time":"10s"},"tlsSettings":{"mode":"DISABLE","subjectAltNames":[]}},"envoyMetricsService":{"enabled":false,"tcpKeepalive":{"interval":"10s","probes":3,"time":"10s"},"tlsSettings":{"mode":"DISABLE","subjectAltNames":[]}},"envoyStatsd":{"enabled":false},"excludeIPRanges":"","excludeInboundPorts":"","excludeOutboundPorts":"","image":"proxyv2","includeIPRanges":"*","includeInboundPorts":"*","kubevirtInterfaces":"","logLevel":"","privileged":false,"protocolDetectionTimeout":"100ms","readinessFailureThreshold":30,"readinessInitialDelaySeconds":1,"readinessPeriodSeconds":2,"resources":{"limits":{"cpu":"2000m","memory":"1024Mi"},"requests":{"cpu":"10m","memory":"40Mi"}},"statusPort":15020,"tracer":"zipkin"},"proxy_init":{"image":"proxyv2","resources":{"limits":{"cpu":"100m","memory":"50Mi"},"requests":{"cpu":"10m","memory":"10Mi"}}},"sds":{"enabled":false,"token":{"aud":"istio-ca"},"udsPath":""},"tag":"1.5.0","tracer":{"datadog":{"address":"$(HOST_IP):8126"},"lightstep":{"accessToken":"","address":"","cacertPath":"","secure":true},"stackdriver":{"debug":false,"maxNumberOfAnnotations":200,"maxNumberOfAttributes":200,"maxNumberOfMessageEvents":200},"zipkin":{"address":""}},"trustDomain":"","trustDomainAliases":[],"useMCP":true},"image":"citadel","nodeSelector":{},"podAnnotations":{},"podAntiAffinityLabelSelector":[],"podAntiAffinityTermLabelSelector":[],"replicaCount":1,"rollingMaxSurge":"100%","rollingMaxUnavailable":"25%","selfSigned":true,"tolerations":[],"workloadCertTtl":"2160h"},"sidecarInjectorWebhook":{"alwaysInjectSelector":[],"enableNamespacesByDefault":false,"enabled":true,"global":{"arch":{"amd64":2,"ppc64le":2,"s390x":2},"certificates":[],"configValidation":true,"controlPlaneSecurityEnabled":false,"defaultNodeSelector":{},"defaultPodDisruptionBudget":{"enabled":true},"defaultResources":{"requests":{"cpu":"10m"}},"defaultTolerations":[],"disablePolicyChecks":false,"enableHelmTest":false,"enableTracing":true,"hub":"docker.io/istio","imagePullPolicy":"IfNotPresent","imagePullSecrets":[],"k8sIngress":{"enableHttps":false,"enabled":false,"gatewayName":"ingressgateway"},"localityLbSetting":{"enabled":true},"logging":{"level":"default:info"},"meshExpansion":{"enabled":false,"useILB":false},"meshID":"","meshNetworks":{},"monitoringPort":15014,"mtls":{"auto":true,"enabled":false},"multiCluster":{"clusterName":"","enabled":false},"network":"","oneNamespace":false,"operatorManageWebhooks":false,"outboundTrafficPolicy":{"mode":"ALLOW_ANY"},"policyCheckFailOpen":false,"priorityClassName":"","proxy":{"accessLogEncoding":"TEXT","accessLogFile":"/dev/stdout","accessLogFormat":"","autoInject":"enabled","clusterDomain":"cluster.local","componentLogLevel":"","concurrency":2,"dnsRefreshRate":"300s","enableCoreDump":false,"enableCoreDumpImage":"ubuntu:xenial","envoyAccessLogService":{"enabled":false,"tcpKeepalive":{"interval":"10s","probes":3,"time":"10s"},"tlsSettings":{"mode":"DISABLE","subjectAltNames":[]}},"envoyMetricsService":{"enabled":false,"tcpKeepalive":{"interval":"10s","probes":3,"time":"10s"},"tlsSettings":{"mode":"DISABLE","subjectAltNames":[]}},"envoyStatsd":{"enabled":false},"excludeIPRanges":"","excludeInboundPorts":"","excludeOutboundPorts":"","image":"proxyv2","includeIPRanges":"*","includeInboundPorts":"*","kubevirtInterfaces":"","logLevel":"","privileged":false,"protocolDetectionTimeout":"100ms","readinessFailureThreshold":30,"readinessInitialDelaySeconds":1,"readinessPeriodSeconds":2,"resources":{"limits":{"cpu":"2000m","memory":"1024Mi"},"requests":{"cpu":"10m","memory":"40Mi"}},"statusPort":15020,"tracer":"zipkin"},"proxy_init":{"image":"proxyv2","resources":{"limits":{"cpu":"100m","memory":"50Mi"},"requests":{"cpu":"10m","memory":"10Mi"}}},"sds":{"enabled":false,"token":{"aud":"istio-ca"},"udsPath":""},"tag":"1.5.0","tracer":{"datadog":{"address":"$(HOST_IP):8126"},"lightstep":{"accessToken":"","address":"","cacertPath":"","secure":true},"stackdriver":{"debug":false,"maxNumberOfAnnotations":200,"maxNumberOfAttributes":200,"maxNumberOfMessageEvents":200},"zipkin":{"address":""}},"trustDomain":"","trustDomainAliases":[],"useMCP":true},"image":"sidecar_injector","injectedAnnotations":{},"neverInjectSelector":[],"nodeSelector":{},"podAnnotations":{},"podAntiAffinityLabelSelector":[],"podAntiAffinityTermLabelSelector":[],"replicaCount":1,"rewriteAppHTTPProbe":false,"rollingMaxSurge":"100%","rollingMaxUnavailable":"25%","tolerations":[]},"tracing":{"enabled":true,"global":{"arch":{"amd64":2,"ppc64le":2,"s390x":2},"certificates":[],"configValidation":true,"controlPlaneSecurityEnabled":false,"defaultNodeSelector":{},"defaultPodDisruptionBudget":{"enabled":true},"defaultResources":{"requests":{"cpu":"10m"}},"defaultTolerations":[],"disablePolicyChecks":false,"enableHelmTest":false,"enableTracing":true,"hub":"docker.io/istio","imagePullPolicy":"IfNotPresent","imagePullSecrets":[],"k8sIngress":{"enableHttps":false,"enabled":false,"gatewayName":"ingressgateway"},"localityLbSetting":{"enabled":true},"logging":{"level":"default:info"},"meshExpansion":{"enabled":false,"useILB":false},"meshID":"","meshNetworks":{},"monitoringPort":15014,"mtls":{"auto":true,"enabled":false},"multiCluster":{"clusterName":"","enabled":false},"network":"","oneNamespace":false,"operatorManageWebhooks":false,"outboundTrafficPolicy":{"mode":"ALLOW_ANY"},"policyCheckFailOpen":false,"priorityClassName":"","proxy":{"accessLogEncoding":"TEXT","accessLogFile":"/dev/stdout","accessLogFormat":"","autoInject":"enabled","clusterDomain":"cluster.local","componentLogLevel":"","concurrency":2,"dnsRefreshRate":"300s","enableCoreDump":false,"enableCoreDumpImage":"ubuntu:xenial","envoyAccessLogService":{"enabled":false,"tcpKeepalive":{"interval":"10s","probes":3,"time":"10s"},"tlsSettings":{"mode":"DISABLE","subjectAltNames":[]}},"envoyMetricsService":{"enabled":false,"tcpKeepalive":{"interval":"10s","probes":3,"time":"10s"},"tlsSettings":{"mode":"DISABLE","subjectAltNames":[]}},"envoyStatsd":{"enabled":false},"excludeIPRanges":"","excludeInboundPorts":"","excludeOutboundPorts":"","image":"proxyv2","includeIPRanges":"*","includeInboundPorts":"*","kubevirtInterfaces":"","logLevel":"","privileged":false,"protocolDetectionTimeout":"100ms","readinessFailureThreshold":30,"readinessInitialDelaySeconds":1,"readinessPeriodSeconds":2,"resources":{"limits":{"cpu":"2000m","memory":"1024Mi"},"requests":{"cpu":"10m","memory":"40Mi"}},"statusPort":15020,"tracer":"zipkin"},"proxy_init":{"image":"proxyv2","resources":{"limits":{"cpu":"100m","memory":"50Mi"},"requests":{"cpu":"10m","memory":"10Mi"}}},"sds":{"enabled":false,"token":{"aud":"istio-ca"},"udsPath":""},"tag":"1.5.0","tracer":{"datadog":{"address":"$(HOST_IP):8126"},"lightstep":{"accessToken":"","address":"","cacertPath":"","secure":true},"stackdriver":{"debug":false,"maxNumberOfAnnotations":200,"maxNumberOfAttributes":200,"maxNumberOfMessageEvents":200},"zipkin":{"address":""}},"trustDomain":"","trustDomainAliases":[],"useMCP":true},"ingress":{"enabled":false},"jaeger":{"accessMode":"ReadWriteMany","hub":"docker.io/jaegertracing","image":"all-in-one","memory":{"max_traces":50000},"persist":false,"podAnnotations":{},"spanStorageType":"badger","storageClassName":"","tag":1.16},"nodeSelector":{},"podAntiAffinityLabelSelector":[],"podAntiAffinityTermLabelSelector":[],"provider":"jaeger","service":{"annotations":{},"externalPort":80,"name":"http","type":"ClusterIP"},"tolerations":[],"zipkin":{"hub":"docker.io/openzipkin","image":"zipkin","javaOptsHeap":700,"maxSpans":500000,"node":{"cpus":2},"podAnnotations":{},"probeStartupDelay":200,"queryPort":9411,"resources":{"limits":{"cpu":"300m","memory":"900Mi"},"requests":{"cpu":"150m","memory":"900Mi"}},"tag":"2.14.2"}}} + + config: |- + policy: enabled + alwaysInjectSelector: + [] + neverInjectSelector: + [] + template: |- + rewriteAppHTTPProbe: {{ valueOrDefault .Values.sidecarInjectorWebhook.rewriteAppHTTPProbe false }} + initContainers: + {{ if ne (annotation .ObjectMeta `sidecar.istio.io/interceptionMode` .ProxyConfig.InterceptionMode) `NONE` }} + {{ if .Values.istio_cni.enabled -}} + - name: istio-validation + {{ else -}} + - name: istio-init + {{ end -}} + {{- if contains "/" .Values.global.proxy_init.image }} + image: "{{ .Values.global.proxy_init.image }}" + {{- else }} + image: "{{ .Values.global.hub }}/{{ .Values.global.proxy_init.image }}:{{ .Values.global.tag }}" + {{- end }} + command: + - istio-iptables + - "-p" + - "15001" + - "-z" + - "15006" + - "-u" + - 1337 + - "-m" + - "{{ annotation .ObjectMeta `sidecar.istio.io/interceptionMode` .ProxyConfig.InterceptionMode }}" + - "-i" + - "{{ annotation .ObjectMeta `traffic.sidecar.istio.io/includeOutboundIPRanges` .Values.global.proxy.includeIPRanges }}" + - "-x" + - "{{ annotation .ObjectMeta `traffic.sidecar.istio.io/excludeOutboundIPRanges` .Values.global.proxy.excludeIPRanges }}" + - "-b" + - "{{ annotation .ObjectMeta `traffic.sidecar.istio.io/includeInboundPorts` `*` }}" + - "-d" + - "{{ excludeInboundPort (annotation .ObjectMeta `status.sidecar.istio.io/port` .Values.global.proxy.statusPort) (annotation .ObjectMeta `traffic.sidecar.istio.io/excludeInboundPorts` .Values.global.proxy.excludeInboundPorts) }}" + {{ if or (isset .ObjectMeta.Annotations `traffic.sidecar.istio.io/excludeOutboundPorts`) (ne (valueOrDefault .Values.global.proxy.excludeOutboundPorts "") "") -}} + - "-o" + - "{{ annotation .ObjectMeta `traffic.sidecar.istio.io/excludeOutboundPorts` .Values.global.proxy.excludeOutboundPorts }}" + {{ end -}} + {{ if (isset .ObjectMeta.Annotations `traffic.sidecar.istio.io/kubevirtInterfaces`) -}} + - "-k" + - "{{ index .ObjectMeta.Annotations `traffic.sidecar.istio.io/kubevirtInterfaces` }}" + {{ end -}} + {{ if .Values.istio_cni.enabled -}} + - "--run-validation" + - "--skip-rule-apply" + {{ end -}} + imagePullPolicy: "{{ valueOrDefault .Values.global.imagePullPolicy `Always` }}" + {{- if .Values.global.proxy_init.resources }} + resources: + {{ toYaml .Values.global.proxy_init.resources | indent 4 }} + {{- else }} + resources: {} + {{- end }} + securityContext: + allowPrivilegeEscalation: {{ .Values.global.proxy.privileged }} + privileged: {{ .Values.global.proxy.privileged }} + capabilities: + {{- if not .Values.istio_cni.enabled }} + add: + - NET_ADMIN + - NET_RAW + {{- end }} + drop: + - ALL + readOnlyRootFilesystem: false + {{- if not .Values.istio_cni.enabled }} + runAsGroup: 0 + runAsNonRoot: false + runAsUser: 0 + {{- else }} + runAsGroup: 1337 + runAsUser: 1337 + runAsNonRoot: true + {{- end }} + restartPolicy: Always + {{ end -}} + {{- if eq (annotation .ObjectMeta `sidecar.istio.io/enableCoreDump` .Values.global.proxy.enableCoreDump) "true" }} + - name: enable-core-dump + args: + - -c + - sysctl -w kernel.core_pattern=/var/lib/istio/core.proxy && ulimit -c unlimited + command: + - /bin/sh + image: {{ $.Values.global.proxy.enableCoreDumpImage }} + imagePullPolicy: IfNotPresent + resources: {} + securityContext: + allowPrivilegeEscalation: true + capabilities: + add: + - SYS_ADMIN + drop: + - ALL + privileged: true + readOnlyRootFilesystem: false + runAsGroup: 0 + runAsNonRoot: false + runAsUser: 0 + {{ end }} + containers: + - name: istio-proxy + {{- if contains "/" (annotation .ObjectMeta `sidecar.istio.io/proxyImage` .Values.global.proxy.image) }} + image: "{{ annotation .ObjectMeta `sidecar.istio.io/proxyImage` .Values.global.proxy.image }}" + {{- else }} + image: "{{ annotation .ObjectMeta `sidecar.istio.io/proxyImage` .Values.global.hub }}/{{ .Values.global.proxy.image }}:{{ .Values.global.tag }}" + {{- end }} + ports: + - containerPort: 15090 + protocol: TCP + name: http-envoy-prom + args: + - proxy + - sidecar + - --domain + - $(POD_NAMESPACE).svc.{{ .Values.global.proxy.clusterDomain }} + - --configPath + - "{{ .ProxyConfig.ConfigPath }}" + - --binaryPath + - "{{ .ProxyConfig.BinaryPath }}" + - --serviceCluster + {{ if ne "" (index .ObjectMeta.Labels "app") -}} + - "{{ index .ObjectMeta.Labels `app` }}.$(POD_NAMESPACE)" + {{ else -}} + - "{{ valueOrDefault .DeploymentMeta.Name `istio-proxy` }}.{{ valueOrDefault .DeploymentMeta.Namespace `default` }}" + {{ end -}} + - --drainDuration + - "{{ formatDuration .ProxyConfig.DrainDuration }}" + - --parentShutdownDuration + - "{{ formatDuration .ProxyConfig.ParentShutdownDuration }}" + - --discoveryAddress + - "{{ annotation .ObjectMeta `sidecar.istio.io/discoveryAddress` .ProxyConfig.DiscoveryAddress }}" + {{- if eq .Values.global.proxy.tracer "lightstep" }} + - --lightstepAddress + - "{{ .ProxyConfig.GetTracing.GetLightstep.GetAddress }}" + - --lightstepAccessToken + - "{{ .ProxyConfig.GetTracing.GetLightstep.GetAccessToken }}" + - --lightstepSecure={{ .ProxyConfig.GetTracing.GetLightstep.GetSecure }} + {{- if .ProxyConfig.GetTracing.GetLightstep.GetSecure }} + - --lightstepCacertPath + - "{{ .ProxyConfig.GetTracing.GetLightstep.GetCacertPath }}" + {{- end }} + {{- else if eq .Values.global.proxy.tracer "zipkin" }} + - --zipkinAddress + - "{{ .ProxyConfig.GetTracing.GetZipkin.GetAddress }}" + {{- else if eq .Values.global.proxy.tracer "datadog" }} + - --datadogAgentAddress + - "{{ .ProxyConfig.GetTracing.GetDatadog.GetAddress }}" + {{- end }} + {{- if .Values.global.proxy.logLevel }} + - --proxyLogLevel={{ .Values.global.proxy.logLevel }} + {{- end}} + {{- if .Values.global.proxy.componentLogLevel }} + - --proxyComponentLogLevel={{ .Values.global.proxy.componentLogLevel }} + {{- end}} + {{- if .Values.global.proxy.outlierLogPath }} + - --outlierLogPath={{ .Values.global.proxy.outlierLogPath }} + {{- end}} + - --dnsRefreshRate + - {{ .Values.global.proxy.dnsRefreshRate }} + - --connectTimeout + - "{{ formatDuration .ProxyConfig.ConnectTimeout }}" + {{- if .Values.global.proxy.envoyStatsd.enabled }} + - --statsdUdpAddress + - "{{ .ProxyConfig.StatsdUdpAddress }}" + {{- end }} + {{- if .Values.global.proxy.envoyMetricsService.enabled }} + - --envoyMetricsService + - '{{ protoToJSON .ProxyConfig.EnvoyMetricsService }}' + {{- end }} + {{- if .Values.global.proxy.envoyAccessLogService.enabled }} + - --envoyAccessLogService + - '{{ protoToJSON .ProxyConfig.EnvoyAccessLogService }}' + {{- end }} + - --proxyAdminPort + - "{{ .ProxyConfig.ProxyAdminPort }}" + {{ if gt .ProxyConfig.Concurrency 0 -}} + - --concurrency + - "{{ .ProxyConfig.Concurrency }}" + {{ end -}} + - --controlPlaneAuthPolicy + - "{{ annotation .ObjectMeta `sidecar.istio.io/controlPlaneAuthPolicy` .ProxyConfig.ControlPlaneAuthPolicy }}" + {{- if (ne (annotation .ObjectMeta "status.sidecar.istio.io/port" (valueOrDefault .Values.global.proxy.statusPort 0 )) `0`) }} + - --statusPort + - "{{ annotation .ObjectMeta `status.sidecar.istio.io/port` .Values.global.proxy.statusPort }}" + {{- end }} + {{- if .Values.global.trustDomain }} + - --trust-domain={{ .Values.global.trustDomain }} + {{- end }} + {{- if .Values.global.proxy.lifecycle }} + lifecycle: + {{ toYaml .Values.global.proxy.lifecycle | indent 4 }} + {{- end }} + env: + - name: POD_NAME + valueFrom: + fieldRef: + fieldPath: metadata.name + - name: ISTIO_META_POD_PORTS + value: |- + [ + {{- $first := true }} + {{- range $index1, $c := .Spec.Containers }} + {{- range $index2, $p := $c.Ports }} + {{- if (structToJSON $p) }} + {{if not $first}},{{end}}{{ structToJSON $p }} + {{- $first = false }} + {{- end }} + {{- end}} + {{- end}} + ] + - name: ISTIO_META_CLUSTER_ID + value: "{{ valueOrDefault .Values.global.multiCluster.clusterName `Kubernetes` }}" + - name: POD_NAMESPACE + valueFrom: + fieldRef: + fieldPath: metadata.namespace + - name: INSTANCE_IP + valueFrom: + fieldRef: + fieldPath: status.podIP + - name: SERVICE_ACCOUNT + valueFrom: + fieldRef: + fieldPath: spec.serviceAccountName + {{- if .Values.global.mtls.auto }} + - name: ISTIO_AUTO_MTLS_ENABLED + value: "true" + {{- end }} + {{- if eq .Values.global.proxy.tracer "datadog" }} + - name: HOST_IP + valueFrom: + fieldRef: + fieldPath: status.hostIP + {{- if isset .ObjectMeta.Annotations `apm.datadoghq.com/env` }} + {{- range $key, $value := fromJSON (index .ObjectMeta.Annotations `apm.datadoghq.com/env`) }} + - name: {{ $key }} + value: "{{ $value }}" + {{- end }} + {{- end }} + {{- end }} + - name: ISTIO_META_POD_NAME + valueFrom: + fieldRef: + fieldPath: metadata.name + - name: ISTIO_META_CONFIG_NAMESPACE + valueFrom: + fieldRef: + fieldPath: metadata.namespace + - name: SDS_ENABLED + value: {{ $.Values.global.sds.enabled }} + - name: ISTIO_META_INTERCEPTION_MODE + value: "{{ or (index .ObjectMeta.Annotations `sidecar.istio.io/interceptionMode`) .ProxyConfig.InterceptionMode.String }}" + {{- if .Values.global.network }} + - name: ISTIO_META_NETWORK + value: "{{ .Values.global.network }}" + {{- end }} + {{ if .ObjectMeta.Annotations }} + - name: ISTIO_METAJSON_ANNOTATIONS + value: | + {{ toJSON .ObjectMeta.Annotations }} + {{ end }} + {{ if .ObjectMeta.Labels }} + - name: ISTIO_METAJSON_LABELS + value: | + {{ toJSON .ObjectMeta.Labels }} + {{ end }} + {{- if .DeploymentMeta.Name }} + - name: ISTIO_META_WORKLOAD_NAME + value: {{ .DeploymentMeta.Name }} + {{ end }} + {{- if and .TypeMeta.APIVersion .DeploymentMeta.Name }} + - name: ISTIO_META_OWNER + value: kubernetes://apis/{{ .TypeMeta.APIVersion }}/namespaces/{{ valueOrDefault .DeploymentMeta.Namespace `default` }}/{{ toLower .TypeMeta.Kind}}s/{{ .DeploymentMeta.Name }} + {{- end}} + {{- if (isset .ObjectMeta.Annotations `sidecar.istio.io/bootstrapOverride`) }} + - name: ISTIO_BOOTSTRAP_OVERRIDE + value: "/etc/istio/custom-bootstrap/custom_bootstrap.json" + {{- end }} + {{- if .Values.global.sds.customTokenDirectory }} + - name: ISTIO_META_SDS_TOKEN_PATH + value: "{{ .Values.global.sds.customTokenDirectory -}}/sdstoken" + {{- end }} + {{- if .Values.global.meshID }} + - name: ISTIO_META_MESH_ID + value: "{{ .Values.global.meshID }}" + {{- else if .Values.global.trustDomain }} + - name: ISTIO_META_MESH_ID + value: "{{ .Values.global.trustDomain }}" + {{- end }} + {{- if eq .Values.global.proxy.tracer "stackdriver" }} + - name: STACKDRIVER_TRACING_ENABLED + value: "true" + - name: STACKDRIVER_TRACING_DEBUG + value: "{{ .ProxyConfig.GetTracing.GetStackdriver.GetDebug }}" + {{- if .ProxyConfig.GetTracing.GetStackdriver.GetMaxNumberOfAnnotations }} + - name: STACKDRIVER_TRACING_MAX_NUMBER_OF_ANNOTATIONS + value: "{{ .ProxyConfig.GetTracing.GetStackdriver.GetMaxNumberOfAnnotations.Value }}" + {{- end }} + {{- if .ProxyConfig.GetTracing.GetStackdriver.GetMaxNumberOfAttributes }} + - name: STACKDRIVER_TRACING_MAX_NUMBER_OF_ATTRIBUTES + value: "{{ .ProxyConfig.GetTracing.GetStackdriver.GetMaxNumberOfAttributes.Value }}" + {{- end }} + {{- if .ProxyConfig.GetTracing.GetStackdriver.GetMaxNumberOfMessageEvents }} + - name: STACKDRIVER_TRACING_MAX_NUMBER_OF_MESSAGE_EVENTS + value: "{{ .ProxyConfig.GetTracing.GetStackdriver.GetMaxNumberOfMessageEvents.Value }}" + {{- end }} + {{- end }} + imagePullPolicy: {{ .Values.global.imagePullPolicy }} + {{ if ne (annotation .ObjectMeta `status.sidecar.istio.io/port` (valueOrDefault .Values.global.proxy.statusPort 0 )) `0` }} + readinessProbe: + httpGet: + path: /healthz/ready + port: {{ annotation .ObjectMeta `status.sidecar.istio.io/port` .Values.global.proxy.statusPort }} + initialDelaySeconds: {{ annotation .ObjectMeta `readiness.status.sidecar.istio.io/initialDelaySeconds` .Values.global.proxy.readinessInitialDelaySeconds }} + periodSeconds: {{ annotation .ObjectMeta `readiness.status.sidecar.istio.io/periodSeconds` .Values.global.proxy.readinessPeriodSeconds }} + failureThreshold: {{ annotation .ObjectMeta `readiness.status.sidecar.istio.io/failureThreshold` .Values.global.proxy.readinessFailureThreshold }} + {{ end -}} + securityContext: + allowPrivilegeEscalation: {{ .Values.global.proxy.privileged }} + capabilities: + {{ if eq (annotation .ObjectMeta `sidecar.istio.io/interceptionMode` .ProxyConfig.InterceptionMode) `TPROXY` -}} + add: + - NET_ADMIN + {{- end }} + drop: + - ALL + privileged: {{ .Values.global.proxy.privileged }} + readOnlyRootFilesystem: {{ ne (annotation .ObjectMeta `sidecar.istio.io/enableCoreDump` .Values.global.proxy.enableCoreDump) "true" }} + runAsGroup: 1337 + {{ if eq (annotation .ObjectMeta `sidecar.istio.io/interceptionMode` .ProxyConfig.InterceptionMode) `TPROXY` -}} + runAsNonRoot: false + runAsUser: 0 + {{- else -}} + runAsNonRoot: true + runAsUser: 1337 + {{- end }} + resources: + {{ if or (isset .ObjectMeta.Annotations `sidecar.istio.io/proxyCPU`) (isset .ObjectMeta.Annotations `sidecar.istio.io/proxyMemory`) -}} + requests: + {{ if (isset .ObjectMeta.Annotations `sidecar.istio.io/proxyCPU`) -}} + cpu: "{{ index .ObjectMeta.Annotations `sidecar.istio.io/proxyCPU` }}" + {{ end}} + {{ if (isset .ObjectMeta.Annotations `sidecar.istio.io/proxyMemory`) -}} + memory: "{{ index .ObjectMeta.Annotations `sidecar.istio.io/proxyMemory` }}" + {{ end }} + {{ else -}} + {{- if .Values.global.proxy.resources }} + {{ toYaml .Values.global.proxy.resources | indent 4 }} + {{- end }} + {{ end -}} + volumeMounts: + {{ if (isset .ObjectMeta.Annotations `sidecar.istio.io/bootstrapOverride`) }} + - mountPath: /etc/istio/custom-bootstrap + name: custom-bootstrap-volume + {{- end }} + - mountPath: /etc/istio/proxy + name: istio-envoy + {{- if .Values.global.sds.enabled }} + - mountPath: /var/run/sds + name: sds-uds-path + readOnly: true + - mountPath: /var/run/secrets/tokens + name: istio-token + {{- if .Values.global.sds.customTokenDirectory }} + - mountPath: "{{ .Values.global.sds.customTokenDirectory -}}" + name: custom-sds-token + readOnly: true + {{- end }} + {{- else }} + - mountPath: /etc/certs/ + name: istio-certs + readOnly: true + {{- end }} + {{- if and (eq .Values.global.proxy.tracer "lightstep") .Values.global.tracer.lightstep.cacertPath }} + - mountPath: {{ directory .ProxyConfig.GetTracing.GetLightstep.GetCacertPath }} + name: lightstep-certs + readOnly: true + {{- end }} + {{- if isset .ObjectMeta.Annotations `sidecar.istio.io/userVolumeMount` }} + {{ range $index, $value := fromJSON (index .ObjectMeta.Annotations `sidecar.istio.io/userVolumeMount`) }} + - name: "{{ $index }}" + {{ toYaml $value | indent 4 }} + {{ end }} + {{- end }} + volumes: + {{- if (isset .ObjectMeta.Annotations `sidecar.istio.io/bootstrapOverride`) }} + - name: custom-bootstrap-volume + configMap: + name: {{ annotation .ObjectMeta `sidecar.istio.io/bootstrapOverride` "" }} + {{- end }} + - emptyDir: + medium: Memory + name: istio-envoy + {{- if .Values.global.sds.enabled }} + - name: sds-uds-path + hostPath: + path: /var/run/sds + - name: istio-token + projected: + sources: + - serviceAccountToken: + path: istio-token + expirationSeconds: 43200 + audience: {{ .Values.global.sds.token.aud }} + {{- if .Values.global.sds.customTokenDirectory }} + - name: custom-sds-token + secret: + secretName: sdstokensecret + {{- end }} + {{- else }} + - name: istio-certs + secret: + optional: true + {{ if eq .Spec.ServiceAccountName "" }} + secretName: istio.default + {{ else -}} + secretName: {{ printf "istio.%s" .Spec.ServiceAccountName }} + {{ end -}} + {{- if isset .ObjectMeta.Annotations `sidecar.istio.io/userVolume` }} + {{range $index, $value := fromJSON (index .ObjectMeta.Annotations `sidecar.istio.io/userVolume`) }} + - name: "{{ $index }}" + {{ toYaml $value | indent 2 }} + {{ end }} + {{ end }} + {{- end }} + {{- if and (eq .Values.global.proxy.tracer "lightstep") .Values.global.tracer.lightstep.cacertPath }} + - name: lightstep-certs + secret: + optional: true + secretName: lightstep.cacert + {{- end }} + {{- if .Values.global.podDNSSearchNamespaces }} + dnsConfig: + searches: + {{- range .Values.global.podDNSSearchNamespaces }} + - {{ render . }} + {{- end }} + {{- end }} + podRedirectAnnot: + sidecar.istio.io/interceptionMode: "{{ annotation .ObjectMeta `sidecar.istio.io/interceptionMode` .ProxyConfig.InterceptionMode }}" + traffic.sidecar.istio.io/includeOutboundIPRanges: "{{ annotation .ObjectMeta `traffic.sidecar.istio.io/includeOutboundIPRanges` .Values.global.proxy.includeIPRanges }}" + traffic.sidecar.istio.io/excludeOutboundIPRanges: "{{ annotation .ObjectMeta `traffic.sidecar.istio.io/excludeOutboundIPRanges` .Values.global.proxy.excludeIPRanges }}" + traffic.sidecar.istio.io/includeInboundPorts: "{{ annotation .ObjectMeta `traffic.sidecar.istio.io/includeInboundPorts` (includeInboundPorts .Spec.Containers) }}" + traffic.sidecar.istio.io/excludeInboundPorts: "{{ excludeInboundPort (annotation .ObjectMeta `status.sidecar.istio.io/port` .Values.global.proxy.statusPort) (annotation .ObjectMeta `traffic.sidecar.istio.io/excludeInboundPorts` .Values.global.proxy.excludeInboundPorts) }}" + {{ if or (isset .ObjectMeta.Annotations `traffic.sidecar.istio.io/excludeOutboundPorts`) (ne .Values.global.proxy.excludeOutboundPorts "") }} + traffic.sidecar.istio.io/excludeOutboundPorts: "{{ annotation .ObjectMeta `traffic.sidecar.istio.io/excludeOutboundPorts` .Values.global.proxy.excludeOutboundPorts }}" + {{- end }} + traffic.sidecar.istio.io/kubevirtInterfaces: "{{ index .ObjectMeta.Annotations `traffic.sidecar.istio.io/kubevirtInterfaces` }}" + injectedAnnotations: + +--- +# Source: istio/charts/galley/templates/serviceaccount.yaml +apiVersion: v1 +kind: ServiceAccount +metadata: + name: istio-galley-service-account + namespace: istio-system + labels: + app: galley + chart: galley + heritage: Tiller + release: istio + +--- +# Source: istio/charts/gateways/templates/serviceaccount.yaml + +apiVersion: v1 +kind: ServiceAccount +metadata: + name: istio-egressgateway-service-account + namespace: istio-system + labels: + app: istio-egressgateway + chart: gateways + heritage: Tiller + release: istio +--- +apiVersion: v1 +kind: ServiceAccount +metadata: + name: istio-ingressgateway-service-account + namespace: istio-system + labels: + app: istio-ingressgateway + chart: gateways + heritage: Tiller + release: istio +--- + + +--- +# Source: istio/charts/grafana/templates/create-custom-resources-job.yaml +apiVersion: v1 +kind: ServiceAccount +metadata: + name: istio-grafana-post-install-account + namespace: istio-system + labels: + app: grafana + chart: grafana + heritage: Tiller + release: istio +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: istio-grafana-post-install-istio-system + labels: + app: grafana + chart: grafana + heritage: Tiller + release: istio +rules: +- apiGroups: ["authentication.istio.io"] # needed to create default authn policy + resources: ["*"] + verbs: ["*"] +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: istio-grafana-post-install-role-binding-istio-system + labels: + app: grafana + chart: grafana + heritage: Tiller + release: istio +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: istio-grafana-post-install-istio-system +subjects: + - kind: ServiceAccount + name: istio-grafana-post-install-account + namespace: istio-system +--- +apiVersion: batch/v1 +kind: Job +metadata: + name: istio-grafana-post-install-1.5.0 + namespace: istio-system + annotations: + "helm.sh/hook": post-install + "helm.sh/hook-delete-policy": hook-succeeded + labels: + app: grafana + chart: grafana + heritage: Tiller + release: istio +spec: + template: + metadata: + name: istio-grafana-post-install + labels: + app: istio-grafana + chart: grafana + heritage: Tiller + release: istio + annotations: + sidecar.istio.io/inject: "false" + spec: + serviceAccountName: istio-grafana-post-install-account + containers: + - name: kubectl + image: "docker.io/istio/kubectl:1.5.0" + command: [ "/bin/bash", "/tmp/grafana/run.sh", "/tmp/grafana/custom-resources.yaml" ] + volumeMounts: + - mountPath: "/tmp/grafana" + name: tmp-configmap-grafana + volumes: + - name: tmp-configmap-grafana + configMap: + name: istio-grafana-custom-resources + restartPolicy: OnFailure + affinity: + nodeAffinity: + requiredDuringSchedulingIgnoredDuringExecution: + nodeSelectorTerms: + - matchExpressions: + - key: beta.kubernetes.io/arch + operator: In + values: + - "amd64" + - "ppc64le" + - "s390x" + preferredDuringSchedulingIgnoredDuringExecution: + - weight: 2 + preference: + matchExpressions: + - key: beta.kubernetes.io/arch + operator: In + values: + - "amd64" + - weight: 2 + preference: + matchExpressions: + - key: beta.kubernetes.io/arch + operator: In + values: + - "ppc64le" + - weight: 2 + preference: + matchExpressions: + - key: beta.kubernetes.io/arch + operator: In + values: + - "s390x" + +--- +# Source: istio/charts/kiali/templates/serviceaccount.yaml +apiVersion: v1 +kind: ServiceAccount +metadata: + name: kiali-service-account + namespace: istio-system + labels: + app: kiali + chart: kiali + heritage: Tiller + release: istio + +--- +# Source: istio/charts/mixer/templates/serviceaccount.yaml + +apiVersion: v1 +kind: ServiceAccount +metadata: + name: istio-mixer-service-account + namespace: istio-system + labels: + app: mixer + chart: mixer + heritage: Tiller + release: istio + +--- +# Source: istio/charts/pilot/templates/serviceaccount.yaml +apiVersion: v1 +kind: ServiceAccount +metadata: + name: istio-pilot-service-account + namespace: istio-system + labels: + app: pilot + chart: pilot + heritage: Tiller + release: istio + +--- +# Source: istio/charts/prometheus/templates/serviceaccount.yaml +apiVersion: v1 +kind: ServiceAccount +metadata: + name: prometheus + namespace: istio-system + labels: + app: prometheus + chart: prometheus + heritage: Tiller + release: istio + +--- +# Source: istio/charts/security/templates/create-custom-resources-job.yaml + +apiVersion: v1 +kind: ServiceAccount +metadata: + name: istio-security-post-install-account + namespace: istio-system + labels: + app: security + chart: security + heritage: Tiller + release: istio +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: istio-security-post-install-istio-system + labels: + app: security + chart: security + heritage: Tiller + release: istio +rules: +- apiGroups: ["authentication.istio.io"] # needed to create default authn policy + resources: ["*"] + verbs: ["*"] +- apiGroups: ["networking.istio.io"] # needed to create security destination rules + resources: ["*"] + verbs: ["*"] +- apiGroups: ["admissionregistration.k8s.io"] + resources: ["validatingwebhookconfigurations"] + verbs: ["get"] +- apiGroups: ["extensions", "apps"] + resources: ["deployments", "replicasets"] + verbs: ["get", "list", "watch"] +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: istio-security-post-install-role-binding-istio-system + labels: + app: security + chart: security + heritage: Tiller + release: istio +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: istio-security-post-install-istio-system +subjects: + - kind: ServiceAccount + name: istio-security-post-install-account + namespace: istio-system +--- +apiVersion: batch/v1 +kind: Job +metadata: + name: istio-security-post-install-1.5.0 + namespace: istio-system + annotations: + "helm.sh/hook": post-install,post-upgrade + "helm.sh/hook-delete-policy": hook-succeeded + labels: + app: security + chart: security + heritage: Tiller + release: istio +spec: + template: + metadata: + name: istio-security-post-install + labels: + app: security + chart: security + heritage: Tiller + release: istio + annotations: + sidecar.istio.io/inject: "false" + spec: + serviceAccountName: istio-security-post-install-account + containers: + - name: kubectl + image: "docker.io/istio/kubectl:1.5.0" + imagePullPolicy: IfNotPresent + command: [ "/bin/bash", "/tmp/security/run.sh", "/tmp/security/custom-resources.yaml" ] + volumeMounts: + - mountPath: "/tmp/security" + name: tmp-configmap-security + volumes: + - name: tmp-configmap-security + configMap: + name: istio-security-custom-resources + restartPolicy: OnFailure + affinity: + nodeAffinity: + requiredDuringSchedulingIgnoredDuringExecution: + nodeSelectorTerms: + - matchExpressions: + - key: beta.kubernetes.io/arch + operator: In + values: + - "amd64" + - "ppc64le" + - "s390x" + preferredDuringSchedulingIgnoredDuringExecution: + - weight: 2 + preference: + matchExpressions: + - key: beta.kubernetes.io/arch + operator: In + values: + - "amd64" + - weight: 2 + preference: + matchExpressions: + - key: beta.kubernetes.io/arch + operator: In + values: + - "ppc64le" + - weight: 2 + preference: + matchExpressions: + - key: beta.kubernetes.io/arch + operator: In + values: + - "s390x" + +--- +# Source: istio/charts/security/templates/serviceaccount.yaml +apiVersion: v1 +kind: ServiceAccount +metadata: + name: istio-citadel-service-account + namespace: istio-system + labels: + app: security + chart: security + heritage: Tiller + release: istio + +--- +# Source: istio/charts/sidecarInjectorWebhook/templates/serviceaccount.yaml +apiVersion: v1 +kind: ServiceAccount +metadata: + name: istio-sidecar-injector-service-account + namespace: istio-system + labels: + app: sidecarInjectorWebhook + chart: sidecarInjectorWebhook + heritage: Tiller + release: istio + istio: sidecar-injector + +--- +# Source: istio/templates/serviceaccount.yaml +apiVersion: v1 +kind: ServiceAccount +metadata: + name: istio-multi + namespace: istio-system +--- +apiVersion: v1 +kind: ServiceAccount +metadata: + name: istio-reader + namespace: istio-system + +--- +# Source: istio/charts/galley/templates/clusterrole.yaml +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: istio-galley-istio-system + labels: + app: galley + chart: galley + heritage: Tiller + release: istio +rules: + # For reading Istio resources +- apiGroups: [ + "authentication.istio.io", + "config.istio.io", + "networking.istio.io", + "rbac.istio.io", + "security.istio.io"] + resources: ["*"] + verbs: ["get", "list", "watch"] + # For updating Istio resource statuses +- apiGroups: [ + "authentication.istio.io", + "config.istio.io", + "networking.istio.io", + "rbac.istio.io", + "security.istio.io"] + resources: ["*/status"] + verbs: ["update"] +- apiGroups: ["admissionregistration.k8s.io"] + resources: ["validatingwebhookconfigurations"] + verbs: ["get", "list", "watch", "update"] +# permissions to verify the webhook is ready and rejecting +# invalid config. We use --server-dry-run so no config is persisted. +- apiGroups: ["networking.istio.io"] + verbs: ["create"] + resources: ["gateways"] +- apiGroups: ["extensions","apps"] + resources: ["deployments"] + verbs: ["get", "list", "watch"] +- apiGroups: [""] + resources: ["pods", "nodes", "services", "endpoints", "namespaces"] + verbs: ["get", "list", "watch"] +- apiGroups: ["extensions"] + resources: ["ingresses"] + verbs: ["get", "list", "watch"] +- apiGroups: ["apiextensions.k8s.io"] + resources: ["customresourcedefinitions"] + verbs: ["get", "list", "watch"] +- apiGroups: ["rbac.authorization.k8s.io"] + resources: ["clusterroles"] + verbs: ["get", "list", "watch"] + +--- +# Source: istio/charts/kiali/templates/clusterrole.yaml +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: kiali + labels: + app: kiali + chart: kiali + heritage: Tiller + release: istio +rules: +- apiGroups: [""] + resources: + - configmaps + - endpoints + - namespaces + - nodes + - pods + - pods/log + - replicationcontrollers + - services + verbs: + - get + - list + - watch +- apiGroups: ["extensions", "apps"] + resources: + - deployments + - replicasets + - statefulsets + verbs: + - get + - list + - watch +- apiGroups: ["autoscaling"] + resources: + - horizontalpodautoscalers + verbs: + - get + - list + - watch +- apiGroups: ["batch"] + resources: + - cronjobs + - jobs + verbs: + - get + - list + - watch +- apiGroups: + - config.istio.io + - networking.istio.io + - authentication.istio.io + - rbac.istio.io + - security.istio.io + resources: ["*"] + verbs: + - create + - delete + - get + - list + - patch + - watch +- apiGroups: ["monitoring.kiali.io"] + resources: + - monitoringdashboards + verbs: + - get + - list +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: kiali-viewer + labels: + app: kiali + chart: kiali + heritage: Tiller + release: istio +rules: +- apiGroups: [""] + resources: + - configmaps + - endpoints + - namespaces + - nodes + - pods + - pods/log + - replicationcontrollers + - services + verbs: + - get + - list + - watch +- apiGroups: ["extensions", "apps"] + resources: + - deployments + - replicasets + - statefulsets + verbs: + - get + - list + - watch +- apiGroups: ["autoscaling"] + resources: + - horizontalpodautoscalers + verbs: + - get + - list + - watch +- apiGroups: ["batch"] + resources: + - cronjobs + - jobs + verbs: + - get + - list + - watch +- apiGroups: + - config.istio.io + - networking.istio.io + - authentication.istio.io + - rbac.istio.io + - security.istio.io + resources: ["*"] + verbs: + - get + - list + - watch +- apiGroups: ["monitoring.kiali.io"] + resources: + - monitoringdashboards + verbs: + - get + - list + +--- +# Source: istio/charts/mixer/templates/clusterrole.yaml + +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: istio-mixer-istio-system + labels: + app: mixer + chart: mixer + heritage: Tiller + release: istio +rules: +- apiGroups: ["config.istio.io"] # istio CRD watcher + resources: ["*"] + verbs: ["create", "get", "list", "watch", "patch"] +- apiGroups: ["apiextensions.k8s.io"] + resources: ["customresourcedefinitions"] + verbs: ["get", "list", "watch"] +- apiGroups: [""] + resources: ["configmaps", "endpoints", "pods", "services", "namespaces", "secrets", "replicationcontrollers"] + verbs: ["get", "list", "watch"] +- apiGroups: ["extensions", "apps"] + resources: ["replicasets"] + verbs: ["get", "list", "watch"] + +--- +# Source: istio/charts/pilot/templates/clusterrole.yaml +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: istio-pilot-istio-system + labels: + app: pilot + chart: pilot + heritage: Tiller + release: istio +rules: +- apiGroups: + - config.istio.io + - rbac.istio.io + - security.istio.io + - networking.istio.io + - authentication.istio.io + resources: ["*"] + verbs: ["get", "list", "watch"] +- apiGroups: ["extensions"] + resources: ["ingresses", "ingresses/status"] + verbs: ["*"] +- apiGroups: [""] + resources: ["configmaps"] + verbs: ["create", "get", "list", "watch", "update"] +- apiGroups: [""] + resources: ["endpoints", "pods", "services", "namespaces", "nodes"] + verbs: ["get", "list", "watch"] +- apiGroups: ["discovery.k8s.io"] + resources: ["endpointslices"] + verbs: ["get", "list", "watch"] +- apiGroups: [""] + resources: ["secrets"] + verbs: ["create", "get", "watch", "list", "update", "delete"] +- apiGroups: ["certificates.k8s.io"] + resources: + - "certificatesigningrequests" + - "certificatesigningrequests/approval" + - "certificatesigningrequests/status" + verbs: ["update", "create", "get", "delete"] + +--- +# Source: istio/charts/prometheus/templates/clusterrole.yaml +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: prometheus-istio-system + labels: + app: prometheus + chart: prometheus + heritage: Tiller + release: istio +rules: +- apiGroups: [""] + resources: + - nodes + - services + - endpoints + - pods + - nodes/proxy + verbs: ["get", "list", "watch"] +- apiGroups: [""] + resources: + - configmaps + verbs: ["get"] +- nonResourceURLs: ["/metrics"] + verbs: ["get"] + +--- +# Source: istio/charts/security/templates/clusterrole.yaml +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: istio-citadel-istio-system + labels: + app: security + chart: security + heritage: Tiller + release: istio +rules: +- apiGroups: [""] + resources: ["configmaps"] + verbs: ["create", "get", "update"] +- apiGroups: [""] + resources: ["secrets"] + verbs: ["create", "get", "watch", "list", "update", "delete"] +- apiGroups: [""] + resources: ["serviceaccounts", "services", "namespaces"] + verbs: ["get", "watch", "list"] +- apiGroups: ["authentication.k8s.io"] + resources: ["tokenreviews"] + verbs: ["create"] + +--- +# Source: istio/charts/sidecarInjectorWebhook/templates/clusterrole.yaml +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: istio-sidecar-injector-istio-system + labels: + app: sidecarInjectorWebhook + chart: sidecarInjectorWebhook + heritage: Tiller + release: istio + istio: sidecar-injector +rules: +- apiGroups: [""] + resources: ["configmaps"] + verbs: ["get", "list", "watch"] +- apiGroups: ["admissionregistration.k8s.io"] + resources: ["mutatingwebhookconfigurations"] + verbs: ["get", "list", "watch", "patch"] + +--- +# Source: istio/templates/clusterrole.yaml +kind: ClusterRole +apiVersion: rbac.authorization.k8s.io/v1 +metadata: + name: istio-reader +rules: + - apiGroups: [''] + resources: ['nodes', 'pods', 'services', 'endpoints', "replicationcontrollers"] + verbs: ['get', 'watch', 'list'] + - apiGroups: ["extensions", "apps"] + resources: ["replicasets"] + verbs: ["get", "list", "watch"] + +--- +# Source: istio/charts/galley/templates/clusterrolebinding.yaml +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: istio-galley-admin-role-binding-istio-system + labels: + app: galley + chart: galley + heritage: Tiller + release: istio +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: istio-galley-istio-system +subjects: + - kind: ServiceAccount + name: istio-galley-service-account + namespace: istio-system + +--- +# Source: istio/charts/kiali/templates/clusterrolebinding.yaml + +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: istio-kiali-admin-role-binding-istio-system + labels: + app: kiali + chart: kiali + heritage: Tiller + release: istio +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: kiali +subjects: +- kind: ServiceAccount + name: kiali-service-account + namespace: istio-system + +--- +# Source: istio/charts/mixer/templates/clusterrolebinding.yaml + +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: istio-mixer-admin-role-binding-istio-system + labels: + app: mixer + chart: mixer + heritage: Tiller + release: istio +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: istio-mixer-istio-system +subjects: + - kind: ServiceAccount + name: istio-mixer-service-account + namespace: istio-system + +--- +# Source: istio/charts/pilot/templates/clusterrolebinding.yaml +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: istio-pilot-istio-system + labels: + app: pilot + chart: pilot + heritage: Tiller + release: istio +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: istio-pilot-istio-system +subjects: + - kind: ServiceAccount + name: istio-pilot-service-account + namespace: istio-system + +--- +# Source: istio/charts/prometheus/templates/clusterrolebindings.yaml +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: prometheus-istio-system + labels: + app: prometheus + chart: prometheus + heritage: Tiller + release: istio +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: prometheus-istio-system +subjects: +- kind: ServiceAccount + name: prometheus + namespace: istio-system + +--- +# Source: istio/charts/security/templates/clusterrolebinding.yaml +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: istio-citadel-istio-system + labels: + app: security + chart: security + heritage: Tiller + release: istio +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: istio-citadel-istio-system +subjects: + - kind: ServiceAccount + name: istio-citadel-service-account + namespace: istio-system + +--- +# Source: istio/charts/sidecarInjectorWebhook/templates/clusterrolebinding.yaml +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: istio-sidecar-injector-admin-role-binding-istio-system + labels: + app: sidecarInjectorWebhook + chart: sidecarInjectorWebhook + heritage: Tiller + release: istio + istio: sidecar-injector +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: istio-sidecar-injector-istio-system +subjects: + - kind: ServiceAccount + name: istio-sidecar-injector-service-account + namespace: istio-system + +--- +# Source: istio/templates/clusterrolebinding.yaml +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: istio-multi + labels: + chart: istio-1.5.0 +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: istio-reader +subjects: +- kind: ServiceAccount + name: istio-multi + namespace: istio-system +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: istio-reader + labels: + chart: istio-1.5.0 +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: istio-reader +subjects: +- kind: ServiceAccount + name: istio-reader + namespace: istio-system + +--- +# Source: istio/charts/gateways/templates/role.yaml + +apiVersion: rbac.authorization.k8s.io/v1 +kind: Role +metadata: + name: istio-ingressgateway-sds + namespace: istio-system +rules: +- apiGroups: [""] + resources: ["secrets"] + verbs: ["get", "watch", "list"] +--- + +--- +# Source: istio/charts/gateways/templates/rolebindings.yaml + +apiVersion: rbac.authorization.k8s.io/v1 +kind: RoleBinding +metadata: + name: istio-ingressgateway-sds + namespace: istio-system +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: Role + name: istio-ingressgateway-sds +subjects: +- kind: ServiceAccount + name: istio-ingressgateway-service-account +--- + +--- +# Source: istio/charts/galley/templates/service.yaml +apiVersion: v1 +kind: Service +metadata: + name: istio-galley + namespace: istio-system + labels: + app: galley + chart: galley + heritage: Tiller + release: istio + istio: galley +spec: + ports: + - port: 443 + targetPort: 9443 + name: https-validation + - port: 15014 + name: http-monitoring + - port: 9901 + name: grpc-mcp + selector: + istio: galley + +--- +# Source: istio/charts/gateways/templates/service.yaml + +apiVersion: v1 +kind: Service +metadata: + name: istio-egressgateway + namespace: istio-system + annotations: + labels: + chart: gateways + heritage: Tiller + release: istio + app: istio-egressgateway + istio: egressgateway +spec: + type: ClusterIP + selector: + release: istio + app: istio-egressgateway + istio: egressgateway + ports: + - + name: http2 + port: 80 + - + name: https + port: 443 + - + name: tls + port: 15443 + targetPort: 15443 +--- +apiVersion: v1 +kind: Service +metadata: + name: istio-ingressgateway + namespace: istio-system + annotations: + labels: + chart: gateways + heritage: Tiller + release: istio + app: istio-ingressgateway + istio: ingressgateway +spec: + type: LoadBalancer + selector: + release: istio + app: istio-ingressgateway + istio: ingressgateway + ports: + - + name: status-port + port: 15020 + targetPort: 15020 + - + name: http2 + nodePort: 31380 + port: 80 + targetPort: 80 + - + name: https + nodePort: 31390 + port: 443 + - + name: tcp + nodePort: 31400 + port: 31400 + - + name: https-kiali + port: 15029 + targetPort: 15029 + - + name: https-prometheus + port: 15030 + targetPort: 15030 + - + name: https-grafana + port: 15031 + targetPort: 15031 + - + name: https-tracing + port: 15032 + targetPort: 15032 + - + name: tls + port: 15443 + targetPort: 15443 +--- + +--- +# Source: istio/charts/grafana/templates/service.yaml +apiVersion: v1 +kind: Service +metadata: + name: grafana + namespace: istio-system + annotations: + labels: + app: grafana + chart: grafana + heritage: Tiller + release: istio +spec: + type: ClusterIP + ports: + - port: 3000 + targetPort: 3000 + protocol: TCP + name: http + selector: + app: grafana + + +--- +# Source: istio/charts/kiali/templates/service.yaml +apiVersion: v1 +kind: Service +metadata: + name: kiali + namespace: istio-system + labels: + app: kiali + chart: kiali + heritage: Tiller + release: istio +spec: + ports: + - name: http-kiali + protocol: TCP + port: 20001 + selector: + app: kiali + +--- +# Source: istio/charts/mixer/templates/service.yaml + +apiVersion: v1 +kind: Service +metadata: + name: istio-policy + namespace: istio-system + annotations: + networking.istio.io/exportTo: "*" + labels: + app: mixer + chart: mixer + heritage: Tiller + release: istio + istio: mixer +spec: + ports: + - name: grpc-mixer + port: 9091 + - name: grpc-mixer-mtls + port: 15004 + - name: http-monitoring + port: 15014 + selector: + istio: mixer + istio-mixer-type: policy +--- +apiVersion: v1 +kind: Service +metadata: + name: istio-telemetry + namespace: istio-system + annotations: + networking.istio.io/exportTo: "*" + labels: + app: mixer + chart: mixer + heritage: Tiller + release: istio + istio: mixer +spec: + ports: + - name: grpc-mixer + port: 9091 + - name: grpc-mixer-mtls + port: 15004 + - name: http-monitoring + port: 15014 + - name: prometheus + port: 42422 + selector: + istio: mixer + istio-mixer-type: telemetry +--- + + +--- +# Source: istio/charts/pilot/templates/service.yaml +apiVersion: v1 +kind: Service +metadata: + name: istio-pilot + namespace: istio-system + labels: + app: pilot + chart: pilot + heritage: Tiller + release: istio + istio: pilot +spec: + ports: + - port: 15010 + name: grpc-xds # direct + - port: 15011 + name: https-xds # mTLS + - port: 8080 + name: http-legacy-discovery # direct + - port: 15014 + name: http-monitoring + selector: + istio: pilot + +--- +# Source: istio/charts/prometheus/templates/service.yaml +apiVersion: v1 +kind: Service +metadata: + name: prometheus + namespace: istio-system + annotations: + prometheus.io/scrape: 'true' + labels: + app: prometheus + chart: prometheus + heritage: Tiller + release: istio +spec: + selector: + app: prometheus + ports: + - name: http-prometheus + protocol: TCP + port: 9090 + +--- +# Source: istio/charts/security/templates/service.yaml +apiVersion: v1 +kind: Service +metadata: + # we use the normal name here (e.g. 'prometheus') + # as grafana is configured to use this as a data source + name: istio-citadel + namespace: istio-system + labels: + app: security + chart: security + heritage: Tiller + release: istio + istio: citadel +spec: + ports: + - name: grpc-citadel + port: 8060 + targetPort: 8060 + protocol: TCP + - name: http-monitoring + port: 15014 + selector: + istio: citadel + +--- +# Source: istio/charts/sidecarInjectorWebhook/templates/service.yaml +apiVersion: v1 +kind: Service +metadata: + name: istio-sidecar-injector + namespace: istio-system + labels: + app: sidecarInjectorWebhook + chart: sidecarInjectorWebhook + heritage: Tiller + release: istio + istio: sidecar-injector +spec: + ports: + - port: 443 + name: https-inject + targetPort: 9443 + - port: 15014 + name: http-monitoring + selector: + istio: sidecar-injector + +--- +# Source: istio/charts/galley/templates/deployment.yaml +apiVersion: apps/v1 +kind: Deployment +metadata: + name: istio-galley + namespace: istio-system + labels: + app: galley + chart: galley + heritage: Tiller + release: istio + istio: galley +spec: + replicas: 1 + selector: + matchLabels: + istio: galley + strategy: + rollingUpdate: + maxSurge: 100% + maxUnavailable: 25% + template: + metadata: + labels: + app: galley + chart: galley + heritage: Tiller + release: istio + istio: galley + annotations: + sidecar.istio.io/inject: "false" + spec: + serviceAccountName: istio-galley-service-account + containers: + - name: galley + image: "docker.io/istio/galley:1.5.0" + imagePullPolicy: IfNotPresent + ports: + - containerPort: 9443 + - containerPort: 15014 + - containerPort: 9901 + command: + - /usr/local/bin/galley + - server + - --meshConfigFile=/etc/mesh-config/mesh + - --livenessProbeInterval=1s + - --livenessProbePath=/tmp/healthliveness + - --readinessProbePath=/tmp/healthready + - --readinessProbeInterval=1s + - --deployment-namespace=istio-system + - --insecure=true + - --enable-reconcileWebhookConfiguration=true + - --monitoringPort=15014 + - --log_output_level=default:info + volumeMounts: + - name: certs + mountPath: /etc/certs + readOnly: true + - name: config + mountPath: /etc/config + readOnly: true + - name: mesh-config + mountPath: /etc/mesh-config + readOnly: true + livenessProbe: + exec: + command: + - /usr/local/bin/galley + - probe + - --probe-path=/tmp/healthliveness + - --interval=10s + initialDelaySeconds: 5 + periodSeconds: 5 + readinessProbe: + exec: + command: + - /usr/local/bin/galley + - probe + - --probe-path=/tmp/healthready + - --interval=10s + initialDelaySeconds: 5 + periodSeconds: 5 + resources: + requests: + cpu: 10m + + volumes: + - name: certs + secret: + secretName: istio.istio-galley-service-account + # galley expects /etc/config to exist even though it doesn't include any files. + - name: config + emptyDir: + medium: Memory + - name: mesh-config + configMap: + name: istio + affinity: + nodeAffinity: + requiredDuringSchedulingIgnoredDuringExecution: + nodeSelectorTerms: + - matchExpressions: + - key: beta.kubernetes.io/arch + operator: In + values: + - "amd64" + - "ppc64le" + - "s390x" + preferredDuringSchedulingIgnoredDuringExecution: + - weight: 2 + preference: + matchExpressions: + - key: beta.kubernetes.io/arch + operator: In + values: + - "amd64" + - weight: 2 + preference: + matchExpressions: + - key: beta.kubernetes.io/arch + operator: In + values: + - "ppc64le" + - weight: 2 + preference: + matchExpressions: + - key: beta.kubernetes.io/arch + operator: In + values: + - "s390x" +--- +# Source: istio/charts/gateways/templates/deployment.yaml + +apiVersion: apps/v1 +kind: Deployment +metadata: + name: istio-egressgateway + namespace: istio-system + labels: + app: istio-egressgateway + chart: gateways + heritage: Tiller + istio: egressgateway + release: istio + +spec: + replicas: 1 + selector: + matchLabels: + app: istio-egressgateway + istio: egressgateway + strategy: + rollingUpdate: + maxSurge: 100% + maxUnavailable: 25% + template: + metadata: + labels: + app: istio-egressgateway + chart: gateways + heritage: Tiller + istio: egressgateway + release: istio + + annotations: + sidecar.istio.io/inject: "false" + spec: + serviceAccountName: istio-egressgateway-service-account + containers: + - name: istio-proxy + image: "docker.io/istio/proxyv2:1.5.0" + imagePullPolicy: IfNotPresent + ports: + - containerPort: 80 + - containerPort: 443 + - containerPort: 15443 + - containerPort: 15090 + protocol: TCP + name: http-envoy-prom + args: + - proxy + - router + - --domain + - $(POD_NAMESPACE).svc.cluster.local + - --log_output_level=default:info + - --drainDuration + - '45s' #drainDuration + - --parentShutdownDuration + - '1m0s' #parentShutdownDuration + - --connectTimeout + - '10s' #connectTimeout + - --serviceCluster + - istio-egressgateway + - --zipkinAddress + - zipkin:9411 + - --proxyAdminPort + - "15000" + - --statusPort + - "15020" + - --controlPlaneAuthPolicy + - NONE + - --discoveryAddress + - istio-pilot:15010 + readinessProbe: + failureThreshold: 30 + httpGet: + path: /healthz/ready + port: 15020 + scheme: HTTP + initialDelaySeconds: 1 + periodSeconds: 2 + successThreshold: 1 + timeoutSeconds: 1 + resources: + limits: + cpu: 2000m + memory: 1024Mi + requests: + cpu: 10m + memory: 40Mi + + env: + - name: NODE_NAME + valueFrom: + fieldRef: + apiVersion: v1 + fieldPath: spec.nodeName + - name: POD_NAME + valueFrom: + fieldRef: + apiVersion: v1 + fieldPath: metadata.name + - name: POD_NAMESPACE + valueFrom: + fieldRef: + apiVersion: v1 + fieldPath: metadata.namespace + - name: INSTANCE_IP + valueFrom: + fieldRef: + apiVersion: v1 + fieldPath: status.podIP + - name: HOST_IP + valueFrom: + fieldRef: + apiVersion: v1 + fieldPath: status.hostIP + - name: SERVICE_ACCOUNT + valueFrom: + fieldRef: + fieldPath: spec.serviceAccountName + - name: ISTIO_AUTO_MTLS_ENABLED + value: "true" + - name: ISTIO_META_POD_NAME + valueFrom: + fieldRef: + apiVersion: v1 + fieldPath: metadata.name + - name: ISTIO_META_CONFIG_NAMESPACE + valueFrom: + fieldRef: + fieldPath: metadata.namespace + - name: ISTIO_METAJSON_LABELS + value: | + {"app":"istio-egressgateway","chart":"gateways","heritage":"Tiller","istio":"egressgateway","release":"istio"} + - name: ISTIO_META_CLUSTER_ID + value: "Kubernetes" + - name: SDS_ENABLED + value: "false" + - name: ISTIO_META_WORKLOAD_NAME + value: istio-egressgateway + - name: ISTIO_META_OWNER + value: kubernetes://apis/apps/v1/namespaces/istio-system/deployments/istio-egressgateway + - name: ISTIO_META_ROUTER_MODE + value: standard + + volumeMounts: + - name: istio-certs + mountPath: /etc/certs + readOnly: true + - name: egressgateway-certs + mountPath: "/etc/istio/egressgateway-certs" + readOnly: true + - name: egressgateway-ca-certs + mountPath: "/etc/istio/egressgateway-ca-certs" + readOnly: true + volumes: + - name: istio-certs + secret: + secretName: istio.istio-egressgateway-service-account + optional: true + - name: egressgateway-certs + secret: + secretName: "istio-egressgateway-certs" + optional: true + - name: egressgateway-ca-certs + secret: + secretName: "istio-egressgateway-ca-certs" + optional: true + affinity: + nodeAffinity: + requiredDuringSchedulingIgnoredDuringExecution: + nodeSelectorTerms: + - matchExpressions: + - key: beta.kubernetes.io/arch + operator: In + values: + - "amd64" + - "ppc64le" + - "s390x" + preferredDuringSchedulingIgnoredDuringExecution: + - weight: 2 + preference: + matchExpressions: + - key: beta.kubernetes.io/arch + operator: In + values: + - "amd64" + - weight: 2 + preference: + matchExpressions: + - key: beta.kubernetes.io/arch + operator: In + values: + - "ppc64le" + - weight: 2 + preference: + matchExpressions: + - key: beta.kubernetes.io/arch + operator: In + values: + - "s390x" +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: istio-ingressgateway + namespace: istio-system + labels: + app: istio-ingressgateway + chart: gateways + heritage: Tiller + istio: ingressgateway + release: istio + +spec: + replicas: 1 + selector: + matchLabels: + app: istio-ingressgateway + istio: ingressgateway + strategy: + rollingUpdate: + maxSurge: 100% + maxUnavailable: 25% + template: + metadata: + labels: + app: istio-ingressgateway + chart: gateways + heritage: Tiller + istio: ingressgateway + release: istio + + annotations: + sidecar.istio.io/inject: "false" + spec: + serviceAccountName: istio-ingressgateway-service-account + containers: + - name: istio-proxy + image: "docker.io/istio/proxyv2:1.5.0" + imagePullPolicy: IfNotPresent + ports: + - containerPort: 15020 + - containerPort: 80 + - containerPort: 443 + - containerPort: 31400 + - containerPort: 15029 + - containerPort: 15030 + - containerPort: 15031 + - containerPort: 15032 + - containerPort: 15443 + - containerPort: 15090 + protocol: TCP + name: http-envoy-prom + args: + - proxy + - router + - --domain + - $(POD_NAMESPACE).svc.cluster.local + - --log_output_level=default:info + - --drainDuration + - '45s' #drainDuration + - --parentShutdownDuration + - '1m0s' #parentShutdownDuration + - --connectTimeout + - '10s' #connectTimeout + - --serviceCluster + - istio-ingressgateway + - --zipkinAddress + - zipkin:9411 + - --proxyAdminPort + - "15000" + - --statusPort + - "15020" + - --controlPlaneAuthPolicy + - NONE + - --discoveryAddress + - istio-pilot:15010 + readinessProbe: + failureThreshold: 30 + httpGet: + path: /healthz/ready + port: 15020 + scheme: HTTP + initialDelaySeconds: 1 + periodSeconds: 2 + successThreshold: 1 + timeoutSeconds: 1 + resources: + limits: + cpu: 2000m + memory: 1024Mi + requests: + cpu: 10m + memory: 40Mi + + env: + - name: NODE_NAME + valueFrom: + fieldRef: + apiVersion: v1 + fieldPath: spec.nodeName + - name: POD_NAME + valueFrom: + fieldRef: + apiVersion: v1 + fieldPath: metadata.name + - name: POD_NAMESPACE + valueFrom: + fieldRef: + apiVersion: v1 + fieldPath: metadata.namespace + - name: INSTANCE_IP + valueFrom: + fieldRef: + apiVersion: v1 + fieldPath: status.podIP + - name: HOST_IP + valueFrom: + fieldRef: + apiVersion: v1 + fieldPath: status.hostIP + - name: SERVICE_ACCOUNT + valueFrom: + fieldRef: + fieldPath: spec.serviceAccountName + - name: ISTIO_AUTO_MTLS_ENABLED + value: "true" + - name: ISTIO_META_POD_NAME + valueFrom: + fieldRef: + apiVersion: v1 + fieldPath: metadata.name + - name: ISTIO_META_CONFIG_NAMESPACE + valueFrom: + fieldRef: + fieldPath: metadata.namespace + - name: ISTIO_METAJSON_LABELS + value: | + {"app":"istio-ingressgateway","chart":"gateways","heritage":"Tiller","istio":"ingressgateway","release":"istio"} + - name: ISTIO_META_CLUSTER_ID + value: "Kubernetes" + - name: SDS_ENABLED + value: "false" + - name: ISTIO_META_WORKLOAD_NAME + value: istio-ingressgateway + - name: ISTIO_META_OWNER + value: kubernetes://apis/apps/v1/namespaces/istio-system/deployments/istio-ingressgateway + - name: ISTIO_META_ROUTER_MODE + value: standard + + + volumeMounts: + - name: istio-certs + mountPath: /etc/certs + readOnly: true + - name: ingressgateway-certs + mountPath: "/etc/istio/ingressgateway-certs" + readOnly: true + - name: ingressgateway-ca-certs + mountPath: "/etc/istio/ingressgateway-ca-certs" + readOnly: true + volumes: + - name: istio-certs + secret: + secretName: istio.istio-ingressgateway-service-account + optional: true + - name: ingressgateway-certs + secret: + secretName: "istio-ingressgateway-certs" + optional: true + - name: ingressgateway-ca-certs + secret: + secretName: "istio-ingressgateway-ca-certs" + optional: true + affinity: + nodeAffinity: + requiredDuringSchedulingIgnoredDuringExecution: + nodeSelectorTerms: + - matchExpressions: + - key: beta.kubernetes.io/arch + operator: In + values: + - "amd64" + - "ppc64le" + - "s390x" + preferredDuringSchedulingIgnoredDuringExecution: + - weight: 2 + preference: + matchExpressions: + - key: beta.kubernetes.io/arch + operator: In + values: + - "amd64" + - weight: 2 + preference: + matchExpressions: + - key: beta.kubernetes.io/arch + operator: In + values: + - "ppc64le" + - weight: 2 + preference: + matchExpressions: + - key: beta.kubernetes.io/arch + operator: In + values: + - "s390x" +--- + +--- +# Source: istio/charts/grafana/templates/deployment.yaml +apiVersion: apps/v1 +kind: Deployment +metadata: + name: grafana + namespace: istio-system + labels: + app: grafana + chart: grafana + heritage: Tiller + release: istio +spec: + replicas: 1 + selector: + matchLabels: + app: grafana + template: + metadata: + labels: + app: grafana + chart: grafana + heritage: Tiller + release: istio + annotations: + sidecar.istio.io/inject: "false" + prometheus.io/scrape: "true" + spec: + securityContext: + runAsUser: 472 + fsGroup: 472 + containers: + - name: grafana + image: "grafana/grafana:6.4.3" + imagePullPolicy: IfNotPresent + ports: + - containerPort: 3000 + readinessProbe: + httpGet: + path: /api/health + port: 3000 + env: + - name: GRAFANA_PORT + value: "3000" + - name: GF_AUTH_BASIC_ENABLED + value: "false" + - name: GF_AUTH_ANONYMOUS_ENABLED + value: "true" + - name: GF_AUTH_ANONYMOUS_ORG_ROLE + value: Admin + - name: GF_PATHS_DATA + value: /data/grafana + resources: + requests: + cpu: 10m + + volumeMounts: + - name: data + mountPath: /data/grafana + - name: dashboards-istio-citadel-dashboard + mountPath: "/var/lib/grafana/dashboards/istio/citadel-dashboard.json" + subPath: citadel-dashboard.json + readOnly: true + - name: dashboards-istio-galley-dashboard + mountPath: "/var/lib/grafana/dashboards/istio/galley-dashboard.json" + subPath: galley-dashboard.json + readOnly: true + - name: dashboards-istio-istio-mesh-dashboard + mountPath: "/var/lib/grafana/dashboards/istio/istio-mesh-dashboard.json" + subPath: istio-mesh-dashboard.json + readOnly: true + - name: dashboards-istio-istio-performance-dashboard + mountPath: "/var/lib/grafana/dashboards/istio/istio-performance-dashboard.json" + subPath: istio-performance-dashboard.json + readOnly: true + - name: dashboards-istio-istio-service-dashboard + mountPath: "/var/lib/grafana/dashboards/istio/istio-service-dashboard.json" + subPath: istio-service-dashboard.json + readOnly: true + - name: dashboards-istio-istio-workload-dashboard + mountPath: "/var/lib/grafana/dashboards/istio/istio-workload-dashboard.json" + subPath: istio-workload-dashboard.json + readOnly: true + - name: dashboards-istio-mixer-dashboard + mountPath: "/var/lib/grafana/dashboards/istio/mixer-dashboard.json" + subPath: mixer-dashboard.json + readOnly: true + - name: dashboards-istio-pilot-dashboard + mountPath: "/var/lib/grafana/dashboards/istio/pilot-dashboard.json" + subPath: pilot-dashboard.json + readOnly: true + - name: config + mountPath: "/etc/grafana/provisioning/datasources/datasources.yaml" + subPath: datasources.yaml + - name: config + mountPath: "/etc/grafana/provisioning/dashboards/dashboardproviders.yaml" + subPath: dashboardproviders.yaml + affinity: + nodeAffinity: + requiredDuringSchedulingIgnoredDuringExecution: + nodeSelectorTerms: + - matchExpressions: + - key: beta.kubernetes.io/arch + operator: In + values: + - "amd64" + - "ppc64le" + - "s390x" + preferredDuringSchedulingIgnoredDuringExecution: + - weight: 2 + preference: + matchExpressions: + - key: beta.kubernetes.io/arch + operator: In + values: + - "amd64" + - weight: 2 + preference: + matchExpressions: + - key: beta.kubernetes.io/arch + operator: In + values: + - "ppc64le" + - weight: 2 + preference: + matchExpressions: + - key: beta.kubernetes.io/arch + operator: In + values: + - "s390x" + volumes: + - name: config + configMap: + name: istio-grafana + - name: data + emptyDir: {} + - name: dashboards-istio-citadel-dashboard + configMap: + name: istio-grafana-configuration-dashboards-citadel-dashboard + - name: dashboards-istio-galley-dashboard + configMap: + name: istio-grafana-configuration-dashboards-galley-dashboard + - name: dashboards-istio-istio-mesh-dashboard + configMap: + name: istio-grafana-configuration-dashboards-istio-mesh-dashboard + - name: dashboards-istio-istio-performance-dashboard + configMap: + name: istio-grafana-configuration-dashboards-istio-performance-dashboard + - name: dashboards-istio-istio-service-dashboard + configMap: + name: istio-grafana-configuration-dashboards-istio-service-dashboard + - name: dashboards-istio-istio-workload-dashboard + configMap: + name: istio-grafana-configuration-dashboards-istio-workload-dashboard + - name: dashboards-istio-mixer-dashboard + configMap: + name: istio-grafana-configuration-dashboards-mixer-dashboard + - name: dashboards-istio-pilot-dashboard + configMap: + name: istio-grafana-configuration-dashboards-pilot-dashboard + +--- +# Source: istio/charts/kiali/templates/deployment.yaml +apiVersion: apps/v1 +kind: Deployment +metadata: + name: kiali + namespace: istio-system + labels: + app: kiali + chart: kiali + heritage: Tiller + release: istio +spec: + replicas: 1 + selector: + matchLabels: + app: kiali + template: + metadata: + name: kiali + labels: + app: kiali + chart: kiali + heritage: Tiller + release: istio + annotations: + sidecar.istio.io/inject: "false" + scheduler.alpha.kubernetes.io/critical-pod: "" + prometheus.io/scrape: "true" + prometheus.io/port: "9090" + kiali.io/runtimes: go,kiali + spec: + serviceAccountName: kiali-service-account + containers: + - image: "quay.io/kiali/kiali:v1.9" + imagePullPolicy: IfNotPresent + name: kiali + command: + - "/opt/kiali/kiali" + - "-config" + - "/kiali-configuration/config.yaml" + - "-v" + - "3" + readinessProbe: + httpGet: + path: /kiali/healthz + port: 20001 + scheme: 'HTTP' + initialDelaySeconds: 5 + periodSeconds: 30 + livenessProbe: + httpGet: + path: /kiali/healthz + port: 20001 + scheme: 'HTTP' + initialDelaySeconds: 5 + periodSeconds: 30 + env: + - name: ACTIVE_NAMESPACE + valueFrom: + fieldRef: + fieldPath: metadata.namespace + volumeMounts: + - name: kiali-configuration + mountPath: "/kiali-configuration" + - name: kiali-cert + mountPath: "/kiali-cert" + - name: kiali-secret + mountPath: "/kiali-secret" + resources: + requests: + cpu: 10m + + volumes: + - name: kiali-configuration + configMap: + name: kiali + - name: kiali-cert + secret: + secretName: istio.kiali-service-account + optional: true + - name: kiali-secret + secret: + secretName: kiali + optional: true + affinity: + nodeAffinity: + requiredDuringSchedulingIgnoredDuringExecution: + nodeSelectorTerms: + - matchExpressions: + - key: beta.kubernetes.io/arch + operator: In + values: + - "amd64" + - "ppc64le" + - "s390x" + preferredDuringSchedulingIgnoredDuringExecution: + - weight: 2 + preference: + matchExpressions: + - key: beta.kubernetes.io/arch + operator: In + values: + - "amd64" + - weight: 2 + preference: + matchExpressions: + - key: beta.kubernetes.io/arch + operator: In + values: + - "ppc64le" + - weight: 2 + preference: + matchExpressions: + - key: beta.kubernetes.io/arch + operator: In + values: + - "s390x" + +--- +# Source: istio/charts/mixer/templates/deployment.yaml + +apiVersion: apps/v1 +kind: Deployment +metadata: + name: istio-policy + namespace: istio-system + labels: + app: istio-mixer + chart: mixer + heritage: Tiller + release: istio + istio: mixer +spec: + replicas: 1 + strategy: + rollingUpdate: + maxSurge: 100% + maxUnavailable: 25% + selector: + matchLabels: + istio: mixer + istio-mixer-type: policy + template: + metadata: + labels: + app: policy + chart: mixer + heritage: Tiller + release: istio + istio: mixer + istio-mixer-type: policy + annotations: + sidecar.istio.io/inject: "false" + spec: + serviceAccountName: istio-mixer-service-account + volumes: + - name: istio-certs + secret: + secretName: istio.istio-mixer-service-account + optional: true + - name: uds-socket + emptyDir: {} + - name: policy-adapter-secret + secret: + secretName: policy-adapter-secret + optional: true + affinity: + nodeAffinity: + requiredDuringSchedulingIgnoredDuringExecution: + nodeSelectorTerms: + - matchExpressions: + - key: beta.kubernetes.io/arch + operator: In + values: + - "amd64" + - "ppc64le" + - "s390x" + preferredDuringSchedulingIgnoredDuringExecution: + - weight: 2 + preference: + matchExpressions: + - key: beta.kubernetes.io/arch + operator: In + values: + - "amd64" + - weight: 2 + preference: + matchExpressions: + - key: beta.kubernetes.io/arch + operator: In + values: + - "ppc64le" + - weight: 2 + preference: + matchExpressions: + - key: beta.kubernetes.io/arch + operator: In + values: + - "s390x" + containers: + - name: mixer + image: "docker.io/istio/mixer:1.5.0" + imagePullPolicy: IfNotPresent + ports: + - containerPort: 15014 + - containerPort: 42422 + args: + - --monitoringPort=15014 + - --address + - unix:///sock/mixer.socket + - --log_output_level=default:info + - --configStoreURL=mcp://istio-galley.istio-system.svc:9901 + - --configDefaultNamespace=istio-system + - --useAdapterCRDs=false + - --useTemplateCRDs=false + - --trace_zipkin_url=http://zipkin.istio-system:9411/api/v1/spans + env: + - name: POD_NAMESPACE + valueFrom: + fieldRef: + apiVersion: v1 + fieldPath: metadata.namespace + - name: GOMAXPROCS + value: "6" + resources: + requests: + cpu: 10m + memory: 100Mi + + volumeMounts: + - name: istio-certs + mountPath: /etc/certs + readOnly: true + - name: uds-socket + mountPath: /sock + livenessProbe: + httpGet: + path: /version + port: 15014 + initialDelaySeconds: 5 + periodSeconds: 5 + - name: istio-proxy + image: "docker.io/istio/proxyv2:1.5.0" + imagePullPolicy: IfNotPresent + ports: + - containerPort: 9091 + - containerPort: 15004 + - containerPort: 15090 + protocol: TCP + name: http-envoy-prom + args: + - proxy + - --domain + - $(POD_NAMESPACE).svc.cluster.local + - --serviceCluster + - istio-policy + - --templateFile + - /etc/istio/proxy/envoy_policy.yaml.tmpl + - --controlPlaneAuthPolicy + - NONE + - --log_output_level=default:info + env: + - name: POD_NAME + valueFrom: + fieldRef: + apiVersion: v1 + fieldPath: metadata.name + - name: POD_NAMESPACE + valueFrom: + fieldRef: + apiVersion: v1 + fieldPath: metadata.namespace + - name: INSTANCE_IP + valueFrom: + fieldRef: + apiVersion: v1 + fieldPath: status.podIP + - name: SDS_ENABLED + value: "false" + resources: + limits: + cpu: 2000m + memory: 1024Mi + requests: + cpu: 10m + memory: 40Mi + + volumeMounts: + - name: istio-certs + mountPath: /etc/certs + readOnly: true + - name: uds-socket + mountPath: /sock + - name: policy-adapter-secret + mountPath: /var/run/secrets/istio.io/policy/adapter + readOnly: true + +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: istio-telemetry + namespace: istio-system + labels: + app: istio-mixer + chart: mixer + heritage: Tiller + release: istio + istio: mixer +spec: + replicas: 1 + strategy: + rollingUpdate: + maxSurge: 100% + maxUnavailable: 25% + selector: + matchLabels: + istio: mixer + istio-mixer-type: telemetry + template: + metadata: + labels: + app: telemetry + chart: mixer + heritage: Tiller + release: istio + istio: mixer + istio-mixer-type: telemetry + annotations: + sidecar.istio.io/inject: "false" + spec: + serviceAccountName: istio-mixer-service-account + volumes: + - name: istio-certs + secret: + secretName: istio.istio-mixer-service-account + optional: true + - name: uds-socket + emptyDir: {} + - name: telemetry-adapter-secret + secret: + secretName: telemetry-adapter-secret + optional: true + affinity: + nodeAffinity: + requiredDuringSchedulingIgnoredDuringExecution: + nodeSelectorTerms: + - matchExpressions: + - key: beta.kubernetes.io/arch + operator: In + values: + - "amd64" + - "ppc64le" + - "s390x" + preferredDuringSchedulingIgnoredDuringExecution: + - weight: 2 + preference: + matchExpressions: + - key: beta.kubernetes.io/arch + operator: In + values: + - "amd64" + - weight: 2 + preference: + matchExpressions: + - key: beta.kubernetes.io/arch + operator: In + values: + - "ppc64le" + - weight: 2 + preference: + matchExpressions: + - key: beta.kubernetes.io/arch + operator: In + values: + - "s390x" + containers: + - name: mixer + image: "docker.io/istio/mixer:1.5.0" + imagePullPolicy: IfNotPresent + ports: + - containerPort: 15014 + - containerPort: 42422 + args: + - --monitoringPort=15014 + - --address + - unix:///sock/mixer.socket + - --log_output_level=default:info + - --configStoreURL=mcp://istio-galley.istio-system.svc:9901 + - --configDefaultNamespace=istio-system + - --useAdapterCRDs=false + - --useTemplateCRDs=false + - --trace_zipkin_url=http://zipkin.istio-system:9411/api/v1/spans + - --averageLatencyThreshold + - 100ms + - --loadsheddingMode + - enforce + env: + - name: POD_NAMESPACE + valueFrom: + fieldRef: + apiVersion: v1 + fieldPath: metadata.namespace + - name: GOMAXPROCS + value: "6" + resources: + limits: + cpu: 4800m + memory: 4G + requests: + cpu: 50m + memory: 100Mi + + volumeMounts: + - name: istio-certs + mountPath: /etc/certs + readOnly: true + - name: telemetry-adapter-secret + mountPath: /var/run/secrets/istio.io/telemetry/adapter + readOnly: true + - name: uds-socket + mountPath: /sock + livenessProbe: + httpGet: + path: /version + port: 15014 + initialDelaySeconds: 5 + periodSeconds: 5 + - name: istio-proxy + image: "docker.io/istio/proxyv2:1.5.0" + imagePullPolicy: IfNotPresent + ports: + - containerPort: 9091 + - containerPort: 15004 + - containerPort: 15090 + protocol: TCP + name: http-envoy-prom + args: + - proxy + - --domain + - $(POD_NAMESPACE).svc.cluster.local + - --serviceCluster + - istio-telemetry + - --templateFile + - /etc/istio/proxy/envoy_telemetry.yaml.tmpl + - --controlPlaneAuthPolicy + - NONE + - --log_output_level=default:info + env: + - name: POD_NAME + valueFrom: + fieldRef: + apiVersion: v1 + fieldPath: metadata.name + - name: POD_NAMESPACE + valueFrom: + fieldRef: + apiVersion: v1 + fieldPath: metadata.namespace + - name: INSTANCE_IP + valueFrom: + fieldRef: + apiVersion: v1 + fieldPath: status.podIP + - name: SDS_ENABLED + value: "false" + resources: + limits: + cpu: 2000m + memory: 1024Mi + requests: + cpu: 10m + memory: 40Mi + + volumeMounts: + - name: istio-certs + mountPath: /etc/certs + readOnly: true + - name: uds-socket + mountPath: /sock + +--- + +--- +# Source: istio/charts/pilot/templates/deployment.yaml +apiVersion: apps/v1 +kind: Deployment +metadata: + name: istio-pilot + namespace: istio-system + # TODO: default template doesn't have this, which one is right ? + labels: + app: pilot + chart: pilot + heritage: Tiller + release: istio + istio: pilot +spec: + replicas: 1 + strategy: + rollingUpdate: + maxSurge: 100% + maxUnavailable: 25% + selector: + matchLabels: + istio: pilot + template: + metadata: + labels: + app: pilot + chart: pilot + heritage: Tiller + release: istio + istio: pilot + annotations: + sidecar.istio.io/inject: "false" + spec: + serviceAccountName: istio-pilot-service-account + containers: + - name: discovery + image: "docker.io/istio/pilot:1.5.0" + imagePullPolicy: IfNotPresent + args: + - "discovery" + - --monitoringAddr=:15014 + - --log_output_level=default:info + - --domain + - cluster.local + - --secureGrpcAddr + - "" + - --keepaliveMaxServerConnectionAge + - "30m" + ports: + - containerPort: 8080 + - containerPort: 15010 + readinessProbe: + httpGet: + path: /ready + port: 8080 + initialDelaySeconds: 5 + periodSeconds: 5 + timeoutSeconds: 5 + env: + - name: POD_NAME + valueFrom: + fieldRef: + apiVersion: v1 + fieldPath: metadata.name + - name: POD_NAMESPACE + valueFrom: + fieldRef: + apiVersion: v1 + fieldPath: metadata.namespace + - name: PILOT_PUSH_THROTTLE + value: "100" + - name: PILOT_TRACE_SAMPLING + value: "100" + - name: PILOT_ENABLE_PROTOCOL_SNIFFING_FOR_OUTBOUND + value: "true" + - name: PILOT_ENABLE_PROTOCOL_SNIFFING_FOR_INBOUND + value: "false" + resources: + requests: + cpu: 10m + memory: 100Mi + + volumeMounts: + - name: config-volume + mountPath: /etc/istio/config + - name: istio-certs + mountPath: /etc/certs + readOnly: true + - name: istio-proxy + image: "docker.io/istio/proxyv2:1.5.0" + imagePullPolicy: IfNotPresent + ports: + - containerPort: 15003 + - containerPort: 15005 + - containerPort: 15007 + - containerPort: 15011 + args: + - proxy + - --domain + - $(POD_NAMESPACE).svc.cluster.local + - --serviceCluster + - istio-pilot + - --templateFile + - /etc/istio/proxy/envoy_pilot.yaml.tmpl + - --controlPlaneAuthPolicy + - NONE + - --log_output_level=default:info + env: + - name: POD_NAME + valueFrom: + fieldRef: + apiVersion: v1 + fieldPath: metadata.name + - name: POD_NAMESPACE + valueFrom: + fieldRef: + apiVersion: v1 + fieldPath: metadata.namespace + - name: INSTANCE_IP + valueFrom: + fieldRef: + apiVersion: v1 + fieldPath: status.podIP + - name: SDS_ENABLED + value: "false" + resources: + limits: + cpu: 2000m + memory: 1024Mi + requests: + cpu: 10m + memory: 40Mi + + volumeMounts: + - name: istio-certs + mountPath: /etc/certs + readOnly: true + volumes: + - name: config-volume + configMap: + name: istio + - name: istio-certs + secret: + secretName: istio.istio-pilot-service-account + optional: true + affinity: + nodeAffinity: + requiredDuringSchedulingIgnoredDuringExecution: + nodeSelectorTerms: + - matchExpressions: + - key: beta.kubernetes.io/arch + operator: In + values: + - "amd64" + - "ppc64le" + - "s390x" + preferredDuringSchedulingIgnoredDuringExecution: + - weight: 2 + preference: + matchExpressions: + - key: beta.kubernetes.io/arch + operator: In + values: + - "amd64" + - weight: 2 + preference: + matchExpressions: + - key: beta.kubernetes.io/arch + operator: In + values: + - "ppc64le" + - weight: 2 + preference: + matchExpressions: + - key: beta.kubernetes.io/arch + operator: In + values: + - "s390x" + +--- +# Source: istio/charts/prometheus/templates/deployment.yaml +# TODO: the original template has service account, roles, etc +apiVersion: apps/v1 +kind: Deployment +metadata: + name: prometheus + namespace: istio-system + labels: + app: prometheus + chart: prometheus + heritage: Tiller + release: istio +spec: + replicas: 1 + selector: + matchLabels: + app: prometheus + template: + metadata: + labels: + app: prometheus + chart: prometheus + heritage: Tiller + release: istio + annotations: + sidecar.istio.io/inject: "false" + spec: + serviceAccountName: prometheus + containers: + - name: prometheus + image: "docker.io/prom/prometheus:v2.12.0" + imagePullPolicy: IfNotPresent + args: + - '--storage.tsdb.retention=6h' + - '--config.file=/etc/prometheus/prometheus.yml' + ports: + - containerPort: 9090 + name: http + livenessProbe: + httpGet: + path: /-/healthy + port: 9090 + readinessProbe: + httpGet: + path: /-/ready + port: 9090 + resources: + requests: + cpu: 10m + + volumeMounts: + - name: config-volume + mountPath: /etc/prometheus + - mountPath: /etc/istio-certs + name: istio-certs + volumes: + - name: config-volume + configMap: + name: prometheus + - name: istio-certs + secret: + defaultMode: 420 + secretName: istio.default + affinity: + nodeAffinity: + requiredDuringSchedulingIgnoredDuringExecution: + nodeSelectorTerms: + - matchExpressions: + - key: beta.kubernetes.io/arch + operator: In + values: + - "amd64" + - "ppc64le" + - "s390x" + preferredDuringSchedulingIgnoredDuringExecution: + - weight: 2 + preference: + matchExpressions: + - key: beta.kubernetes.io/arch + operator: In + values: + - "amd64" + - weight: 2 + preference: + matchExpressions: + - key: beta.kubernetes.io/arch + operator: In + values: + - "ppc64le" + - weight: 2 + preference: + matchExpressions: + - key: beta.kubernetes.io/arch + operator: In + values: + - "s390x" + +--- +# Source: istio/charts/security/templates/deployment.yaml +# istio CA watching all namespaces +apiVersion: apps/v1 +kind: Deployment +metadata: + name: istio-citadel + namespace: istio-system + labels: + app: security + chart: security + heritage: Tiller + release: istio + istio: citadel +spec: + replicas: 1 + selector: + matchLabels: + istio: citadel + strategy: + rollingUpdate: + maxSurge: 100% + maxUnavailable: 25% + template: + metadata: + labels: + app: security + chart: security + heritage: Tiller + release: istio + istio: citadel + annotations: + sidecar.istio.io/inject: "false" + spec: + serviceAccountName: istio-citadel-service-account + containers: + - name: citadel + image: "docker.io/istio/citadel:1.5.0" + imagePullPolicy: IfNotPresent + args: + - --append-dns-names=true + - --grpc-port=8060 + - --citadel-storage-namespace=istio-system + - --custom-dns-names=istio-pilot-service-account.istio-system:istio-pilot.istio-system + - --monitoring-port=15014 + - --self-signed-ca=true + - --workload-cert-ttl=2160h + env: + - name: CITADEL_ENABLE_NAMESPACES_BY_DEFAULT + value: "true" + resources: + requests: + cpu: 10m + + affinity: + nodeAffinity: + requiredDuringSchedulingIgnoredDuringExecution: + nodeSelectorTerms: + - matchExpressions: + - key: beta.kubernetes.io/arch + operator: In + values: + - "amd64" + - "ppc64le" + - "s390x" + preferredDuringSchedulingIgnoredDuringExecution: + - weight: 2 + preference: + matchExpressions: + - key: beta.kubernetes.io/arch + operator: In + values: + - "amd64" + - weight: 2 + preference: + matchExpressions: + - key: beta.kubernetes.io/arch + operator: In + values: + - "ppc64le" + - weight: 2 + preference: + matchExpressions: + - key: beta.kubernetes.io/arch + operator: In + values: + - "s390x" + +--- +# Source: istio/charts/sidecarInjectorWebhook/templates/deployment.yaml +apiVersion: apps/v1 +kind: Deployment +metadata: + name: istio-sidecar-injector + namespace: istio-system + labels: + app: sidecarInjectorWebhook + chart: sidecarInjectorWebhook + heritage: Tiller + release: istio + istio: sidecar-injector +spec: + replicas: 1 + selector: + matchLabels: + istio: sidecar-injector + strategy: + rollingUpdate: + maxSurge: 100% + maxUnavailable: 25% + template: + metadata: + labels: + app: sidecarInjectorWebhook + chart: sidecarInjectorWebhook + heritage: Tiller + release: istio + istio: sidecar-injector + annotations: + sidecar.istio.io/inject: "false" + spec: + serviceAccountName: istio-sidecar-injector-service-account + containers: + - name: sidecar-injector-webhook + image: "docker.io/istio/sidecar_injector:1.5.0" + imagePullPolicy: IfNotPresent + args: + - --caCertFile=/etc/istio/certs/root-cert.pem + - --tlsCertFile=/etc/istio/certs/cert-chain.pem + - --tlsKeyFile=/etc/istio/certs/key.pem + - --injectConfig=/etc/istio/inject/config + - --meshConfig=/etc/istio/config/mesh + - --healthCheckInterval=2s + - --healthCheckFile=/tmp/health + - --reconcileWebhookConfig=true + volumeMounts: + - name: config-volume + mountPath: /etc/istio/config + readOnly: true + - name: certs + mountPath: /etc/istio/certs + readOnly: true + - name: inject-config + mountPath: /etc/istio/inject + readOnly: true + livenessProbe: + exec: + command: + - /usr/local/bin/sidecar-injector + - probe + - --probe-path=/tmp/health + - --interval=4s + initialDelaySeconds: 4 + periodSeconds: 4 + readinessProbe: + exec: + command: + - /usr/local/bin/sidecar-injector + - probe + - --probe-path=/tmp/health + - --interval=4s + initialDelaySeconds: 4 + periodSeconds: 4 + resources: + requests: + cpu: 10m + + volumes: + - name: config-volume + configMap: + name: istio + - name: certs + secret: + secretName: istio.istio-sidecar-injector-service-account + - name: inject-config + configMap: + name: istio-sidecar-injector + items: + - key: config + path: config + - key: values + path: values + affinity: + nodeAffinity: + requiredDuringSchedulingIgnoredDuringExecution: + nodeSelectorTerms: + - matchExpressions: + - key: beta.kubernetes.io/arch + operator: In + values: + - "amd64" + - "ppc64le" + - "s390x" + preferredDuringSchedulingIgnoredDuringExecution: + - weight: 2 + preference: + matchExpressions: + - key: beta.kubernetes.io/arch + operator: In + values: + - "amd64" + - weight: 2 + preference: + matchExpressions: + - key: beta.kubernetes.io/arch + operator: In + values: + - "ppc64le" + - weight: 2 + preference: + matchExpressions: + - key: beta.kubernetes.io/arch + operator: In + values: + - "s390x" + +--- +# Source: istio/charts/tracing/templates/deployment-jaeger.yaml + + +apiVersion: apps/v1 +kind: Deployment +metadata: + name: istio-tracing + namespace: istio-system + labels: + app: jaeger + chart: tracing + heritage: Tiller + release: istio +spec: + selector: + matchLabels: + app: jaeger + template: + metadata: + labels: + app: jaeger + chart: tracing + heritage: Tiller + release: istio + annotations: + sidecar.istio.io/inject: "false" + prometheus.io/scrape: "true" + prometheus.io/port: "14269" + spec: + containers: + - name: jaeger + image: "docker.io/jaegertracing/all-in-one:1.16" + imagePullPolicy: IfNotPresent + ports: + - containerPort: 9411 + - containerPort: 16686 + - containerPort: 14250 + - containerPort: 14267 + - containerPort: 14268 + - containerPort: 14269 + - containerPort: 5775 + protocol: UDP + - containerPort: 6831 + protocol: UDP + - containerPort: 6832 + protocol: UDP + env: + - name: POD_NAMESPACE + valueFrom: + fieldRef: + apiVersion: v1 + fieldPath: metadata.namespace + - name: BADGER_EPHEMERAL + value: "false" + - name: SPAN_STORAGE_TYPE + value: "badger" + - name: BADGER_DIRECTORY_VALUE + value: "/badger/data" + - name: BADGER_DIRECTORY_KEY + value: "/badger/key" + - name: COLLECTOR_ZIPKIN_HTTP_PORT + value: "9411" + - name: MEMORY_MAX_TRACES + value: "50000" + - name: QUERY_BASE_PATH + value: /jaeger + livenessProbe: + httpGet: + path: / + port: 14269 + readinessProbe: + httpGet: + path: / + port: 14269 + volumeMounts: + - name: data + mountPath: /badger + resources: + requests: + cpu: 10m + + affinity: + nodeAffinity: + requiredDuringSchedulingIgnoredDuringExecution: + nodeSelectorTerms: + - matchExpressions: + - key: beta.kubernetes.io/arch + operator: In + values: + - "amd64" + - "ppc64le" + - "s390x" + preferredDuringSchedulingIgnoredDuringExecution: + - weight: 2 + preference: + matchExpressions: + - key: beta.kubernetes.io/arch + operator: In + values: + - "amd64" + - weight: 2 + preference: + matchExpressions: + - key: beta.kubernetes.io/arch + operator: In + values: + - "ppc64le" + - weight: 2 + preference: + matchExpressions: + - key: beta.kubernetes.io/arch + operator: In + values: + - "s390x" + volumes: + - name: data + emptyDir: {} + + +--- +# Source: istio/charts/tracing/templates/service-jaeger.yaml + + +apiVersion: v1 +kind: List +metadata: + name: jaeger-services + namespace: istio-system + labels: + app: jaeger + chart: tracing + heritage: Tiller + release: istio +items: +- apiVersion: v1 + kind: Service + metadata: + name: jaeger-query + namespace: istio-system + annotations: + labels: + app: jaeger + jaeger-infra: jaeger-service + chart: tracing + heritage: Tiller + release: istio + spec: + ports: + - name: query-http + port: 16686 + protocol: TCP + targetPort: 16686 + selector: + app: jaeger +- apiVersion: v1 + kind: Service + metadata: + name: jaeger-collector + namespace: istio-system + labels: + app: jaeger + jaeger-infra: collector-service + chart: tracing + heritage: Tiller + release: istio + spec: + ports: + - name: jaeger-collector-tchannel + port: 14267 + protocol: TCP + targetPort: 14267 + - name: jaeger-collector-http + port: 14268 + targetPort: 14268 + protocol: TCP + - name: jaeger-collector-grpc + port: 14250 + targetPort: 14250 + protocol: TCP + selector: + app: jaeger + type: ClusterIP +- apiVersion: v1 + kind: Service + metadata: + name: jaeger-collector-headless + namespace: istio-system + labels: + app: jaeger + jaeger-infra: collector-service + chart: tracing + heritage: Tiller + release: istio + spec: + ports: + - name: jaeger-collector-grpc + port: 14250 + targetPort: 14250 + protocol: TCP + selector: + app: jaeger + clusterIP: None +- apiVersion: v1 + kind: Service + metadata: + name: jaeger-agent + namespace: istio-system + labels: + app: jaeger + jaeger-infra: agent-service + chart: tracing + heritage: Tiller + release: istio + spec: + ports: + - name: agent-zipkin-thrift + port: 5775 + protocol: UDP + targetPort: 5775 + - name: agent-compact + port: 6831 + protocol: UDP + targetPort: 6831 + - name: agent-binary + port: 6832 + protocol: UDP + targetPort: 6832 + clusterIP: None + selector: + app: jaeger + + + +--- +# Source: istio/charts/tracing/templates/service.yaml +apiVersion: v1 +kind: List +metadata: + name: tracing-services + namespace: istio-system + labels: + app: jaeger + chart: tracing + heritage: Tiller + release: istio +items: +- apiVersion: v1 + kind: Service + metadata: + name: zipkin + namespace: istio-system + labels: + app: jaeger + chart: tracing + heritage: Tiller + release: istio + spec: + ports: + - port: 9411 + targetPort: 9411 + protocol: TCP + name: http + selector: + app: jaeger +- apiVersion: v1 + kind: Service + metadata: + name: tracing + namespace: istio-system + annotations: + labels: + app: jaeger + chart: tracing + heritage: Tiller + release: istio + spec: + type: ClusterIP + ports: + - name: http-query + port: 80 + protocol: TCP + + targetPort: 16686 + + selector: + app: jaeger + +--- +# Source: istio/charts/sidecarInjectorWebhook/templates/mutatingwebhook.yaml + +apiVersion: admissionregistration.k8s.io/v1beta1 +kind: MutatingWebhookConfiguration +metadata: + name: istio-sidecar-injector + labels: + app: sidecarInjectorWebhook + chart: sidecarInjectorWebhook + heritage: Tiller + release: istio +webhooks: + - name: sidecar-injector.istio.io + clientConfig: + service: + name: istio-sidecar-injector + namespace: istio-system + path: "/inject" + caBundle: "" + rules: + - operations: [ "CREATE" ] + apiGroups: [""] + apiVersions: ["v1"] + resources: ["pods"] + failurePolicy: Fail + namespaceSelector: + matchLabels: + istio-injection: enabled + +--- +# Source: istio/charts/galley/templates/validatingwebhookconfiguration.yaml.tpl + + + +--- +# Source: istio/charts/gateways/templates/autoscale.yaml + + +--- +# Source: istio/charts/gateways/templates/preconfigured.yaml + + +--- +# Source: istio/charts/grafana/templates/grafana-ports-mtls.yaml + + +--- +# Source: istio/charts/grafana/templates/ingress.yaml + +--- +# Source: istio/charts/grafana/templates/pvc.yaml + + +--- +# Source: istio/charts/grafana/templates/tests/test-grafana-connection.yaml + + +--- +# Source: istio/charts/kiali/templates/ingress.yaml + +--- +# Source: istio/charts/kiali/templates/tests/test-kiali-connection.yaml + + +--- +# Source: istio/charts/mixer/templates/autoscale.yaml + + +--- +# Source: istio/charts/pilot/templates/autoscale.yaml + + +--- +# Source: istio/charts/pilot/templates/configmap.yaml + + +--- +# Source: istio/charts/pilot/templates/meshexpansion.yaml + + + +--- +# Source: istio/charts/prometheus/templates/ingress.yaml + +--- +# Source: istio/charts/prometheus/templates/tests/test-prometheus-connection.yaml + + +--- +# Source: istio/charts/security/templates/enable-mesh-mtls.yaml + + +--- +# Source: istio/charts/security/templates/enable-mesh-permissive.yaml + + +--- +# Source: istio/charts/security/templates/meshexpansion.yaml + + +--- +# Source: istio/charts/security/templates/tests/test-citadel-connection.yaml + + +--- +# Source: istio/charts/tracing/templates/deployment-zipkin.yaml + + +--- +# Source: istio/charts/tracing/templates/ingress.yaml + +--- +# Source: istio/charts/tracing/templates/pvc.yaml + + +--- +# Source: istio/charts/tracing/templates/tests/test-tracing-connection.yaml + + +--- +# Source: istio/templates/endpoints.yaml + + +--- +# Source: istio/templates/install-custom-resources.sh.tpl + + +--- +# Source: istio/templates/service.yaml + + +--- +# Source: istio/charts/galley/templates/validatingwebhookconfiguration.yaml + +apiVersion: admissionregistration.k8s.io/v1beta1 +kind: ValidatingWebhookConfiguration +metadata: + name: istio-galley + labels: + app: galley + chart: galley + heritage: Tiller + release: istio + istio: galley +webhooks: + - name: pilot.validation.istio.io + clientConfig: + service: + name: istio-galley + namespace: istio-system + path: "/admitpilot" + caBundle: "" + rules: + - operations: + - CREATE + - UPDATE + apiGroups: + - config.istio.io + apiVersions: + - v1alpha2 + resources: + - httpapispecs + - httpapispecbindings + - quotaspecs + - quotaspecbindings + - operations: + - CREATE + - UPDATE + apiGroups: + - rbac.istio.io + apiVersions: + - "*" + resources: + - "*" + - operations: + - CREATE + - UPDATE + apiGroups: + - security.istio.io + apiVersions: + - "*" + resources: + - "*" + - operations: + - CREATE + - UPDATE + apiGroups: + - authentication.istio.io + apiVersions: + - "*" + resources: + - "*" + - operations: + - CREATE + - UPDATE + apiGroups: + - networking.istio.io + apiVersions: + - "*" + resources: + - destinationrules + - envoyfilters + - gateways + - serviceentries + - sidecars + - virtualservices + # Fail open until the validation webhook is ready. The webhook controller + # will update this to `Fail` and patch in the `caBundle` when the webhook + # endpoint is ready. + failurePolicy: Ignore + sideEffects: None + - name: mixer.validation.istio.io + clientConfig: + service: + name: istio-galley + namespace: istio-system + path: "/admitmixer" + caBundle: "" + rules: + - operations: + - CREATE + - UPDATE + apiGroups: + - config.istio.io + apiVersions: + - v1alpha2 + resources: + - rules + - attributemanifests + - adapters + - handlers + - instances + - templates + # Fail open until the validation webhook is ready. The webhook controller + # will update this to `Fail` and patch in the `caBundle` when the webhook + # endpoint is ready. + failurePolicy: Ignore + sideEffects: None +--- +# Source: istio/charts/mixer/templates/config.yaml + +apiVersion: "config.istio.io/v1alpha2" +kind: attributemanifest +metadata: + name: istioproxy + namespace: istio-system + labels: + app: mixer + chart: mixer + heritage: Tiller + release: istio +spec: + attributes: + origin.ip: + valueType: IP_ADDRESS + origin.uid: + valueType: STRING + origin.user: + valueType: STRING + request.headers: + valueType: STRING_MAP + request.id: + valueType: STRING + request.host: + valueType: STRING + request.method: + valueType: STRING + request.path: + valueType: STRING + request.url_path: + valueType: STRING + request.query_params: + valueType: STRING_MAP + request.reason: + valueType: STRING + request.referer: + valueType: STRING + request.scheme: + valueType: STRING + request.total_size: + valueType: INT64 + request.size: + valueType: INT64 + request.time: + valueType: TIMESTAMP + request.useragent: + valueType: STRING + response.code: + valueType: INT64 + response.duration: + valueType: DURATION + response.headers: + valueType: STRING_MAP + response.total_size: + valueType: INT64 + response.size: + valueType: INT64 + response.time: + valueType: TIMESTAMP + response.grpc_status: + valueType: STRING + response.grpc_message: + valueType: STRING + source.uid: + valueType: STRING + source.user: # DEPRECATED + valueType: STRING + source.principal: + valueType: STRING + destination.uid: + valueType: STRING + destination.principal: + valueType: STRING + destination.port: + valueType: INT64 + connection.event: + valueType: STRING + connection.id: + valueType: STRING + connection.received.bytes: + valueType: INT64 + connection.received.bytes_total: + valueType: INT64 + connection.sent.bytes: + valueType: INT64 + connection.sent.bytes_total: + valueType: INT64 + connection.duration: + valueType: DURATION + connection.mtls: + valueType: BOOL + connection.requested_server_name: + valueType: STRING + context.protocol: + valueType: STRING + context.proxy_error_code: + valueType: STRING + context.timestamp: + valueType: TIMESTAMP + context.time: + valueType: TIMESTAMP + # Deprecated, kept for compatibility + context.reporter.local: + valueType: BOOL + context.reporter.kind: + valueType: STRING + context.reporter.uid: + valueType: STRING + api.service: + valueType: STRING + api.version: + valueType: STRING + api.operation: + valueType: STRING + api.protocol: + valueType: STRING + request.auth.principal: + valueType: STRING + request.auth.audiences: + valueType: STRING + request.auth.presenter: + valueType: STRING + request.auth.claims: + valueType: STRING_MAP + request.auth.raw_claims: + valueType: STRING + request.api_key: + valueType: STRING + rbac.permissive.response_code: + valueType: STRING + rbac.permissive.effective_policy_id: + valueType: STRING + check.error_code: + valueType: INT64 + check.error_message: + valueType: STRING + check.cache_hit: + valueType: BOOL + quota.cache_hit: + valueType: BOOL + context.proxy_version: + valueType: STRING + +--- +apiVersion: "config.istio.io/v1alpha2" +kind: attributemanifest +metadata: + name: kubernetes + namespace: istio-system + labels: + app: mixer + chart: mixer + heritage: Tiller + release: istio +spec: + attributes: + source.ip: + valueType: IP_ADDRESS + source.labels: + valueType: STRING_MAP + source.metadata: + valueType: STRING_MAP + source.name: + valueType: STRING + source.namespace: + valueType: STRING + source.owner: + valueType: STRING + source.serviceAccount: + valueType: STRING + source.services: + valueType: STRING + source.workload.uid: + valueType: STRING + source.workload.name: + valueType: STRING + source.workload.namespace: + valueType: STRING + destination.ip: + valueType: IP_ADDRESS + destination.labels: + valueType: STRING_MAP + destination.metadata: + valueType: STRING_MAP + destination.owner: + valueType: STRING + destination.name: + valueType: STRING + destination.container.name: + valueType: STRING + destination.namespace: + valueType: STRING + destination.service.uid: + valueType: STRING + destination.service.name: + valueType: STRING + destination.service.namespace: + valueType: STRING + destination.service.host: + valueType: STRING + destination.serviceAccount: + valueType: STRING + destination.workload.uid: + valueType: STRING + destination.workload.name: + valueType: STRING + destination.workload.namespace: + valueType: STRING +--- +apiVersion: "config.istio.io/v1alpha2" +kind: handler +metadata: + name: stdio + namespace: istio-system + labels: + app: mixer + chart: mixer + heritage: Tiller + release: istio +spec: + compiledAdapter: stdio + params: + outputAsJson: true +--- +apiVersion: "config.istio.io/v1alpha2" +kind: instance +metadata: + name: accesslog + namespace: istio-system + labels: + app: mixer + chart: mixer + heritage: Tiller + release: istio +spec: + compiledTemplate: logentry + params: + severity: '"Info"' + timestamp: request.time + variables: + sourceIp: source.ip | ip("0.0.0.0") + sourceApp: source.labels["app"] | "" + sourcePrincipal: source.principal | "" + sourceName: source.name | "" + sourceWorkload: source.workload.name | "" + sourceNamespace: source.namespace | "" + sourceOwner: source.owner | "" + destinationApp: destination.labels["app"] | "" + destinationIp: destination.ip | ip("0.0.0.0") + destinationServiceHost: destination.service.host | request.host | "" + destinationWorkload: destination.workload.name | "" + destinationName: destination.name | "" + destinationNamespace: destination.namespace | "" + destinationOwner: destination.owner | "" + destinationPrincipal: destination.principal | "" + apiClaims: request.auth.raw_claims | "" + apiKey: request.api_key | request.headers["x-api-key"] | "" + protocol: api.protocol | context.protocol | "http" + method: request.method | "" + url: request.path | "" + responseCode: response.code | 0 + responseFlags: context.proxy_error_code | "" + responseSize: response.size | 0 + permissiveResponseCode: rbac.permissive.response_code | "none" + permissiveResponsePolicyID: rbac.permissive.effective_policy_id | "none" + requestSize: request.size | 0 + requestId: request.headers["x-request-id"] | "" + clientTraceId: request.headers["x-client-trace-id"] | "" + latency: response.duration | "0ms" + connection_security_policy: conditional((context.reporter.kind | "inbound") == "outbound", "unknown", conditional(connection.mtls | false, "mutual_tls", "none")) + requestedServerName: connection.requested_server_name | "" + userAgent: request.useragent | "" + responseTimestamp: response.time + receivedBytes: request.total_size | 0 + sentBytes: response.total_size | 0 + referer: request.referer | "" + httpAuthority: request.headers[":authority"] | request.host | "" + xForwardedFor: request.headers["x-forwarded-for"] | "0.0.0.0" + reporter: conditional((context.reporter.kind | "inbound") == "outbound", "source", "destination") + grpcStatus: response.grpc_status | "" + grpcMessage: response.grpc_message | "" + monitored_resource_type: '"global"' +--- +apiVersion: "config.istio.io/v1alpha2" +kind: instance +metadata: + name: tcpaccesslog + namespace: istio-system + labels: + app: mixer + chart: mixer + heritage: Tiller + release: istio +spec: + compiledTemplate: logentry + params: + severity: '"Info"' + timestamp: context.time | timestamp("2017-01-01T00:00:00Z") + variables: + connectionEvent: connection.event | "" + sourceIp: source.ip | ip("0.0.0.0") + sourceApp: source.labels["app"] | "" + sourcePrincipal: source.principal | "" + sourceName: source.name | "" + sourceWorkload: source.workload.name | "" + sourceNamespace: source.namespace | "" + sourceOwner: source.owner | "" + destinationApp: destination.labels["app"] | "" + destinationIp: destination.ip | ip("0.0.0.0") + destinationServiceHost: destination.service.host | "" + destinationWorkload: destination.workload.name | "" + destinationName: destination.name | "" + destinationNamespace: destination.namespace | "" + destinationOwner: destination.owner | "" + destinationPrincipal: destination.principal | "" + protocol: context.protocol | "tcp" + connectionDuration: connection.duration | "0ms" + connection_security_policy: conditional((context.reporter.kind | "inbound") == "outbound", "unknown", conditional(connection.mtls | false, "mutual_tls", "none")) + requestedServerName: connection.requested_server_name | "" + receivedBytes: connection.received.bytes | 0 + sentBytes: connection.sent.bytes | 0 + totalReceivedBytes: connection.received.bytes_total | 0 + totalSentBytes: connection.sent.bytes_total | 0 + reporter: conditional((context.reporter.kind | "inbound") == "outbound", "source", "destination") + responseFlags: context.proxy_error_code | "" + monitored_resource_type: '"global"' +--- +apiVersion: "config.istio.io/v1alpha2" +kind: rule +metadata: + name: stdio + namespace: istio-system + labels: + app: mixer + chart: mixer + heritage: Tiller + release: istio +spec: + match: context.protocol == "http" || context.protocol == "grpc" + actions: + - handler: stdio + instances: + - accesslog +--- +apiVersion: "config.istio.io/v1alpha2" +kind: rule +metadata: + name: stdiotcp + namespace: istio-system + labels: + app: mixer + chart: mixer + heritage: Tiller + release: istio +spec: + match: context.protocol == "tcp" + actions: + - handler: stdio + instances: + - tcpaccesslog +--- +apiVersion: "config.istio.io/v1alpha2" +kind: instance +metadata: + name: requestcount + namespace: istio-system + labels: + app: mixer + chart: mixer + heritage: Tiller + release: istio +spec: + compiledTemplate: metric + params: + value: "1" + dimensions: + reporter: conditional((context.reporter.kind | "inbound") == "outbound", "source", "destination") + source_workload: source.workload.name | "unknown" + source_workload_namespace: source.workload.namespace | "unknown" + source_principal: source.principal | "unknown" + source_app: source.labels["app"] | "unknown" + source_version: source.labels["version"] | "unknown" + destination_workload: destination.workload.name | "unknown" + destination_workload_namespace: destination.workload.namespace | "unknown" + destination_principal: destination.principal | "unknown" + destination_app: destination.labels["app"] | "unknown" + destination_version: destination.labels["version"] | "unknown" + destination_service: destination.service.host | conditional((destination.service.name | "unknown") == "unknown", "unknown", request.host) + destination_service_name: destination.service.name | "unknown" + destination_service_namespace: destination.service.namespace | "unknown" + request_protocol: api.protocol | context.protocol | "unknown" + response_code: response.code | 200 + grpc_response_status: response.grpc_status | "" + response_flags: context.proxy_error_code | "-" + connection_security_policy: conditional((context.reporter.kind | "inbound") == "outbound", "unknown", conditional(connection.mtls | false, "mutual_tls", "none")) + monitored_resource_type: '"UNSPECIFIED"' +--- +apiVersion: "config.istio.io/v1alpha2" +kind: instance +metadata: + name: requestduration + namespace: istio-system + labels: + app: mixer + chart: mixer + heritage: Tiller + release: istio +spec: + compiledTemplate: metric + params: + value: response.duration | "0ms" + dimensions: + reporter: conditional((context.reporter.kind | "inbound") == "outbound", "source", "destination") + source_workload: source.workload.name | "unknown" + source_workload_namespace: source.workload.namespace | "unknown" + source_principal: source.principal | "unknown" + source_app: source.labels["app"] | "unknown" + source_version: source.labels["version"] | "unknown" + destination_workload: destination.workload.name | "unknown" + destination_workload_namespace: destination.workload.namespace | "unknown" + destination_principal: destination.principal | "unknown" + destination_app: destination.labels["app"] | "unknown" + destination_version: destination.labels["version"] | "unknown" + destination_service: destination.service.host | conditional((destination.service.name | "unknown") == "unknown", "unknown", request.host) + destination_service_name: destination.service.name | "unknown" + destination_service_namespace: destination.service.namespace | "unknown" + request_protocol: api.protocol | context.protocol | "unknown" + response_code: response.code | 200 + grpc_response_status: response.grpc_status | "" + response_flags: context.proxy_error_code | "-" + connection_security_policy: conditional((context.reporter.kind | "inbound") == "outbound", "unknown", conditional(connection.mtls | false, "mutual_tls", "none")) + monitored_resource_type: '"UNSPECIFIED"' +--- +apiVersion: "config.istio.io/v1alpha2" +kind: instance +metadata: + name: requestsize + namespace: istio-system + labels: + app: mixer + chart: mixer + heritage: Tiller + release: istio +spec: + compiledTemplate: metric + params: + value: request.size | 0 + dimensions: + reporter: conditional((context.reporter.kind | "inbound") == "outbound", "source", "destination") + source_workload: source.workload.name | "unknown" + source_workload_namespace: source.workload.namespace | "unknown" + source_principal: source.principal | "unknown" + source_app: source.labels["app"] | "unknown" + source_version: source.labels["version"] | "unknown" + destination_workload: destination.workload.name | "unknown" + destination_workload_namespace: destination.workload.namespace | "unknown" + destination_principal: destination.principal | "unknown" + destination_app: destination.labels["app"] | "unknown" + destination_version: destination.labels["version"] | "unknown" + destination_service: destination.service.host | conditional((destination.service.name | "unknown") == "unknown", "unknown", request.host) + destination_service_name: destination.service.name | "unknown" + destination_service_namespace: destination.service.namespace | "unknown" + request_protocol: api.protocol | context.protocol | "unknown" + response_code: response.code | 200 + grpc_response_status: response.grpc_status | "" + response_flags: context.proxy_error_code | "-" + connection_security_policy: conditional((context.reporter.kind | "inbound") == "outbound", "unknown", conditional(connection.mtls | false, "mutual_tls", "none")) + monitored_resource_type: '"UNSPECIFIED"' +--- +apiVersion: "config.istio.io/v1alpha2" +kind: instance +metadata: + name: responsesize + namespace: istio-system + labels: + app: mixer + chart: mixer + heritage: Tiller + release: istio +spec: + compiledTemplate: metric + params: + value: response.size | 0 + dimensions: + reporter: conditional((context.reporter.kind | "inbound") == "outbound", "source", "destination") + source_workload: source.workload.name | "unknown" + source_workload_namespace: source.workload.namespace | "unknown" + source_principal: source.principal | "unknown" + source_app: source.labels["app"] | "unknown" + source_version: source.labels["version"] | "unknown" + destination_workload: destination.workload.name | "unknown" + destination_workload_namespace: destination.workload.namespace | "unknown" + destination_principal: destination.principal | "unknown" + destination_app: destination.labels["app"] | "unknown" + destination_version: destination.labels["version"] | "unknown" + destination_service: destination.service.host | conditional((destination.service.name | "unknown") == "unknown", "unknown", request.host) + destination_service_name: destination.service.name | "unknown" + destination_service_namespace: destination.service.namespace | "unknown" + request_protocol: api.protocol | context.protocol | "unknown" + response_code: response.code | 200 + grpc_response_status: response.grpc_status | "" + response_flags: context.proxy_error_code | "-" + connection_security_policy: conditional((context.reporter.kind | "inbound") == "outbound", "unknown", conditional(connection.mtls | false, "mutual_tls", "none")) + monitored_resource_type: '"UNSPECIFIED"' +--- +apiVersion: "config.istio.io/v1alpha2" +kind: instance +metadata: + name: tcpbytesent + namespace: istio-system + labels: + app: mixer + chart: mixer + heritage: Tiller + release: istio +spec: + compiledTemplate: metric + params: + value: connection.sent.bytes | 0 + dimensions: + reporter: conditional((context.reporter.kind | "inbound") == "outbound", "source", "destination") + source_workload: source.workload.name | "unknown" + source_workload_namespace: source.workload.namespace | "unknown" + source_principal: source.principal | "unknown" + source_app: source.labels["app"] | "unknown" + source_version: source.labels["version"] | "unknown" + destination_workload: destination.workload.name | "unknown" + destination_workload_namespace: destination.workload.namespace | "unknown" + destination_principal: destination.principal | "unknown" + destination_app: destination.labels["app"] | "unknown" + destination_version: destination.labels["version"] | "unknown" + destination_service: destination.service.host | "unknown" + destination_service_name: destination.service.name | "unknown" + destination_service_namespace: destination.service.namespace | "unknown" + connection_security_policy: conditional((context.reporter.kind | "inbound") == "outbound", "unknown", conditional(connection.mtls | false, "mutual_tls", "none")) + response_flags: context.proxy_error_code | "-" + monitored_resource_type: '"UNSPECIFIED"' +--- +apiVersion: "config.istio.io/v1alpha2" +kind: instance +metadata: + name: tcpbytereceived + namespace: istio-system + labels: + app: mixer + chart: mixer + heritage: Tiller + release: istio +spec: + compiledTemplate: metric + params: + value: connection.received.bytes | 0 + dimensions: + reporter: conditional((context.reporter.kind | "inbound") == "outbound", "source", "destination") + source_workload: source.workload.name | "unknown" + source_workload_namespace: source.workload.namespace | "unknown" + source_principal: source.principal | "unknown" + source_app: source.labels["app"] | "unknown" + source_version: source.labels["version"] | "unknown" + destination_workload: destination.workload.name | "unknown" + destination_workload_namespace: destination.workload.namespace | "unknown" + destination_principal: destination.principal | "unknown" + destination_app: destination.labels["app"] | "unknown" + destination_version: destination.labels["version"] | "unknown" + destination_service: destination.service.host | "unknown" + destination_service_name: destination.service.name | "unknown" + destination_service_namespace: destination.service.namespace | "unknown" + connection_security_policy: conditional((context.reporter.kind | "inbound") == "outbound", "unknown", conditional(connection.mtls | false, "mutual_tls", "none")) + response_flags: context.proxy_error_code | "-" + monitored_resource_type: '"UNSPECIFIED"' +--- +apiVersion: "config.istio.io/v1alpha2" +kind: instance +metadata: + name: tcpconnectionsopened + namespace: istio-system + labels: + app: mixer + chart: mixer + heritage: Tiller + release: istio +spec: + compiledTemplate: metric + params: + value: "1" + dimensions: + reporter: conditional((context.reporter.kind | "inbound") == "outbound", "source", "destination") + source_workload: source.workload.name | "unknown" + source_workload_namespace: source.workload.namespace | "unknown" + source_principal: source.principal | "unknown" + source_app: source.labels["app"] | "unknown" + source_version: source.labels["version"] | "unknown" + destination_workload: destination.workload.name | "unknown" + destination_workload_namespace: destination.workload.namespace | "unknown" + destination_principal: destination.principal | "unknown" + destination_app: destination.labels["app"] | "unknown" + destination_version: destination.labels["version"] | "unknown" + destination_service: destination.service.host | "unknown" + destination_service_name: destination.service.name | "unknown" + destination_service_namespace: destination.service.namespace | "unknown" + connection_security_policy: conditional((context.reporter.kind | "inbound") == "outbound", "unknown", conditional(connection.mtls | false, "mutual_tls", "none")) + response_flags: context.proxy_error_code | "-" + monitored_resource_type: '"UNSPECIFIED"' +--- +apiVersion: "config.istio.io/v1alpha2" +kind: instance +metadata: + name: tcpconnectionsclosed + namespace: istio-system + labels: + app: mixer + chart: mixer + heritage: Tiller + release: istio +spec: + compiledTemplate: metric + params: + value: "1" + dimensions: + reporter: conditional((context.reporter.kind | "inbound") == "outbound", "source", "destination") + source_workload: source.workload.name | "unknown" + source_workload_namespace: source.workload.namespace | "unknown" + source_principal: source.principal | "unknown" + source_app: source.labels["app"] | "unknown" + source_version: source.labels["version"] | "unknown" + destination_workload: destination.workload.name | "unknown" + destination_workload_namespace: destination.workload.namespace | "unknown" + destination_principal: destination.principal | "unknown" + destination_app: destination.labels["app"] | "unknown" + destination_version: destination.labels["version"] | "unknown" + destination_service: destination.service.host | "unknown" + destination_service_name: destination.service.name | "unknown" + destination_service_namespace: destination.service.namespace | "unknown" + connection_security_policy: conditional((context.reporter.kind | "inbound") == "outbound", "unknown", conditional(connection.mtls | false, "mutual_tls", "none")) + response_flags: context.proxy_error_code | "-" + monitored_resource_type: '"UNSPECIFIED"' +--- +apiVersion: "config.istio.io/v1alpha2" +kind: handler +metadata: + name: prometheus + namespace: istio-system + labels: + app: mixer + chart: mixer + heritage: Tiller + release: istio +spec: + compiledAdapter: prometheus + params: + metricsExpirationPolicy: + metricsExpiryDuration: "10m" + metrics: + - name: requests_total + instance_name: requestcount.instance.istio-system + kind: COUNTER + label_names: + - reporter + - source_app + - source_principal + - source_workload + - source_workload_namespace + - source_version + - destination_app + - destination_principal + - destination_workload + - destination_workload_namespace + - destination_version + - destination_service + - destination_service_name + - destination_service_namespace + - request_protocol + - response_code + - grpc_response_status + - response_flags + - connection_security_policy + - name: request_duration_seconds + instance_name: requestduration.instance.istio-system + kind: DISTRIBUTION + label_names: + - reporter + - source_app + - source_principal + - source_workload + - source_workload_namespace + - source_version + - destination_app + - destination_principal + - destination_workload + - destination_workload_namespace + - destination_version + - destination_service + - destination_service_name + - destination_service_namespace + - request_protocol + - response_code + - grpc_response_status + - response_flags + - connection_security_policy + buckets: + explicit_buckets: + bounds: [0.005, 0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 1, 2.5, 5, 10] + - name: request_bytes + instance_name: requestsize.instance.istio-system + kind: DISTRIBUTION + label_names: + - reporter + - source_app + - source_principal + - source_workload + - source_workload_namespace + - source_version + - destination_app + - destination_principal + - destination_workload + - destination_workload_namespace + - destination_version + - destination_service + - destination_service_name + - destination_service_namespace + - request_protocol + - response_code + - grpc_response_status + - response_flags + - connection_security_policy + buckets: + exponentialBuckets: + numFiniteBuckets: 8 + scale: 1 + growthFactor: 10 + - name: response_bytes + instance_name: responsesize.instance.istio-system + kind: DISTRIBUTION + label_names: + - reporter + - source_app + - source_principal + - source_workload + - source_workload_namespace + - source_version + - destination_app + - destination_principal + - destination_workload + - destination_workload_namespace + - destination_version + - destination_service + - destination_service_name + - destination_service_namespace + - request_protocol + - response_code + - grpc_response_status + - response_flags + - connection_security_policy + buckets: + exponentialBuckets: + numFiniteBuckets: 8 + scale: 1 + growthFactor: 10 + - name: tcp_sent_bytes_total + instance_name: tcpbytesent.instance.istio-system + kind: COUNTER + label_names: + - reporter + - source_app + - source_principal + - source_workload + - source_workload_namespace + - source_version + - destination_app + - destination_principal + - destination_workload + - destination_workload_namespace + - destination_version + - destination_service + - destination_service_name + - destination_service_namespace + - connection_security_policy + - response_flags + - name: tcp_received_bytes_total + instance_name: tcpbytereceived.instance.istio-system + kind: COUNTER + label_names: + - reporter + - source_app + - source_principal + - source_workload + - source_workload_namespace + - source_version + - destination_app + - destination_principal + - destination_workload + - destination_workload_namespace + - destination_version + - destination_service + - destination_service_name + - destination_service_namespace + - connection_security_policy + - response_flags + - name: tcp_connections_opened_total + instance_name: tcpconnectionsopened.instance.istio-system + kind: COUNTER + label_names: + - reporter + - source_app + - source_principal + - source_workload + - source_workload_namespace + - source_version + - destination_app + - destination_principal + - destination_workload + - destination_workload_namespace + - destination_version + - destination_service + - destination_service_name + - destination_service_namespace + - connection_security_policy + - response_flags + - name: tcp_connections_closed_total + instance_name: tcpconnectionsclosed.instance.istio-system + kind: COUNTER + label_names: + - reporter + - source_app + - source_principal + - source_workload + - source_workload_namespace + - source_version + - destination_app + - destination_principal + - destination_workload + - destination_workload_namespace + - destination_version + - destination_service + - destination_service_name + - destination_service_namespace + - connection_security_policy + - response_flags +--- +apiVersion: "config.istio.io/v1alpha2" +kind: rule +metadata: + name: promhttp + namespace: istio-system + labels: + app: mixer + chart: mixer + heritage: Tiller + release: istio +spec: + match: (context.protocol == "http" || context.protocol == "grpc") && (match((request.useragent | "-"), "kube-probe*") == false) && (match((request.useragent | "-"), "Prometheus*") == false) + actions: + - handler: prometheus + instances: + - requestcount + - requestduration + - requestsize + - responsesize +--- +apiVersion: "config.istio.io/v1alpha2" +kind: rule +metadata: + name: promtcp + namespace: istio-system + labels: + app: mixer + chart: mixer + heritage: Tiller + release: istio +spec: + match: context.protocol == "tcp" + actions: + - handler: prometheus + instances: + - tcpbytesent + - tcpbytereceived +--- +apiVersion: "config.istio.io/v1alpha2" +kind: rule +metadata: + name: promtcpconnectionopen + namespace: istio-system + labels: + app: mixer + chart: mixer + heritage: Tiller + release: istio +spec: + match: context.protocol == "tcp" && ((connection.event | "na") == "open") + actions: + - handler: prometheus + instances: + - tcpconnectionsopened +--- +apiVersion: "config.istio.io/v1alpha2" +kind: rule +metadata: + name: promtcpconnectionclosed + namespace: istio-system + labels: + app: mixer + chart: mixer + heritage: Tiller + release: istio +spec: + match: context.protocol == "tcp" && ((connection.event | "na") == "close") + actions: + - handler: prometheus + instances: + - tcpconnectionsclosed +--- +apiVersion: "config.istio.io/v1alpha2" +kind: handler +metadata: + name: kubernetesenv + namespace: istio-system + labels: + app: mixer + chart: mixer + heritage: Tiller + release: istio +spec: + compiledAdapter: kubernetesenv + params: {} + # when running from mixer root, use the following config after adding a + # symbolic link to a kubernetes config file via: + # + # $ ln -s ~/.kube/config mixer/adapter/kubernetes/kubeconfig + # + # kubeconfig_path: "mixer/adapter/kubernetes/kubeconfig" + +--- +apiVersion: "config.istio.io/v1alpha2" +kind: rule +metadata: + name: kubeattrgenrulerule + namespace: istio-system + labels: + app: mixer + chart: mixer + heritage: Tiller + release: istio +spec: + actions: + - handler: kubernetesenv + instances: + - attributes +--- +apiVersion: "config.istio.io/v1alpha2" +kind: rule +metadata: + name: tcpkubeattrgenrulerule + namespace: istio-system + labels: + app: mixer + chart: mixer + heritage: Tiller + release: istio +spec: + match: context.protocol == "tcp" + actions: + - handler: kubernetesenv + instances: + - attributes +--- +apiVersion: "config.istio.io/v1alpha2" +kind: instance +metadata: + name: attributes + namespace: istio-system + labels: + app: mixer + chart: mixer + heritage: Tiller + release: istio +spec: + compiledTemplate: kubernetes + params: + # Pass the required attribute data to the adapter + source_uid: source.uid | "" + source_ip: source.ip | ip("0.0.0.0") # default to unspecified ip addr + destination_uid: destination.uid | "" + destination_port: destination.port | 0 + attributeBindings: + # Fill the new attributes from the adapter produced output. + # $out refers to an instance of OutputTemplate message + source.ip: $out.source_pod_ip | ip("0.0.0.0") + source.uid: $out.source_pod_uid | "unknown" + source.labels: $out.source_labels | emptyStringMap() + source.name: $out.source_pod_name | "unknown" + source.namespace: $out.source_namespace | "default" + source.owner: $out.source_owner | "unknown" + source.serviceAccount: $out.source_service_account_name | "unknown" + source.workload.uid: $out.source_workload_uid | "unknown" + source.workload.name: $out.source_workload_name | "unknown" + source.workload.namespace: $out.source_workload_namespace | "unknown" + destination.ip: $out.destination_pod_ip | ip("0.0.0.0") + destination.uid: $out.destination_pod_uid | "unknown" + destination.labels: $out.destination_labels | emptyStringMap() + destination.name: $out.destination_pod_name | "unknown" + destination.container.name: $out.destination_container_name | "unknown" + destination.namespace: $out.destination_namespace | "default" + destination.owner: $out.destination_owner | "unknown" + destination.serviceAccount: $out.destination_service_account_name | "unknown" + destination.workload.uid: $out.destination_workload_uid | "unknown" + destination.workload.name: $out.destination_workload_name | "unknown" + destination.workload.namespace: $out.destination_workload_namespace | "unknown" +--- +# Configuration needed by Mixer. +# Mixer cluster is delivered via CDS +# Specify mixer cluster settings +apiVersion: networking.istio.io/v1alpha3 +kind: DestinationRule +metadata: + name: istio-policy + namespace: istio-system + labels: + app: mixer + chart: mixer + heritage: Tiller + release: istio +spec: + host: istio-policy.istio-system.svc.cluster.local + trafficPolicy: + portLevelSettings: + - port: + number: 15004 # grpc-mixer-mtls + tls: + mode: ISTIO_MUTUAL + - port: + number: 9091 # grpc-mixer + tls: + mode: DISABLE + connectionPool: + http: + http2MaxRequests: 10000 + maxRequestsPerConnection: 10000 +--- +apiVersion: networking.istio.io/v1alpha3 +kind: DestinationRule +metadata: + name: istio-telemetry + namespace: istio-system + labels: + app: mixer + chart: mixer + heritage: Tiller + release: istio +spec: + host: istio-telemetry.istio-system.svc.cluster.local + trafficPolicy: + portLevelSettings: + - port: + number: 15004 # grpc-mixer-mtls + tls: + mode: ISTIO_MUTUAL + - port: + number: 9091 # grpc-mixer + tls: + mode: DISABLE + connectionPool: + http: + http2MaxRequests: 10000 + maxRequestsPerConnection: 10000 +--- + diff --git a/istio-1.5.0/install/kubernetes/mesh-expansion.yaml b/istio-1.5.0/install/kubernetes/mesh-expansion.yaml new file mode 100644 index 0000000..16b95b4 --- /dev/null +++ b/istio-1.5.0/install/kubernetes/mesh-expansion.yaml @@ -0,0 +1,86 @@ +# Currently specific to GKE. Annotations specific to other providers should be added +# after they get tested. +apiVersion: v1 +kind: Service +metadata: + name: istio-pilot-ilb + namespace: istio-system + annotations: + cloud.google.com/load-balancer-type: "internal" + labels: + istio: pilot +spec: + type: LoadBalancer + ports: + - name: https-pilot + port: 15005 + protocol: TCP + - port: 8080 + name: http-pilot + protocol: TCP + - port: 15010 + name: grpc-pilot + protocol: TCP + - port: 15011 + name: tls-grpc-pilot + protocol: TCP + selector: + istio: pilot +--- +apiVersion: v1 +kind: Service +metadata: + name: dns-ilb + namespace: kube-system + annotations: + cloud.google.com/load-balancer-type: "internal" + labels: + k8s-app: kube-dns +spec: + type: LoadBalancer + ports: + - port: 53 + protocol: UDP + selector: + k8s-app: kube-dns + +--- + +apiVersion: v1 +kind: Service +metadata: + name: mixer-ilb + namespace: istio-system + annotations: + cloud.google.com/load-balancer-type: "internal" + labels: + istio: mixer +spec: + type: LoadBalancer + ports: + - port: 15004 + protocol: TCP + selector: + istio: mixer + istio-mixer-type: telemetry + +# This points to istio-telemetry until we are able to support both +# istio-policy and istio-telemetry as separate services for mesh expansion. + +--- +apiVersion: v1 +kind: Service +metadata: + name: citadel-ilb + namespace: istio-system + annotations: + cloud.google.com/load-balancer-type: "internal" + labels: + istio: citadel +spec: + type: LoadBalancer + ports: + - port: 8060 + protocol: TCP + selector: + istio: citadel diff --git a/istio-1.5.0/install/kubernetes/namespace.yaml b/istio-1.5.0/install/kubernetes/namespace.yaml new file mode 100644 index 0000000..96fb18e --- /dev/null +++ b/istio-1.5.0/install/kubernetes/namespace.yaml @@ -0,0 +1,7 @@ +apiVersion: v1 +kind: Namespace +metadata: + name: istio-system + labels: + istio-injection: disabled +--- diff --git a/istio-1.5.0/install/kubernetes/operator/charts/base/Chart.yaml b/istio-1.5.0/install/kubernetes/operator/charts/base/Chart.yaml new file mode 100644 index 0000000..9300ae3 --- /dev/null +++ b/istio-1.5.0/install/kubernetes/operator/charts/base/Chart.yaml @@ -0,0 +1,11 @@ +apiVersion: v1 +name: base +version: 1.1.0 +tillerVersion: ">=2.7.2" +description: Helm chart for deploying Istio base components +keywords: + - istio +sources: + - http://github.com/istio/istio +engine: gotpl +icon: https://istio.io/favicons/android-192x192.png diff --git a/istio-1.5.0/install/kubernetes/operator/charts/base/files/crd-all.gen.yaml b/istio-1.5.0/install/kubernetes/operator/charts/base/files/crd-all.gen.yaml new file mode 100644 index 0000000..431c993 --- /dev/null +++ b/istio-1.5.0/install/kubernetes/operator/charts/base/files/crd-all.gen.yaml @@ -0,0 +1,5603 @@ +# DO NOT EDIT - Generated by Cue OpenAPI generator based on Istio APIs. +apiVersion: apiextensions.k8s.io/v1beta1 +kind: CustomResourceDefinition +metadata: + annotations: + "helm.sh/resource-policy": keep + labels: + app: istio-citadel + chart: istio + heritage: Tiller + release: istio + name: meshpolicies.authentication.istio.io +spec: + group: authentication.istio.io + names: + categories: + - istio-io + - authentication-istio-io + kind: MeshPolicy + listKind: MeshPolicyList + plural: meshpolicies + singular: meshpolicy + scope: Cluster + subresources: + status: {} + validation: + openAPIV3Schema: + properties: + spec: + description: 'Authentication policy for Istio services. See more details + at: https://istio.io/docs/reference/config/security/istio.authentication.v1alpha1.html' + properties: + originIsOptional: + description: Deprecated. + type: boolean + origins: + description: Deprecated. + items: + properties: + jwt: + description: Jwt params for the method. + properties: + audiences: + items: + format: string + type: string + type: array + issuer: + description: Identifies the issuer that issued the JWT. + format: string + type: string + jwks: + description: JSON Web Key Set of public keys to validate signature + of the JWT. + format: string + type: string + jwks_uri: + format: string + type: string + jwksUri: + format: string + type: string + jwt_headers: + description: JWT is sent in a request header. + items: + format: string + type: string + type: array + jwtHeaders: + description: JWT is sent in a request header. + items: + format: string + type: string + type: array + jwtParams: + description: JWT is sent in a query parameter. + items: + format: string + type: string + type: array + trigger_rules: + items: + properties: + excluded_paths: + description: List of paths to be excluded from the request. + items: + oneOf: + - required: + - exact + - required: + - prefix + - required: + - suffix + - required: + - regex + properties: + exact: + description: exact string match. + format: string + type: string + prefix: + description: prefix-based match. + format: string + type: string + regex: + description: ECMAscript style regex-based match + as defined by [EDCA-262](http://en.cppreference.com/w/cpp/regex/ecmascript). + format: string + type: string + suffix: + description: suffix-based match. + format: string + type: string + type: object + type: array + excludedPaths: + description: List of paths to be excluded from the request. + items: + oneOf: + - required: + - exact + - required: + - prefix + - required: + - suffix + - required: + - regex + properties: + exact: + description: exact string match. + format: string + type: string + prefix: + description: prefix-based match. + format: string + type: string + regex: + description: ECMAscript style regex-based match + as defined by [EDCA-262](http://en.cppreference.com/w/cpp/regex/ecmascript). + format: string + type: string + suffix: + description: suffix-based match. + format: string + type: string + type: object + type: array + included_paths: + description: List of paths that the request must include. + items: + oneOf: + - required: + - exact + - required: + - prefix + - required: + - suffix + - required: + - regex + properties: + exact: + description: exact string match. + format: string + type: string + prefix: + description: prefix-based match. + format: string + type: string + regex: + description: ECMAscript style regex-based match + as defined by [EDCA-262](http://en.cppreference.com/w/cpp/regex/ecmascript). + format: string + type: string + suffix: + description: suffix-based match. + format: string + type: string + type: object + type: array + includedPaths: + description: List of paths that the request must include. + items: + oneOf: + - required: + - exact + - required: + - prefix + - required: + - suffix + - required: + - regex + properties: + exact: + description: exact string match. + format: string + type: string + prefix: + description: prefix-based match. + format: string + type: string + regex: + description: ECMAscript style regex-based match + as defined by [EDCA-262](http://en.cppreference.com/w/cpp/regex/ecmascript). + format: string + type: string + suffix: + description: suffix-based match. + format: string + type: string + type: object + type: array + type: object + type: array + triggerRules: + items: + properties: + excluded_paths: + description: List of paths to be excluded from the request. + items: + oneOf: + - required: + - exact + - required: + - prefix + - required: + - suffix + - required: + - regex + properties: + exact: + description: exact string match. + format: string + type: string + prefix: + description: prefix-based match. + format: string + type: string + regex: + description: ECMAscript style regex-based match + as defined by [EDCA-262](http://en.cppreference.com/w/cpp/regex/ecmascript). + format: string + type: string + suffix: + description: suffix-based match. + format: string + type: string + type: object + type: array + excludedPaths: + description: List of paths to be excluded from the request. + items: + oneOf: + - required: + - exact + - required: + - prefix + - required: + - suffix + - required: + - regex + properties: + exact: + description: exact string match. + format: string + type: string + prefix: + description: prefix-based match. + format: string + type: string + regex: + description: ECMAscript style regex-based match + as defined by [EDCA-262](http://en.cppreference.com/w/cpp/regex/ecmascript). + format: string + type: string + suffix: + description: suffix-based match. + format: string + type: string + type: object + type: array + included_paths: + description: List of paths that the request must include. + items: + oneOf: + - required: + - exact + - required: + - prefix + - required: + - suffix + - required: + - regex + properties: + exact: + description: exact string match. + format: string + type: string + prefix: + description: prefix-based match. + format: string + type: string + regex: + description: ECMAscript style regex-based match + as defined by [EDCA-262](http://en.cppreference.com/w/cpp/regex/ecmascript). + format: string + type: string + suffix: + description: suffix-based match. + format: string + type: string + type: object + type: array + includedPaths: + description: List of paths that the request must include. + items: + oneOf: + - required: + - exact + - required: + - prefix + - required: + - suffix + - required: + - regex + properties: + exact: + description: exact string match. + format: string + type: string + prefix: + description: prefix-based match. + format: string + type: string + regex: + description: ECMAscript style regex-based match + as defined by [EDCA-262](http://en.cppreference.com/w/cpp/regex/ecmascript). + format: string + type: string + suffix: + description: suffix-based match. + format: string + type: string + type: object + type: array + type: object + type: array + type: object + type: object + type: array + peerIsOptional: + description: Deprecated. + type: boolean + peers: + description: List of authentication methods that can be used for peer + authentication. + items: + oneOf: + - required: + - mtls + - properties: + jwt: {} + required: + - jwt + properties: + jwt: + properties: + audiences: + items: + format: string + type: string + type: array + issuer: + description: Identifies the issuer that issued the JWT. + format: string + type: string + jwks: + description: JSON Web Key Set of public keys to validate signature + of the JWT. + format: string + type: string + jwks_uri: + format: string + type: string + jwksUri: + format: string + type: string + jwt_headers: + description: JWT is sent in a request header. + items: + format: string + type: string + type: array + jwtHeaders: + description: JWT is sent in a request header. + items: + format: string + type: string + type: array + jwtParams: + description: JWT is sent in a query parameter. + items: + format: string + type: string + type: array + trigger_rules: + items: + properties: + excluded_paths: + description: List of paths to be excluded from the request. + items: + oneOf: + - required: + - exact + - required: + - prefix + - required: + - suffix + - required: + - regex + properties: + exact: + description: exact string match. + format: string + type: string + prefix: + description: prefix-based match. + format: string + type: string + regex: + description: ECMAscript style regex-based match + as defined by [EDCA-262](http://en.cppreference.com/w/cpp/regex/ecmascript). + format: string + type: string + suffix: + description: suffix-based match. + format: string + type: string + type: object + type: array + excludedPaths: + description: List of paths to be excluded from the request. + items: + oneOf: + - required: + - exact + - required: + - prefix + - required: + - suffix + - required: + - regex + properties: + exact: + description: exact string match. + format: string + type: string + prefix: + description: prefix-based match. + format: string + type: string + regex: + description: ECMAscript style regex-based match + as defined by [EDCA-262](http://en.cppreference.com/w/cpp/regex/ecmascript). + format: string + type: string + suffix: + description: suffix-based match. + format: string + type: string + type: object + type: array + included_paths: + description: List of paths that the request must include. + items: + oneOf: + - required: + - exact + - required: + - prefix + - required: + - suffix + - required: + - regex + properties: + exact: + description: exact string match. + format: string + type: string + prefix: + description: prefix-based match. + format: string + type: string + regex: + description: ECMAscript style regex-based match + as defined by [EDCA-262](http://en.cppreference.com/w/cpp/regex/ecmascript). + format: string + type: string + suffix: + description: suffix-based match. + format: string + type: string + type: object + type: array + includedPaths: + description: List of paths that the request must include. + items: + oneOf: + - required: + - exact + - required: + - prefix + - required: + - suffix + - required: + - regex + properties: + exact: + description: exact string match. + format: string + type: string + prefix: + description: prefix-based match. + format: string + type: string + regex: + description: ECMAscript style regex-based match + as defined by [EDCA-262](http://en.cppreference.com/w/cpp/regex/ecmascript). + format: string + type: string + suffix: + description: suffix-based match. + format: string + type: string + type: object + type: array + type: object + type: array + triggerRules: + items: + properties: + excluded_paths: + description: List of paths to be excluded from the request. + items: + oneOf: + - required: + - exact + - required: + - prefix + - required: + - suffix + - required: + - regex + properties: + exact: + description: exact string match. + format: string + type: string + prefix: + description: prefix-based match. + format: string + type: string + regex: + description: ECMAscript style regex-based match + as defined by [EDCA-262](http://en.cppreference.com/w/cpp/regex/ecmascript). + format: string + type: string + suffix: + description: suffix-based match. + format: string + type: string + type: object + type: array + excludedPaths: + description: List of paths to be excluded from the request. + items: + oneOf: + - required: + - exact + - required: + - prefix + - required: + - suffix + - required: + - regex + properties: + exact: + description: exact string match. + format: string + type: string + prefix: + description: prefix-based match. + format: string + type: string + regex: + description: ECMAscript style regex-based match + as defined by [EDCA-262](http://en.cppreference.com/w/cpp/regex/ecmascript). + format: string + type: string + suffix: + description: suffix-based match. + format: string + type: string + type: object + type: array + included_paths: + description: List of paths that the request must include. + items: + oneOf: + - required: + - exact + - required: + - prefix + - required: + - suffix + - required: + - regex + properties: + exact: + description: exact string match. + format: string + type: string + prefix: + description: prefix-based match. + format: string + type: string + regex: + description: ECMAscript style regex-based match + as defined by [EDCA-262](http://en.cppreference.com/w/cpp/regex/ecmascript). + format: string + type: string + suffix: + description: suffix-based match. + format: string + type: string + type: object + type: array + includedPaths: + description: List of paths that the request must include. + items: + oneOf: + - required: + - exact + - required: + - prefix + - required: + - suffix + - required: + - regex + properties: + exact: + description: exact string match. + format: string + type: string + prefix: + description: prefix-based match. + format: string + type: string + regex: + description: ECMAscript style regex-based match + as defined by [EDCA-262](http://en.cppreference.com/w/cpp/regex/ecmascript). + format: string + type: string + suffix: + description: suffix-based match. + format: string + type: string + type: object + type: array + type: object + type: array + type: object + mtls: + description: Set if mTLS is used. + properties: + allowTls: + description: Deprecated. + type: boolean + mode: + description: Defines the mode of mTLS authentication. + enum: + - STRICT + - PERMISSIVE + type: string + type: object + type: object + type: array + principalBinding: + description: Deprecated. + enum: + - USE_PEER + - USE_ORIGIN + type: string + targets: + description: Deprecated. + items: + properties: + name: + description: The name must be a short name from the service registry. + format: string + type: string + ports: + description: Specifies the ports. + items: + oneOf: + - required: + - number + - required: + - name + properties: + name: + format: string + type: string + number: + type: integer + type: object + type: array + type: object + type: array + type: object + type: object + versions: + - name: v1alpha1 + served: true + storage: true + +--- +apiVersion: apiextensions.k8s.io/v1beta1 +kind: CustomResourceDefinition +metadata: + annotations: + "helm.sh/resource-policy": keep + labels: + app: istio-citadel + chart: istio + heritage: Tiller + release: istio + name: policies.authentication.istio.io +spec: + group: authentication.istio.io + names: + categories: + - istio-io + - authentication-istio-io + kind: Policy + listKind: PolicyList + plural: policies + singular: policy + scope: Namespaced + subresources: + status: {} + validation: + openAPIV3Schema: + properties: + spec: + description: 'Authentication policy for Istio services. See more details + at: https://istio.io/docs/reference/config/security/istio.authentication.v1alpha1.html' + properties: + originIsOptional: + description: Deprecated. + type: boolean + origins: + description: Deprecated. + items: + properties: + jwt: + description: Jwt params for the method. + properties: + audiences: + items: + format: string + type: string + type: array + issuer: + description: Identifies the issuer that issued the JWT. + format: string + type: string + jwks: + description: JSON Web Key Set of public keys to validate signature + of the JWT. + format: string + type: string + jwks_uri: + format: string + type: string + jwksUri: + format: string + type: string + jwt_headers: + description: JWT is sent in a request header. + items: + format: string + type: string + type: array + jwtHeaders: + description: JWT is sent in a request header. + items: + format: string + type: string + type: array + jwtParams: + description: JWT is sent in a query parameter. + items: + format: string + type: string + type: array + trigger_rules: + items: + properties: + excluded_paths: + description: List of paths to be excluded from the request. + items: + oneOf: + - required: + - exact + - required: + - prefix + - required: + - suffix + - required: + - regex + properties: + exact: + description: exact string match. + format: string + type: string + prefix: + description: prefix-based match. + format: string + type: string + regex: + description: ECMAscript style regex-based match + as defined by [EDCA-262](http://en.cppreference.com/w/cpp/regex/ecmascript). + format: string + type: string + suffix: + description: suffix-based match. + format: string + type: string + type: object + type: array + excludedPaths: + description: List of paths to be excluded from the request. + items: + oneOf: + - required: + - exact + - required: + - prefix + - required: + - suffix + - required: + - regex + properties: + exact: + description: exact string match. + format: string + type: string + prefix: + description: prefix-based match. + format: string + type: string + regex: + description: ECMAscript style regex-based match + as defined by [EDCA-262](http://en.cppreference.com/w/cpp/regex/ecmascript). + format: string + type: string + suffix: + description: suffix-based match. + format: string + type: string + type: object + type: array + included_paths: + description: List of paths that the request must include. + items: + oneOf: + - required: + - exact + - required: + - prefix + - required: + - suffix + - required: + - regex + properties: + exact: + description: exact string match. + format: string + type: string + prefix: + description: prefix-based match. + format: string + type: string + regex: + description: ECMAscript style regex-based match + as defined by [EDCA-262](http://en.cppreference.com/w/cpp/regex/ecmascript). + format: string + type: string + suffix: + description: suffix-based match. + format: string + type: string + type: object + type: array + includedPaths: + description: List of paths that the request must include. + items: + oneOf: + - required: + - exact + - required: + - prefix + - required: + - suffix + - required: + - regex + properties: + exact: + description: exact string match. + format: string + type: string + prefix: + description: prefix-based match. + format: string + type: string + regex: + description: ECMAscript style regex-based match + as defined by [EDCA-262](http://en.cppreference.com/w/cpp/regex/ecmascript). + format: string + type: string + suffix: + description: suffix-based match. + format: string + type: string + type: object + type: array + type: object + type: array + triggerRules: + items: + properties: + excluded_paths: + description: List of paths to be excluded from the request. + items: + oneOf: + - required: + - exact + - required: + - prefix + - required: + - suffix + - required: + - regex + properties: + exact: + description: exact string match. + format: string + type: string + prefix: + description: prefix-based match. + format: string + type: string + regex: + description: ECMAscript style regex-based match + as defined by [EDCA-262](http://en.cppreference.com/w/cpp/regex/ecmascript). + format: string + type: string + suffix: + description: suffix-based match. + format: string + type: string + type: object + type: array + excludedPaths: + description: List of paths to be excluded from the request. + items: + oneOf: + - required: + - exact + - required: + - prefix + - required: + - suffix + - required: + - regex + properties: + exact: + description: exact string match. + format: string + type: string + prefix: + description: prefix-based match. + format: string + type: string + regex: + description: ECMAscript style regex-based match + as defined by [EDCA-262](http://en.cppreference.com/w/cpp/regex/ecmascript). + format: string + type: string + suffix: + description: suffix-based match. + format: string + type: string + type: object + type: array + included_paths: + description: List of paths that the request must include. + items: + oneOf: + - required: + - exact + - required: + - prefix + - required: + - suffix + - required: + - regex + properties: + exact: + description: exact string match. + format: string + type: string + prefix: + description: prefix-based match. + format: string + type: string + regex: + description: ECMAscript style regex-based match + as defined by [EDCA-262](http://en.cppreference.com/w/cpp/regex/ecmascript). + format: string + type: string + suffix: + description: suffix-based match. + format: string + type: string + type: object + type: array + includedPaths: + description: List of paths that the request must include. + items: + oneOf: + - required: + - exact + - required: + - prefix + - required: + - suffix + - required: + - regex + properties: + exact: + description: exact string match. + format: string + type: string + prefix: + description: prefix-based match. + format: string + type: string + regex: + description: ECMAscript style regex-based match + as defined by [EDCA-262](http://en.cppreference.com/w/cpp/regex/ecmascript). + format: string + type: string + suffix: + description: suffix-based match. + format: string + type: string + type: object + type: array + type: object + type: array + type: object + type: object + type: array + peerIsOptional: + description: Deprecated. + type: boolean + peers: + description: List of authentication methods that can be used for peer + authentication. + items: + oneOf: + - required: + - mtls + - properties: + jwt: {} + required: + - jwt + properties: + jwt: + properties: + audiences: + items: + format: string + type: string + type: array + issuer: + description: Identifies the issuer that issued the JWT. + format: string + type: string + jwks: + description: JSON Web Key Set of public keys to validate signature + of the JWT. + format: string + type: string + jwks_uri: + format: string + type: string + jwksUri: + format: string + type: string + jwt_headers: + description: JWT is sent in a request header. + items: + format: string + type: string + type: array + jwtHeaders: + description: JWT is sent in a request header. + items: + format: string + type: string + type: array + jwtParams: + description: JWT is sent in a query parameter. + items: + format: string + type: string + type: array + trigger_rules: + items: + properties: + excluded_paths: + description: List of paths to be excluded from the request. + items: + oneOf: + - required: + - exact + - required: + - prefix + - required: + - suffix + - required: + - regex + properties: + exact: + description: exact string match. + format: string + type: string + prefix: + description: prefix-based match. + format: string + type: string + regex: + description: ECMAscript style regex-based match + as defined by [EDCA-262](http://en.cppreference.com/w/cpp/regex/ecmascript). + format: string + type: string + suffix: + description: suffix-based match. + format: string + type: string + type: object + type: array + excludedPaths: + description: List of paths to be excluded from the request. + items: + oneOf: + - required: + - exact + - required: + - prefix + - required: + - suffix + - required: + - regex + properties: + exact: + description: exact string match. + format: string + type: string + prefix: + description: prefix-based match. + format: string + type: string + regex: + description: ECMAscript style regex-based match + as defined by [EDCA-262](http://en.cppreference.com/w/cpp/regex/ecmascript). + format: string + type: string + suffix: + description: suffix-based match. + format: string + type: string + type: object + type: array + included_paths: + description: List of paths that the request must include. + items: + oneOf: + - required: + - exact + - required: + - prefix + - required: + - suffix + - required: + - regex + properties: + exact: + description: exact string match. + format: string + type: string + prefix: + description: prefix-based match. + format: string + type: string + regex: + description: ECMAscript style regex-based match + as defined by [EDCA-262](http://en.cppreference.com/w/cpp/regex/ecmascript). + format: string + type: string + suffix: + description: suffix-based match. + format: string + type: string + type: object + type: array + includedPaths: + description: List of paths that the request must include. + items: + oneOf: + - required: + - exact + - required: + - prefix + - required: + - suffix + - required: + - regex + properties: + exact: + description: exact string match. + format: string + type: string + prefix: + description: prefix-based match. + format: string + type: string + regex: + description: ECMAscript style regex-based match + as defined by [EDCA-262](http://en.cppreference.com/w/cpp/regex/ecmascript). + format: string + type: string + suffix: + description: suffix-based match. + format: string + type: string + type: object + type: array + type: object + type: array + triggerRules: + items: + properties: + excluded_paths: + description: List of paths to be excluded from the request. + items: + oneOf: + - required: + - exact + - required: + - prefix + - required: + - suffix + - required: + - regex + properties: + exact: + description: exact string match. + format: string + type: string + prefix: + description: prefix-based match. + format: string + type: string + regex: + description: ECMAscript style regex-based match + as defined by [EDCA-262](http://en.cppreference.com/w/cpp/regex/ecmascript). + format: string + type: string + suffix: + description: suffix-based match. + format: string + type: string + type: object + type: array + excludedPaths: + description: List of paths to be excluded from the request. + items: + oneOf: + - required: + - exact + - required: + - prefix + - required: + - suffix + - required: + - regex + properties: + exact: + description: exact string match. + format: string + type: string + prefix: + description: prefix-based match. + format: string + type: string + regex: + description: ECMAscript style regex-based match + as defined by [EDCA-262](http://en.cppreference.com/w/cpp/regex/ecmascript). + format: string + type: string + suffix: + description: suffix-based match. + format: string + type: string + type: object + type: array + included_paths: + description: List of paths that the request must include. + items: + oneOf: + - required: + - exact + - required: + - prefix + - required: + - suffix + - required: + - regex + properties: + exact: + description: exact string match. + format: string + type: string + prefix: + description: prefix-based match. + format: string + type: string + regex: + description: ECMAscript style regex-based match + as defined by [EDCA-262](http://en.cppreference.com/w/cpp/regex/ecmascript). + format: string + type: string + suffix: + description: suffix-based match. + format: string + type: string + type: object + type: array + includedPaths: + description: List of paths that the request must include. + items: + oneOf: + - required: + - exact + - required: + - prefix + - required: + - suffix + - required: + - regex + properties: + exact: + description: exact string match. + format: string + type: string + prefix: + description: prefix-based match. + format: string + type: string + regex: + description: ECMAscript style regex-based match + as defined by [EDCA-262](http://en.cppreference.com/w/cpp/regex/ecmascript). + format: string + type: string + suffix: + description: suffix-based match. + format: string + type: string + type: object + type: array + type: object + type: array + type: object + mtls: + description: Set if mTLS is used. + properties: + allowTls: + description: Deprecated. + type: boolean + mode: + description: Defines the mode of mTLS authentication. + enum: + - STRICT + - PERMISSIVE + type: string + type: object + type: object + type: array + principalBinding: + description: Deprecated. + enum: + - USE_PEER + - USE_ORIGIN + type: string + targets: + description: Deprecated. + items: + properties: + name: + description: The name must be a short name from the service registry. + format: string + type: string + ports: + description: Specifies the ports. + items: + oneOf: + - required: + - number + - required: + - name + properties: + name: + format: string + type: string + number: + type: integer + type: object + type: array + type: object + type: array + type: object + type: object + versions: + - name: v1alpha1 + served: true + storage: true + +--- +apiVersion: apiextensions.k8s.io/v1beta1 +kind: CustomResourceDefinition +metadata: + annotations: + "helm.sh/resource-policy": keep + labels: + app: istio-mixer + chart: istio + heritage: Tiller + release: istio + name: httpapispecs.config.istio.io +spec: + group: config.istio.io + names: + categories: + - istio-io + - apim-istio-io + kind: HTTPAPISpec + listKind: HTTPAPISpecList + plural: httpapispecs + singular: httpapispec + scope: Namespaced + subresources: + status: {} + validation: + openAPIV3Schema: + properties: + spec: + properties: + api_keys: + items: + oneOf: + - required: + - query + - required: + - header + - required: + - cookie + properties: + cookie: + format: string + type: string + header: + description: API key is sent in a request header. + format: string + type: string + query: + description: API Key is sent as a query parameter. + format: string + type: string + type: object + type: array + apiKeys: + items: + oneOf: + - required: + - query + - required: + - header + - required: + - cookie + properties: + cookie: + format: string + type: string + header: + description: API key is sent in a request header. + format: string + type: string + query: + description: API Key is sent as a query parameter. + format: string + type: string + type: object + type: array + attributes: + properties: + attributes: + additionalProperties: + oneOf: + - required: + - stringValue + - required: + - int64Value + - required: + - doubleValue + - required: + - boolValue + - required: + - bytesValue + - required: + - timestampValue + - required: + - durationValue + - required: + - stringMapValue + properties: + boolValue: + type: boolean + bytesValue: + format: binary + type: string + doubleValue: + format: double + type: number + durationValue: + type: string + int64Value: + format: int64 + type: integer + stringMapValue: + properties: + entries: + additionalProperties: + format: string + type: string + description: Holds a set of name/value pairs. + type: object + type: object + stringValue: + format: string + type: string + timestampValue: + format: dateTime + type: string + type: object + description: A map of attribute name to its value. + type: object + type: object + patterns: + description: List of HTTP patterns to match. + items: + oneOf: + - required: + - uriTemplate + - required: + - regex + properties: + attributes: + properties: + attributes: + additionalProperties: + oneOf: + - required: + - stringValue + - required: + - int64Value + - required: + - doubleValue + - required: + - boolValue + - required: + - bytesValue + - required: + - timestampValue + - required: + - durationValue + - required: + - stringMapValue + properties: + boolValue: + type: boolean + bytesValue: + format: binary + type: string + doubleValue: + format: double + type: number + durationValue: + type: string + int64Value: + format: int64 + type: integer + stringMapValue: + properties: + entries: + additionalProperties: + format: string + type: string + description: Holds a set of name/value pairs. + type: object + type: object + stringValue: + format: string + type: string + timestampValue: + format: dateTime + type: string + type: object + description: A map of attribute name to its value. + type: object + type: object + httpMethod: + format: string + type: string + regex: + format: string + type: string + uriTemplate: + format: string + type: string + type: object + type: array + type: object + type: object + versions: + - name: v1alpha2 + served: true + storage: true + +--- +apiVersion: apiextensions.k8s.io/v1beta1 +kind: CustomResourceDefinition +metadata: + annotations: + "helm.sh/resource-policy": keep + labels: + app: istio-mixer + chart: istio + heritage: Tiller + release: istio + name: httpapispecbindings.config.istio.io +spec: + group: config.istio.io + names: + categories: + - istio-io + - apim-istio-io + kind: HTTPAPISpecBinding + listKind: HTTPAPISpecBindingList + plural: httpapispecbindings + singular: httpapispecbinding + scope: Namespaced + subresources: + status: {} + validation: + openAPIV3Schema: + properties: + spec: + properties: + api_specs: + items: + properties: + name: + description: The short name of the HTTPAPISpec. + format: string + type: string + namespace: + description: Optional namespace of the HTTPAPISpec. + format: string + type: string + type: object + type: array + apiSpecs: + items: + properties: + name: + description: The short name of the HTTPAPISpec. + format: string + type: string + namespace: + description: Optional namespace of the HTTPAPISpec. + format: string + type: string + type: object + type: array + services: + description: One or more services to map the listed HTTPAPISpec onto. + items: + properties: + domain: + description: Domain suffix used to construct the service FQDN + in implementations that support such specification. + format: string + type: string + labels: + additionalProperties: + format: string + type: string + description: Optional one or more labels that uniquely identify + the service version. + type: object + name: + description: The short name of the service such as "foo". + format: string + type: string + namespace: + description: Optional namespace of the service. + format: string + type: string + service: + description: The service FQDN. + format: string + type: string + type: object + type: array + type: object + type: object + versions: + - name: v1alpha2 + served: true + storage: true + +--- +apiVersion: apiextensions.k8s.io/v1beta1 +kind: CustomResourceDefinition +metadata: + annotations: + "helm.sh/resource-policy": keep + labels: + app: istio-mixer + chart: istio + heritage: Tiller + release: istio + name: quotaspecs.config.istio.io +spec: + group: config.istio.io + names: + categories: + - istio-io + - apim-istio-io + kind: QuotaSpec + listKind: QuotaSpecList + plural: quotaspecs + singular: quotaspec + scope: Namespaced + subresources: + status: {} + validation: + openAPIV3Schema: + properties: + spec: + description: Determines the quotas used for individual requests. + properties: + rules: + description: A list of Quota rules. + items: + properties: + match: + description: If empty, match all request. + items: + properties: + clause: + additionalProperties: + oneOf: + - required: + - exact + - required: + - prefix + - required: + - regex + properties: + exact: + format: string + type: string + prefix: + format: string + type: string + regex: + format: string + type: string + type: object + description: Map of attribute names to StringMatch type. + type: object + type: object + type: array + quotas: + description: The list of quotas to charge. + items: + properties: + charge: + format: int32 + type: integer + quota: + format: string + type: string + type: object + type: array + type: object + type: array + type: object + type: object + versions: + - name: v1alpha2 + served: true + storage: true + +--- +apiVersion: apiextensions.k8s.io/v1beta1 +kind: CustomResourceDefinition +metadata: + annotations: + "helm.sh/resource-policy": keep + labels: + app: istio-mixer + chart: istio + heritage: Tiller + release: istio + name: quotaspecbindings.config.istio.io +spec: + group: config.istio.io + names: + categories: + - istio-io + - apim-istio-io + kind: QuotaSpecBinding + listKind: QuotaSpecBindingList + plural: quotaspecbindings + singular: quotaspecbinding + scope: Namespaced + subresources: + status: {} + validation: + openAPIV3Schema: + properties: + spec: + properties: + quotaSpecs: + items: + properties: + name: + description: The short name of the QuotaSpec. + format: string + type: string + namespace: + description: Optional namespace of the QuotaSpec. + format: string + type: string + type: object + type: array + services: + description: One or more services to map the listed QuotaSpec onto. + items: + properties: + domain: + description: Domain suffix used to construct the service FQDN + in implementations that support such specification. + format: string + type: string + labels: + additionalProperties: + format: string + type: string + description: Optional one or more labels that uniquely identify + the service version. + type: object + name: + description: The short name of the service such as "foo". + format: string + type: string + namespace: + description: Optional namespace of the service. + format: string + type: string + service: + description: The service FQDN. + format: string + type: string + type: object + type: array + type: object + type: object + versions: + - name: v1alpha2 + served: true + storage: true + +--- +apiVersion: apiextensions.k8s.io/v1beta1 +kind: CustomResourceDefinition +metadata: + annotations: + "helm.sh/resource-policy": keep + labels: + app: istio-pilot + chart: istio + heritage: Tiller + release: istio + name: destinationrules.networking.istio.io +spec: + additionalPrinterColumns: + - JSONPath: .spec.host + description: The name of a service from the service registry + name: Host + type: string + - JSONPath: .metadata.creationTimestamp + description: 'CreationTimestamp is a timestamp representing the server time when + this object was created. It is not guaranteed to be set in happens-before order + across separate operations. Clients may not set this value. It is represented + in RFC3339 form and is in UTC. Populated by the system. Read-only. Null for + lists. More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#metadata' + name: Age + type: date + group: networking.istio.io + names: + categories: + - istio-io + - networking-istio-io + kind: DestinationRule + listKind: DestinationRuleList + plural: destinationrules + shortNames: + - dr + singular: destinationrule + scope: Namespaced + subresources: + status: {} + validation: + openAPIV3Schema: + properties: + spec: + description: 'Configuration affecting load balancing, outlier detection, + etc. See more details at: https://istio.io/docs/reference/config/networking/destination-rule.html' + properties: + exportTo: + description: A list of namespaces to which this destination rule is + exported. + items: + format: string + type: string + type: array + host: + description: The name of a service from the service registry. + format: string + type: string + subsets: + items: + properties: + labels: + additionalProperties: + format: string + type: string + type: object + name: + description: Name of the subset. + format: string + type: string + trafficPolicy: + description: Traffic policies that apply to this subset. + properties: + connectionPool: + properties: + http: + description: HTTP connection pool settings. + properties: + h2UpgradePolicy: + description: Specify if http1.1 connection should + be upgraded to http2 for the associated destination. + enum: + - DEFAULT + - DO_NOT_UPGRADE + - UPGRADE + type: string + http1MaxPendingRequests: + description: Maximum number of pending HTTP requests + to a destination. + format: int32 + type: integer + http2MaxRequests: + description: Maximum number of requests to a backend. + format: int32 + type: integer + idleTimeout: + description: The idle timeout for upstream connection + pool connections. + type: string + maxRequestsPerConnection: + description: Maximum number of requests per connection + to a backend. + format: int32 + type: integer + maxRetries: + format: int32 + type: integer + type: object + tcp: + description: Settings common to both HTTP and TCP upstream + connections. + properties: + connectTimeout: + description: TCP connection timeout. + type: string + maxConnections: + description: Maximum number of HTTP1 /TCP connections + to a destination host. + format: int32 + type: integer + tcpKeepalive: + description: If set then set SO_KEEPALIVE on the socket + to enable TCP Keepalives. + properties: + interval: + description: The time duration between keep-alive + probes. + type: string + probes: + type: integer + time: + type: string + type: object + type: object + type: object + loadBalancer: + description: Settings controlling the load balancer algorithms. + oneOf: + - required: + - simple + - properties: + consistentHash: + oneOf: + - required: + - httpHeaderName + - required: + - httpCookie + - required: + - useSourceIp + required: + - consistentHash + properties: + consistentHash: + properties: + httpCookie: + description: Hash based on HTTP cookie. + properties: + name: + description: Name of the cookie. + format: string + type: string + path: + description: Path to set for the cookie. + format: string + type: string + ttl: + description: Lifetime of the cookie. + type: string + type: object + httpHeaderName: + description: Hash based on a specific HTTP header. + format: string + type: string + minimumRingSize: + type: integer + useSourceIp: + description: Hash based on the source IP address. + type: boolean + type: object + localityLbSetting: + properties: + distribute: + description: 'Optional: only one of distribute or + failover can be set.' + items: + properties: + from: + description: Originating locality, '/' separated, + e.g. + format: string + type: string + to: + additionalProperties: + type: integer + description: Map of upstream localities to traffic + distribution weights. + type: object + type: object + type: array + enabled: + description: enable locality load balancing, this + is DestinationRule-level and will override mesh + wide settings in entirety. + type: boolean + failover: + description: 'Optional: only failover or distribute + can be set.' + items: + properties: + from: + description: Originating region. + format: string + type: string + to: + format: string + type: string + type: object + type: array + type: object + simple: + enum: + - ROUND_ROBIN + - LEAST_CONN + - RANDOM + - PASSTHROUGH + type: string + type: object + outlierDetection: + properties: + baseEjectionTime: + description: Minimum ejection duration. + type: string + consecutive5xxErrors: + description: Number of 5xx errors before a host is ejected + from the connection pool. + type: integer + consecutiveErrors: + format: int32 + type: integer + consecutiveGatewayErrors: + description: Number of gateway errors before a host is + ejected from the connection pool. + type: integer + interval: + description: Time interval between ejection sweep analysis. + type: string + maxEjectionPercent: + format: int32 + type: integer + minHealthPercent: + format: int32 + type: integer + type: object + portLevelSettings: + description: Traffic policies specific to individual ports. + items: + properties: + connectionPool: + properties: + http: + description: HTTP connection pool settings. + properties: + h2UpgradePolicy: + description: Specify if http1.1 connection should + be upgraded to http2 for the associated destination. + enum: + - DEFAULT + - DO_NOT_UPGRADE + - UPGRADE + type: string + http1MaxPendingRequests: + description: Maximum number of pending HTTP + requests to a destination. + format: int32 + type: integer + http2MaxRequests: + description: Maximum number of requests to a + backend. + format: int32 + type: integer + idleTimeout: + description: The idle timeout for upstream connection + pool connections. + type: string + maxRequestsPerConnection: + description: Maximum number of requests per + connection to a backend. + format: int32 + type: integer + maxRetries: + format: int32 + type: integer + type: object + tcp: + description: Settings common to both HTTP and TCP + upstream connections. + properties: + connectTimeout: + description: TCP connection timeout. + type: string + maxConnections: + description: Maximum number of HTTP1 /TCP connections + to a destination host. + format: int32 + type: integer + tcpKeepalive: + description: If set then set SO_KEEPALIVE on + the socket to enable TCP Keepalives. + properties: + interval: + description: The time duration between keep-alive + probes. + type: string + probes: + type: integer + time: + type: string + type: object + type: object + type: object + loadBalancer: + description: Settings controlling the load balancer + algorithms. + oneOf: + - required: + - simple + - properties: + consistentHash: + oneOf: + - required: + - httpHeaderName + - required: + - httpCookie + - required: + - useSourceIp + required: + - consistentHash + properties: + consistentHash: + properties: + httpCookie: + description: Hash based on HTTP cookie. + properties: + name: + description: Name of the cookie. + format: string + type: string + path: + description: Path to set for the cookie. + format: string + type: string + ttl: + description: Lifetime of the cookie. + type: string + type: object + httpHeaderName: + description: Hash based on a specific HTTP header. + format: string + type: string + minimumRingSize: + type: integer + useSourceIp: + description: Hash based on the source IP address. + type: boolean + type: object + localityLbSetting: + properties: + distribute: + description: 'Optional: only one of distribute + or failover can be set.' + items: + properties: + from: + description: Originating locality, '/' + separated, e.g. + format: string + type: string + to: + additionalProperties: + type: integer + description: Map of upstream localities + to traffic distribution weights. + type: object + type: object + type: array + enabled: + description: enable locality load balancing, + this is DestinationRule-level and will override + mesh wide settings in entirety. + type: boolean + failover: + description: 'Optional: only failover or distribute + can be set.' + items: + properties: + from: + description: Originating region. + format: string + type: string + to: + format: string + type: string + type: object + type: array + type: object + simple: + enum: + - ROUND_ROBIN + - LEAST_CONN + - RANDOM + - PASSTHROUGH + type: string + type: object + outlierDetection: + properties: + baseEjectionTime: + description: Minimum ejection duration. + type: string + consecutive5xxErrors: + description: Number of 5xx errors before a host + is ejected from the connection pool. + type: integer + consecutiveErrors: + format: int32 + type: integer + consecutiveGatewayErrors: + description: Number of gateway errors before a host + is ejected from the connection pool. + type: integer + interval: + description: Time interval between ejection sweep + analysis. + type: string + maxEjectionPercent: + format: int32 + type: integer + minHealthPercent: + format: int32 + type: integer + type: object + port: + properties: + number: + type: integer + type: object + tls: + description: TLS related settings for connections to + the upstream service. + properties: + caCertificates: + format: string + type: string + clientCertificate: + description: REQUIRED if mode is `MUTUAL`. + format: string + type: string + mode: + enum: + - DISABLE + - SIMPLE + - MUTUAL + - ISTIO_MUTUAL + type: string + privateKey: + description: REQUIRED if mode is `MUTUAL`. + format: string + type: string + sni: + description: SNI string to present to the server + during TLS handshake. + format: string + type: string + subjectAltNames: + items: + format: string + type: string + type: array + type: object + type: object + type: array + tls: + description: TLS related settings for connections to the upstream + service. + properties: + caCertificates: + format: string + type: string + clientCertificate: + description: REQUIRED if mode is `MUTUAL`. + format: string + type: string + mode: + enum: + - DISABLE + - SIMPLE + - MUTUAL + - ISTIO_MUTUAL + type: string + privateKey: + description: REQUIRED if mode is `MUTUAL`. + format: string + type: string + sni: + description: SNI string to present to the server during + TLS handshake. + format: string + type: string + subjectAltNames: + items: + format: string + type: string + type: array + type: object + type: object + type: object + type: array + trafficPolicy: + properties: + connectionPool: + properties: + http: + description: HTTP connection pool settings. + properties: + h2UpgradePolicy: + description: Specify if http1.1 connection should be upgraded + to http2 for the associated destination. + enum: + - DEFAULT + - DO_NOT_UPGRADE + - UPGRADE + type: string + http1MaxPendingRequests: + description: Maximum number of pending HTTP requests to + a destination. + format: int32 + type: integer + http2MaxRequests: + description: Maximum number of requests to a backend. + format: int32 + type: integer + idleTimeout: + description: The idle timeout for upstream connection pool + connections. + type: string + maxRequestsPerConnection: + description: Maximum number of requests per connection to + a backend. + format: int32 + type: integer + maxRetries: + format: int32 + type: integer + type: object + tcp: + description: Settings common to both HTTP and TCP upstream connections. + properties: + connectTimeout: + description: TCP connection timeout. + type: string + maxConnections: + description: Maximum number of HTTP1 /TCP connections to + a destination host. + format: int32 + type: integer + tcpKeepalive: + description: If set then set SO_KEEPALIVE on the socket + to enable TCP Keepalives. + properties: + interval: + description: The time duration between keep-alive probes. + type: string + probes: + type: integer + time: + type: string + type: object + type: object + type: object + loadBalancer: + description: Settings controlling the load balancer algorithms. + oneOf: + - required: + - simple + - properties: + consistentHash: + oneOf: + - required: + - httpHeaderName + - required: + - httpCookie + - required: + - useSourceIp + required: + - consistentHash + properties: + consistentHash: + properties: + httpCookie: + description: Hash based on HTTP cookie. + properties: + name: + description: Name of the cookie. + format: string + type: string + path: + description: Path to set for the cookie. + format: string + type: string + ttl: + description: Lifetime of the cookie. + type: string + type: object + httpHeaderName: + description: Hash based on a specific HTTP header. + format: string + type: string + minimumRingSize: + type: integer + useSourceIp: + description: Hash based on the source IP address. + type: boolean + type: object + localityLbSetting: + properties: + distribute: + description: 'Optional: only one of distribute or failover + can be set.' + items: + properties: + from: + description: Originating locality, '/' separated, + e.g. + format: string + type: string + to: + additionalProperties: + type: integer + description: Map of upstream localities to traffic + distribution weights. + type: object + type: object + type: array + enabled: + description: enable locality load balancing, this is DestinationRule-level + and will override mesh wide settings in entirety. + type: boolean + failover: + description: 'Optional: only failover or distribute can + be set.' + items: + properties: + from: + description: Originating region. + format: string + type: string + to: + format: string + type: string + type: object + type: array + type: object + simple: + enum: + - ROUND_ROBIN + - LEAST_CONN + - RANDOM + - PASSTHROUGH + type: string + type: object + outlierDetection: + properties: + baseEjectionTime: + description: Minimum ejection duration. + type: string + consecutive5xxErrors: + description: Number of 5xx errors before a host is ejected from + the connection pool. + type: integer + consecutiveErrors: + format: int32 + type: integer + consecutiveGatewayErrors: + description: Number of gateway errors before a host is ejected + from the connection pool. + type: integer + interval: + description: Time interval between ejection sweep analysis. + type: string + maxEjectionPercent: + format: int32 + type: integer + minHealthPercent: + format: int32 + type: integer + type: object + portLevelSettings: + description: Traffic policies specific to individual ports. + items: + properties: + connectionPool: + properties: + http: + description: HTTP connection pool settings. + properties: + h2UpgradePolicy: + description: Specify if http1.1 connection should + be upgraded to http2 for the associated destination. + enum: + - DEFAULT + - DO_NOT_UPGRADE + - UPGRADE + type: string + http1MaxPendingRequests: + description: Maximum number of pending HTTP requests + to a destination. + format: int32 + type: integer + http2MaxRequests: + description: Maximum number of requests to a backend. + format: int32 + type: integer + idleTimeout: + description: The idle timeout for upstream connection + pool connections. + type: string + maxRequestsPerConnection: + description: Maximum number of requests per connection + to a backend. + format: int32 + type: integer + maxRetries: + format: int32 + type: integer + type: object + tcp: + description: Settings common to both HTTP and TCP upstream + connections. + properties: + connectTimeout: + description: TCP connection timeout. + type: string + maxConnections: + description: Maximum number of HTTP1 /TCP connections + to a destination host. + format: int32 + type: integer + tcpKeepalive: + description: If set then set SO_KEEPALIVE on the socket + to enable TCP Keepalives. + properties: + interval: + description: The time duration between keep-alive + probes. + type: string + probes: + type: integer + time: + type: string + type: object + type: object + type: object + loadBalancer: + description: Settings controlling the load balancer algorithms. + oneOf: + - required: + - simple + - properties: + consistentHash: + oneOf: + - required: + - httpHeaderName + - required: + - httpCookie + - required: + - useSourceIp + required: + - consistentHash + properties: + consistentHash: + properties: + httpCookie: + description: Hash based on HTTP cookie. + properties: + name: + description: Name of the cookie. + format: string + type: string + path: + description: Path to set for the cookie. + format: string + type: string + ttl: + description: Lifetime of the cookie. + type: string + type: object + httpHeaderName: + description: Hash based on a specific HTTP header. + format: string + type: string + minimumRingSize: + type: integer + useSourceIp: + description: Hash based on the source IP address. + type: boolean + type: object + localityLbSetting: + properties: + distribute: + description: 'Optional: only one of distribute or + failover can be set.' + items: + properties: + from: + description: Originating locality, '/' separated, + e.g. + format: string + type: string + to: + additionalProperties: + type: integer + description: Map of upstream localities to traffic + distribution weights. + type: object + type: object + type: array + enabled: + description: enable locality load balancing, this + is DestinationRule-level and will override mesh + wide settings in entirety. + type: boolean + failover: + description: 'Optional: only failover or distribute + can be set.' + items: + properties: + from: + description: Originating region. + format: string + type: string + to: + format: string + type: string + type: object + type: array + type: object + simple: + enum: + - ROUND_ROBIN + - LEAST_CONN + - RANDOM + - PASSTHROUGH + type: string + type: object + outlierDetection: + properties: + baseEjectionTime: + description: Minimum ejection duration. + type: string + consecutive5xxErrors: + description: Number of 5xx errors before a host is ejected + from the connection pool. + type: integer + consecutiveErrors: + format: int32 + type: integer + consecutiveGatewayErrors: + description: Number of gateway errors before a host is + ejected from the connection pool. + type: integer + interval: + description: Time interval between ejection sweep analysis. + type: string + maxEjectionPercent: + format: int32 + type: integer + minHealthPercent: + format: int32 + type: integer + type: object + port: + properties: + number: + type: integer + type: object + tls: + description: TLS related settings for connections to the upstream + service. + properties: + caCertificates: + format: string + type: string + clientCertificate: + description: REQUIRED if mode is `MUTUAL`. + format: string + type: string + mode: + enum: + - DISABLE + - SIMPLE + - MUTUAL + - ISTIO_MUTUAL + type: string + privateKey: + description: REQUIRED if mode is `MUTUAL`. + format: string + type: string + sni: + description: SNI string to present to the server during + TLS handshake. + format: string + type: string + subjectAltNames: + items: + format: string + type: string + type: array + type: object + type: object + type: array + tls: + description: TLS related settings for connections to the upstream + service. + properties: + caCertificates: + format: string + type: string + clientCertificate: + description: REQUIRED if mode is `MUTUAL`. + format: string + type: string + mode: + enum: + - DISABLE + - SIMPLE + - MUTUAL + - ISTIO_MUTUAL + type: string + privateKey: + description: REQUIRED if mode is `MUTUAL`. + format: string + type: string + sni: + description: SNI string to present to the server during TLS + handshake. + format: string + type: string + subjectAltNames: + items: + format: string + type: string + type: array + type: object + type: object + type: object + type: object + versions: + - name: v1alpha3 + served: true + storage: true + - name: v1beta1 + served: true + storage: false + +--- +apiVersion: apiextensions.k8s.io/v1beta1 +kind: CustomResourceDefinition +metadata: + annotations: + "helm.sh/resource-policy": keep + labels: + app: istio-pilot + chart: istio + heritage: Tiller + release: istio + name: envoyfilters.networking.istio.io +spec: + group: networking.istio.io + names: + categories: + - istio-io + - networking-istio-io + kind: EnvoyFilter + listKind: EnvoyFilterList + plural: envoyfilters + singular: envoyfilter + scope: Namespaced + subresources: + status: {} + validation: + openAPIV3Schema: + properties: + spec: + description: 'Customizing Envoy configuration generated by Istio. See more + details at: https://istio.io/docs/reference/config/networking/envoy-filter.html' + properties: + configPatches: + description: One or more patches with match conditions. + items: + properties: + applyTo: + enum: + - INVALID + - LISTENER + - FILTER_CHAIN + - NETWORK_FILTER + - HTTP_FILTER + - ROUTE_CONFIGURATION + - VIRTUAL_HOST + - HTTP_ROUTE + - CLUSTER + type: string + match: + description: Match on listener/route configuration/cluster. + oneOf: + - required: + - listener + - required: + - routeConfiguration + - required: + - cluster + properties: + cluster: + description: Match on envoy cluster attributes. + properties: + name: + description: The exact name of the cluster to match. + format: string + type: string + portNumber: + description: The service port for which this cluster was + generated. + type: integer + service: + description: The fully qualified service name for this + cluster. + format: string + type: string + subset: + description: The subset associated with the service. + format: string + type: string + type: object + context: + description: The specific config generation context to match + on. + enum: + - ANY + - SIDECAR_INBOUND + - SIDECAR_OUTBOUND + - GATEWAY + type: string + listener: + description: Match on envoy listener attributes. + properties: + filterChain: + description: Match a specific filter chain in a listener. + properties: + applicationProtocols: + description: Applies only to sidecars. + format: string + type: string + filter: + description: The name of a specific filter to apply + the patch to. + properties: + name: + description: The filter name to match on. + format: string + type: string + subFilter: + properties: + name: + description: The filter name to match on. + format: string + type: string + type: object + type: object + name: + description: The name assigned to the filter chain. + format: string + type: string + sni: + description: The SNI value used by a filter chain's + match condition. + format: string + type: string + transportProtocol: + description: Applies only to SIDECAR_INBOUND context. + format: string + type: string + type: object + name: + description: Match a specific listener by its name. + format: string + type: string + portName: + format: string + type: string + portNumber: + type: integer + type: object + proxy: + description: Match on properties associated with a proxy. + properties: + metadata: + additionalProperties: + format: string + type: string + type: object + proxyVersion: + format: string + type: string + type: object + routeConfiguration: + description: Match on envoy HTTP route configuration attributes. + properties: + gateway: + format: string + type: string + name: + description: Route configuration name to match on. + format: string + type: string + portName: + description: Applicable only for GATEWAY context. + format: string + type: string + portNumber: + type: integer + vhost: + properties: + name: + format: string + type: string + route: + description: Match a specific route within the virtual + host. + properties: + action: + description: Match a route with specific action + type. + enum: + - ANY + - ROUTE + - REDIRECT + - DIRECT_RESPONSE + type: string + name: + format: string + type: string + type: object + type: object + type: object + type: object + patch: + description: The patch to apply along with the operation. + properties: + operation: + description: Determines how the patch should be applied. + enum: + - INVALID + - MERGE + - ADD + - REMOVE + - INSERT_BEFORE + - INSERT_AFTER + - INSERT_FIRST + type: string + value: + description: The JSON config of the object being patched. + type: object + type: object + type: object + type: array + filters: + items: + properties: + filterConfig: + type: object + filterName: + description: The name of the filter to instantiate. + format: string + type: string + filterType: + description: The type of filter to instantiate. + enum: + - INVALID + - HTTP + - NETWORK + type: string + insertPosition: + description: Insert position in the filter chain. + properties: + index: + description: Position of this filter in the filter chain. + enum: + - FIRST + - LAST + - BEFORE + - AFTER + type: string + relativeTo: + format: string + type: string + type: object + listenerMatch: + properties: + address: + description: One or more IP addresses to which the listener + is bound. + items: + format: string + type: string + type: array + listenerProtocol: + description: Selects a class of listeners for the same protocol. + enum: + - ALL + - HTTP + - TCP + type: string + listenerType: + description: Inbound vs outbound sidecar listener or gateway + listener. + enum: + - ANY + - SIDECAR_INBOUND + - SIDECAR_OUTBOUND + - GATEWAY + type: string + portNamePrefix: + format: string + type: string + portNumber: + type: integer + type: object + type: object + type: array + workloadLabels: + additionalProperties: + format: string + type: string + description: Deprecated. + type: object + workloadSelector: + properties: + labels: + additionalProperties: + format: string + type: string + type: object + type: object + type: object + type: object + versions: + - name: v1alpha3 + served: true + storage: true + +--- +apiVersion: apiextensions.k8s.io/v1beta1 +kind: CustomResourceDefinition +metadata: + annotations: + "helm.sh/resource-policy": keep + labels: + app: istio-pilot + chart: istio + heritage: Tiller + release: istio + name: gateways.networking.istio.io +spec: + group: networking.istio.io + names: + categories: + - istio-io + - networking-istio-io + kind: Gateway + listKind: GatewayList + plural: gateways + shortNames: + - gw + singular: gateway + scope: Namespaced + subresources: + status: {} + validation: + openAPIV3Schema: + properties: + spec: + description: 'Configuration affecting edge load balancer. See more details + at: https://istio.io/docs/reference/config/networking/gateway.html' + properties: + selector: + additionalProperties: + format: string + type: string + type: object + servers: + description: A list of server specifications. + items: + properties: + bind: + format: string + type: string + defaultEndpoint: + format: string + type: string + hosts: + description: One or more hosts exposed by this gateway. + items: + format: string + type: string + type: array + port: + properties: + name: + description: Label assigned to the port. + format: string + type: string + number: + description: A valid non-negative integer port number. + type: integer + protocol: + description: The protocol exposed on the port. + format: string + type: string + type: object + tls: + description: Set of TLS related options that govern the server's + behavior. + properties: + caCertificates: + description: REQUIRED if mode is `MUTUAL`. + format: string + type: string + cipherSuites: + description: 'Optional: If specified, only support the specified + cipher list.' + items: + format: string + type: string + type: array + credentialName: + format: string + type: string + httpsRedirect: + type: boolean + maxProtocolVersion: + description: 'Optional: Maximum TLS protocol version.' + enum: + - TLS_AUTO + - TLSV1_0 + - TLSV1_1 + - TLSV1_2 + - TLSV1_3 + type: string + minProtocolVersion: + description: 'Optional: Minimum TLS protocol version.' + enum: + - TLS_AUTO + - TLSV1_0 + - TLSV1_1 + - TLSV1_2 + - TLSV1_3 + type: string + mode: + enum: + - PASSTHROUGH + - SIMPLE + - MUTUAL + - AUTO_PASSTHROUGH + - ISTIO_MUTUAL + type: string + privateKey: + description: REQUIRED if mode is `SIMPLE` or `MUTUAL`. + format: string + type: string + serverCertificate: + description: REQUIRED if mode is `SIMPLE` or `MUTUAL`. + format: string + type: string + subjectAltNames: + items: + format: string + type: string + type: array + verifyCertificateHash: + items: + format: string + type: string + type: array + verifyCertificateSpki: + items: + format: string + type: string + type: array + type: object + type: object + type: array + type: object + type: object + versions: + - name: v1alpha3 + served: true + storage: true + - name: v1beta1 + served: true + storage: false + +--- +apiVersion: apiextensions.k8s.io/v1beta1 +kind: CustomResourceDefinition +metadata: + annotations: + "helm.sh/resource-policy": keep + labels: + app: istio-pilot + chart: istio + heritage: Tiller + release: istio + name: serviceentries.networking.istio.io +spec: + additionalPrinterColumns: + - JSONPath: .spec.hosts + description: The hosts associated with the ServiceEntry + name: Hosts + type: string + - JSONPath: .spec.location + description: Whether the service is external to the mesh or part of the mesh (MESH_EXTERNAL + or MESH_INTERNAL) + name: Location + type: string + - JSONPath: .spec.resolution + description: Service discovery mode for the hosts (NONE, STATIC, or DNS) + name: Resolution + type: string + - JSONPath: .metadata.creationTimestamp + description: 'CreationTimestamp is a timestamp representing the server time when + this object was created. It is not guaranteed to be set in happens-before order + across separate operations. Clients may not set this value. It is represented + in RFC3339 form and is in UTC. Populated by the system. Read-only. Null for + lists. More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#metadata' + name: Age + type: date + group: networking.istio.io + names: + categories: + - istio-io + - networking-istio-io + kind: ServiceEntry + listKind: ServiceEntryList + plural: serviceentries + shortNames: + - se + singular: serviceentry + scope: Namespaced + subresources: + status: {} + validation: + openAPIV3Schema: + properties: + spec: + description: 'Configuration affecting service registry. See more details + at: https://istio.io/docs/reference/config/networking/service-entry.html' + properties: + addresses: + description: The virtual IP addresses associated with the service. + items: + format: string + type: string + type: array + endpoints: + description: One or more endpoints associated with the service. + items: + properties: + address: + format: string + type: string + labels: + additionalProperties: + format: string + type: string + description: One or more labels associated with the endpoint. + type: object + locality: + description: The locality associated with the endpoint. + format: string + type: string + network: + format: string + type: string + ports: + additionalProperties: + type: integer + description: Set of ports associated with the endpoint. + type: object + weight: + description: The load balancing weight associated with the endpoint. + type: integer + type: object + type: array + exportTo: + description: A list of namespaces to which this service is exported. + items: + format: string + type: string + type: array + hosts: + description: The hosts associated with the ServiceEntry. + items: + format: string + type: string + type: array + location: + enum: + - MESH_EXTERNAL + - MESH_INTERNAL + type: string + ports: + description: The ports associated with the external service. + items: + properties: + name: + description: Label assigned to the port. + format: string + type: string + number: + description: A valid non-negative integer port number. + type: integer + protocol: + description: The protocol exposed on the port. + format: string + type: string + type: object + type: array + resolution: + description: Service discovery mode for the hosts. + enum: + - NONE + - STATIC + - DNS + type: string + subjectAltNames: + items: + format: string + type: string + type: array + type: object + type: object + versions: + - name: v1alpha3 + served: true + storage: true + - name: v1beta1 + served: true + storage: false + +--- +apiVersion: apiextensions.k8s.io/v1beta1 +kind: CustomResourceDefinition +metadata: + annotations: + "helm.sh/resource-policy": keep + labels: + app: istio-pilot + chart: istio + heritage: Tiller + release: istio + name: sidecars.networking.istio.io +spec: + group: networking.istio.io + names: + categories: + - istio-io + - networking-istio-io + kind: Sidecar + listKind: SidecarList + plural: sidecars + singular: sidecar + scope: Namespaced + subresources: + status: {} + validation: + openAPIV3Schema: + properties: + spec: + description: 'Configuration affecting network reachability of a sidecar. + See more details at: https://istio.io/docs/reference/config/networking/sidecar.html' + properties: + egress: + items: + properties: + bind: + format: string + type: string + captureMode: + enum: + - DEFAULT + - IPTABLES + - NONE + type: string + hosts: + items: + format: string + type: string + type: array + port: + description: The port associated with the listener. + properties: + name: + description: Label assigned to the port. + format: string + type: string + number: + description: A valid non-negative integer port number. + type: integer + protocol: + description: The protocol exposed on the port. + format: string + type: string + type: object + type: object + type: array + ingress: + items: + properties: + bind: + description: The IP to which the listener should be bound. + format: string + type: string + captureMode: + enum: + - DEFAULT + - IPTABLES + - NONE + type: string + defaultEndpoint: + format: string + type: string + port: + description: The port associated with the listener. + properties: + name: + description: Label assigned to the port. + format: string + type: string + number: + description: A valid non-negative integer port number. + type: integer + protocol: + description: The protocol exposed on the port. + format: string + type: string + type: object + type: object + type: array + outboundTrafficPolicy: + description: This allows to configure the outbound traffic policy. + properties: + mode: + enum: + - REGISTRY_ONLY + - ALLOW_ANY + type: string + type: object + workloadSelector: + properties: + labels: + additionalProperties: + format: string + type: string + type: object + type: object + type: object + type: object + versions: + - name: v1alpha3 + served: true + storage: true + - name: v1beta1 + served: true + storage: false + +--- +apiVersion: apiextensions.k8s.io/v1beta1 +kind: CustomResourceDefinition +metadata: + annotations: + "helm.sh/resource-policy": keep + labels: + app: istio-pilot + chart: istio + heritage: Tiller + release: istio + name: virtualservices.networking.istio.io +spec: + additionalPrinterColumns: + - JSONPath: .spec.gateways + description: The names of gateways and sidecars that should apply these routes + name: Gateways + type: string + - JSONPath: .spec.hosts + description: The destination hosts to which traffic is being sent + name: Hosts + type: string + - JSONPath: .metadata.creationTimestamp + description: 'CreationTimestamp is a timestamp representing the server time when + this object was created. It is not guaranteed to be set in happens-before order + across separate operations. Clients may not set this value. It is represented + in RFC3339 form and is in UTC. Populated by the system. Read-only. Null for + lists. More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#metadata' + name: Age + type: date + group: networking.istio.io + names: + categories: + - istio-io + - networking-istio-io + kind: VirtualService + listKind: VirtualServiceList + plural: virtualservices + shortNames: + - vs + singular: virtualservice + scope: Namespaced + subresources: + status: {} + validation: + openAPIV3Schema: + properties: + spec: + description: 'Configuration affecting label/content routing, sni routing, + etc. See more details at: https://istio.io/docs/reference/config/networking/virtual-service.html' + properties: + exportTo: + description: A list of namespaces to which this virtual service is exported. + items: + format: string + type: string + type: array + gateways: + description: The names of gateways and sidecars that should apply these + routes. + items: + format: string + type: string + type: array + hosts: + description: The destination hosts to which traffic is being sent. + items: + format: string + type: string + type: array + http: + description: An ordered list of route rules for HTTP traffic. + items: + properties: + corsPolicy: + description: Cross-Origin Resource Sharing policy (CORS). + properties: + allowCredentials: + type: boolean + allowHeaders: + items: + format: string + type: string + type: array + allowMethods: + description: List of HTTP methods allowed to access the resource. + items: + format: string + type: string + type: array + allowOrigin: + description: The list of origins that are allowed to perform + CORS requests. + items: + format: string + type: string + type: array + allowOrigins: + description: String patterns that match allowed origins. + items: + oneOf: + - required: + - exact + - required: + - prefix + - required: + - regex + properties: + exact: + format: string + type: string + prefix: + format: string + type: string + regex: + format: string + type: string + type: object + type: array + exposeHeaders: + items: + format: string + type: string + type: array + maxAge: + type: string + type: object + fault: + description: Fault injection policy to apply on HTTP traffic at + the client side. + properties: + abort: + oneOf: + - required: + - httpStatus + - required: + - grpcStatus + - required: + - http2Error + properties: + grpcStatus: + format: string + type: string + http2Error: + format: string + type: string + httpStatus: + description: HTTP status code to use to abort the Http + request. + format: int32 + type: integer + percentage: + description: Percentage of requests to be aborted with + the error code provided. + properties: + value: + format: double + type: number + type: object + type: object + delay: + oneOf: + - properties: + percent: {} + required: + - fixedDelay + - properties: + percent: {} + required: + - exponentialDelay + properties: + exponentialDelay: + type: string + fixedDelay: + description: Add a fixed delay before forwarding the request. + type: string + percent: + description: Percentage of requests on which the delay + will be injected (0-100). + format: int32 + type: integer + percentage: + description: Percentage of requests on which the delay + will be injected. + properties: + value: + format: double + type: number + type: object + type: object + type: object + headers: + properties: + request: + properties: + add: + additionalProperties: + format: string + type: string + type: object + remove: + items: + format: string + type: string + type: array + set: + additionalProperties: + format: string + type: string + type: object + type: object + response: + properties: + add: + additionalProperties: + format: string + type: string + type: object + remove: + items: + format: string + type: string + type: array + set: + additionalProperties: + format: string + type: string + type: object + type: object + type: object + match: + items: + properties: + authority: + oneOf: + - required: + - exact + - required: + - prefix + - required: + - regex + properties: + exact: + format: string + type: string + prefix: + format: string + type: string + regex: + format: string + type: string + type: object + gateways: + description: Names of gateways where the rule should be + applied. + items: + format: string + type: string + type: array + headers: + additionalProperties: + oneOf: + - required: + - exact + - required: + - prefix + - required: + - regex + properties: + exact: + format: string + type: string + prefix: + format: string + type: string + regex: + format: string + type: string + type: object + type: object + ignoreUriCase: + description: Flag to specify whether the URI matching should + be case-insensitive. + type: boolean + method: + oneOf: + - required: + - exact + - required: + - prefix + - required: + - regex + properties: + exact: + format: string + type: string + prefix: + format: string + type: string + regex: + format: string + type: string + type: object + name: + description: The name assigned to a match. + format: string + type: string + port: + description: Specifies the ports on the host that is being + addressed. + type: integer + queryParams: + additionalProperties: + oneOf: + - required: + - exact + - required: + - prefix + - required: + - regex + properties: + exact: + format: string + type: string + prefix: + format: string + type: string + regex: + format: string + type: string + type: object + description: Query parameters for matching. + type: object + scheme: + oneOf: + - required: + - exact + - required: + - prefix + - required: + - regex + properties: + exact: + format: string + type: string + prefix: + format: string + type: string + regex: + format: string + type: string + type: object + sourceLabels: + additionalProperties: + format: string + type: string + type: object + uri: + oneOf: + - required: + - exact + - required: + - prefix + - required: + - regex + properties: + exact: + format: string + type: string + prefix: + format: string + type: string + regex: + format: string + type: string + type: object + type: object + type: array + mirror: + properties: + host: + description: The name of a service from the service registry. + format: string + type: string + port: + description: Specifies the port on the host that is being + addressed. + properties: + number: + type: integer + type: object + subset: + description: The name of a subset within the service. + format: string + type: string + type: object + mirror_percent: + description: Percentage of the traffic to be mirrored by the `mirror` + field. + type: integer + mirrorPercent: + description: Percentage of the traffic to be mirrored by the `mirror` + field. + type: integer + mirrorPercentage: + description: Percentage of the traffic to be mirrored by the `mirror` + field. + properties: + value: + format: double + type: number + type: object + name: + description: The name assigned to the route for debugging purposes. + format: string + type: string + redirect: + description: A HTTP rule can either redirect or forward (default) + traffic. + properties: + authority: + format: string + type: string + redirectCode: + type: integer + uri: + format: string + type: string + type: object + retries: + description: Retry policy for HTTP requests. + properties: + attempts: + description: Number of retries for a given request. + format: int32 + type: integer + perTryTimeout: + description: Timeout per retry attempt for a given request. + type: string + retryOn: + description: Specifies the conditions under which retry takes + place. + format: string + type: string + type: object + rewrite: + description: Rewrite HTTP URIs and Authority headers. + properties: + authority: + description: rewrite the Authority/Host header with this value. + format: string + type: string + uri: + format: string + type: string + type: object + route: + description: A HTTP rule can either redirect or forward (default) + traffic. + items: + properties: + destination: + properties: + host: + description: The name of a service from the service + registry. + format: string + type: string + port: + description: Specifies the port on the host that is + being addressed. + properties: + number: + type: integer + type: object + subset: + description: The name of a subset within the service. + format: string + type: string + type: object + headers: + properties: + request: + properties: + add: + additionalProperties: + format: string + type: string + type: object + remove: + items: + format: string + type: string + type: array + set: + additionalProperties: + format: string + type: string + type: object + type: object + response: + properties: + add: + additionalProperties: + format: string + type: string + type: object + remove: + items: + format: string + type: string + type: array + set: + additionalProperties: + format: string + type: string + type: object + type: object + type: object + weight: + format: int32 + type: integer + type: object + type: array + timeout: + description: Timeout for HTTP requests. + type: string + type: object + type: array + tcp: + description: An ordered list of route rules for opaque TCP traffic. + items: + properties: + match: + items: + properties: + destinationSubnets: + description: IPv4 or IPv6 ip addresses of destination with + optional subnet. + items: + format: string + type: string + type: array + gateways: + description: Names of gateways where the rule should be + applied. + items: + format: string + type: string + type: array + port: + description: Specifies the port on the host that is being + addressed. + type: integer + sourceLabels: + additionalProperties: + format: string + type: string + type: object + sourceSubnet: + description: IPv4 or IPv6 ip address of source with optional + subnet. + format: string + type: string + type: object + type: array + route: + description: The destination to which the connection should be + forwarded to. + items: + properties: + destination: + properties: + host: + description: The name of a service from the service + registry. + format: string + type: string + port: + description: Specifies the port on the host that is + being addressed. + properties: + number: + type: integer + type: object + subset: + description: The name of a subset within the service. + format: string + type: string + type: object + weight: + format: int32 + type: integer + type: object + type: array + type: object + type: array + tls: + items: + properties: + match: + items: + properties: + destinationSubnets: + description: IPv4 or IPv6 ip addresses of destination with + optional subnet. + items: + format: string + type: string + type: array + gateways: + description: Names of gateways where the rule should be + applied. + items: + format: string + type: string + type: array + port: + description: Specifies the port on the host that is being + addressed. + type: integer + sniHosts: + description: SNI (server name indicator) to match on. + items: + format: string + type: string + type: array + sourceLabels: + additionalProperties: + format: string + type: string + type: object + type: object + type: array + route: + description: The destination to which the connection should be + forwarded to. + items: + properties: + destination: + properties: + host: + description: The name of a service from the service + registry. + format: string + type: string + port: + description: Specifies the port on the host that is + being addressed. + properties: + number: + type: integer + type: object + subset: + description: The name of a subset within the service. + format: string + type: string + type: object + weight: + format: int32 + type: integer + type: object + type: array + type: object + type: array + type: object + type: object + versions: + - name: v1alpha3 + served: true + storage: true + - name: v1beta1 + served: true + storage: false + +--- +apiVersion: apiextensions.k8s.io/v1beta1 +kind: CustomResourceDefinition +metadata: + annotations: + "helm.sh/resource-policy": keep + labels: + app: mixer + chart: istio + heritage: Tiller + istio: core + package: istio.io.mixer + release: istio + name: attributemanifests.config.istio.io +spec: + group: config.istio.io + names: + categories: + - istio-io + - policy-istio-io + kind: attributemanifest + listKind: attributemanifestList + plural: attributemanifests + singular: attributemanifest + scope: Namespaced + subresources: + status: {} + validation: + openAPIV3Schema: + properties: + spec: + description: 'Describes the rules used to configure Mixer''s policy and + telemetry features. See more details at: https://istio.io/docs/reference/config/policy-and-telemetry/istio.policy.v1beta1.html' + properties: + attributes: + additionalProperties: + properties: + description: + description: A human-readable description of the attribute's purpose. + format: string + type: string + valueType: + description: The type of data carried by this attribute. + enum: + - VALUE_TYPE_UNSPECIFIED + - STRING + - INT64 + - DOUBLE + - BOOL + - TIMESTAMP + - IP_ADDRESS + - EMAIL_ADDRESS + - URI + - DNS_NAME + - DURATION + - STRING_MAP + type: string + type: object + description: The set of attributes this Istio component will be responsible + for producing at runtime. + type: object + name: + description: Name of the component producing these attributes. + format: string + type: string + revision: + description: The revision of this document. + format: string + type: string + type: object + type: object + versions: + - name: v1alpha2 + served: true + storage: true + +--- +apiVersion: apiextensions.k8s.io/v1beta1 +kind: CustomResourceDefinition +metadata: + annotations: + "helm.sh/resource-policy": keep + labels: + app: mixer + chart: istio + heritage: Tiller + istio: mixer-handler + package: handler + release: istio + name: handlers.config.istio.io +spec: + group: config.istio.io + names: + categories: + - istio-io + - policy-istio-io + kind: handler + listKind: handlerList + plural: handlers + singular: handler + scope: Namespaced + subresources: + status: {} + validation: + openAPIV3Schema: + properties: + spec: + description: Handler allows the operator to configure a specific adapter + implementation. + properties: + adapter: + description: The name of a specific adapter implementation. + format: string + type: string + compiledAdapter: + description: The name of the compiled in adapter this handler instantiates. + format: string + type: string + connection: + description: Information on how to connect to the out-of-process adapter. + properties: + address: + description: The address of the backend. + format: string + type: string + authentication: + description: Auth config for the connection to the backend. + oneOf: + - properties: + tls: + allOf: + - oneOf: + - required: + - tokenPath + - required: + - oauth + - oneOf: + - required: + - authHeader + - required: + - customHeader + required: + - tls + - required: + - mutual + properties: + mutual: + properties: + caCertificates: + format: string + type: string + clientCertificate: + description: The path to the file holding client certificate + for mutual TLS. + format: string + type: string + privateKey: + description: The path to the file holding the private key + for mutual TLS. + format: string + type: string + serverName: + description: Used to configure mixer mutual TLS client to + supply server name for SNI. + format: string + type: string + type: object + tls: + properties: + authHeader: + description: Access token is passed as authorization header. + enum: + - PLAIN + - BEARER + type: string + caCertificates: + format: string + type: string + customHeader: + description: Customized header key to hold access token, + e.g. + format: string + type: string + oauth: + description: Oauth config to fetch access token from auth + provider. + properties: + clientId: + description: OAuth client id for mixer. + format: string + type: string + clientSecret: + description: The path to the file holding the client + secret for oauth. + format: string + type: string + endpointParams: + additionalProperties: + format: string + type: string + description: Additional parameters for requests to the + token endpoint. + type: object + scopes: + description: List of requested permissions. + items: + format: string + type: string + type: array + tokenUrl: + description: The Resource server's token endpoint URL. + format: string + type: string + type: object + serverName: + format: string + type: string + tokenPath: + format: string + type: string + type: object + type: object + timeout: + description: Timeout for remote calls to the backend. + type: string + type: object + name: + description: Must be unique in the entire Mixer configuration. + format: string + type: string + params: + description: Depends on adapter implementation. + type: object + type: object + type: object + versions: + - name: v1alpha2 + served: true + storage: true + +--- +apiVersion: apiextensions.k8s.io/v1beta1 +kind: CustomResourceDefinition +metadata: + annotations: + "helm.sh/resource-policy": keep + labels: + app: mixer + chart: istio + heritage: Tiller + istio: mixer-instance + package: instance + release: istio + name: instances.config.istio.io +spec: + group: config.istio.io + names: + categories: + - istio-io + - policy-istio-io + kind: instance + listKind: instanceList + plural: instances + singular: instance + scope: Namespaced + subresources: + status: {} + validation: + openAPIV3Schema: + properties: + spec: + description: An Instance tells Mixer how to create instances for particular + template. + properties: + attributeBindings: + additionalProperties: + format: string + type: string + type: object + compiledTemplate: + description: The name of the compiled in template this instance creates + instances for. + format: string + type: string + name: + format: string + type: string + params: + description: Depends on referenced template. + type: object + template: + description: The name of the template this instance creates instances + for. + format: string + type: string + type: object + type: object + versions: + - name: v1alpha2 + served: true + storage: true + +--- +apiVersion: apiextensions.k8s.io/v1beta1 +kind: CustomResourceDefinition +metadata: + annotations: + "helm.sh/resource-policy": keep + labels: + app: mixer + chart: istio + heritage: Tiller + istio: core + package: istio.io.mixer + release: istio + name: rules.config.istio.io +spec: + group: config.istio.io + names: + categories: + - istio-io + - policy-istio-io + kind: rule + listKind: ruleList + plural: rules + singular: rule + scope: Namespaced + subresources: + status: {} + validation: + openAPIV3Schema: + properties: + spec: + description: 'Describes the rules used to configure Mixer''s policy and + telemetry features. See more details at: https://istio.io/docs/reference/config/policy-and-telemetry/istio.policy.v1beta1.html' + properties: + actions: + description: The actions that will be executed when match evaluates + to `true`. + items: + properties: + handler: + description: Fully qualified name of the handler to invoke. + format: string + type: string + instances: + items: + format: string + type: string + type: array + name: + description: A handle to refer to the results of the action. + format: string + type: string + type: object + type: array + match: + description: Match is an attribute based predicate. + format: string + type: string + requestHeaderOperations: + items: + properties: + name: + description: Header name literal value. + format: string + type: string + operation: + description: Header operation type. + enum: + - REPLACE + - REMOVE + - APPEND + type: string + values: + description: Header value expressions. + items: + format: string + type: string + type: array + type: object + type: array + responseHeaderOperations: + items: + properties: + name: + description: Header name literal value. + format: string + type: string + operation: + description: Header operation type. + enum: + - REPLACE + - REMOVE + - APPEND + type: string + values: + description: Header value expressions. + items: + format: string + type: string + type: array + type: object + type: array + sampling: + properties: + random: + description: Provides filtering of actions based on random selection + per request. + properties: + attributeExpression: + description: Specifies an attribute expression to use to override + the numerator in the `percent_sampled` field. + format: string + type: string + percentSampled: + description: The default sampling rate, expressed as a percentage. + properties: + denominator: + description: Specifies the denominator. + enum: + - HUNDRED + - TEN_THOUSAND + type: string + numerator: + description: Specifies the numerator. + type: integer + type: object + useIndependentRandomness: + description: By default sampling will be based on the value + of the request header `x-request-id`. + type: boolean + type: object + rateLimit: + properties: + maxUnsampledEntries: + description: Number of entries to allow during the `sampling_duration` + before sampling is enforced. + format: int64 + type: integer + samplingDuration: + description: Window in which to enforce the sampling rate. + type: string + samplingRate: + description: The rate at which to sample entries once the unsampled + limit has been reached. + format: int64 + type: integer + type: object + type: object + type: object + type: object + versions: + - name: v1alpha2 + served: true + storage: true + +--- +apiVersion: apiextensions.k8s.io/v1beta1 +kind: CustomResourceDefinition +metadata: + annotations: + "helm.sh/resource-policy": keep + labels: + app: istio-pilot + chart: istio + heritage: Tiller + istio: rbac + release: istio + name: clusterrbacconfigs.rbac.istio.io +spec: + group: rbac.istio.io + names: + categories: + - istio-io + - rbac-istio-io + kind: ClusterRbacConfig + listKind: ClusterRbacConfigList + plural: clusterrbacconfigs + singular: clusterrbacconfig + scope: Cluster + subresources: + status: {} + validation: + openAPIV3Schema: + properties: + spec: + description: 'Configuration for Role Based Access Control. See more details + at: https://istio.io/docs/reference/config/security/istio.rbac.v1alpha1.html' + properties: + enforcementMode: + enum: + - ENFORCED + - PERMISSIVE + type: string + exclusion: + description: A list of services or namespaces that should not be enforced + by Istio RBAC policies. + properties: + namespaces: + description: A list of namespaces. + items: + format: string + type: string + type: array + services: + description: A list of services. + items: + format: string + type: string + type: array + type: object + inclusion: + description: A list of services or namespaces that should be enforced + by Istio RBAC policies. + properties: + namespaces: + description: A list of namespaces. + items: + format: string + type: string + type: array + services: + description: A list of services. + items: + format: string + type: string + type: array + type: object + mode: + description: Istio RBAC mode. + enum: + - "OFF" + - "ON" + - ON_WITH_INCLUSION + - ON_WITH_EXCLUSION + type: string + type: object + type: object + versions: + - name: v1alpha1 + served: true + storage: true + +--- +apiVersion: apiextensions.k8s.io/v1beta1 +kind: CustomResourceDefinition +metadata: + annotations: + "helm.sh/resource-policy": keep + labels: + app: mixer + chart: istio + heritage: Tiller + istio: rbac + package: istio.io.mixer + release: istio + name: rbacconfigs.rbac.istio.io +spec: + group: rbac.istio.io + names: + categories: + - istio-io + - rbac-istio-io + kind: RbacConfig + listKind: RbacConfigList + plural: rbacconfigs + singular: rbacconfig + scope: Namespaced + subresources: + status: {} + validation: + openAPIV3Schema: + properties: + spec: + description: 'Configuration for Role Based Access Control. See more details + at: https://istio.io/docs/reference/config/security/istio.rbac.v1alpha1.html' + properties: + enforcementMode: + enum: + - ENFORCED + - PERMISSIVE + type: string + exclusion: + description: A list of services or namespaces that should not be enforced + by Istio RBAC policies. + properties: + namespaces: + description: A list of namespaces. + items: + format: string + type: string + type: array + services: + description: A list of services. + items: + format: string + type: string + type: array + type: object + inclusion: + description: A list of services or namespaces that should be enforced + by Istio RBAC policies. + properties: + namespaces: + description: A list of namespaces. + items: + format: string + type: string + type: array + services: + description: A list of services. + items: + format: string + type: string + type: array + type: object + mode: + description: Istio RBAC mode. + enum: + - "OFF" + - "ON" + - ON_WITH_INCLUSION + - ON_WITH_EXCLUSION + type: string + type: object + type: object + versions: + - name: v1alpha1 + served: true + storage: true + +--- +apiVersion: apiextensions.k8s.io/v1beta1 +kind: CustomResourceDefinition +metadata: + annotations: + "helm.sh/resource-policy": keep + labels: + app: mixer + chart: istio + heritage: Tiller + istio: rbac + package: istio.io.mixer + release: istio + name: serviceroles.rbac.istio.io +spec: + group: rbac.istio.io + names: + categories: + - istio-io + - rbac-istio-io + kind: ServiceRole + listKind: ServiceRoleList + plural: serviceroles + singular: servicerole + scope: Namespaced + subresources: + status: {} + validation: + openAPIV3Schema: + properties: + spec: + description: 'Configuration for Role Based Access Control. See more details + at: https://istio.io/docs/reference/config/security/istio.rbac.v1alpha1.html' + properties: + rules: + description: The set of access rules (permissions) that the role has. + items: + properties: + constraints: + description: Optional. + items: + properties: + key: + description: Key of the constraint. + format: string + type: string + values: + description: List of valid values for the constraint. + items: + format: string + type: string + type: array + type: object + type: array + hosts: + items: + format: string + type: string + type: array + methods: + description: Optional. + items: + format: string + type: string + type: array + notHosts: + items: + format: string + type: string + type: array + notMethods: + items: + format: string + type: string + type: array + notPaths: + items: + format: string + type: string + type: array + notPorts: + items: + format: int32 + type: integer + type: array + paths: + description: Optional. + items: + format: string + type: string + type: array + ports: + items: + format: int32 + type: integer + type: array + services: + description: A list of service names. + items: + format: string + type: string + type: array + type: object + type: array + type: object + type: object + versions: + - name: v1alpha1 + served: true + storage: true + +--- +apiVersion: apiextensions.k8s.io/v1beta1 +kind: CustomResourceDefinition +metadata: + annotations: + "helm.sh/resource-policy": keep + labels: + app: mixer + chart: istio + heritage: Tiller + istio: rbac + package: istio.io.mixer + release: istio + name: servicerolebindings.rbac.istio.io +spec: + additionalPrinterColumns: + - JSONPath: .spec.roleRef.name + description: The name of the ServiceRole object being referenced + name: Reference + type: string + - JSONPath: .metadata.creationTimestamp + description: 'CreationTimestamp is a timestamp representing the server time when + this object was created. It is not guaranteed to be set in happens-before order + across separate operations. Clients may not set this value. It is represented + in RFC3339 form and is in UTC. Populated by the system. Read-only. Null for + lists. More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#metadata' + name: Age + type: date + group: rbac.istio.io + names: + categories: + - istio-io + - rbac-istio-io + kind: ServiceRoleBinding + listKind: ServiceRoleBindingList + plural: servicerolebindings + singular: servicerolebinding + scope: Namespaced + subresources: + status: {} + validation: + openAPIV3Schema: + properties: + spec: + description: 'Configuration for Role Based Access Control. See more details + at: https://istio.io/docs/reference/config/security/istio.rbac.v1alpha1.html' + properties: + actions: + items: + properties: + constraints: + description: Optional. + items: + properties: + key: + description: Key of the constraint. + format: string + type: string + values: + description: List of valid values for the constraint. + items: + format: string + type: string + type: array + type: object + type: array + hosts: + items: + format: string + type: string + type: array + methods: + description: Optional. + items: + format: string + type: string + type: array + notHosts: + items: + format: string + type: string + type: array + notMethods: + items: + format: string + type: string + type: array + notPaths: + items: + format: string + type: string + type: array + notPorts: + items: + format: int32 + type: integer + type: array + paths: + description: Optional. + items: + format: string + type: string + type: array + ports: + items: + format: int32 + type: integer + type: array + services: + description: A list of service names. + items: + format: string + type: string + type: array + type: object + type: array + mode: + enum: + - ENFORCED + - PERMISSIVE + type: string + role: + format: string + type: string + roleRef: + description: Reference to the ServiceRole object. + properties: + kind: + description: The type of the role being referenced. + format: string + type: string + name: + description: The name of the ServiceRole object being referenced. + format: string + type: string + type: object + subjects: + description: List of subjects that are assigned the ServiceRole object. + items: + properties: + group: + format: string + type: string + groups: + items: + format: string + type: string + type: array + ips: + items: + format: string + type: string + type: array + names: + items: + format: string + type: string + type: array + namespaces: + items: + format: string + type: string + type: array + notGroups: + items: + format: string + type: string + type: array + notIps: + items: + format: string + type: string + type: array + notNames: + items: + format: string + type: string + type: array + notNamespaces: + items: + format: string + type: string + type: array + properties: + additionalProperties: + format: string + type: string + description: Optional. + type: object + user: + description: Optional. + format: string + type: string + type: object + type: array + type: object + type: object + versions: + - name: v1alpha1 + served: true + storage: true + +--- +apiVersion: apiextensions.k8s.io/v1beta1 +kind: CustomResourceDefinition +metadata: + annotations: + "helm.sh/resource-policy": keep + labels: + app: istio-pilot + chart: istio + heritage: Tiller + istio: security + release: istio + name: authorizationpolicies.security.istio.io +spec: + group: security.istio.io + names: + categories: + - istio-io + - security-istio-io + kind: AuthorizationPolicy + listKind: AuthorizationPolicyList + plural: authorizationpolicies + singular: authorizationpolicy + scope: Namespaced + subresources: + status: {} + validation: + openAPIV3Schema: + properties: + spec: + description: 'Configuration for access control on workloads. See more details + at: https://istio.io/docs/reference/config/security/authorization-policy.html' + properties: + action: + description: Optional. + enum: + - ALLOW + - DENY + type: string + rules: + description: Optional. + items: + properties: + from: + description: Optional. + items: + properties: + source: + description: Source specifies the source of a request. + properties: + ipBlocks: + description: Optional. + items: + format: string + type: string + type: array + namespaces: + description: Optional. + items: + format: string + type: string + type: array + notIpBlocks: + description: Optional. + items: + format: string + type: string + type: array + notNamespaces: + description: Optional. + items: + format: string + type: string + type: array + notPrincipals: + description: Optional. + items: + format: string + type: string + type: array + notRequestPrincipals: + description: Optional. + items: + format: string + type: string + type: array + principals: + description: Optional. + items: + format: string + type: string + type: array + requestPrincipals: + description: Optional. + items: + format: string + type: string + type: array + type: object + type: object + type: array + to: + description: Optional. + items: + properties: + operation: + description: Operation specifies the operation of a request. + properties: + hosts: + description: Optional. + items: + format: string + type: string + type: array + methods: + description: Optional. + items: + format: string + type: string + type: array + notHosts: + description: Optional. + items: + format: string + type: string + type: array + notMethods: + description: Optional. + items: + format: string + type: string + type: array + notPaths: + description: Optional. + items: + format: string + type: string + type: array + notPorts: + description: Optional. + items: + format: string + type: string + type: array + paths: + description: Optional. + items: + format: string + type: string + type: array + ports: + description: Optional. + items: + format: string + type: string + type: array + type: object + type: object + type: array + when: + description: Optional. + items: + properties: + key: + description: The name of an Istio attribute. + format: string + type: string + notValues: + description: Optional. + items: + format: string + type: string + type: array + values: + description: Optional. + items: + format: string + type: string + type: array + type: object + type: array + type: object + type: array + selector: + description: Optional. + properties: + matchLabels: + additionalProperties: + format: string + type: string + type: object + type: object + type: object + type: object + versions: + - name: v1beta1 + served: true + storage: true + +--- +apiVersion: apiextensions.k8s.io/v1beta1 +kind: CustomResourceDefinition +metadata: + annotations: + "helm.sh/resource-policy": keep + labels: + app: istio-pilot + chart: istio + heritage: Tiller + istio: security + release: istio + name: peerauthentications.security.istio.io +spec: + group: security.istio.io + names: + categories: + - istio-io + - security-istio-io + kind: PeerAuthentication + listKind: PeerAuthenticationList + plural: peerauthentications + singular: peerauthentication + scope: Namespaced + subresources: + status: {} + validation: + openAPIV3Schema: + properties: + spec: + description: PeerAuthentication defines how traffic will be tunneled (or + not) to the sidecar. + properties: + mtls: + description: Mutual TLS settings for workload. + properties: + mode: + description: Defines the mTLS mode used for peer authentication. + enum: + - UNSET + - DISABLE + - PERMISSIVE + - STRICT + type: string + type: object + portLevelMtls: + additionalProperties: + properties: + mode: + description: Defines the mTLS mode used for peer authentication. + enum: + - UNSET + - DISABLE + - PERMISSIVE + - STRICT + type: string + type: object + description: Port specific mutual TLS settings. + type: object + selector: + description: The selector determines the workloads to apply the ChannelAuthentication + on. + properties: + matchLabels: + additionalProperties: + format: string + type: string + type: object + type: object + type: object + type: object + versions: + - name: v1beta1 + served: true + storage: true + +--- +apiVersion: apiextensions.k8s.io/v1beta1 +kind: CustomResourceDefinition +metadata: + annotations: + "helm.sh/resource-policy": keep + labels: + app: istio-pilot + chart: istio + heritage: Tiller + istio: security + release: istio + name: requestauthentications.security.istio.io +spec: + group: security.istio.io + names: + categories: + - istio-io + - security-istio-io + kind: RequestAuthentication + listKind: RequestAuthenticationList + plural: requestauthentications + singular: requestauthentication + scope: Namespaced + subresources: + status: {} + validation: + openAPIV3Schema: + properties: + spec: + description: RequestAuthentication defines what request authentication methods + are supported by a workload. + properties: + jwtRules: + description: Define the list of JWTs that can be validated at the selected + workloads' proxy. + items: + properties: + audiences: + items: + format: string + type: string + type: array + forwardOriginalToken: + description: If set to true, the orginal token will be kept for + the ustream request. + type: boolean + fromHeaders: + description: List of header locations from which JWT is expected. + items: + properties: + name: + description: The HTTP header name. + format: string + type: string + prefix: + description: The prefix that should be stripped before decoding + the token. + format: string + type: string + type: object + type: array + fromParams: + description: List of query parameters from which JWT is expected. + items: + format: string + type: string + type: array + issuer: + description: Identifies the issuer that issued the JWT. + format: string + type: string + jwks: + description: JSON Web Key Set of public keys to validate signature + of the JWT. + format: string + type: string + jwks_uri: + format: string + type: string + jwksUri: + format: string + type: string + outputPayloadToHeader: + format: string + type: string + type: object + type: array + selector: + description: The selector determines the workloads to apply the RequestAuthentication + on. + properties: + matchLabels: + additionalProperties: + format: string + type: string + type: object + type: object + type: object + type: object + versions: + - name: v1beta1 + served: true + storage: true + +--- diff --git a/istio-1.5.0/install/kubernetes/operator/charts/base/files/crd-mixer.yaml b/istio-1.5.0/install/kubernetes/operator/charts/base/files/crd-mixer.yaml new file mode 100644 index 0000000..89588fe --- /dev/null +++ b/istio-1.5.0/install/kubernetes/operator/charts/base/files/crd-mixer.yaml @@ -0,0 +1,60 @@ +kind: CustomResourceDefinition +apiVersion: apiextensions.k8s.io/v1beta1 +metadata: + name: adapters.config.istio.io + labels: + app: mixer + package: adapter + istio: mixer-adapter + chart: istio + heritage: Tiller + release: istio + annotations: + "helm.sh/resource-policy": keep +spec: + group: config.istio.io + names: + kind: adapter + plural: adapters + singular: adapter + categories: + - istio-io + - policy-istio-io + scope: Namespaced + subresources: + status: {} + versions: + - name: v1alpha2 + served: true + storage: true +--- +kind: CustomResourceDefinition +apiVersion: apiextensions.k8s.io/v1beta1 +metadata: + name: templates.config.istio.io + labels: + app: mixer + package: template + istio: mixer-template + chart: istio + heritage: Tiller + release: istio + annotations: + "helm.sh/resource-policy": keep +spec: + group: config.istio.io + names: + kind: template + plural: templates + singular: template + categories: + - istio-io + - policy-istio-io + scope: Namespaced + subresources: + status: {} + versions: + - name: v1alpha2 + served: true + storage: true +--- diff --git a/istio-1.5.0/install/kubernetes/operator/charts/base/kustomization.yaml b/istio-1.5.0/install/kubernetes/operator/charts/base/kustomization.yaml new file mode 100644 index 0000000..4548a36 --- /dev/null +++ b/istio-1.5.0/install/kubernetes/operator/charts/base/kustomization.yaml @@ -0,0 +1,6 @@ +apiVersion: kustomize.config.k8s.io/v1beta1 +kind: Kustomization + +resources: + - files/crd-all.gen.yaml + - files/crd-mixer.yaml diff --git a/istio-1.5.0/install/kubernetes/operator/charts/base/templates/clusterrole.yaml b/istio-1.5.0/install/kubernetes/operator/charts/base/templates/clusterrole.yaml new file mode 100644 index 0000000..d123ddc --- /dev/null +++ b/istio-1.5.0/install/kubernetes/operator/charts/base/templates/clusterrole.yaml @@ -0,0 +1,25 @@ +{{ if .Values.clusterResources }} +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: istio-reader-{{ .Release.Namespace }} + labels: + app: istio-reader + release: {{ .Release.Name }} +rules: +- apiGroups: + - "config.istio.io" + - "rbac.istio.io" + - "security.istio.io" + - "networking.istio.io" + - "authentication.istio.io" + resources: ["*"] + verbs: ["get", "list", "watch"] +- apiGroups: [""] + resources: ["endpoints", "pods", "services", "nodes", "replicationcontrollers"] + verbs: ["get", "list", "watch"] +- apiGroups: ["apps"] + resources: ["replicasets"] + verbs: ["get", "list", "watch"] +--- +{{ end }} \ No newline at end of file diff --git a/istio-1.5.0/install/kubernetes/operator/charts/base/templates/clusterrolebinding.yaml b/istio-1.5.0/install/kubernetes/operator/charts/base/templates/clusterrolebinding.yaml new file mode 100644 index 0000000..f77efb2 --- /dev/null +++ b/istio-1.5.0/install/kubernetes/operator/charts/base/templates/clusterrolebinding.yaml @@ -0,0 +1,18 @@ +{{ if .Values.clusterResources }} +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: istio-reader-{{ .Release.Namespace }} + labels: + app: istio-reader + release: {{ .Release.Name }} +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: istio-reader-{{ .Release.Namespace }} +subjects: + - kind: ServiceAccount + name: istio-reader-service-account + namespace: {{ .Release.Namespace }} +--- +{{ end }} diff --git a/istio-1.5.0/install/kubernetes/operator/charts/base/templates/crds.yaml b/istio-1.5.0/install/kubernetes/operator/charts/base/templates/crds.yaml new file mode 100644 index 0000000..429baa3 --- /dev/null +++ b/istio-1.5.0/install/kubernetes/operator/charts/base/templates/crds.yaml @@ -0,0 +1,2 @@ +{{ .Files.Get "files/crd-all.gen.yaml" }} +{{ .Files.Get "files/crd-mixer.yaml" }} diff --git a/istio-1.5.0/install/kubernetes/operator/charts/base/templates/endpoints.yaml b/istio-1.5.0/install/kubernetes/operator/charts/base/templates/endpoints.yaml new file mode 100644 index 0000000..c9495fd --- /dev/null +++ b/istio-1.5.0/install/kubernetes/operator/charts/base/templates/endpoints.yaml @@ -0,0 +1,72 @@ +{{- if or .Values.global.remotePilotCreateSvcEndpoint .Values.global.createRemoteSvcEndpoints }} +apiVersion: v1 +kind: Endpoints +metadata: + name: istio-pilot + namespace: {{ .Release.Namespace }} +subsets: +- addresses: + - ip: {{ .Values.global.remotePilotAddress }} + ports: + - port: 15010 + name: grpc-xds # direct + - port: 15011 + name: https-xds # mTLS or non-mTLS depending on auth setting + - port: 8080 + name: http-legacy-discovery # direct + - port: 15012 + name: http-istiod + - port: 15014 + name: http-monitoring +--- +apiVersion: v1 +kind: Endpoints +metadata: + name: istiod + namespace: {{ .Release.Namespace }} +subsets: +- addresses: + - ip: {{ .Values.global.remotePilotAddress }} + ports: + - port: 15012 + name: http-istiod +{{- end }} + +{{- if and .Values.global.remotePolicyAddress .Values.global.createRemoteSvcEndpoints }} +--- +apiVersion: v1 +kind: Endpoints +metadata: + name: istio-policy + namespace: {{ .Release.Namespace }} +subsets: +- addresses: + - ip: {{ .Values.global.remotePolicyAddress }} + ports: + - name: grpc-mixer + port: 9091 + - name: grpc-mixer-mtls + port: 15004 + - name: http-monitoring + port: 15014 +{{- end }} +{{- if and .Values.global.remoteTelemetryAddress .Values.global.createRemoteSvcEndpoints }} +--- +apiVersion: v1 +kind: Endpoints +metadata: + name: istio-telemetry + namespace: {{ .Release.Namespace }} +subsets: +- addresses: + - ip: {{ .Values.global.remoteTelemetryAddress }} + ports: + - name: grpc-mixer + port: 9091 + - name: grpc-mixer-mtls + port: 15004 + - name: http-monitoring + port: 15014 + - name: prometheus + port: 42422 +{{- end }} diff --git a/istio-1.5.0/install/kubernetes/operator/charts/base/templates/namespaces.yaml b/istio-1.5.0/install/kubernetes/operator/charts/base/templates/namespaces.yaml new file mode 100644 index 0000000..65759a6 --- /dev/null +++ b/istio-1.5.0/install/kubernetes/operator/charts/base/templates/namespaces.yaml @@ -0,0 +1,64 @@ +# To prevent accidental injection into istio control plane namespaces. +apiVersion: v1 +kind: Namespace +metadata: + name: {{ .Release.Namespace }} + labels: + istio-operator-managed: Reconcile + istio-injection: disabled +--- + +{{- if ne .Values.global.istioNamespace .Release.Namespace }} +apiVersion: v1 +kind: Namespace +metadata: + name: {{ .Values.global.istioNamespace }} + labels: + istio-operator-managed: Reconcile + istio-injection: disabled +--- +{{- end }} + +{{- if and (ne .Values.global.configNamespace .Release.Namespace) (ne .Values.global.configNamespace .Values.global.istioNamespace) }} +apiVersion: v1 +kind: Namespace +metadata: + name: {{ .Values.global.configNamespace }} + labels: + istio-operator-managed: Reconcile + istio-injection: disabled +--- +{{- end }} + +{{- if ne .Values.global.telemetryNamespace .Release.Namespace }} +apiVersion: v1 +kind: Namespace +metadata: + name: {{ .Values.global.telemetryNamespace }} + labels: + istio-operator-managed: Reconcile + istio-injection: disabled +--- +{{- end }} + +{{- if and (ne .Values.global.prometheusNamespace .Release.Namespace) (ne .Values.global.prometheusNamespace .Values.global.telemetryNamespace) }} +apiVersion: v1 +kind: Namespace +metadata: + name: {{ .Values.global.prometheusNamespace }} + labels: + istio-operator-managed: Reconcile + istio-injection: disabled +--- +{{- end }} + +{{- if ne .Values.global.policyNamespace .Release.Namespace }} +apiVersion: v1 +kind: Namespace +metadata: + name: {{ .Values.global.policyNamespace }} + labels: + istio-operator-managed: Reconcile + istio-injection: disabled +--- +{{- end }} diff --git a/istio-1.5.0/install/kubernetes/operator/charts/base/templates/serviceaccount.yaml b/istio-1.5.0/install/kubernetes/operator/charts/base/templates/serviceaccount.yaml new file mode 100644 index 0000000..82abed6 --- /dev/null +++ b/istio-1.5.0/install/kubernetes/operator/charts/base/templates/serviceaccount.yaml @@ -0,0 +1,17 @@ +{{ if .Values.clusterResources }} +apiVersion: v1 +kind: ServiceAccount +{{- if .Values.global.imagePullSecrets }} +imagePullSecrets: +{{- range .Values.global.imagePullSecrets }} + - name: {{ . }} +{{- end }} +{{- end }} +metadata: + name: istio-reader-service-account + namespace: {{ .Release.Namespace }} + labels: + app: istio-reader + release: {{ .Release.Name }} +--- +{{ end }} diff --git a/istio-1.5.0/install/kubernetes/operator/charts/base/templates/services.yaml b/istio-1.5.0/install/kubernetes/operator/charts/base/templates/services.yaml new file mode 100644 index 0000000..93ce2c9 --- /dev/null +++ b/istio-1.5.0/install/kubernetes/operator/charts/base/templates/services.yaml @@ -0,0 +1,67 @@ +{{- if or .Values.global.remotePilotCreateSvcEndpoint .Values.global.createRemoteSvcEndpoints }} +apiVersion: v1 +kind: Service +metadata: + name: istio-pilot + namespace: {{ .Release.Namespace }} +spec: + ports: + - port: 15010 + name: grpc-xds # direct + - port: 15011 + name: https-xds # mTLS or non-mTLS depending on auth setting + - port: 8080 + name: http-legacy-discovery # direct + - port: 15012 + name: http-istiod + - port: 15014 + name: http-monitoring + clusterIP: None +--- +apiVersion: v1 +kind: Service +metadata: + name: istiod + namespace: {{ .Release.Namespace }} +spec: + ports: + - port: 15012 + name: http-istiod +--- +{{- end }} +{{- if and .Values.global.remotePolicyAddress .Values.global.createRemoteSvcEndpoints }} +apiVersion: v1 +kind: Service +metadata: + name: istio-policy + namespace: {{ .Release.Namespace }} +spec: + ports: + - name: grpc-mixer + port: 9091 + - name: grpc-mixer-mtls + port: 15004 + - name: http-monitoring + port: 15014 + clusterIP: None +--- +{{- end }} +{{- if and .Values.global.remoteTelemetryAddress .Values.global.createRemoteSvcEndpoints }} +apiVersion: v1 +kind: Service +metadata: + name: istio-telemetry + namespace: {{ .Release.Namespace }} +spec: + ports: + - name: grpc-mixer + port: 9091 + - name: grpc-mixer-mtls + port: 15004 + - name: http-monitoring + port: 15014 + - name: prometheus + port: 42422 + clusterIP: None +--- +{{- end }} diff --git a/istio-1.5.0/install/kubernetes/operator/charts/base/values.yaml b/istio-1.5.0/install/kubernetes/operator/charts/base/values.yaml new file mode 100644 index 0000000..e69de29 diff --git a/istio-1.5.0/install/kubernetes/operator/charts/gateways/istio-egress/Chart.yaml b/istio-1.5.0/install/kubernetes/operator/charts/gateways/istio-egress/Chart.yaml new file mode 100644 index 0000000..f6c62e5 --- /dev/null +++ b/istio-1.5.0/install/kubernetes/operator/charts/gateways/istio-egress/Chart.yaml @@ -0,0 +1,13 @@ +apiVersion: v1 +name: istio-egress +version: 1.1.0 +tillerVersion: ">=2.7.2" +description: Helm chart for deploying Istio gateways +keywords: + - istio + - egressgateway + - gateways +sources: + - http://github.com/istio/istio +engine: gotpl +icon: https://istio.io/favicons/android-192x192.png diff --git a/istio-1.5.0/install/kubernetes/operator/charts/gateways/istio-egress/NOTES.txt b/istio-1.5.0/install/kubernetes/operator/charts/gateways/istio-egress/NOTES.txt new file mode 100644 index 0000000..9baacc0 --- /dev/null +++ b/istio-1.5.0/install/kubernetes/operator/charts/gateways/istio-egress/NOTES.txt @@ -0,0 +1,45 @@ + +Changes: +- separate namespace allows: +-- easier reconfig of just the gateway +-- TLS secrets and domain name management is isolated, for better security +-- simplified configuration +-- multiple versions of the ingress can be used, to minize upgrade risks + +- the new chart uses the default namespace service account, and doesn't require +additional RBAC permissions. + +- simplified label structure. Label change is not supported on upgrade. + +- for 'internal load balancer' you should deploy a separate gateway, in a different +namespace. + +All ingress gateway have a "app:ingressgateway" label, used to identify it as an +ingress, and an "istio: ingressgateway$SUFFIX" label of Gateway selection. + +The Gateways use "istio: ingressgateway$SUFFIX" selectors. + + +# Multiple gateway versions + + + +# Using different pilot versions + + + +# Migration from istio-system + +Istio 1.0 includes the gateways in istio-system. Since the external IP is associated +with the Service and bound to the namespace, it is recommended to: + +1. Install the new gateway in a new namespace. +2. Copy any TLS certificate to the new namespace, and configure the domains. +3. Checking the new gateway work - for example by overriding the IP in /etc/hosts +4. Modify the DNS server to add the A record of the new namespace +5. Check traffic +6. Delete the A record corresponding to the gateway in istio-system +7. Upgrade istio-system, disabling the ingressgateway +8. Delete the domain TLS certs from istio-system. + +If using certmanager, all Certificate and associated configs must be moved as well. diff --git a/istio-1.5.0/install/kubernetes/operator/charts/gateways/istio-egress/templates/_affinity.tpl b/istio-1.5.0/install/kubernetes/operator/charts/gateways/istio-egress/templates/_affinity.tpl new file mode 100644 index 0000000..5335b59 --- /dev/null +++ b/istio-1.5.0/install/kubernetes/operator/charts/gateways/istio-egress/templates/_affinity.tpl @@ -0,0 +1,93 @@ +{{/* affinity - https://kubernetes.io/docs/concepts/configuration/assign-pod-node/ */}} + +{{- define "nodeaffinity" }} + nodeAffinity: + requiredDuringSchedulingIgnoredDuringExecution: + {{- include "nodeAffinityRequiredDuringScheduling" . }} + preferredDuringSchedulingIgnoredDuringExecution: + {{- include "nodeAffinityPreferredDuringScheduling" . }} +{{- end }} + +{{- define "nodeAffinityRequiredDuringScheduling" }} + nodeSelectorTerms: + - matchExpressions: + - key: beta.kubernetes.io/arch + operator: In + values: + {{- range $key, $val := .global.arch }} + {{- if gt ($val | int) 0 }} + - {{ $key | quote }} + {{- end }} + {{- end }} + {{- $nodeSelector := default .global.defaultNodeSelector .nodeSelector -}} + {{- range $key, $val := $nodeSelector }} + - key: {{ $key }} + operator: In + values: + - {{ $val | quote }} + {{- end }} +{{- end }} + +{{- define "nodeAffinityPreferredDuringScheduling" }} + {{- range $key, $val := .global.arch }} + {{- if gt ($val | int) 0 }} + - weight: {{ $val | int }} + preference: + matchExpressions: + - key: beta.kubernetes.io/arch + operator: In + values: + - {{ $key | quote }} + {{- end }} + {{- end }} +{{- end }} + +{{- define "podAntiAffinity" }} +{{- if or .podAntiAffinityLabelSelector .podAntiAffinityTermLabelSelector}} + podAntiAffinity: + {{- if .podAntiAffinityLabelSelector }} + requiredDuringSchedulingIgnoredDuringExecution: + {{- include "podAntiAffinityRequiredDuringScheduling" . }} + {{- end }} + {{- if .podAntiAffinityTermLabelSelector }} + preferredDuringSchedulingIgnoredDuringExecution: + {{- include "podAntiAffinityPreferredDuringScheduling" . }} + {{- end }} +{{- end }} +{{- end }} + +{{- define "podAntiAffinityRequiredDuringScheduling" }} + {{- range $index, $item := .podAntiAffinityLabelSelector }} + - labelSelector: + matchExpressions: + - key: {{ $item.key }} + operator: {{ $item.operator }} + {{- if $item.values }} + values: + {{- $vals := split "," $item.values }} + {{- range $i, $v := $vals }} + - {{ $v | quote }} + {{- end }} + {{- end }} + topologyKey: {{ $item.topologyKey }} + {{- end }} +{{- end }} + +{{- define "podAntiAffinityPreferredDuringScheduling" }} + {{- range $index, $item := .podAntiAffinityTermLabelSelector }} + - podAffinityTerm: + labelSelector: + matchExpressions: + - key: {{ $item.key }} + operator: {{ $item.operator }} + {{- if $item.values }} + values: + {{- $vals := split "," $item.values }} + {{- range $i, $v := $vals }} + - {{ $v | quote }} + {{- end }} + {{- end }} + topologyKey: {{ $item.topologyKey }} + weight: 100 + {{- end }} +{{- end }} diff --git a/istio-1.5.0/install/kubernetes/operator/charts/gateways/istio-egress/templates/_helpers.tpl b/istio-1.5.0/install/kubernetes/operator/charts/gateways/istio-egress/templates/_helpers.tpl new file mode 100644 index 0000000..54735a2 --- /dev/null +++ b/istio-1.5.0/install/kubernetes/operator/charts/gateways/istio-egress/templates/_helpers.tpl @@ -0,0 +1,34 @@ +{{/* vim: set filetype=mustache: */}} +{{/* +Expand the name of the chart. +*/}} +{{- define "gateway.name" -}} +{{ $gateway := index .Values "gateways" "istio-egressgateway" }} +{{- default .Chart.Name $gateway.nameOverride | trunc 63 | trimSuffix "-" -}} +{{- end -}} + +{{/* +Create a default fully qualified app name. +We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). +If release name contains chart name it will be used as a full name. +*/}} +{{- define "gateway.fullname" -}} +{{ $gateway := index .Values "gateways" "istio-egressgateway" }} +{{- if $gateway.fullnameOverride -}} +{{- $gateway.fullnameOverride | trunc 63 | trimSuffix "-" -}} +{{- else -}} +{{- $name := default .Chart.Name $gateway.nameOverride -}} +{{- if contains $name .Release.Name -}} +{{- .Release.Name | trunc 63 | trimSuffix "-" -}} +{{- else -}} +{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" -}} +{{- end -}} +{{- end -}} +{{- end -}} + +{{/* +Create chart name and version as used by the chart label. +*/}} +{{- define "gateway.chart" -}} +{{- .Chart.Name | trunc 63 | trimSuffix "-" -}} +{{- end -}} diff --git a/istio-1.5.0/install/kubernetes/operator/charts/gateways/istio-egress/templates/autoscale.yaml b/istio-1.5.0/install/kubernetes/operator/charts/gateways/istio-egress/templates/autoscale.yaml new file mode 100644 index 0000000..282a714 --- /dev/null +++ b/istio-1.5.0/install/kubernetes/operator/charts/gateways/istio-egress/templates/autoscale.yaml @@ -0,0 +1,24 @@ +{{ $gateway := index .Values "gateways" "istio-egressgateway" }} +{{- if and $gateway.autoscaleEnabled $gateway.autoscaleMin $gateway.autoscaleMax }} +apiVersion: autoscaling/v2beta1 +kind: HorizontalPodAutoscaler +metadata: + name: istio-egressgateway + namespace: {{ .Release.Namespace }} + labels: +{{ $gateway.labels | toYaml | indent 4 }} + release: {{ .Release.Name }} +spec: + maxReplicas: {{ $gateway.autoscaleMax }} + minReplicas: {{ $gateway.autoscaleMin }} + scaleTargetRef: + apiVersion: apps/v1 + kind: Deployment + name: istio-egressgateway + metrics: + - type: Resource + resource: + name: cpu + targetAverageUtilization: {{ $gateway.cpu.targetAverageUtilization }} +--- +{{- end }} diff --git a/istio-1.5.0/install/kubernetes/operator/charts/gateways/istio-egress/templates/deployment.yaml b/istio-1.5.0/install/kubernetes/operator/charts/gateways/istio-egress/templates/deployment.yaml new file mode 100644 index 0000000..d92799e --- /dev/null +++ b/istio-1.5.0/install/kubernetes/operator/charts/gateways/istio-egress/templates/deployment.yaml @@ -0,0 +1,314 @@ +{{ $gateway := index .Values "gateways" "istio-egressgateway" }} +apiVersion: apps/v1 +kind: Deployment +metadata: + name: istio-egressgateway + namespace: {{ .Release.Namespace }} + labels: +{{ $gateway.labels | toYaml | indent 4 }} + release: {{ .Release.Name }} +spec: +{{- if not $gateway.autoscaleEnabled }} +{{- if $gateway.replicaCount }} + replicas: {{ $gateway.replicaCount }} +{{- end }} +{{- end }} + selector: + matchLabels: +{{ $gateway.labels | toYaml | indent 6 }} + strategy: + rollingUpdate: + maxSurge: {{ $gateway.rollingMaxSurge }} + maxUnavailable: {{ $gateway.rollingMaxUnavailable }} + template: + metadata: + labels: +{{ $gateway.labels | toYaml | indent 8 }} +{{- if eq .Release.Namespace "istio-system"}} + heritage: Tiller + release: istio + chart: gateways +{{- end }} + service.istio.io/canonical-name: istio-egressgateway + service.istio.io/canonical-revision: "1.5" + annotations: + sidecar.istio.io/inject: "false" +{{- if $gateway.podAnnotations }} +{{ toYaml $gateway.podAnnotations | indent 8 }} +{{ end }} + spec: + serviceAccountName: istio-egressgateway-service-account +{{- if .Values.global.priorityClassName }} + priorityClassName: "{{ .Values.global.priorityClassName }}" +{{- end }} +{{- if .Values.global.proxy.enableCoreDump }} + initContainers: + - name: enable-core-dump +{{- if contains "/" .Values.global.proxy_init.image }} + image: "{{ .Values.global.proxy_init.image }}" +{{- else }} + image: "{{ .Values.global.hub }}/{{ .Values.global.proxy_init.image | default "proxy_init" }}:{{ .Values.global.tag }}" +{{- end }} + imagePullPolicy: {{ .Values.global.imagePullPolicy | default "Always" }} + command: + - /bin/sh + args: + - -c + - sysctl -w kernel.core_pattern=/var/lib/istio/core.proxy && ulimit -c unlimited + securityContext: + privileged: true +{{- end }} + containers: + - name: istio-proxy +{{- if contains "/" .Values.global.proxy.image }} + image: "{{ .Values.global.proxy.image }}" +{{- else }} + image: "{{ .Values.global.hub }}/{{ .Values.global.proxy.image }}:{{ .Values.global.tag }}" +{{- end }} + imagePullPolicy: {{ .Values.global.imagePullPolicy | default "Always" }} + ports: + {{- range $key, $val := $gateway.ports }} + - containerPort: {{ $val.port }} + {{- end }} + - containerPort: 15090 + protocol: TCP + name: http-envoy-prom + args: + - proxy + - router + - --domain + - $(POD_NAMESPACE).svc.{{ .Values.global.proxy.clusterDomain }} + {{- if .Values.global.proxy.logLevel }} + - --proxyLogLevel={{ .Values.global.proxy.logLevel }} + {{- end}} + {{- if .Values.global.proxy.componentLogLevel }} + - --proxyComponentLogLevel={{ .Values.global.proxy.componentLogLevel }} + {{- end}} + {{- if .Values.global.logging.level }} + - --log_output_level={{ .Values.global.logging.level }} + {{- end}} + {{- if .Values.global.logAsJson }} + - --log_as_json + {{- end }} + - --drainDuration + - '45s' #drainDuration + - --parentShutdownDuration + - '1m0s' #parentShutdownDuration + - --connectTimeout + - '10s' #connectTimeout + - --serviceCluster + - istio-egressgateway + - --zipkinAddress + {{- if .Values.global.tracer.zipkin.address }} + - {{ .Values.global.tracer.zipkin.address }} + {{- else if .Values.global.telemetryNamespace }} + - zipkin.{{ .Values.global.telemetryNamespace }}:9411 + {{- else }} + - zipkin:9411 + {{- end }} + - --proxyAdminPort + - "15000" + - --statusPort + - "15020" + {{- if .Values.global.sts.servicePort }} + - --stsPort={{ .Values.global.sts.servicePort }} + {{- end }} + {{- if .Values.global.istiod.enabled }} + - --controlPlaneAuthPolicy + - NONE + - --discoveryAddress + {{- if .Values.global.configNamespace }} + - istio-pilot.{{ .Values.global.configNamespace }}.svc:15012 + {{- else }} + - istio-pilot.istio-system.svc:15012 + {{- end }} + {{- else if .Values.global.controlPlaneSecurityEnabled }} + - --controlPlaneAuthPolicy + - MUTUAL_TLS + - --discoveryAddress + {{- if .Values.global.configNamespace }} + - istio-pilot.{{ .Values.global.configNamespace }}:15011 + {{- else }} + - istio-pilot:15011 + {{- end }} + {{- else }} + - --controlPlaneAuthPolicy + - NONE + - --discoveryAddress + {{- if .Values.global.configNamespace }} + - istio-pilot.{{ .Values.global.configNamespace }}:15010 + {{- else }} + - istio-pilot:15010 + {{- end }} + {{- end }} + {{- if .Values.global.trustDomain }} + - --trust-domain={{ .Values.global.trustDomain }} + {{- end }} + readinessProbe: + failureThreshold: 30 + httpGet: + path: /healthz/ready + port: 15020 + scheme: HTTP + initialDelaySeconds: 1 + periodSeconds: 2 + successThreshold: 1 + timeoutSeconds: 1 + resources: +{{- if $gateway.resources }} +{{ toYaml $gateway.resources | indent 12 }} +{{- else }} +{{ toYaml .Values.global.defaultResources | indent 12 }} +{{- end }} + env: + - name: JWT_POLICY + value: {{ .Values.global.jwtPolicy }} + - name: PILOT_CERT_PROVIDER + value: {{ .Values.global.pilotCertProvider }} + - name: NODE_NAME + valueFrom: + fieldRef: + apiVersion: v1 + fieldPath: spec.nodeName + - name: POD_NAME + valueFrom: + fieldRef: + apiVersion: v1 + fieldPath: metadata.name + - name: POD_NAMESPACE + valueFrom: + fieldRef: + apiVersion: v1 + fieldPath: metadata.namespace + - name: INSTANCE_IP + valueFrom: + fieldRef: + apiVersion: v1 + fieldPath: status.podIP + - name: HOST_IP + valueFrom: + fieldRef: + apiVersion: v1 + fieldPath: status.hostIP + - name: SERVICE_ACCOUNT + valueFrom: + fieldRef: + fieldPath: spec.serviceAccountName + - name: ISTIO_META_WORKLOAD_NAME + value: istio-egressgateway + - name: ISTIO_META_OWNER + value: kubernetes://apis/apps/v1/namespaces/{{ .Release.Namespace }}/deployments/istio-egressgateway + {{- if $.Values.global.meshID }} + - name: ISTIO_META_MESH_ID + value: "{{ $.Values.global.meshID }}" + {{- else if $.Values.global.trustDomain }} + - name: ISTIO_META_MESH_ID + value: "{{ $.Values.global.trustDomain }}" + {{- end }} + {{- if $.Values.global.mtls.auto }} + - name: ISTIO_AUTO_MTLS_ENABLED + value: "true" + {{- end }} + - name: ISTIO_META_POD_NAME + valueFrom: + fieldRef: + apiVersion: v1 + fieldPath: metadata.name + - name: ISTIO_META_CONFIG_NAMESPACE + valueFrom: + fieldRef: + fieldPath: metadata.namespace + {{- if $gateway.env }} + {{- range $key, $val := $gateway.env }} + - name: {{ $key }} + value: {{ $val }} + {{- end }} + {{ end }} +{{- if $gateway.podAnnotations }} + - name: "ISTIO_METAJSON_ANNOTATIONS" + value: | +{{ toJson $gateway.podAnnotations | indent 16}} +{{ end }} + - name: ISTIO_META_CLUSTER_ID + value: "{{ $.Values.global.multiCluster.clusterName | default `Kubernetes` }}" + volumeMounts: + {{- if eq .Values.global.pilotCertProvider "istiod" }} + - mountPath: /var/run/secrets/istio + name: istiod-ca-cert + {{- end }} + {{- if .Values.global.istiod.enabled }} + {{- if eq .Values.global.jwtPolicy "third-party-jwt" }} + - name: istio-token + mountPath: /var/run/secrets/tokens + readOnly: true + {{- end }} + {{- end }} + {{- if .Values.global.mountMtlsCerts }} + - name: istio-certs + mountPath: /etc/certs + readOnly: true + {{- end }} + - name: podinfo + mountPath: /etc/istio/pod + {{- range $gateway.secretVolumes }} + - name: {{ .name }} + mountPath: {{ .mountPath | quote }} + readOnly: true + {{- end }} +{{- if $gateway.additionalContainers }} +{{ toYaml $gateway.additionalContainers | indent 8 }} +{{- end }} + volumes: + {{- if eq .Values.global.pilotCertProvider "istiod" }} + - name: istiod-ca-cert + configMap: + name: istio-ca-root-cert + {{- end }} + - name: podinfo + downwardAPI: + items: + - path: "labels" + fieldRef: + fieldPath: metadata.labels + - path: "annotations" + fieldRef: + fieldPath: metadata.annotations +{{- if .Values.global.istiod.enabled }} +{{- if eq .Values.global.jwtPolicy "third-party-jwt" }} + - name: istio-token + projected: + sources: + - serviceAccountToken: + path: istio-token + expirationSeconds: 43200 + audience: {{ .Values.global.sds.token.aud }} +{{- end }} +{{- end }} + {{- if .Values.global.mountMtlsCerts }} + - name: istio-certs + secret: + secretName: istio.default + optional: true + {{- end }} + {{- range $gateway.secretVolumes }} + - name: {{ .name }} + secret: + secretName: {{ .secretName | quote }} + optional: true + {{- end }} + {{- range $gateway.configVolumes }} + - name: {{ .name }} + configMap: + name: {{ .configMapName | quote }} + optional: true + {{- end }} + affinity: + {{- include "nodeaffinity" (dict "global" .Values.global "nodeSelector" $gateway.nodeSelector) | indent 6 }} + {{- include "podAntiAffinity" $gateway | indent 6 }} +{{- if $gateway.tolerations }} + tolerations: +{{ toYaml $gateway.tolerations | indent 6 }} +{{- else if .Values.global.defaultTolerations }} + tolerations: +{{ toYaml .Values.global.defaultTolerations | indent 6 }} +{{- end }} diff --git a/istio-1.5.0/install/kubernetes/operator/charts/gateways/istio-egress/templates/poddisruptionbudget.yaml b/istio-1.5.0/install/kubernetes/operator/charts/gateways/istio-egress/templates/poddisruptionbudget.yaml new file mode 100644 index 0000000..f8005d7 --- /dev/null +++ b/istio-1.5.0/install/kubernetes/operator/charts/gateways/istio-egress/templates/poddisruptionbudget.yaml @@ -0,0 +1,17 @@ +{{- if .Values.global.defaultPodDisruptionBudget.enabled }} +{{ $gateway := index .Values "gateways" "istio-egressgateway" }} +apiVersion: policy/v1beta1 +kind: PodDisruptionBudget +metadata: + name: istio-egressgateway + namespace: {{ .Release.Namespace }} + labels: +{{ $gateway.labels | toYaml | indent 4 }} + release: {{ .Release.Name }} +spec: + minAvailable: 1 + selector: + matchLabels: +{{ $gateway.labels | toYaml | indent 6 }} + release: {{ .Release.Name }} +{{- end }} diff --git a/istio-1.5.0/install/kubernetes/operator/charts/gateways/istio-egress/templates/preconfigured.yaml b/istio-1.5.0/install/kubernetes/operator/charts/gateways/istio-egress/templates/preconfigured.yaml new file mode 100644 index 0000000..2157f2c --- /dev/null +++ b/istio-1.5.0/install/kubernetes/operator/charts/gateways/istio-egress/templates/preconfigured.yaml @@ -0,0 +1,82 @@ +{{ $gateway := index .Values "gateways" "istio-egressgateway" }} +{{- if $gateway.zvpn.enabled }} +apiVersion: networking.istio.io/v1alpha3 +kind: Gateway +metadata: + name: istio-multicluster-egressgateway + namespace: {{ .Release.Namespace }} + labels: +{{ $gateway.labels | toYaml | indent 4 }} + release: {{ .Release.Name }} +spec: + selector: + istio: egressgateway + servers: + - hosts: + - "*.{{ $gateway.zvpn.suffix }}" + port: + name: tls + number: 15443 + protocol: TLS + tls: {} +--- +apiVersion: networking.istio.io/v1alpha3 +kind: VirtualService +metadata: + name: istio-multicluster-egressgateway + namespace: {{ .Release.Namespace }} + labels: +{{ $gateway.labels | toYaml | indent 4 }} + release: {{ .Release.Name }} +spec: + gateways: + - istio-multicluster-egressgateway + hosts: + - "*.{{ $gateway.zvpn.suffix }}" + tls: + - match: + - port: 15443 + sniHosts: + - "*.{{ $gateway.zvpn.suffix }}" + route: + - destination: + host: non.existent.cluster + port: + number: 15443 + weight: 100 +--- +apiVersion: networking.istio.io/v1alpha3 +kind: EnvoyFilter +metadata: + name: istio-multicluster-egressgateway + namespace: {{ .Release.Namespace }} + labels: +{{ $gateway.labels | toYaml | indent 4 }} + release: {{ .Release.Name }} +spec: + workloadLabels: + istio: egressgateway + filters: + - listenerMatch: + portNumber: 15443 + listenerType: GATEWAY + filterName: envoy.filters.network.sni_cluster + filterType: NETWORK + filterConfig: {} +--- +## To ensure all traffic to *.global is using mTLS +apiVersion: networking.istio.io/v1alpha3 +kind: DestinationRule +metadata: + name: istio-multicluster-egressgateway + namespace: {{ .Release.Namespace }} + labels: +{{ $gateway.labels | toYaml | indent 4 }} + release: {{ .Release.Name }} +spec: + host: "*.{{ $gateway.zvpn.suffix }}" + trafficPolicy: + tls: + mode: ISTIO_MUTUAL +--- +{{- end }} diff --git a/istio-1.5.0/install/kubernetes/operator/charts/gateways/istio-egress/templates/service.yaml b/istio-1.5.0/install/kubernetes/operator/charts/gateways/istio-egress/templates/service.yaml new file mode 100644 index 0000000..5517e75 --- /dev/null +++ b/istio-1.5.0/install/kubernetes/operator/charts/gateways/istio-egress/templates/service.yaml @@ -0,0 +1,25 @@ +{{ $gateway := index .Values "gateways" "istio-egressgateway" }} +apiVersion: v1 +kind: Service +metadata: + name: istio-egressgateway + namespace: {{ .Release.Namespace }} + annotations: + {{- range $key, $val := $gateway.serviceAnnotations }} + {{ $key }}: {{ $val | quote }} + {{- end }} + labels: +{{ $gateway.labels | toYaml | indent 4 }} + release: {{ .Release.Name }} +spec: + type: ClusterIP + selector: +{{ $gateway.labels | toYaml | indent 4 }} + ports: + {{- range $key, $val := $gateway.ports }} + - + {{- range $pkey, $pval := $val }} + {{ $pkey}}: {{ $pval }} + {{- end }} + {{- end }} +--- diff --git a/istio-1.5.0/install/kubernetes/operator/charts/gateways/istio-egress/templates/serviceaccount.yaml b/istio-1.5.0/install/kubernetes/operator/charts/gateways/istio-egress/templates/serviceaccount.yaml new file mode 100644 index 0000000..dd73d72 --- /dev/null +++ b/istio-1.5.0/install/kubernetes/operator/charts/gateways/istio-egress/templates/serviceaccount.yaml @@ -0,0 +1,15 @@ +{{ $gateway := index .Values "gateways" "istio-egressgateway" }} +apiVersion: v1 +kind: ServiceAccount +{{- if .Values.global.imagePullSecrets }} +imagePullSecrets: +{{- range .Values.global.imagePullSecrets }} + - name: {{ . }} +{{- end }} +{{- end }} +metadata: + name: istio-egressgateway-service-account + namespace: {{ .Release.Namespace }} + labels: +{{ $gateway.labels | toYaml | indent 4 }} + release: {{ .Release.Name }} diff --git a/istio-1.5.0/install/kubernetes/operator/charts/gateways/istio-egress/values.yaml b/istio-1.5.0/install/kubernetes/operator/charts/gateways/istio-egress/values.yaml new file mode 100644 index 0000000..5d9dc2c --- /dev/null +++ b/istio-1.5.0/install/kubernetes/operator/charts/gateways/istio-egress/values.yaml @@ -0,0 +1,103 @@ +# Standalone istio egress gateway. +# Should be installed in a separate namespace, to minimize access to config +gateways: + istio-egressgateway: + ports: + - port: 80 + name: http2 + - port: 443 + name: https + # This is the port where sni routing happens + - port: 15443 + targetPort: 15443 + name: tls + + # Enable cross-cluster access using SNI matching. + # Make sure you set suffix if deploying multiple egress gateways. + zvpn: + # Must be different for each egress namespace. + # Used to control the domain name suffix for zero vpn routing. + # Domain names ending with this suffix will be routed to this egress gateway + # automatically. + # This can be a real domain name ( istio.example.com ) + suffix: global + enabled: false + + labels: + app: istio-egressgateway + istio: egressgateway + + + # Scalability tunning + # replicaCount: 1 + rollingMaxSurge: 100% + rollingMaxUnavailable: 25% + autoscaleEnabled: true + autoscaleMin: 1 + autoscaleMax: 5 + resources: + requests: + cpu: 100m + memory: 128Mi + limits: + cpu: 2000m + memory: 1024Mi + cpu: + targetAverageUtilization: 80 + + drainDuration: 45s + connectTimeout: 10s + + serviceAnnotations: {} + podAnnotations: {} + type: ClusterIP # change to NodePort or LoadBalancer if need be + + secretVolumes: + - name: egressgateway-certs + secretName: istio-egressgateway-certs + mountPath: /etc/istio/egressgateway-certs + - name: egressgateway-ca-certs + secretName: istio-egressgateway-ca-certs + mountPath: /etc/istio/egressgateway-ca-certs + + configVolumes: [] + additionalContainers: [] + ### Advanced options ############ + # TODO: convert to real options, env should not be exposed + env: + # Set this to "external" if and only if you want the egress gateway to + # act as a transparent SNI gateway that routes mTLS/TLS traffic to + # external services defined using service entries, where the service + # entry has resolution set to DNS, has one or more endpoints with + # network field set to "external". By default its set to "" so that + # the egress gateway sees the same set of endpoints as the sidecars + # preserving backward compatibility + # ISTIO_META_REQUESTED_NETWORK_VIEW: "" + # A gateway with this mode ensures that pilot generates an additional + # set of clusters for internal services but without Istio mTLS, to + # enable cross cluster routing. + ISTIO_META_ROUTER_MODE: "sni-dnat" + + nodeSelector: {} + tolerations: [] + + # Specify the pod anti-affinity that allows you to constrain which nodes + # your pod is eligible to be scheduled based on labels on pods that are + # already running on the node rather than based on labels on nodes. + # There are currently two types of anti-affinity: + # "requiredDuringSchedulingIgnoredDuringExecution" + # "preferredDuringSchedulingIgnoredDuringExecution" + # which denote "hard" vs. "soft" requirements, you can define your values + # in "podAntiAffinityLabelSelector" and "podAntiAffinityTermLabelSelector" + # correspondingly. + # For example: + # podAntiAffinityLabelSelector: + # - key: security + # operator: In + # values: S1,S2 + # topologyKey: "kubernetes.io/hostname" + # This pod anti-affinity rule says that the pod requires not to be scheduled + # onto a node if that node is already running a pod with label having key + # "security" and value "S1". + podAntiAffinityLabelSelector: [] + podAntiAffinityTermLabelSelector: [] diff --git a/istio-1.5.0/install/kubernetes/operator/charts/gateways/istio-ingress/Chart.yaml b/istio-1.5.0/install/kubernetes/operator/charts/gateways/istio-ingress/Chart.yaml new file mode 100644 index 0000000..3ef0d25 --- /dev/null +++ b/istio-1.5.0/install/kubernetes/operator/charts/gateways/istio-ingress/Chart.yaml @@ -0,0 +1,13 @@ +apiVersion: v1 +name: istio-ingress +version: 1.1.0 +tillerVersion: ">=2.7.2" +description: Helm chart for deploying Istio gateways +keywords: + - istio + - ingressgateway + - gateways +sources: + - http://github.com/istio/istio +engine: gotpl +icon: https://istio.io/favicons/android-192x192.png diff --git a/istio-1.5.0/install/kubernetes/operator/charts/gateways/istio-ingress/NOTES.txt b/istio-1.5.0/install/kubernetes/operator/charts/gateways/istio-ingress/NOTES.txt new file mode 100644 index 0000000..221ee56 --- /dev/null +++ b/istio-1.5.0/install/kubernetes/operator/charts/gateways/istio-ingress/NOTES.txt @@ -0,0 +1,43 @@ + +Changes: +- separate namespace allows: +-- easier reconfig of just the gateway +-- TLS secrets and domain name management is isolated, for better security +-- simplified configuration +-- multiple versions of the ingress can be used, to minimize upgrade risks + +- the new chart uses the default namespace service account, and doesn't require +additional RBAC permissions. + +- simplified label and chart structure. +- ability to run a pilot dedicated for the gateway, isolated from the main pilot. This is more robust, safer on upgrades +and allows a bit more flexibility. +- the dedicated pilot-per-ingress is required if the gateway needs to support k8s-style ingress. + +# Port and basic host configuration + +In order to configure the Service object, the install/upgrade needs to provide a list of all ports. +In the past, this was done when installing/upgrading full istio, and involved some duplication - ports configured +both in upgrade, Gateway and VirtualService. + +The new Ingress chart uses a 'values.yaml' (see user-example-ingress), which auto-generates Service ports, +Gateways and basic VirtualService. It is still possible to only configure the ports in Service, and do manual +config for the rest. + +All internal services ( telemetry, pilot debug ports, mesh expansion ) can now be configured via the new mechanism. + +# Migration from istio-system + +Istio 1.0 includes the gateways in istio-system. Since the external IP is associated +with the Service and bound to the namespace, it is recommended to: + +1. Install the new gateway in a new namespace. +2. Copy any TLS certificate to the new namespace, and configure the domains. +3. Checking the new gateway work - for example by overriding the IP in /etc/hosts +4. Modify the DNS server to add the A record of the new namespace +5. Check traffic +6. Delete the A record corresponding to the gateway in istio-system +7. Upgrade istio-system, disabling the ingressgateway +8. Delete the domain TLS certs from istio-system. + +If using certmanager, all Certificate and associated configs must be moved as well. diff --git a/istio-1.5.0/install/kubernetes/operator/charts/gateways/istio-ingress/templates/_affinity.tpl b/istio-1.5.0/install/kubernetes/operator/charts/gateways/istio-ingress/templates/_affinity.tpl new file mode 100644 index 0000000..5335b59 --- /dev/null +++ b/istio-1.5.0/install/kubernetes/operator/charts/gateways/istio-ingress/templates/_affinity.tpl @@ -0,0 +1,93 @@ +{{/* affinity - https://kubernetes.io/docs/concepts/configuration/assign-pod-node/ */}} + +{{- define "nodeaffinity" }} + nodeAffinity: + requiredDuringSchedulingIgnoredDuringExecution: + {{- include "nodeAffinityRequiredDuringScheduling" . }} + preferredDuringSchedulingIgnoredDuringExecution: + {{- include "nodeAffinityPreferredDuringScheduling" . }} +{{- end }} + +{{- define "nodeAffinityRequiredDuringScheduling" }} + nodeSelectorTerms: + - matchExpressions: + - key: beta.kubernetes.io/arch + operator: In + values: + {{- range $key, $val := .global.arch }} + {{- if gt ($val | int) 0 }} + - {{ $key | quote }} + {{- end }} + {{- end }} + {{- $nodeSelector := default .global.defaultNodeSelector .nodeSelector -}} + {{- range $key, $val := $nodeSelector }} + - key: {{ $key }} + operator: In + values: + - {{ $val | quote }} + {{- end }} +{{- end }} + +{{- define "nodeAffinityPreferredDuringScheduling" }} + {{- range $key, $val := .global.arch }} + {{- if gt ($val | int) 0 }} + - weight: {{ $val | int }} + preference: + matchExpressions: + - key: beta.kubernetes.io/arch + operator: In + values: + - {{ $key | quote }} + {{- end }} + {{- end }} +{{- end }} + +{{- define "podAntiAffinity" }} +{{- if or .podAntiAffinityLabelSelector .podAntiAffinityTermLabelSelector}} + podAntiAffinity: + {{- if .podAntiAffinityLabelSelector }} + requiredDuringSchedulingIgnoredDuringExecution: + {{- include "podAntiAffinityRequiredDuringScheduling" . }} + {{- end }} + {{- if .podAntiAffinityTermLabelSelector }} + preferredDuringSchedulingIgnoredDuringExecution: + {{- include "podAntiAffinityPreferredDuringScheduling" . }} + {{- end }} +{{- end }} +{{- end }} + +{{- define "podAntiAffinityRequiredDuringScheduling" }} + {{- range $index, $item := .podAntiAffinityLabelSelector }} + - labelSelector: + matchExpressions: + - key: {{ $item.key }} + operator: {{ $item.operator }} + {{- if $item.values }} + values: + {{- $vals := split "," $item.values }} + {{- range $i, $v := $vals }} + - {{ $v | quote }} + {{- end }} + {{- end }} + topologyKey: {{ $item.topologyKey }} + {{- end }} +{{- end }} + +{{- define "podAntiAffinityPreferredDuringScheduling" }} + {{- range $index, $item := .podAntiAffinityTermLabelSelector }} + - podAffinityTerm: + labelSelector: + matchExpressions: + - key: {{ $item.key }} + operator: {{ $item.operator }} + {{- if $item.values }} + values: + {{- $vals := split "," $item.values }} + {{- range $i, $v := $vals }} + - {{ $v | quote }} + {{- end }} + {{- end }} + topologyKey: {{ $item.topologyKey }} + weight: 100 + {{- end }} +{{- end }} diff --git a/istio-1.5.0/install/kubernetes/operator/charts/gateways/istio-ingress/templates/addongateway.yaml b/istio-1.5.0/install/kubernetes/operator/charts/gateways/istio-ingress/templates/addongateway.yaml new file mode 100644 index 0000000..5b49beb --- /dev/null +++ b/istio-1.5.0/install/kubernetes/operator/charts/gateways/istio-ingress/templates/addongateway.yaml @@ -0,0 +1,65 @@ +# Template for telemetry addon gateways +{{ $gateway := index .Values "gateways" "istio-ingressgateway" }} +{{ range $addon := $gateway.telemetry_addon_gateways }} +{{ if $addon.enabled }} +apiVersion: networking.istio.io/v1alpha3 +kind: Gateway +metadata: + name: istio-{{ $addon.name }}-gateway + namespace: {{ $.Release.Namespace }} + labels: + app: {{ $addon.name }} + release: {{ $.Release.Name }} +spec: + selector: + istio: ingressgateway + servers: + - port: + number: {{ $addon.port }} + name: https-{{ $addon.name }} + protocol: HTTPS + tls: + mode: SIMPLE + serverCertificate: /etc/istio/ingressgateway-certs/tls.crt + privateKey: /etc/istio/ingressgateway-certs/tls.key + hosts: + - "*" +--- +apiVersion: networking.istio.io/v1alpha3 +kind: VirtualService +metadata: + name: {{ $addon.name }}-virtual-service + namespace: {{ $.Release.Namespace }} + labels: + app: {{ $addon.name }} + release: {{ $.Release.Name }} +spec: + hosts: + - "*" + gateways: + - istio-{{ $addon.name }}-gateway + http: + - match: + - port: {{ $addon.port }} + route: + - destination: + host: {{ $addon.name }}.{{ $.Release.Namespace }}.svc.{{ $.Values.global.proxy.clusterDomain }} + port: + number: {{ $addon.desPort }} +--- +apiVersion: networking.istio.io/v1alpha3 +kind: DestinationRule +metadata: + name: {{ $addon.name }} + namespace: {{ $.Release.Namespace }} + labels: + app: {{ $addon.name }} + release: {{ $.Release.Name }} +spec: + host: {{ $addon.name }}.{{ $.Release.Namespace }}.svc.{{ $.Values.global.proxy.clusterDomain }} + trafficPolicy: + tls: + mode: DISABLE +--- +{{- end }} +{{- end }} diff --git a/istio-1.5.0/install/kubernetes/operator/charts/gateways/istio-ingress/templates/autoscale.yaml b/istio-1.5.0/install/kubernetes/operator/charts/gateways/istio-ingress/templates/autoscale.yaml new file mode 100644 index 0000000..bcac2b9 --- /dev/null +++ b/istio-1.5.0/install/kubernetes/operator/charts/gateways/istio-ingress/templates/autoscale.yaml @@ -0,0 +1,24 @@ +{{ $gateway := index .Values "gateways" "istio-ingressgateway" }} +{{- if and $gateway.autoscaleEnabled $gateway.autoscaleMin $gateway.autoscaleMax }} +apiVersion: autoscaling/v2beta1 +kind: HorizontalPodAutoscaler +metadata: + name: istio-ingressgateway + namespace: {{ .Release.Namespace }} + labels: +{{ $gateway.labels | toYaml | indent 4 }} + release: {{ .Release.Name }} +spec: + maxReplicas: {{ $gateway.autoscaleMax }} + minReplicas: {{ $gateway.autoscaleMin }} + scaleTargetRef: + apiVersion: apps/v1 + kind: Deployment + name: istio-ingressgateway + metrics: + - type: Resource + resource: + name: cpu + targetAverageUtilization: {{ $gateway.cpu.targetAverageUtilization }} +--- +{{- end }} diff --git a/istio-1.5.0/install/kubernetes/operator/charts/gateways/istio-ingress/templates/certificate.yaml b/istio-1.5.0/install/kubernetes/operator/charts/gateways/istio-ingress/templates/certificate.yaml new file mode 100644 index 0000000..b66611b --- /dev/null +++ b/istio-1.5.0/install/kubernetes/operator/charts/gateways/istio-ingress/templates/certificate.yaml @@ -0,0 +1,45 @@ +{{ $gateway := index .Values "gateways" "istio-ingressgateway" }} +{{ if $gateway.certificates }} +--- +# Auto-generate Certmanager Issuer and certificate requests. +# Requires 'email' to be set, for Let's Encrypt use. + +apiVersion: certmanager.k8s.io/v1alpha1 +kind: Issuer +metadata: + name: letsencrypt + namespace: {{ .Release.Namespace }} +spec: + acme: + server: https://acme-v02.api.letsencrypt.org/directory + email: {{ $gateway.email }} + privateKeySecretRef: + name: letsencrypt + http01: {} +--- + +apiVersion: certmanager.k8s.io/v1alpha1 +kind: Certificate +metadata: + name: istio-ingressgateway-certs + namespace: {{ .Release.Namespace }} +spec: + secretName: istio-ingressgateway-certs + issuerRef: + name: letsencrypt + kind: ClusterIssuer + commonName: {{ $gateway.commonName }} + dnsNames: +{{- range $key := $gateway.certificates }} + - {{ $key }} +{{- end }} + acme: + config: + - http01: + ingressClass: istio + domains: +{{- range $key := $gateway.certificates }} + - {{ $key }} +{{- end }} +{{- end }} + diff --git a/istio-1.5.0/install/kubernetes/operator/charts/gateways/istio-ingress/templates/deployment.yaml b/istio-1.5.0/install/kubernetes/operator/charts/gateways/istio-ingress/templates/deployment.yaml new file mode 100644 index 0000000..325e117 --- /dev/null +++ b/istio-1.5.0/install/kubernetes/operator/charts/gateways/istio-ingress/templates/deployment.yaml @@ -0,0 +1,384 @@ +{{- $gateway := index .Values "gateways" "istio-ingressgateway" }} +apiVersion: apps/v1 +kind: Deployment +metadata: + name: istio-ingressgateway + namespace: {{ .Release.Namespace }} + labels: +{{ $gateway.labels | toYaml | indent 4 }} + release: {{ .Release.Name }} +spec: +{{- if not $gateway.autoscaleEnabled }} +{{- if $gateway.replicaCount }} + replicas: {{ $gateway.replicaCount }} +{{- end }} +{{- end }} + selector: + matchLabels: +{{ $gateway.labels | toYaml | indent 6 }} + strategy: + rollingUpdate: + maxSurge: {{ $gateway.rollingMaxSurge }} + maxUnavailable: {{ $gateway.rollingMaxUnavailable }} + template: + metadata: + labels: +{{ $gateway.labels | toYaml | indent 8 }} +{{- if eq .Release.Namespace "istio-system"}} + heritage: Tiller + release: istio + chart: gateways +{{- end }} + service.istio.io/canonical-name: istio-ingressgateway + service.istio.io/canonical-revision: "1.5" + annotations: + sidecar.istio.io/inject: "false" +{{- if $gateway.podAnnotations }} +{{ toYaml $gateway.podAnnotations | indent 8 }} +{{ end }} + spec: + serviceAccountName: istio-ingressgateway-service-account +{{- if .Values.global.priorityClassName }} + priorityClassName: "{{ .Values.global.priorityClassName }}" +{{- end }} +{{- if .Values.global.proxy.enableCoreDump }} + initContainers: + - name: enable-core-dump +{{- if contains "/" .Values.global.proxy.image }} + image: "{{ .Values.global.proxy.image }}" +{{- else }} + image: "{{ .Values.global.hub }}/{{ .Values.global.proxy.image | default "proxyv2" }}:{{ .Values.global.tag }}" +{{- end }} + imagePullPolicy: {{ .Values.global.imagePullPolicy | default "Always" }} + command: + - /bin/sh + args: + - -c + - sysctl -w kernel.core_pattern=/var/lib/istio/core.proxy && ulimit -c unlimited + securityContext: + privileged: true +{{- end }} + containers: +{{- if and $gateway.sds.enabled (not .Values.global.istiod.enabled) }} + - name: ingress-sds +{{- if contains "/" $gateway.sds.image }} + image: "{{ $gateway.sds.image }}" +{{- else }} + image: "{{ .Values.global.hub }}/{{ $gateway.sds.image }}:{{ .Values.global.tag }}" +{{- end }} + imagePullPolicy: {{ .Values.global.imagePullPolicy | default "Always" }} + resources: +{{- if $gateway.sds.resources }} +{{ toYaml $gateway.sds.resources | indent 12 }} +{{- else }} +{{ toYaml .Values.global.defaultResources | indent 12 }} +{{- end }} + env: + - name: "ENABLE_WORKLOAD_SDS" + value: "false" + - name: "ENABLE_INGRESS_GATEWAY_SDS" + value: "true" + - name: "INGRESS_GATEWAY_NAMESPACE" + valueFrom: + fieldRef: + apiVersion: v1 + fieldPath: metadata.namespace + volumeMounts: + - name: ingressgatewaysdsudspath + mountPath: /var/run/ingress_gateway +{{- end }} + - name: istio-proxy +{{- if contains "/" .Values.global.proxy.image }} + image: "{{ .Values.global.proxy.image }}" +{{- else }} + image: "{{ .Values.global.hub }}/{{ .Values.global.proxy.image | default "proxyv2" }}:{{ .Values.global.tag }}" +{{- end }} + imagePullPolicy: {{ .Values.global.imagePullPolicy | default "Always" }} + ports: + {{- range $key, $val := $gateway.ports }} + - containerPort: {{ $val.port }} + {{- end }} + {{- range $key, $val := $gateway.meshExpansionPorts }} + - containerPort: {{ $val.port }} + {{- end }} + - containerPort: 15090 + protocol: TCP + name: http-envoy-prom + args: + - proxy + - router + - --domain + - $(POD_NAMESPACE).svc.{{ .Values.global.proxy.clusterDomain }} + {{- if .Values.global.proxy.logLevel }} + - --proxyLogLevel={{ .Values.global.proxy.logLevel }} + {{- end}} + {{- if .Values.global.proxy.componentLogLevel }} + - --proxyComponentLogLevel={{ .Values.global.proxy.componentLogLevel }} + {{- end}} + {{- if .Values.global.logging.level }} + - --log_output_level={{ .Values.global.logging.level }} + {{- end}} + {{- if .Values.global.logAsJson }} + - --log_as_json + {{- end }} + - --drainDuration + - '45s' #drainDuration + - --parentShutdownDuration + - '1m0s' #parentShutdownDuration + - --connectTimeout + - '10s' #connectTimeout + - --serviceCluster + - istio-ingressgateway + - --zipkinAddress + {{- if .Values.global.tracer.zipkin.address }} + - {{ .Values.global.tracer.zipkin.address }} + {{- else if .Values.global.telemetryNamespace }} + - zipkin.{{ .Values.global.telemetryNamespace }}:9411 + {{- else }} + - zipkin:9411 + {{- end }} + {{- if $.Values.global.proxy.envoyMetricsService.enabled }} + - --envoyMetricsService + {{- with $.Values.global.proxy.envoyMetricsService }} + - '{"address":"{{ .host }}:{{.port }}"{{ if .tlsSettings }},"tlsSettings":{{ .tlsSettings | toJson }}{{- end }}{{ if .tcpKeepalive }},"tcpKeepalive":{{ .tcpKeepalive | toJson }}{{- end }}}' + {{- end }} + {{- end}} + {{- if $.Values.global.proxy.envoyAccessLogService.enabled }} + - --envoyAccessLogService + {{- with $.Values.global.proxy.envoyAccessLogService }} + - '{"address":"{{ .host }}:{{.port }}"{{ if .tlsSettings }},"tlsSettings":{{ .tlsSettings | toJson }}{{- end }}{{ if .tcpKeepalive }},"tcpKeepalive":{{ .tcpKeepalive | toJson }}{{- end }}}' + {{- end }} + {{- end }} + - --proxyAdminPort + - "15000" + - --statusPort + - "15020" + {{- if .Values.global.sts.servicePort }} + - --stsPort={{ .Values.global.sts.servicePort }} + {{- end }} + {{- if .Values.global.istiod.enabled }} + - --controlPlaneAuthPolicy + - NONE + - --discoveryAddress + {{- if .Values.global.configNamespace }} + - istio-pilot.{{ .Values.global.configNamespace }}.svc:15012 + {{- else }} + - istio-pilot.istio-system.svc:15012 + {{- end }} + {{- else if .Values.global.controlPlaneSecurityEnabled }} + - --controlPlaneAuthPolicy + - MUTUAL_TLS + - --discoveryAddress + {{- if .Values.global.configNamespace }} + - istio-pilot.{{ .Values.global.configNamespace }}:15011 + {{- else }} + - istio-pilot:15011 + {{- end }} + {{- else }} + - --controlPlaneAuthPolicy + - NONE + - --discoveryAddress + {{- if .Values.global.configNamespace }} + - istio-pilot.{{ .Values.global.configNamespace }}:15010 + {{- else }} + - istio-pilot:15010 + {{- end }} + {{- end }} + {{- if .Values.global.trustDomain }} + - --trust-domain={{ .Values.global.trustDomain }} + {{- end }} + readinessProbe: + failureThreshold: 30 + httpGet: + path: /healthz/ready + port: 15020 + scheme: HTTP + initialDelaySeconds: 1 + periodSeconds: 2 + successThreshold: 1 + timeoutSeconds: 1 + resources: +{{- if $gateway.resources }} +{{ toYaml $gateway.resources | indent 12 }} +{{- else }} +{{ toYaml .Values.global.defaultResources | indent 12 }} +{{- end }} + env: + - name: JWT_POLICY + value: {{ .Values.global.jwtPolicy }} + - name: PILOT_CERT_PROVIDER + value: {{ .Values.global.pilotCertProvider }} +{{- if or .Values.global.istiod.enabled $gateway.sds.enabled }} + - name: "ISTIO_META_USER_SDS" + value: "true" +{{- if .Values.global.istiod.enabled }} + - name: CA_ADDR + value: istio-pilot.{{ .Values.global.configNamespace }}.svc:15012 +{{- end }} +{{- end }} + - name: NODE_NAME + valueFrom: + fieldRef: + apiVersion: v1 + fieldPath: spec.nodeName + - name: POD_NAME + valueFrom: + fieldRef: + apiVersion: v1 + fieldPath: metadata.name + - name: POD_NAMESPACE + valueFrom: + fieldRef: + apiVersion: v1 + fieldPath: metadata.namespace + - name: INSTANCE_IP + valueFrom: + fieldRef: + apiVersion: v1 + fieldPath: status.podIP + - name: HOST_IP + valueFrom: + fieldRef: + apiVersion: v1 + fieldPath: status.hostIP + - name: SERVICE_ACCOUNT + valueFrom: + fieldRef: + fieldPath: spec.serviceAccountName + - name: ISTIO_META_WORKLOAD_NAME + value: istio-ingressgateway + - name: ISTIO_META_OWNER + value: kubernetes://apis/apps/v1/namespaces/{{ .Release.Namespace }}/deployments/istio-ingressgateway + {{- if $.Values.global.meshID }} + - name: ISTIO_META_MESH_ID + value: "{{ $.Values.global.meshID }}" + {{- else if $.Values.global.trustDomain }} + - name: ISTIO_META_MESH_ID + value: "{{ $.Values.global.trustDomain }}" + {{- end }} + {{- if $.Values.global.mtls.auto }} + - name: ISTIO_AUTO_MTLS_ENABLED + value: "true" + {{- end }} + - name: ISTIO_META_POD_NAME + valueFrom: + fieldRef: + apiVersion: v1 + fieldPath: metadata.name + - name: ISTIO_META_CONFIG_NAMESPACE + valueFrom: + fieldRef: + fieldPath: metadata.namespace + {{- range $key, $val := $gateway.env }} + - name: {{ $key }} + value: {{ $val }} + {{- end }} + {{ $network_set := index $gateway.env "ISTIO_META_NETWORK" }} + {{- if and (not $network_set) .Values.global.network }} + - name: ISTIO_META_NETWORK + value: {{ .Values.global.network }} + {{- end }} +{{- if $gateway.podAnnotations }} + - name: "ISTIO_METAJSON_ANNOTATIONS" + value: | +{{ toJson $gateway.podAnnotations | indent 16}} +{{ end }} + - name: ISTIO_META_CLUSTER_ID + value: "{{ $.Values.global.multiCluster.clusterName | default `Kubernetes` }}" + volumeMounts: +{{- if eq .Values.global.pilotCertProvider "istiod" }} + - mountPath: /var/run/secrets/istio + name: istiod-ca-cert +{{- end }} +{{- if .Values.global.istiod.enabled }} +{{- if eq .Values.global.jwtPolicy "third-party-jwt" }} + - name: istio-token + mountPath: /var/run/secrets/tokens + readOnly: true +{{- end }} + - name: ingressgatewaysdsudspath + mountPath: /var/run/ingress_gateway +{{ else }} + {{- if $gateway.sds.enabled }} + - name: ingressgatewaysdsudspath + mountPath: /var/run/ingress_gateway + {{- end }} +{{- end }} + {{- if .Values.global.mountMtlsCerts }} + # Use the key and cert mounted to /etc/certs/ for the in-cluster mTLS communications. + - name: istio-certs + mountPath: /etc/certs + readOnly: true + {{- end }} + - name: podinfo + mountPath: /etc/istio/pod + {{- range $gateway.secretVolumes }} + - name: {{ .name }} + mountPath: {{ .mountPath | quote }} + readOnly: true + {{- end }} +{{- if $gateway.additionalContainers }} +{{ toYaml $gateway.additionalContainers | indent 8 }} +{{- end }} + volumes: +{{- if eq .Values.global.pilotCertProvider "istiod" }} + - name: istiod-ca-cert + configMap: + name: istio-ca-root-cert +{{- end }} + - name: podinfo + downwardAPI: + items: + - path: "labels" + fieldRef: + fieldPath: metadata.labels + - path: "annotations" + fieldRef: + fieldPath: metadata.annotations +{{- if .Values.global.istiod.enabled }} + - name: ingressgatewaysdsudspath + emptyDir: {} +{{- if eq .Values.global.jwtPolicy "third-party-jwt" }} + - name: istio-token + projected: + sources: + - serviceAccountToken: + path: istio-token + expirationSeconds: 43200 + audience: {{ .Values.global.sds.token.aud }} +{{- end }} +{{- else }} + {{- if $gateway.sds.enabled }} + - name: ingressgatewaysdsudspath + emptyDir: {} + {{- end }} +{{- end }} + {{- if .Values.global.mountMtlsCerts }} + # Use the key and cert mounted to /etc/certs/ for the in-cluster mTLS communications. + - name: istio-certs + secret: + secretName: istio.istio-ingressgateway-service-account + optional: true + {{- end }} + {{- range $gateway.secretVolumes }} + - name: {{ .name }} + secret: + secretName: {{ .secretName | quote }} + optional: true + {{- end }} + {{- range $gateway.configVolumes }} + - name: {{ .name }} + configMap: + name: {{ .configMapName | quote }} + optional: true + {{- end }} + affinity: + {{- include "nodeaffinity" (dict "global" .Values.global "nodeSelector" $gateway.nodeSelector) | indent 6 }} + {{- include "podAntiAffinity" $gateway | indent 6 }} +{{- if $gateway.tolerations }} + tolerations: +{{ toYaml $gateway.tolerations | indent 6 }} +{{- else if .Values.global.defaultTolerations }} + tolerations: +{{ toYaml .Values.global.defaultTolerations | indent 6 }} +{{- end }} diff --git a/istio-1.5.0/install/kubernetes/operator/charts/gateways/istio-ingress/templates/gateway.yaml b/istio-1.5.0/install/kubernetes/operator/charts/gateways/istio-ingress/templates/gateway.yaml new file mode 100644 index 0000000..3cc0de8 --- /dev/null +++ b/istio-1.5.0/install/kubernetes/operator/charts/gateways/istio-ingress/templates/gateway.yaml @@ -0,0 +1,40 @@ +{{ $gateway := index .Values "gateways" "istio-ingressgateway" }} +# Main Gateway. Apps must bind to NAMESPACE/ingressgateway +apiVersion: networking.istio.io/v1alpha3 +kind: Gateway +metadata: + name: ingressgateway + namespace: {{ .Release.Namespace }} + labels: + release: {{ .Release.Name }} +spec: + selector: + istio: ingressgateway + servers: +{{- if $gateway.tls }} + - port: + number: 443 + name: https-default + protocol: HTTPS + tls: + mode: SIMPLE + serverCertificate: /etc/istio/ingressgateway-certs/tls.crt + privateKey: /etc/istio/ingressgateway-certs/tls.key + hosts: + - "*" + {{- end }} + - port: + number: 80 + name: http + protocol: HTTP + hosts: + - "*" + # Additional ports in gateaway for the ingressPorts - apps using dedicated port instead of hostname +{{ range $app := $gateway.ingressPorts }} + - port: + number: {{ $app.port }} + name: {{ $app.name }} + protocol: HTTP2 + hosts: + - "*" +{{- end }} diff --git a/istio-1.5.0/install/kubernetes/operator/charts/gateways/istio-ingress/templates/hosts.yaml b/istio-1.5.0/install/kubernetes/operator/charts/gateways/istio-ingress/templates/hosts.yaml new file mode 100644 index 0000000..90f5f7d --- /dev/null +++ b/istio-1.5.0/install/kubernetes/operator/charts/gateways/istio-ingress/templates/hosts.yaml @@ -0,0 +1,50 @@ +{{ $gateway := index .Values "gateways" "istio-ingressgateway" }} + +# TODO: range TCP ports, add ports +# {{ $gateway.domain }} +{{ range $app := $gateway.hosts }} +--- +apiVersion: networking.istio.io/v1alpha3 +kind: VirtualService +metadata: + name: {{ $app.name }} + namespace: {{ $.Release.Namespace }} + labels: + release: {{ $.Release.Name }} +spec: + hosts: + - "{{ $app.name }}.{{ $gateway.domain }}" + gateways: + - ingressgateway + http: + - route: + - destination: + host: {{ $app.dest }} + port: + number: {{ $app.destPort }} +{{- end }} + +{{ range $app := $gateway.ingressPorts }} +--- +apiVersion: networking.istio.io/v1alpha3 +kind: VirtualService +metadata: + name: {{ $app.name }} + namespace: {{ $.Release.Namespace }} + labels: + release: {{ $.Release.Name }} +spec: + hosts: + - "*" + gateways: + - ingressgateway + http: + - + match: + - port: {{ $app.port }} + route: + - destination: + host: {{ $app.dest }} + port: + number: {{ $app.destPort }} +{{- end }} diff --git a/istio-1.5.0/install/kubernetes/operator/charts/gateways/istio-ingress/templates/meshexpansion.yaml b/istio-1.5.0/install/kubernetes/operator/charts/gateways/istio-ingress/templates/meshexpansion.yaml new file mode 100644 index 0000000..b8ae631 --- /dev/null +++ b/istio-1.5.0/install/kubernetes/operator/charts/gateways/istio-ingress/templates/meshexpansion.yaml @@ -0,0 +1,60 @@ +{{- if .Values.global.meshExpansion.enabled }} +apiVersion: networking.istio.io/v1alpha3 +kind: Gateway +metadata: + name: meshexpansion-gateway + namespace: {{ .Release.Namespace }} + labels: + release: {{ .Release.Name }} +spec: + selector: + istio: ingressgateway + servers: + - port: + number: 15012 + protocol: TCP + name: tcp-istiod + hosts: + - "*" +--- + +apiVersion: networking.istio.io/v1alpha3 +kind: VirtualService +metadata: + name: meshexpansion-vs-istiod + namespace: {{ .Release.Namespace }} + labels: + release: {{ .Release.Name }} +spec: + hosts: + - istiod.{{ .Values.global.istioNamespace }}.svc.{{ .Values.global.proxy.clusterDomain }} + gateways: + - meshexpansion-gateway + tcp: + - match: + - port: 15012 + route: + - destination: + host: istiod.{{ .Values.global.istioNamespace }}.svc.{{ .Values.global.proxy.clusterDomain }} + port: + number: 15012 +--- + +apiVersion: networking.istio.io/v1alpha3 +kind: DestinationRule +metadata: + name: meshexpansion-dr-istiod + namespace: {{ .Release.Namespace }} + labels: + release: {{ .Release.Name }} +spec: + host: istiod.{{ .Release.Namespace }}.svc.{{ .Values.global.proxy.clusterDomain }} + trafficPolicy: + portLevelSettings: + - port: + number: 15012 + tls: + mode: DISABLE + +{{- end }} + diff --git a/istio-1.5.0/install/kubernetes/operator/charts/gateways/istio-ingress/templates/poddisruptionbudget.yaml b/istio-1.5.0/install/kubernetes/operator/charts/gateways/istio-ingress/templates/poddisruptionbudget.yaml new file mode 100644 index 0000000..347290d --- /dev/null +++ b/istio-1.5.0/install/kubernetes/operator/charts/gateways/istio-ingress/templates/poddisruptionbudget.yaml @@ -0,0 +1,17 @@ +{{- if .Values.global.defaultPodDisruptionBudget.enabled }} +{{ $gateway := index .Values "gateways" "istio-ingressgateway" }} +apiVersion: policy/v1beta1 +kind: PodDisruptionBudget +metadata: + name: ingressgateway + namespace: {{ .Release.Namespace }} + labels: +{{ $gateway.labels | toYaml | indent 4 }} + release: {{ .Release.Name }} +spec: + minAvailable: 1 + selector: + matchLabels: +{{ $gateway.labels | toYaml | indent 6 }} + release: {{ .Release.Name }} +{{- end }} diff --git a/istio-1.5.0/install/kubernetes/operator/charts/gateways/istio-ingress/templates/preconfigured.yaml b/istio-1.5.0/install/kubernetes/operator/charts/gateways/istio-ingress/templates/preconfigured.yaml new file mode 100644 index 0000000..963cb98 --- /dev/null +++ b/istio-1.5.0/install/kubernetes/operator/charts/gateways/istio-ingress/templates/preconfigured.yaml @@ -0,0 +1,107 @@ +{{ $gateway := index .Values "gateways" "istio-ingressgateway" }} +{{- if .Values.global.k8sIngress.enabled }} +apiVersion: networking.istio.io/v1alpha3 +kind: Gateway +metadata: + name: istio-autogenerated-k8s-ingress + namespace: {{ .Release.Namespace }} + labels: +{{ $gateway.labels | toYaml | indent 4 }} + release: {{ .Release.Name }} +spec: + selector: + istio: {{ .Values.global.k8sIngress.gatewayName }} + servers: + - port: + number: 80 + protocol: HTTP + name: http + hosts: + - "*" +{{ if .Values.global.k8sIngress.enableHttps }} + - port: + number: 443 + protocol: HTTPS + name: https-default + tls: + mode: SIMPLE + serverCertificate: /etc/istio/ingressgateway-certs/tls.crt + privateKey: /etc/istio/ingressgateway-certs/tls.key + hosts: + - "*" +{{ end }} +--- +{{ end }} + + +{{- if .Values.global.multiCluster.enabled }} +apiVersion: networking.istio.io/v1alpha3 +kind: Gateway +metadata: + name: istio-multicluster-ingressgateway + namespace: {{ .Release.Namespace }} + labels: +{{ $gateway.labels | toYaml | indent 4 }} + release: {{ .Release.Name }} +spec: + selector: + istio: ingressgateway + servers: + - hosts: + - "*.global" + port: + name: tls + number: 15443 + protocol: TLS + tls: + mode: AUTO_PASSTHROUGH +--- +apiVersion: networking.istio.io/v1alpha3 +kind: EnvoyFilter +metadata: + name: istio-multicluster-ingressgateway + namespace: {{ .Release.Namespace }} + labels: +{{ $gateway.labels | toYaml | indent 4 }} + release: {{ .Release.Name }} +spec: + workloadSelector: + labels: + istio: ingressgateway + configPatches: + - applyTo: NETWORK_FILTER + match: + context: GATEWAY + listener: + portNumber: 15443 + filterChain: + filter: + name: "envoy.filters.network.sni_cluster" + patch: + operation: INSERT_AFTER + value: + name: "envoy.filters.network.tcp_cluster_rewrite" + config: + cluster_pattern: "\\.global$" + cluster_replacement: ".svc.{{ .Values.global.proxy.clusterDomain }}" +--- +## To ensure all traffic to *.global is using mTLS +apiVersion: networking.istio.io/v1alpha3 +kind: DestinationRule +metadata: + name: istio-multicluster-ingressgateway + namespace: {{ .Release.Namespace }} + labels: +{{ $gateway.labels | toYaml | indent 4 }} + release: {{ .Release.Name }} +spec: + host: "*.global" + {{- if .Values.global.defaultConfigVisibilitySettings }} + exportTo: + - '*' + {{- end }} + trafficPolicy: + tls: + mode: ISTIO_MUTUAL +--- +{{- end }} diff --git a/istio-1.5.0/install/kubernetes/operator/charts/gateways/istio-ingress/templates/role.yaml b/istio-1.5.0/install/kubernetes/operator/charts/gateways/istio-ingress/templates/role.yaml new file mode 100644 index 0000000..5ac7916 --- /dev/null +++ b/istio-1.5.0/install/kubernetes/operator/charts/gateways/istio-ingress/templates/role.yaml @@ -0,0 +1,15 @@ +{{ $gateway := index .Values "gateways" "istio-ingressgateway" }} +{{- if or $gateway.sds.enabled .Values.global.istiod.enabled }} +apiVersion: rbac.authorization.k8s.io/v1 +kind: Role +metadata: + name: istio-ingressgateway-sds + namespace: {{ .Release.Namespace }} + labels: + release: {{ .Release.Name }} +rules: +- apiGroups: [""] + resources: ["secrets"] + verbs: ["get", "watch", "list"] +--- +{{- end }} diff --git a/istio-1.5.0/install/kubernetes/operator/charts/gateways/istio-ingress/templates/rolebindings.yaml b/istio-1.5.0/install/kubernetes/operator/charts/gateways/istio-ingress/templates/rolebindings.yaml new file mode 100644 index 0000000..565fd03 --- /dev/null +++ b/istio-1.5.0/install/kubernetes/operator/charts/gateways/istio-ingress/templates/rolebindings.yaml @@ -0,0 +1,18 @@ +{{ $gateway := index .Values "gateways" "istio-ingressgateway" }} +{{- if or $gateway.sds.enabled .Values.global.istiod.enabled }} +apiVersion: rbac.authorization.k8s.io/v1 +kind: RoleBinding +metadata: + name: istio-ingressgateway-sds + namespace: {{ .Release.Namespace }} + labels: + release: {{ .Release.Name }} +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: Role + name: istio-ingressgateway-sds +subjects: +- kind: ServiceAccount + name: istio-ingressgateway-service-account +--- +{{- end }} diff --git a/istio-1.5.0/install/kubernetes/operator/charts/gateways/istio-ingress/templates/service.yaml b/istio-1.5.0/install/kubernetes/operator/charts/gateways/istio-ingress/templates/service.yaml new file mode 100644 index 0000000..25cc70b --- /dev/null +++ b/istio-1.5.0/install/kubernetes/operator/charts/gateways/istio-ingress/templates/service.yaml @@ -0,0 +1,52 @@ +{{ $gateway := index .Values "gateways" "istio-ingressgateway" }} +{{- if not $gateway.customService }} +apiVersion: v1 +kind: Service +metadata: + name: istio-ingressgateway + namespace: {{ .Release.Namespace }} + annotations: + {{- range $key, $val := $gateway.serviceAnnotations }} + {{ $key }}: {{ $val | quote }} + {{- end }} + labels: +{{ $gateway.labels | toYaml | indent 4 }} + release: {{ .Release.Name }} +spec: +{{- if $gateway.loadBalancerIP }} + loadBalancerIP: "{{ $gateway.loadBalancerIP }}" +{{- end }} +{{- if $gateway.loadBalancerSourceRanges }} + loadBalancerSourceRanges: +{{ toYaml $gateway.loadBalancerSourceRanges | indent 4 }} +{{- end }} +{{- if $gateway.externalTrafficPolicy }} + externalTrafficPolicy: {{$gateway.externalTrafficPolicy }} +{{- end }} + type: {{ $gateway.type }} + selector: +{{ $gateway.labels | toYaml | indent 4 }} + ports: + + {{- range $key, $val := $gateway.ports }} + - + {{- range $pkey, $pval := $val }} + {{ $pkey}}: {{ $pval }} + {{- end }} + {{- end }} + + {{- if $.Values.global.meshExpansion.enabled }} + {{- range $key, $val := $gateway.meshExpansionPorts }} + - + {{- range $pkey, $pval := $val }} + {{ $pkey}}: {{ $pval }} + {{- end }} + {{- end }} + {{- end }} + {{ range $app := $gateway.ingressPorts }} + - + port: {{ $app.port }} + name: {{ $app.name }} + {{- end }} +--- +{{ end }} diff --git a/istio-1.5.0/install/kubernetes/operator/charts/gateways/istio-ingress/templates/serviceaccount.yaml b/istio-1.5.0/install/kubernetes/operator/charts/gateways/istio-ingress/templates/serviceaccount.yaml new file mode 100644 index 0000000..e259b99 --- /dev/null +++ b/istio-1.5.0/install/kubernetes/operator/charts/gateways/istio-ingress/templates/serviceaccount.yaml @@ -0,0 +1,15 @@ +{{ $gateway := index .Values "gateways" "istio-ingressgateway" }} +apiVersion: v1 +kind: ServiceAccount +{{- if .Values.global.imagePullSecrets }} +imagePullSecrets: +{{- range .Values.global.imagePullSecrets }} + - name: {{ . }} +{{- end }} +{{- end }} +metadata: + name: istio-ingressgateway-service-account + namespace: {{ .Release.Namespace }} + labels: +{{ $gateway.labels | toYaml | indent 4 }} + release: {{ .Release.Name }} diff --git a/istio-1.5.0/install/kubernetes/operator/charts/gateways/istio-ingress/templates/sidecar.yaml b/istio-1.5.0/install/kubernetes/operator/charts/gateways/istio-ingress/templates/sidecar.yaml new file mode 100644 index 0000000..d03af8c --- /dev/null +++ b/istio-1.5.0/install/kubernetes/operator/charts/gateways/istio-ingress/templates/sidecar.yaml @@ -0,0 +1,11 @@ +apiVersion: networking.istio.io/v1alpha3 +kind: Sidecar +metadata: + name: default + namespace: {{ .Release.Namespace }} + labels: + release: {{ .Release.Name }} +spec: + egress: + - hosts: + - "*/*" diff --git a/istio-1.5.0/install/kubernetes/operator/charts/gateways/istio-ingress/values.yaml b/istio-1.5.0/install/kubernetes/operator/charts/gateways/istio-ingress/values.yaml new file mode 100644 index 0000000..b4f77c7 --- /dev/null +++ b/istio-1.5.0/install/kubernetes/operator/charts/gateways/istio-ingress/values.yaml @@ -0,0 +1,200 @@ +# A-la-carte istio ingress gateway. +# Must be installed in a separate namespace, to minimize access to secrets. + +gateways: + istio-ingressgateway: + # + # Secret Discovery Service (SDS) configuration for ingress gateway. + # + sds: + # If true, ingress gateway fetches credentials from SDS server to handle TLS connections. + enabled: false + # SDS server that watches kubernetes secrets and provisions credentials to ingress gateway. + # This server runs in the same pod as ingress gateway. + image: node-agent-k8s + resources: + requests: + cpu: 100m + memory: 128Mi + limits: + cpu: 2000m + memory: 1024Mi + labels: + app: istio-ingressgateway + istio: ingressgateway + ports: + ## You can add custom gateway ports in user values overrides, but it must include those ports since helm replaces. + # Note that AWS ELB will by default perform health checks on the first port + # on this list. Setting this to the health check port will ensure that health + # checks always work. https://github.com/istio/istio/issues/12503 + - port: 15020 + targetPort: 15020 + name: status-port + - port: 80 + targetPort: 80 + name: http2 + - port: 443 + name: https + - port: 15029 + targetPort: 15029 + name: kiali + - port: 15030 + targetPort: 15030 + name: prometheus + - port: 15031 + targetPort: 15031 + name: grafana + - port: 15032 + targetPort: 15032 + name: tracing + - port: 31400 + targetPort: 31400 + name: tcp + # This is the port where sni routing happens + - port: 15443 + targetPort: 15443 + name: tls + + # Scalability tunning + # replicaCount: 1 + rollingMaxSurge: 100% + rollingMaxUnavailable: 25% + autoscaleEnabled: true + autoscaleMin: 1 + autoscaleMax: 5 + + cpu: + targetAverageUtilization: 80 + + resources: + requests: + cpu: 100m + memory: 128Mi + limits: + cpu: 2000m + memory: 1024Mi + + # Debug level for envoy. Can be set to 'debug' + debug: info + + loadBalancerIP: "" + loadBalancerSourceRanges: [] + externalIPs: [] + serviceAnnotations: {} + + domain: "" + + # Enable cross-cluster access using SNI matching + zvpn: + enabled: false + suffix: global + + # To generate an internal load balancer: + # --set serviceAnnotations.cloud.google.com/load-balancer-type=internal + #serviceAnnotations: + # cloud.google.com/load-balancer-type: "internal" + + podAnnotations: {} + type: LoadBalancer #change to NodePort, ClusterIP or LoadBalancer if need be + + #### MESH EXPANSION PORTS ######## + # Pilot and Citadel MTLS ports are enabled in gateway - but will only redirect + # to pilot/citadel if global.meshExpansion settings are enabled. + # Delete these ports if mesh expansion is not enabled, to avoid + # exposing unnecessary ports on the web. + # You can remove these ports if you are not using mesh expansion + meshExpansionPorts: + - port: 15011 + targetPort: 15011 + name: tcp-pilot-grpc-tls + - port: 8060 + targetPort: 8060 + name: tcp-citadel-grpc-tls + - port: 853 + targetPort: 853 + name: tcp-dns-tls + ####### end MESH EXPANSION PORTS ###### + + ############## + secretVolumes: + - name: ingressgateway-certs + secretName: istio-ingressgateway-certs + mountPath: /etc/istio/ingressgateway-certs + - name: ingressgateway-ca-certs + secretName: istio-ingressgateway-ca-certs + mountPath: /etc/istio/ingressgateway-ca-certs + + # Domain name for telemetry addons + telemetry_domain_name: "" + + customService: false + externalTrafficPolicy: "" + + ingressPorts: [] + hosts: [] + additionalContainers: [] + configVolumes: [] + certificates: false + tls: false + + # Telemetry addon gateways example config + telemetry_addon_gateways: + tracing_gateway: + name: tracing + port: 15032 + desPort: 80 + enabled: false + tls: false + kiali_gateway: + name: kiali + port: 15029 + desPort: 20001 + enabled: false + tls: false + grafana_gateway: + name: grafana + port: 15031 + desPort: 3000 + enabled: false + tls: false + prometheus_gateway: + name: prometheus + port: 15030 + desPort: 9090 + enabled: false + tls: false + + # For Certmanager Issuer and Certificate generation + # certificates: {} + # email: "" + + ### Advanced options ############ + env: + # A gateway with this mode ensures that pilot generates an additional + # set of clusters for internal services but without Istio mTLS, to + # enable cross cluster routing. + ISTIO_META_ROUTER_MODE: "sni-dnat" + + nodeSelector: {} + tolerations: [] + + # Specify the pod anti-affinity that allows you to constrain which nodes + # your pod is eligible to be scheduled based on labels on pods that are + # already running on the node rather than based on labels on nodes. + # There are currently two types of anti-affinity: + # "requiredDuringSchedulingIgnoredDuringExecution" + # "preferredDuringSchedulingIgnoredDuringExecution" + # which denote "hard" vs. "soft" requirements, you can define your values + # in "podAntiAffinityLabelSelector" and "podAntiAffinityTermLabelSelector" + # correspondingly. + # For example: + # podAntiAffinityLabelSelector: + # - key: security + # operator: In + # values: S1,S2 + # topologyKey: "kubernetes.io/hostname" + # This pod anti-affinity rule says that the pod requires not to be scheduled + # onto a node if that node is already running a pod with label having key + # "security" and value "S1". + podAntiAffinityLabelSelector: [] + podAntiAffinityTermLabelSelector: [] diff --git a/istio-1.5.0/install/kubernetes/operator/charts/istio-cni/Chart.yaml b/istio-1.5.0/install/kubernetes/operator/charts/istio-cni/Chart.yaml new file mode 100644 index 0000000..4cb4308 --- /dev/null +++ b/istio-1.5.0/install/kubernetes/operator/charts/istio-cni/Chart.yaml @@ -0,0 +1,11 @@ +apiVersion: v1 +name: istio-cni +version: 1.1.0 +description: Helm chart for istio-cni components +keywords: + - istio-cni + - istio +sources: + - http://github.com/istio/cni +engine: gotpl +icon: https://istio.io/favicons/android-192x192.png diff --git a/istio-1.5.0/install/kubernetes/operator/charts/istio-cni/templates/clusterrole.yaml b/istio-1.5.0/install/kubernetes/operator/charts/istio-cni/templates/clusterrole.yaml new file mode 100644 index 0000000..ddba115 --- /dev/null +++ b/istio-1.5.0/install/kubernetes/operator/charts/istio-cni/templates/clusterrole.yaml @@ -0,0 +1,31 @@ +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: istio-cni + labels: + app: istio-cni + release: {{ .Release.Name }} +rules: +- apiGroups: [""] + resources: + - pods + - nodes + verbs: + - get +--- +{{- if .Values.cni.repair.enabled }} +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: istio-cni-repair-role + labels: + app: istio-cni + release: {{ .Release.Name }} +rules: +- apiGroups: [""] + resources: ["pods"] + verbs: ["get", "list", "watch", "delete", "patch", "update" ] +- apiGroups: [""] + resources: ["events"] + verbs: ["get", "list", "watch", "delete", "patch", "update", "create" ] +{{- end }} \ No newline at end of file diff --git a/istio-1.5.0/install/kubernetes/operator/charts/istio-cni/templates/clusterrolebinding.yaml b/istio-1.5.0/install/kubernetes/operator/charts/istio-cni/templates/clusterrolebinding.yaml new file mode 100644 index 0000000..d7b3ce9 --- /dev/null +++ b/istio-1.5.0/install/kubernetes/operator/charts/istio-cni/templates/clusterrolebinding.yaml @@ -0,0 +1,49 @@ +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: istio-cni + labels: + app: istio-cni + release: {{ .Release.Name }} +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: istio-cni +subjects: +- kind: ServiceAccount + name: istio-cni + namespace: {{ .Release.Namespace }} +--- +{{- if .Values.cni.repair.enabled }} +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: istio-cni-repair-rolebinding + namespace: {{ .Release.Namespace}} + labels: + k8s-app: istio-cni-repair +subjects: +- kind: ServiceAccount + name: istio-cni + namespace: {{ .Release.Namespace}} +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: istio-cni-repair-role +{{- end }} +--- +{{- if ne .Values.cni.psp_cluster_role "" }} +apiVersion: rbac.authorization.k8s.io/v1 +kind: RoleBinding +metadata: + name: istio-cni-psp + namespace: {{ .Release.Namespace }} +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: {{ .Values.cni.psp_cluster_role }} +subjects: +- kind: ServiceAccount + name: istio-cni + namespace: {{ .Release.Namespace }} +{{- end }} diff --git a/istio-1.5.0/install/kubernetes/operator/charts/istio-cni/templates/configmap-cni.yaml b/istio-1.5.0/install/kubernetes/operator/charts/istio-cni/templates/configmap-cni.yaml new file mode 100644 index 0000000..0a7dd90 --- /dev/null +++ b/istio-1.5.0/install/kubernetes/operator/charts/istio-cni/templates/configmap-cni.yaml @@ -0,0 +1,23 @@ +kind: ConfigMap +apiVersion: v1 +metadata: + name: istio-cni-config + namespace: {{ .Release.Namespace }} + labels: + app: istio-cni + release: {{ .Release.Name }} +data: + # The CNI network configuration to add to the plugin chain on each node. The special + # values in this config will be automatically populated. + cni_network_config: |- + { + "cniVersion": "0.3.1", + "name": "istio-cni", + "type": "istio-cni", + "log_level": {{ quote .Values.cni.logLevel }}, + "kubernetes": { + "kubeconfig": "__KUBECONFIG_FILEPATH__", + "cni_bin_dir": {{ quote .Values.cni.cniBinDir }}, + "exclude_namespaces": [ {{ range $idx, $ns := .Values.cni.excludeNamespaces }}{{ if $idx }}, {{ end }}{{ quote $ns }}{{ end }} ] + } + } diff --git a/istio-1.5.0/install/kubernetes/operator/charts/istio-cni/templates/daemonset.yaml b/istio-1.5.0/install/kubernetes/operator/charts/istio-cni/templates/daemonset.yaml new file mode 100644 index 0000000..b201bee --- /dev/null +++ b/istio-1.5.0/install/kubernetes/operator/charts/istio-cni/templates/daemonset.yaml @@ -0,0 +1,124 @@ +# This manifest installs the Istio install-cni container, as well +# as the Istio CNI plugin and config on +# each master and worker node in a Kubernetes cluster. +kind: DaemonSet +apiVersion: apps/v1 +metadata: + name: istio-cni-node + namespace: {{ .Release.Namespace }} + labels: + k8s-app: istio-cni-node + release: {{ .Release.Name }} +spec: + selector: + matchLabels: + k8s-app: istio-cni-node + updateStrategy: + type: RollingUpdate + rollingUpdate: + maxUnavailable: 1 + template: + metadata: + labels: + k8s-app: istio-cni-node + annotations: + # This, along with the CriticalAddonsOnly toleration below, + # marks the pod as a critical add-on, ensuring it gets + # priority scheduling and that its resources are reserved + # if it ever gets evicted. + scheduler.alpha.kubernetes.io/critical-pod: '' + {{- if .Values.cni.podAnnotations }} +{{ toYaml .Values.cni.podAnnotations | indent 8 }} + {{- end }} + spec: + nodeSelector: + beta.kubernetes.io/os: linux + hostNetwork: true + tolerations: + # Make sure istio-cni-node gets scheduled on all nodes. + - effect: NoSchedule + operator: Exists + # Mark the pod as a critical add-on for rescheduling. + - key: CriticalAddonsOnly + operator: Exists + - effect: NoExecute + operator: Exists + priorityClassName: system-cluster-critical + serviceAccountName: istio-cni + # Minimize downtime during a rolling upgrade or deletion; tell Kubernetes to do a "force + # deletion": https://kubernetes.io/docs/concepts/workloads/pods/pod/#termination-of-pods. + terminationGracePeriodSeconds: 5 + containers: + # This container installs the Istio CNI binaries + # and CNI network config file on each node. + - name: install-cni +{{- if contains "/" .Values.cni.image }} + image: "{{ .Values.cni.image }}" +{{- else }} + image: "{{ .Values.cni.hub | default .Values.global.hub }}/{{ .Values.cni.image | default "install-cni" }}:{{ .Values.cni.tag | default .Values.global.tag }}" +{{- end }} + imagePullPolicy: {{ .Values.cni.pullPolicy | default .Values.global.imagePullPolicy }} + command: ["/install-cni.sh"] + env: +{{- if .Values.cni.cniConfFileName }} + # Name of the CNI config file to create. + - name: CNI_CONF_NAME + value: "{{ .Values.cni.cniConfFileName }}" +{{- end }} + # The CNI network config to install on each node. + - name: CNI_NETWORK_CONFIG + valueFrom: + configMapKeyRef: + name: istio-cni-config + key: cni_network_config + - name: CNI_NET_DIR + value: {{ default "/etc/cni/net.d" .Values.cni.cniConfDir }} + # Deploy as a standalone CNI plugin or as chained? + - name: CHAINED_CNI_PLUGIN + value: "{{ .Values.cni.chained }}" + volumeMounts: + - mountPath: /host/opt/cni/bin + name: cni-bin-dir + - mountPath: /host/etc/cni/net.d + name: cni-net-dir +{{- if .Values.cni.repair.enabled }} + - name: repair-cni +{{- if contains "/" .Values.cni.image }} + image: "{{ .Values.cni.image }}" +{{- else }} + image: "{{ .Values.cni.hub | default .Values.global.hub }}/{{ .Values.cni.image | default "install-cni" }}:{{ .Values.cni.tag | default .Values.global.tag }}" +{{- end }} +{{- if or .Values.cni.pullPolicy .Values.global.imagePullPolicy }} + imagePullPolicy: {{ .Values.cni.pullPolicy | default .Values.global.imagePullPolicy }} +{{- end }} + + command: ["/opt/cni/bin/istio-cni-repair"] + env: + - name: "REPAIR_NODE-NAME" + valueFrom: + fieldRef: + fieldPath: spec.nodeName + - name: "REPAIR_LABEL-PODS" + value: "{{.Values.cni.repair.labelPods}}" + # Set to true to enable pod deletion + - name: "REPAIR_DELETE-PODS" + value: "{{.Values.cni.repair.deletePods}}" + - name: "REPAIR_RUN-AS-DAEMON" + value: "true" + - name: "REPAIR_SIDECAR-ANNOTATION" + value: "sidecar.istio.io/status" + - name: "REPAIR_INIT-CONTAINER-NAME" + value: "{{ .Values.cni.repair.initContainerName }}" + - name: "REPAIR_BROKEN-POD-LABEL-KEY" + value: "{{.Values.cni.repair.brokenPodLabelKey}}" + - name: "REPAIR_BROKEN-POD-LABEL-VALUE" + value: "{{.Values.cni.repair.brokenPodLabelValue}}" +{{- end }} + volumes: + # Used to install CNI. + - name: cni-bin-dir + hostPath: + path: {{ default "/opt/cni/bin" .Values.cni.cniBinDir }} + - name: cni-net-dir + hostPath: + path: {{ default "/etc/cni/net.d" .Values.cni.cniConfDir }} diff --git a/istio-1.5.0/install/kubernetes/operator/charts/istio-cni/templates/serviceaccount.yaml b/istio-1.5.0/install/kubernetes/operator/charts/istio-cni/templates/serviceaccount.yaml new file mode 100644 index 0000000..7a8aa71 --- /dev/null +++ b/istio-1.5.0/install/kubernetes/operator/charts/istio-cni/templates/serviceaccount.yaml @@ -0,0 +1,14 @@ +apiVersion: v1 +kind: ServiceAccount +{{- if .Values.global.imagePullSecrets }} +imagePullSecrets: +{{- range .Values.global.imagePullSecrets }} + - name: {{ . }} +{{- end }} +{{- end }} +metadata: + name: istio-cni + namespace: {{ .Release.Namespace }} + labels: + app: istio-cni + release: {{ .Release.Name }} diff --git a/istio-1.5.0/install/kubernetes/operator/charts/istio-cni/values.yaml b/istio-1.5.0/install/kubernetes/operator/charts/istio-cni/values.yaml new file mode 100644 index 0000000..8c58c80 --- /dev/null +++ b/istio-1.5.0/install/kubernetes/operator/charts/istio-cni/values.yaml @@ -0,0 +1,47 @@ +cni: + hub: "" + tag: "" + image: install-cni + pullPolicy: Always + + logLevel: info + + # Configuration file to insert istio-cni plugin configuration + # by default this will be the first file found in the cni-conf-dir + # Example + # cniConfFileName: 10-calico.conflist + + # CNI bin and conf dir override settings + # defaults: + cniBinDir: /opt/cni/bin + cniConfDir: /etc/cni/net.d + cniConfFileName: "" + + excludeNamespaces: + - istio-system + + # Custom annotations on pod level, if you need them + podAnnotations: {} + + # If this value is set a RoleBinding will be created + # in the same namespace as the istio-cni DaemonSet is created. + # This can be used to bind a preexisting ClusterRole to the istio/cni ServiceAccount + # e.g. if you use PodSecurityPolicies + psp_cluster_role: "" + + # Deploy the config files as plugin chain (value "true") or as standalone files in the conf dir (value "false")? + # Some k8s flavors (e.g. OpenShift) do not support the chain approach, set to false if this is the case + chained: true + + repair: + enabled: true + hub: "" + tag: "" + + labelPods: true + deletePods: true + + initContainerName: "istio-validation" + + brokenPodLabelKey: "cni.istio.io/uninitialized" + brokenPodLabelValue: "true" diff --git a/istio-1.5.0/install/kubernetes/operator/charts/istio-control/istio-autoinject/Chart.yaml b/istio-1.5.0/install/kubernetes/operator/charts/istio-control/istio-autoinject/Chart.yaml new file mode 100644 index 0000000..ecd466a --- /dev/null +++ b/istio-1.5.0/install/kubernetes/operator/charts/istio-control/istio-autoinject/Chart.yaml @@ -0,0 +1,14 @@ +apiVersion: v1 +name: istio-autoinject +version: 1.1.0 +appVersion: 1.1.0 +tillerVersion: ">=2.7.2" +description: Helm chart for sidecar injector webhook deployment +keywords: + - istio + - sidecarInjectorWebhook + - autoinject +sources: + - http://github.com/istio/istio +engine: gotpl +icon: https://istio.io/favicons/android-192x192.png diff --git a/istio-1.5.0/install/kubernetes/operator/charts/istio-control/istio-autoinject/NOTES.txt b/istio-1.5.0/install/kubernetes/operator/charts/istio-control/istio-autoinject/NOTES.txt new file mode 100644 index 0000000..8d77938 --- /dev/null +++ b/istio-1.5.0/install/kubernetes/operator/charts/istio-control/istio-autoinject/NOTES.txt @@ -0,0 +1,33 @@ +Sidecar injector (optional): if disabled, manual injection or other tools need to be used. + +Sidecar injection in each profile can be selected by labeling the namespace with the appropriate profile. + +The new label is 'istio-env' and the value is the namespace where the injector is installed. + +Note that it is possible to install a profile with only the injector app - using remote Pilot and MCP. + +``` + # New style, using the istio-pilot11 profile + kubectl create ns fortio + kubectl label ns fortio istio-env=istio-control + + # Second pilot profile + kubectl create ns fortio-test + kubectl label ns fortio istio-env=istio-master + + # Old-style, using istio-system and Istio 1.0 or 1.1 default installations. + kubectl create ns fortio-istio-system + kubectl label ns fortio istio-injection=enabled +``` + +# Uninstall + +After uninstalling, you should cleanup the global CRD using: + +```bash + + kubectl delete MutatingWebhookConfiguration istio-sidecar-injector-istio-control + +``` + +Any app using the uninstalled istio-env label will no longer be auto-injected once the config is deleted. diff --git a/istio-1.5.0/install/kubernetes/operator/charts/istio-control/istio-autoinject/files/injection-template.yaml b/istio-1.5.0/install/kubernetes/operator/charts/istio-control/istio-autoinject/files/injection-template.yaml new file mode 100644 index 0000000..55b10f1 --- /dev/null +++ b/istio-1.5.0/install/kubernetes/operator/charts/istio-control/istio-autoinject/files/injection-template.yaml @@ -0,0 +1,413 @@ +template: | + rewriteAppHTTPProbe: {{ valueOrDefault .Values.sidecarInjectorWebhook.rewriteAppHTTPProbe false }} + initContainers: + {{ if ne (annotation .ObjectMeta `sidecar.istio.io/interceptionMode` .ProxyConfig.InterceptionMode) `NONE` }} + {{ if .Values.istio_cni.enabled -}} + - name: istio-validation + {{ else -}} + - name: istio-init + {{ end -}} + {{- if contains "/" .Values.global.proxy_init.image }} + image: "{{ .Values.global.proxy_init.image }}" + {{- else }} + image: "{{ .Values.global.hub }}/{{ .Values.global.proxy_init.image }}:{{ .Values.global.tag }}" + {{- end }} + command: + - istio-iptables + - "-p" + - 15001 + - "-z" + - "15006" + - "-u" + - 1337 + - "-m" + - "{{ annotation .ObjectMeta `sidecar.istio.io/interceptionMode` .ProxyConfig.InterceptionMode }}" + - "-i" + - "{{ annotation .ObjectMeta `traffic.sidecar.istio.io/includeOutboundIPRanges` .Values.global.proxy.includeIPRanges }}" + - "-x" + - "{{ annotation .ObjectMeta `traffic.sidecar.istio.io/excludeOutboundIPRanges` .Values.global.proxy.excludeIPRanges }}" + - "-b" + - "{{ annotation .ObjectMeta `traffic.sidecar.istio.io/includeInboundPorts` `*` }}" + - "-d" + - "{{ excludeInboundPort (annotation .ObjectMeta `status.sidecar.istio.io/port` .Values.global.proxy.statusPort) (annotation .ObjectMeta `traffic.sidecar.istio.io/excludeInboundPorts` .Values.global.proxy.excludeInboundPorts) }}" + {{ if or (isset .ObjectMeta.Annotations `traffic.sidecar.istio.io/excludeOutboundPorts`) (ne (valueOrDefault .Values.global.proxy.excludeOutboundPorts "") "") -}} + - "-o" + - "{{ annotation .ObjectMeta `traffic.sidecar.istio.io/excludeOutboundPorts` .Values.global.proxy.excludeOutboundPorts }}" + {{ end -}} + {{ if (isset .ObjectMeta.Annotations `traffic.sidecar.istio.io/kubevirtInterfaces`) -}} + - "-k" + - "{{ index .ObjectMeta.Annotations `traffic.sidecar.istio.io/kubevirtInterfaces` }}" + {{ end -}} + {{ if .Values.istio_cni.enabled -}} + - "--run-validation" + - "--skip-rule-apply" + {{ end -}} + imagePullPolicy: "{{ valueOrDefault .Values.global.imagePullPolicy `Always` }}" + {{- if .Values.global.proxy_init.resources }} + resources: + {{ toYaml .Values.global.proxy_init.resources | indent 4 }} + {{- else }} + resources: {} + {{- end }} + securityContext: + allowPrivilegeEscalation: {{ .Values.global.proxy.privileged }} + privileged: {{ .Values.global.proxy.privileged }} + capabilities: + {{- if not .Values.istio_cni.enabled }} + add: + - NET_ADMIN + - NET_RAW + {{- end }} + drop: + - ALL + readOnlyRootFilesystem: false + {{- if not .Values.istio_cni.enabled }} + runAsGroup: 0 + runAsNonRoot: false + runAsUser: 0 + {{- else }} + runAsGroup: 1337 + runAsUser: 1337 + runAsNonRoot: true + {{- end }} + restartPolicy: Always + {{ end -}} + {{- if eq .Values.global.proxy.enableCoreDump true }} + - name: enable-core-dump + args: + - -c + - sysctl -w kernel.core_pattern=/var/lib/istio/core.proxy && ulimit -c unlimited + command: + - /bin/sh + {{- if contains "/" .Values.global.proxy_init.image }} + image: "{{ .Values.global.proxy_init.image }}" + {{- else }} + image: "{{ .Values.global.hub }}/{{ .Values.global.proxy_init.image }}:{{ .Values.global.tag }}" + {{- end }} + imagePullPolicy: "{{ valueOrDefault .Values.global.imagePullPolicy `Always` }}" + resources: {} + securityContext: + allowPrivilegeEscalation: true + capabilities: + add: + - SYS_ADMIN + drop: + - ALL + privileged: true + readOnlyRootFilesystem: false + runAsGroup: 0 + runAsNonRoot: false + runAsUser: 0 + {{ end }} + containers: + - name: istio-proxy + {{- if contains "/" (annotation .ObjectMeta `sidecar.istio.io/proxyImage` .Values.global.proxy.image) }} + image: "{{ annotation .ObjectMeta `sidecar.istio.io/proxyImage` .Values.global.proxy.image }}" + {{- else }} + image: "{{ .Values.global.hub }}/{{ .Values.global.proxy.image }}:{{ .Values.global.tag }}" + {{- end }} + ports: + - containerPort: 15090 + protocol: TCP + name: http-envoy-prom + args: + - proxy + - sidecar + - --domain + - $(POD_NAMESPACE).svc.{{ .Values.global.proxy.clusterDomain }} + - --configPath + - "/etc/istio/proxy" + - --binaryPath + - "/usr/local/bin/envoy" + - --serviceCluster + {{ if ne "" (index .ObjectMeta.Labels "app") -}} + - "{{ index .ObjectMeta.Labels `app` }}.$(POD_NAMESPACE)" + {{ else -}} + - "{{ valueOrDefault .DeploymentMeta.Name `istio-proxy` }}.{{ valueOrDefault .DeploymentMeta.Namespace `default` }}" + {{ end -}} + - --drainDuration + - "{{ formatDuration .ProxyConfig.DrainDuration }}" + - --parentShutdownDuration + - "{{ formatDuration .ProxyConfig.ParentShutdownDuration }}" + - --discoveryAddress + - "{{ annotation .ObjectMeta `sidecar.istio.io/discoveryAddress` .ProxyConfig.DiscoveryAddress }}" + {{- if eq .Values.global.proxy.tracer "lightstep" }} + - --lightstepAddress + - "{{ .ProxyConfig.GetTracing.GetLightstep.GetAddress }}" + - --lightstepAccessToken + - "{{ .ProxyConfig.GetTracing.GetLightstep.GetAccessToken }}" + - --lightstepSecure={{ .ProxyConfig.GetTracing.GetLightstep.GetSecure }} + - --lightstepCacertPath + - "{{ .ProxyConfig.GetTracing.GetLightstep.GetCacertPath }}" + {{- else if eq .Values.global.proxy.tracer "zipkin" }} + - --zipkinAddress + - "{{ .ProxyConfig.GetTracing.GetZipkin.GetAddress }}" + {{- else if eq .Values.global.proxy.tracer "datadog" }} + - --datadogAgentAddress + - "{{ .ProxyConfig.GetTracing.GetDatadog.GetAddress }}" + {{- end }} + - --proxyLogLevel={{ annotation .ObjectMeta `sidecar.istio.io/logLevel` .Values.global.proxy.logLevel}} + - --proxyComponentLogLevel={{ annotation .ObjectMeta `sidecar.istio.io/componentLogLevel` .Values.global.proxy.componentLogLevel}} + - --connectTimeout + - "{{ formatDuration .ProxyConfig.ConnectTimeout }}" + {{- if .Values.global.proxy.envoyStatsd.enabled }} + - --statsdUdpAddress + - "{{ .ProxyConfig.StatsdUdpAddress }}" + {{- end }} + {{- if .Values.global.proxy.envoyMetricsService.enabled }} + - --envoyMetricsService + - '{{ protoToJSON .ProxyConfig.EnvoyMetricsService }}' + {{- end }} + {{- if .Values.global.proxy.envoyAccessLogService.enabled }} + - --envoyAccessLogService + - '{{ protoToJSON .ProxyConfig.EnvoyAccessLogService }}' + {{- end }} + - --proxyAdminPort + - "{{ .ProxyConfig.ProxyAdminPort }}" + {{ if gt .ProxyConfig.Concurrency 0 -}} + - --concurrency + - "{{ .ProxyConfig.Concurrency }}" + {{ end -}} + {{- if .Values.global.controlPlaneSecurityEnabled }} + - --controlPlaneAuthPolicy + - MUTUAL_TLS + {{- else }} + - --controlPlaneAuthPolicy + - NONE + {{- end }} + - --dnsRefreshRate + - {{ valueOrDefault .Values.global.proxy.dnsRefreshRate "300s" }} + {{- if (ne (annotation .ObjectMeta "status.sidecar.istio.io/port" .Values.global.proxy.statusPort) "0") }} + - --statusPort + - "{{ annotation .ObjectMeta `status.sidecar.istio.io/port` .Values.global.proxy.statusPort }}" + {{- end }} + {{- if .Values.global.trustDomain }} + - --trust-domain={{ .Values.global.trustDomain }} + {{- end }} + {{- if .Values.global.logAsJson }} + - --log_as_json + {{- end }} + {{- if .Values.global.proxy.lifecycle }} + lifecycle: + {{ toYaml .Values.global.proxy.lifecycle | indent 4 }} + {{- end }} + env: + - name: JWT_POLICY + value: {{ .Values.global.jwtPolicy }} + - name: POD_NAME + valueFrom: + fieldRef: + fieldPath: metadata.name + - name: POD_NAMESPACE + valueFrom: + fieldRef: + fieldPath: metadata.namespace + - name: INSTANCE_IP + valueFrom: + fieldRef: + fieldPath: status.podIP + - name: SERVICE_ACCOUNT + valueFrom: + fieldRef: + fieldPath: spec.serviceAccountName + - name: HOST_IP + valueFrom: + fieldRef: + fieldPath: status.hostIP + {{- if eq .Values.global.proxy.tracer "datadog" }} + {{- if isset .ObjectMeta.Annotations `apm.datadoghq.com/env` }} + {{- range $key, $value := fromJSON (index .ObjectMeta.Annotations `apm.datadoghq.com/env`) }} + - name: {{ $key }} + value: "{{ $value }}" + {{- end }} + {{- end }} + {{- end }} + - name: ISTIO_META_POD_PORTS + value: |- + [ + {{- $first := true }} + {{- range $index1, $c := .Spec.Containers }} + {{- range $index2, $p := $c.Ports }} + {{- if (structToJSON $p) }} + {{if not $first}},{{end}}{{ structToJSON $p }} + {{- $first = false }} + {{- end }} + {{- end}} + {{- end}} + ] + - name: ISTIO_META_CLUSTER_ID + value: "{{ valueOrDefault .Values.global.multiCluster.clusterName `Kubernetes` }}" + - name: ISTIO_META_POD_NAME + valueFrom: + fieldRef: + fieldPath: metadata.name + - name: ISTIO_META_CONFIG_NAMESPACE + valueFrom: + fieldRef: + fieldPath: metadata.namespace + - name: ISTIO_META_INTERCEPTION_MODE + value: "{{ or (index .ObjectMeta.Annotations `sidecar.istio.io/interceptionMode`) .ProxyConfig.InterceptionMode.String }}" + {{- if .Values.global.network }} + - name: ISTIO_META_NETWORK + value: "{{ .Values.global.network }}" + {{- end }} + {{ if .ObjectMeta.Annotations }} + - name: ISTIO_METAJSON_ANNOTATIONS + value: | + {{ toJSON .ObjectMeta.Annotations }} + {{ end }} + {{ if .ObjectMeta.Labels }} + - name: ISTIO_METAJSON_LABELS + value: | + {{ toJSON .ObjectMeta.Labels }} + {{ end }} + {{- if .DeploymentMeta.Name }} + - name: ISTIO_META_WORKLOAD_NAME + value: {{ .DeploymentMeta.Name }} + {{ end }} + {{- if and .TypeMeta.APIVersion .DeploymentMeta.Name }} + - name: ISTIO_META_OWNER + value: kubernetes://apis/{{ .TypeMeta.APIVersion }}/namespaces/{{ valueOrDefault .DeploymentMeta.Namespace `default` }}/{{ toLower .TypeMeta.Kind}}s/{{ .DeploymentMeta.Name }} + {{- end}} + {{- if (isset .ObjectMeta.Annotations `sidecar.istio.io/bootstrapOverride`) }} + - name: ISTIO_BOOTSTRAP_OVERRIDE + value: "/etc/istio/custom-bootstrap/custom_bootstrap.json" + {{- end }} + {{- if .Values.global.sds.customTokenDirectory }} + - name: ISTIO_META_SDS_TOKEN_PATH + value: "{{ .Values.global.sds.customTokenDirectory -}}/sdstoken" + {{- end }} + {{- if .Values.global.meshID }} + - name: ISTIO_META_MESH_ID + value: "{{ .Values.global.meshID }}" + {{- else if .Values.global.trustDomain }} + - name: ISTIO_META_MESH_ID + value: "{{ .Values.global.trustDomain }}" + {{- end }} + {{- if eq .Values.global.proxy.tracer "stackdriver" }} + - name: STACKDRIVER_TRACING_ENABLED + value: "true" + - name: STACKDRIVER_TRACING_DEBUG + value: "{{ .ProxyConfig.GetTracing.GetStackdriver.GetDebug }}" + - name: STACKDRIVER_TRACING_MAX_NUMBER_OF_ANNOTATIONS + value: "{{ .ProxyConfig.GetTracing.GetStackdriver.GetMaxNumberOfAnnotations }}" + - name: STACKDRIVER_TRACING_MAX_NUMBER_OF_ATTRIBUTES + value: "{{ .ProxyConfig.GetTracing.GetStackdriver.GetMaxNumberOfAttributes }}" + - name: STACKDRIVER_TRACING_MAX_NUMBER_OF_MESSAGE_EVENTS + value: "{{ .ProxyConfig.GetTracing.GetStackdriver.GetMaxNumberOfMessageEvents }}" + {{- end }} + {{- if and (eq .Values.global.proxy.tracer "datadog") (isset .ObjectMeta.Annotations `apm.datadoghq.com/env`) }} + {{- range $key, $value := fromJSON (index .ObjectMeta.Annotations `apm.datadoghq.com/env`) }} + - name: {{ $key }} + value: "{{ $value }}" + {{- end }} + {{- end }} + {{- range $key, $value := .ProxyConfig.ProxyMetadata }} + - name: {{ $key }} + value: "{{ $value }}" + {{- end }} + imagePullPolicy: "{{ valueOrDefault .Values.global.imagePullPolicy `Always` }}" + {{ if ne (annotation .ObjectMeta `status.sidecar.istio.io/port` .Values.global.proxy.statusPort) `0` }} + readinessProbe: + httpGet: + path: /healthz/ready + port: {{ annotation .ObjectMeta `status.sidecar.istio.io/port` .Values.global.proxy.statusPort }} + initialDelaySeconds: {{ annotation .ObjectMeta `readiness.status.sidecar.istio.io/initialDelaySeconds` .Values.global.proxy.readinessInitialDelaySeconds }} + periodSeconds: {{ annotation .ObjectMeta `readiness.status.sidecar.istio.io/periodSeconds` .Values.global.proxy.readinessPeriodSeconds }} + failureThreshold: {{ annotation .ObjectMeta `readiness.status.sidecar.istio.io/failureThreshold` .Values.global.proxy.readinessFailureThreshold }} + {{ end -}} + securityContext: + allowPrivilegeEscalation: {{ .Values.global.proxy.privileged }} + capabilities: + {{ if or (eq (annotation .ObjectMeta `sidecar.istio.io/interceptionMode` .ProxyConfig.InterceptionMode) `TPROXY`) (eq (annotation .ObjectMeta `sidecar.istio.io/capNetBindService` .Values.global.proxy.capNetBindService) `true`) -}} + add: + {{ if eq (annotation .ObjectMeta `sidecar.istio.io/interceptionMode` .ProxyConfig.InterceptionMode) `TPROXY` -}} + - NET_ADMIN + {{- end }} + {{ if eq (annotation .ObjectMeta `sidecar.istio.io/capNetBindService` .Values.global.proxy.capNetBindService) `true` -}} + - NET_BIND_SERVICE + {{- end }} + {{- end }} + drop: + - ALL + privileged: {{ .Values.global.proxy.privileged }} + readOnlyRootFilesystem: {{ not .Values.global.proxy.enableCoreDump }} + runAsGroup: 1337 + {{ if or (eq (annotation .ObjectMeta `sidecar.istio.io/interceptionMode` .ProxyConfig.InterceptionMode) `TPROXY`) (eq (annotation .ObjectMeta `sidecar.istio.io/capNetBindService` .Values.global.proxy.capNetBindService) `true`) -}} + runAsNonRoot: false + runAsUser: 0 + {{- else -}} + runAsNonRoot: true + runAsUser: 1337 + {{- end }} + resources: + {{ if or (isset .ObjectMeta.Annotations `sidecar.istio.io/proxyCPU`) (isset .ObjectMeta.Annotations `sidecar.istio.io/proxyMemory`) -}} + requests: + {{ if (isset .ObjectMeta.Annotations `sidecar.istio.io/proxyCPU`) -}} + cpu: "{{ index .ObjectMeta.Annotations `sidecar.istio.io/proxyCPU` }}" + {{ end}} + {{ if (isset .ObjectMeta.Annotations `sidecar.istio.io/proxyMemory`) -}} + memory: "{{ index .ObjectMeta.Annotations `sidecar.istio.io/proxyMemory` }}" + {{ end }} + {{ else -}} + {{- if .Values.global.proxy.resources }} + {{ toYaml .Values.global.proxy.resources | indent 4 }} + {{- end }} + {{ end -}} + volumeMounts: + {{ if (isset .ObjectMeta.Annotations `sidecar.istio.io/bootstrapOverride`) }} + - mountPath: /etc/istio/custom-bootstrap + name: custom-bootstrap-volume + {{- end }} + - mountPath: /etc/istio/proxy + name: istio-envoy + - mountPath: /etc/certs/ + name: istio-certs + readOnly: true + {{- if and (eq .Values.global.proxy.tracer "lightstep") .Values.global.tracer.lightstep.cacertPath }} + - mountPath: {{ directory .ProxyConfig.GetTracing.GetLightstep.GetCacertPath }} + name: lightstep-certs + readOnly: true + {{- end }} + {{- if isset .ObjectMeta.Annotations `sidecar.istio.io/userVolumeMount` }} + {{ range $index, $value := fromJSON (index .ObjectMeta.Annotations `sidecar.istio.io/userVolumeMount`) }} + - name: "{{ $index }}" + {{ toYaml $value | indent 4 }} + {{ end }} + {{- end }} + volumes: + {{- if (isset .ObjectMeta.Annotations `sidecar.istio.io/bootstrapOverride`) }} + - name: custom-bootstrap-volume + configMap: + name: {{ annotation .ObjectMeta `sidecar.istio.io/bootstrapOverride` "" }} + {{- end }} + - emptyDir: + medium: Memory + name: istio-envoy + - name: istio-certs + secret: + optional: true + {{ if eq .Spec.ServiceAccountName "" }} + secretName: istio.default + {{ else -}} + secretName: {{ printf "istio.%s" .Spec.ServiceAccountName }} + {{ end -}} + {{- if isset .ObjectMeta.Annotations `sidecar.istio.io/userVolume` }} + {{range $index, $value := fromJSON (index .ObjectMeta.Annotations `sidecar.istio.io/userVolume`) }} + - name: "{{ $index }}" + {{ toYaml $value | indent 2 }} + {{ end }} + {{ end }} + {{- if and (eq .Values.global.proxy.tracer "lightstep") .Values.global.tracer.lightstep.cacertPath }} + - name: lightstep-certs + secret: + optional: true + secretName: lightstep.cacert + {{- end }} + {{- if .Values.global.podDNSSearchNamespaces }} + dnsConfig: + searches: + {{- range .Values.global.podDNSSearchNamespaces }} + - {{ render . }} + {{- end }} + {{- end }} diff --git a/istio-1.5.0/install/kubernetes/operator/charts/istio-control/istio-autoinject/templates/_affinity.tpl b/istio-1.5.0/install/kubernetes/operator/charts/istio-control/istio-autoinject/templates/_affinity.tpl new file mode 100644 index 0000000..4b0c817 --- /dev/null +++ b/istio-1.5.0/install/kubernetes/operator/charts/istio-control/istio-autoinject/templates/_affinity.tpl @@ -0,0 +1,93 @@ +{{/* affinity - https://kubernetes.io/docs/concepts/configuration/assign-pod-node/ */}} + +{{- define "nodeaffinity" }} + nodeAffinity: + requiredDuringSchedulingIgnoredDuringExecution: + {{- include "nodeAffinityRequiredDuringScheduling" . }} + preferredDuringSchedulingIgnoredDuringExecution: + {{- include "nodeAffinityPreferredDuringScheduling" . }} +{{- end }} + +{{- define "nodeAffinityRequiredDuringScheduling" }} + nodeSelectorTerms: + - matchExpressions: + - key: beta.kubernetes.io/arch + operator: In + values: + {{- range $key, $val := .Values.global.arch }} + {{- if gt ($val | int) 0 }} + - {{ $key | quote }} + {{- end }} + {{- end }} + {{- $nodeSelector := default .Values.global.defaultNodeSelector .Values.sidecarInjectorWebhook.nodeSelector -}} + {{- range $key, $val := $nodeSelector }} + - key: {{ $key }} + operator: In + values: + - {{ $val | quote }} + {{- end }} +{{- end }} + +{{- define "nodeAffinityPreferredDuringScheduling" }} + {{- range $key, $val := .Values.global.arch }} + {{- if gt ($val | int) 0 }} + - weight: {{ $val | int }} + preference: + matchExpressions: + - key: beta.kubernetes.io/arch + operator: In + values: + - {{ $key | quote }} + {{- end }} + {{- end }} +{{- end }} + +{{- define "podAntiAffinity" }} +{{- if or .Values.sidecarInjectorWebhook.podAntiAffinityLabelSelector .Values.sidecarInjectorWebhook.podAntiAffinityTermLabelSelector}} + podAntiAffinity: + {{- if .Values.sidecarInjectorWebhook.podAntiAffinityLabelSelector }} + requiredDuringSchedulingIgnoredDuringExecution: + {{- include "podAntiAffinityRequiredDuringScheduling" . }} + {{- end }} + {{- if .Values.sidecarInjectorWebhook.podAntiAffinityTermLabelSelector }} + preferredDuringSchedulingIgnoredDuringExecution: + {{- include "podAntiAffinityPreferredDuringScheduling" . }} + {{- end }} +{{- end }} +{{- end }} + +{{- define "podAntiAffinityRequiredDuringScheduling" }} + {{- range $index, $item := .Values.sidecarInjectorWebhook.podAntiAffinityLabelSelector }} + - labelSelector: + matchExpressions: + - key: {{ $item.key }} + operator: {{ $item.operator }} + {{- if $item.values }} + values: + {{- $vals := split "," $item.values }} + {{- range $i, $v := $vals }} + - {{ $v | quote }} + {{- end }} + {{- end }} + topologyKey: {{ $item.topologyKey }} + {{- end }} +{{- end }} + +{{- define "podAntiAffinityPreferredDuringScheduling" }} + {{- range $index, $item := .Values.sidecarInjectorWebhook.podAntiAffinityTermLabelSelector }} + - podAffinityTerm: + labelSelector: + matchExpressions: + - key: {{ $item.key }} + operator: {{ $item.operator }} + {{- if $item.values }} + values: + {{- $vals := split "," $item.values }} + {{- range $i, $v := $vals }} + - {{ $v | quote }} + {{- end }} + {{- end }} + topologyKey: {{ $item.topologyKey }} + weight: 100 + {{- end }} +{{- end }} diff --git a/istio-1.5.0/install/kubernetes/operator/charts/istio-control/istio-autoinject/templates/_helpers.tpl b/istio-1.5.0/install/kubernetes/operator/charts/istio-control/istio-autoinject/templates/_helpers.tpl new file mode 100644 index 0000000..df59a7c --- /dev/null +++ b/istio-1.5.0/install/kubernetes/operator/charts/istio-control/istio-autoinject/templates/_helpers.tpl @@ -0,0 +1,32 @@ +{{/* vim: set filetype=mustache: */}} +{{/* +Expand the name of the chart. +*/}} +{{- define "sidecar-injector.name" -}} +{{- default .Chart.Name .Values.sidecarInjectorWebhook.nameOverride | trunc 63 | trimSuffix "-" -}} +{{- end -}} + +{{/* +Create a default fully qualified app name. +We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). +If release name contains chart name it will be used as a full name. +*/}} +{{- define "sidecar-injector.fullname" -}} +{{- if .Values.sidecarInjectorWebhook.fullnameOverride -}} +{{- .Values.sidecarInjectorWebhook.fullnameOverride | trunc 63 | trimSuffix "-" -}} +{{- else -}} +{{- $name := default .Chart.Name .Values.sidecarInjectorWebhook.nameOverride -}} +{{- if contains $name .Release.Name -}} +{{- .Release.Name | trunc 63 | trimSuffix "-" -}} +{{- else -}} +{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" -}} +{{- end -}} +{{- end -}} +{{- end -}} + +{{/* +Create chart name and version as used by the chart label. +*/}} +{{- define "sidecar-injector.chart" -}} +{{- .Chart.Name | trunc 63 | trimSuffix "-" -}} +{{- end -}} diff --git a/istio-1.5.0/install/kubernetes/operator/charts/istio-control/istio-autoinject/templates/clusterrole.yaml b/istio-1.5.0/install/kubernetes/operator/charts/istio-control/istio-autoinject/templates/clusterrole.yaml new file mode 100644 index 0000000..2463284 --- /dev/null +++ b/istio-1.5.0/install/kubernetes/operator/charts/istio-control/istio-autoinject/templates/clusterrole.yaml @@ -0,0 +1,19 @@ +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: istio-sidecar-injector-{{ .Release.Namespace }} + labels: + app: sidecar-injector + release: {{ .Release.Name }} + istio: sidecar-injector +rules: +- apiGroups: [""] + resources: ["configmaps"] + resourceNames: ["istio-sidecar-injector"] + verbs: ["get", "list", "watch"] +{{- if not .Values.global.operatorManageWebhooks }} +- apiGroups: ["admissionregistration.k8s.io"] + resources: ["mutatingwebhookconfigurations"] + resourceNames: ["istio-sidecar-injector", "istio-sidecar-injector-{{.Release.Namespace}}"] + verbs: ["get", "list", "watch", "patch"] +{{- end }} \ No newline at end of file diff --git a/istio-1.5.0/install/kubernetes/operator/charts/istio-control/istio-autoinject/templates/clusterrolebinding.yaml b/istio-1.5.0/install/kubernetes/operator/charts/istio-control/istio-autoinject/templates/clusterrolebinding.yaml new file mode 100644 index 0000000..338467e --- /dev/null +++ b/istio-1.5.0/install/kubernetes/operator/charts/istio-control/istio-autoinject/templates/clusterrolebinding.yaml @@ -0,0 +1,16 @@ +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: istio-sidecar-injector-admin-role-binding-{{ .Release.Namespace }} + labels: + app: sidecar-injector + release: {{ .Release.Name }} + istio: sidecar-injector +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: istio-sidecar-injector-{{ .Release.Namespace }} +subjects: + - kind: ServiceAccount + name: istio-sidecar-injector-service-account + namespace: {{ .Release.Namespace }} diff --git a/istio-1.5.0/install/kubernetes/operator/charts/istio-control/istio-autoinject/templates/configmap.yaml b/istio-1.5.0/install/kubernetes/operator/charts/istio-control/istio-autoinject/templates/configmap.yaml new file mode 100644 index 0000000..55f28fa --- /dev/null +++ b/istio-1.5.0/install/kubernetes/operator/charts/istio-control/istio-autoinject/templates/configmap.yaml @@ -0,0 +1,119 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: injector-mesh + namespace: {{ .Release.Namespace }} + labels: + release: {{ .Release.Name }} +data: + # This is the 'mesh' config, loaded by the sidecar injector. + # It is a different configmap from pilot to allow a-la-carte install of the injector and follow the model + # of reducing blast-radius of config changes and avoiding globals. + + # Note that injector uses a subset of the mesh config only - for clarity this is only generating the + # required config, i.e. the defaultConfig section. See injection-template .ProxyConfig settings. + + + mesh: |- + # Unix Domain Socket through which envoy communicates with NodeAgent SDS to get + # key/cert for mTLS. Use secret-mount files instead of SDS if set to empty. + sdsUdsPath: {{ .Values.global.sds.udsPath | quote }} + + defaultConfig: + # + # TCP connection timeout between Envoy & the application, and between Envoys. + connectTimeout: 10s + # + ### ADVANCED SETTINGS ############# + # Where should envoy's configuration be stored in the istio-proxy container + configPath: "/etc/istio/proxy" + # The pseudo service name used for Envoy. + serviceCluster: istio-proxy + # These settings that determine how long an old Envoy + # process should be kept alive after an occasional reload. + drainDuration: 45s + parentShutdownDuration: 1m0s + # + # Port where Envoy listens (on local host) for admin commands + # You can exec into the istio-proxy container in a pod and + # curl the admin port (curl http://localhost:15000/) to obtain + # diagnostic information from Envoy. See + # https://lyft.github.io/envoy/docs/operations/admin.html + # for more details + proxyAdminPort: 15000 + # + # Set concurrency to a specific number to control the number of Proxy worker threads. + # If set to 0 (default), then start worker thread for each CPU thread/core. + concurrency: {{ .Values.global.proxy.concurrency }} + # + {{- if eq .Values.global.proxy.tracer "lightstep" }} + tracing: + lightstep: + # Address of the LightStep Satellite pool + address: {{ .Values.global.tracer.lightstep.address }} + # Access Token used to communicate with the Satellite pool + accessToken: {{ .Values.global.tracer.lightstep.accessToken }} + # Whether communication with the Satellite pool should be secure + secure: {{ .Values.global.tracer.lightstep.secure }} + # Path to the file containing the cacert to use when verifying TLS + cacertPath: {{ .Values.global.tracer.lightstep.cacertPath }} + {{- else if eq .Values.global.proxy.tracer "zipkin" }} + tracing: + zipkin: + # Address of the Zipkin collector + {{- if .Values.global.tracer.zipkin.address }} + address: {{ .Values.global.tracer.zipkin.address }} + {{- else }} + address: zipkin.{{ .Values.global.telemetryNamespace }}:9411 + {{- end }} + {{- else if eq .Values.global.proxy.tracer "datadog" }} + tracing: + datadog: + # Address of the DataDog Agent + address: {{ .Values.global.tracer.datadog.address }} + {{- else if eq .Values.global.proxy.tracer "stackdriver" }} + tracing: + stackdriver: + # enables trace output to stdout. + debug: {{ $.Values.global.tracer.stackdriver.debug }} + {{- if $.Values.global.tracer.stackdriver.maxNumberOfAttributes }} + # The global default max number of attributes per span. + maxNumberOfAttributes: {{ $.Values.global.tracer.stackdriver.maxNumberOfAttributes }} + {{- end }} + {{- if $.Values.global.tracer.stackdriver.maxNumberOfAnnotations }} + # The global default max number of annotation events per span. + maxNumberOfAnnotations: {{ $.Values.global.tracer.stackdriver.maxNumberOfAnnotations }} + {{- end }} + {{- if $.Values.global.tracer.stackdriver.maxNumberOfMessageEvents }} + # The global default max number of message events per span. + maxNumberOfMessageEvents: {{ $.Values.global.tracer.stackdriver.maxNumberOfMessageEvents }} + {{- end }} + {{- end }} + + {{- $defPilotHostname := printf "istio-pilot%s.%s" .Values.version .Values.global.configNamespace }} + {{- $pilotAddress := .Values.global.remotePilotAddress | default $defPilotHostname }} + + {{- if .Values.global.controlPlaneSecurityEnabled }} + # + # Mutual TLS authentication between sidecars and istio control plane. + controlPlaneAuthPolicy: MUTUAL_TLS + # + # Address where istio Pilot service is running + {{- if or .Values.global.remotePilotCreateSvcEndpoint .Values.global.createRemoteSvcEndpoints }} + discoveryAddress: {{ $defPilotHostname }}:15011 + {{- else }} + discoveryAddress: {{ $pilotAddress }}:15011 + {{- end }} + {{- else }} + # + # Mutual TLS authentication between sidecars and istio control plane. + controlPlaneAuthPolicy: NONE + # + # Address where istio Pilot service is running + {{- if or .Values.global.remotePilotCreateSvcEndpoint .Values.global.createRemoteSvcEndpoints }} + discoveryAddress: {{ $defPilotHostname }}:15010 + {{- else }} + discoveryAddress: {{ $pilotAddress }}:15010 + {{- end }} + {{- end }} +--- diff --git a/istio-1.5.0/install/kubernetes/operator/charts/istio-control/istio-autoinject/templates/deployment.yaml b/istio-1.5.0/install/kubernetes/operator/charts/istio-control/istio-autoinject/templates/deployment.yaml new file mode 100644 index 0000000..5e9de92 --- /dev/null +++ b/istio-1.5.0/install/kubernetes/operator/charts/istio-control/istio-autoinject/templates/deployment.yaml @@ -0,0 +1,142 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: istio-sidecar-injector + namespace: {{ .Release.Namespace }} + labels: + app: sidecarInjectorWebhook + release: {{ .Release.Name }} + istio: sidecar-injector +spec: +{{- if .Values.sidecarInjectorWebhook.replicaCount }} + replicas: {{ .Values.sidecarInjectorWebhook.replicaCount }} +{{- end }} + selector: + matchLabels: + istio: sidecar-injector + strategy: + rollingUpdate: + maxSurge: {{ .Values.sidecarInjectorWebhook.rollingMaxSurge }} + maxUnavailable: {{ .Values.sidecarInjectorWebhook.rollingMaxUnavailable }} + template: + metadata: + labels: + app: sidecarInjectorWebhook + istio: sidecar-injector +{{- if eq .Release.Namespace "istio-system"}} + heritage: Tiller + release: istio + chart: sidecarInjectorWebhook +{{- end }} + annotations: + sidecar.istio.io/inject: "false" + {{- if .Values.sidecarInjectorWebhook.podAnnotations }} +{{ toYaml .Values.sidecarInjectorWebhook.podAnnotations | indent 8 }} + {{- end }} + spec: + serviceAccountName: istio-sidecar-injector-service-account +{{- if .Values.global.priorityClassName }} + priorityClassName: "{{ .Values.global.priorityClassName }}" +{{- end }} + containers: + - name: sidecar-injector-webhook +{{- if contains "/" .Values.sidecarInjectorWebhook.image }} + image: "{{ .Values.sidecarInjectorWebhook.image }}" +{{- else }} + image: "{{ .Values.sidecarInjectorWebhook.hub | default .Values.global.hub }}/{{ .Values.sidecarInjectorWebhook.image | default "sidecar_injector" }}:{{ .Values.sidecarInjectorWebhook.tag | default .Values.global.tag }}" +{{- end }} + imagePullPolicy: {{ .Values.global.imagePullPolicy | default "Always" }} + args: + - --caCertFile=/etc/istio/certs/root-cert.pem + - --tlsCertFile=/etc/istio/certs/cert-chain.pem + - --tlsKeyFile=/etc/istio/certs/key.pem + - --injectConfig=/etc/istio/inject/config + - --meshConfig=/etc/istio/config/mesh + - --port=9443 + - --healthCheckInterval=2s + - --healthCheckFile=/tmp/health +{{- if or .Values.global.operatorManageWebhooks .Values.global.istiod.enabled}} + - --reconcileWebhookConfig=false +{{- else }} + - --reconcileWebhookConfig=true +{{- end }} + {{- if eq .Release.Namespace "istio-system"}} + - --webhookConfigName=istio-sidecar-injector + {{ else }} + - --webhookConfigName=istio-sidecar-injector-{{ .Release.Namespace }} + {{- end }} + - --log_output_level=debug + {{- if .Values.global.logAsJson }} + - --log_as_json + {{- end }} + securityContext: + runAsUser: 1337 + runAsGroup: 1337 + runAsNonRoot: true + volumeMounts: + - name: config-volume + mountPath: /etc/istio/config + readOnly: true + - name: certs + mountPath: /etc/istio/certs + readOnly: true + - name: inject-config + mountPath: /etc/istio/inject + readOnly: true + livenessProbe: + exec: + command: + - /usr/local/bin/sidecar-injector + - probe + - --probe-path=/tmp/health + - --interval=4s + initialDelaySeconds: 4 + periodSeconds: 4 + readinessProbe: + exec: + command: + - /usr/local/bin/sidecar-injector + - probe + - --probe-path=/tmp/health + - --interval=4s + initialDelaySeconds: 4 + periodSeconds: 4 + resources: +{{- if .Values.sidecarInjectorWebhook.resources }} +{{ toYaml .Values.sidecarInjectorWebhook.resources | indent 12 }} +{{- else }} +{{ toYaml .Values.global.defaultResources | indent 12 }} +{{- end }} + securityContext: + fsGroup: 1337 + volumes: + - name: config-volume + configMap: + name: injector-mesh + - name: certs + secret: +{{- if .Values.sidecarInjectorWebhook.selfSigned }} + secretName: istio-sidecar-injector-self-signed +{{- else if .Values.global.certificates }} + secretName: dns.istio-sidecar-injector-service-account +{{- else }} + secretName: istio.istio-sidecar-injector-service-account +{{- end }} + - name: inject-config + configMap: + name: istio-sidecar-injector + items: + - key: config + path: config + - key: values + path: values + affinity: + {{- include "nodeaffinity" . | indent 6 }} + {{- include "podAntiAffinity" . | indent 6 }} +{{- if .Values.sidecarInjectorWebhook.tolerations }} + tolerations: +{{ toYaml .Values.sidecarInjectorWebhook.tolerations | indent 6 }} +{{- else if .Values.global.defaultTolerations }} + tolerations: +{{ toYaml .Values.global.defaultTolerations | indent 6 }} +{{- end }} diff --git a/istio-1.5.0/install/kubernetes/operator/charts/istio-control/istio-autoinject/templates/mutatingwebhook.yaml b/istio-1.5.0/install/kubernetes/operator/charts/istio-control/istio-autoinject/templates/mutatingwebhook.yaml new file mode 100644 index 0000000..de32f09 --- /dev/null +++ b/istio-1.5.0/install/kubernetes/operator/charts/istio-control/istio-autoinject/templates/mutatingwebhook.yaml @@ -0,0 +1,86 @@ +{{- $ca := genCA "istio-sidecar-injector-ca-{{ .Release.Namespace }}" 3650 }} +{{- if not .Values.global.operatorManageWebhooks }} +apiVersion: admissionregistration.k8s.io/v1beta1 +kind: MutatingWebhookConfiguration +metadata: + {{- if eq .Release.Namespace "istio-system"}} + name: istio-sidecar-injector + {{ else }} + name: istio-sidecar-injector-{{ .Release.Namespace }} + {{- end }} + labels: + app: sidecar-injector + release: {{ .Release.Name }} +webhooks: + - name: sidecar-injector.istio.io + clientConfig: + service: + name: istio-sidecar-injector + namespace: {{ .Release.Namespace }} + path: "/inject" +{{- if .Values.sidecarInjectorWebhook.selfSigned }} + caBundle: {{ $ca.Cert | b64enc }} +{{- else }} + caBundle: "" +{{- end }} + rules: + - operations: [ "CREATE" ] + apiGroups: [""] + apiVersions: ["v1"] + resources: ["pods"] + failurePolicy: Fail + namespaceSelector: +{{- if .Values.sidecarInjectorWebhook.enableNamespacesByDefault }} + matchExpressions: + - key: name + operator: NotIn + values: + - {{ .Release.Namespace }} + - key: istio-injection + operator: NotIn + values: + - disabled + - key: istio-env + operator: DoesNotExist +{{- else if eq .Values.sidecarInjectorWebhook.injectLabel "istio-injection" }} + matchLabels: + istio-injection: enabled +{{- else }} + matchLabels: + istio-env: {{ .Release.Namespace }} +{{- end }} +{{- if .Values.sidecarInjectorWebhook.objectSelector.enabled }} + objectSelector: +{{- if .Values.sidecarInjectorWebhook.objectSelector.autoInject }} + matchExpressions: + - key: "sidecar.istio.io/inject" + operator: NotIn + values: + - "false" +{{- else }} + matchLabels: + "sidecar.istio.io/inject": "true" +{{- end }} +{{- end }} +{{- end }} +--- +{{- if .Values.sidecarInjectorWebhook.selfSigned }} + {{- $cn := "istio-sidecar-injector" }} + {{- $altName1 := printf "%s.%s" $cn .Release.Namespace }} + {{- $altName2 := printf "%s.%s.svc" $cn .Release.Namespace }} + {{- $altNames := (list $altName1 $altName2) }} + {{- $cert := genSignedCert $cn nil $altNames 3650 $ca }} +apiVersion: v1 +kind: Secret +metadata: + name: istio-sidecar-injector-self-signed + namespace: {{ .Release.Namespace }} + labels: + app: sidecar-injector + release: {{ .Release.Name }} +type: Opaque +data: + root-cert.pem: {{ $ca.Cert | b64enc }} + cert-chain.pem: {{ $cert.Cert | b64enc }} + key.pem: {{ $cert.Key | b64enc }} +{{- end }} diff --git a/istio-1.5.0/install/kubernetes/operator/charts/istio-control/istio-autoinject/templates/poddisruptionbudget.yaml b/istio-1.5.0/install/kubernetes/operator/charts/istio-control/istio-autoinject/templates/poddisruptionbudget.yaml new file mode 100644 index 0000000..96dfc49 --- /dev/null +++ b/istio-1.5.0/install/kubernetes/operator/charts/istio-control/istio-autoinject/templates/poddisruptionbudget.yaml @@ -0,0 +1,18 @@ +{{- if .Values.global.defaultPodDisruptionBudget.enabled }} +apiVersion: policy/v1beta1 +kind: PodDisruptionBudget +metadata: + name: istio-sidecar-injector + namespace: {{ .Release.Namespace }} + labels: + app: sidecar-injector + release: {{ .Release.Name }} + istio: sidecar-injector +spec: + minAvailable: 1 + selector: + matchLabels: + app: sidecar-injector + release: {{ .Release.Name }} + istio: sidecar-injector +{{- end }} diff --git a/istio-1.5.0/install/kubernetes/operator/charts/istio-control/istio-autoinject/templates/service.yaml b/istio-1.5.0/install/kubernetes/operator/charts/istio-control/istio-autoinject/templates/service.yaml new file mode 100644 index 0000000..5c1a55c --- /dev/null +++ b/istio-1.5.0/install/kubernetes/operator/charts/istio-control/istio-autoinject/templates/service.yaml @@ -0,0 +1,15 @@ +apiVersion: v1 +kind: Service +metadata: + name: istio-sidecar-injector + namespace: {{ .Release.Namespace }} + labels: + app: sidecarInjectorWebhook + release: {{ .Release.Name }} + istio: sidecar-injector +spec: + ports: + - port: 443 + targetPort: 9443 + selector: + istio: sidecar-injector diff --git a/istio-1.5.0/install/kubernetes/operator/charts/istio-control/istio-autoinject/templates/serviceaccount.yaml b/istio-1.5.0/install/kubernetes/operator/charts/istio-control/istio-autoinject/templates/serviceaccount.yaml new file mode 100644 index 0000000..60deddf --- /dev/null +++ b/istio-1.5.0/install/kubernetes/operator/charts/istio-control/istio-autoinject/templates/serviceaccount.yaml @@ -0,0 +1,15 @@ +apiVersion: v1 +kind: ServiceAccount +{{- if .Values.global.imagePullSecrets }} +imagePullSecrets: +{{- range .Values.global.imagePullSecrets }} + - name: {{ . }} +{{- end }} +{{- end }} +metadata: + name: istio-sidecar-injector-service-account + namespace: {{ .Release.Namespace }} + labels: + app: sidecarInjectorWebhook + release: {{ .Release.Name }} + istio: sidecar-injector diff --git a/istio-1.5.0/install/kubernetes/operator/charts/istio-control/istio-autoinject/templates/sidecar-injector-configmap.yaml b/istio-1.5.0/install/kubernetes/operator/charts/istio-control/istio-autoinject/templates/sidecar-injector-configmap.yaml new file mode 100644 index 0000000..3e51e6f --- /dev/null +++ b/istio-1.5.0/install/kubernetes/operator/charts/istio-control/istio-autoinject/templates/sidecar-injector-configmap.yaml @@ -0,0 +1,27 @@ +{{- if not .Values.global.omitSidecarInjectorConfigMap }} +apiVersion: v1 +kind: ConfigMap +metadata: + name: istio-sidecar-injector + namespace: {{ .Release.Namespace }} + labels: + release: {{ .Release.Name }} + app: sidecar-injector + istio: sidecar-injector +data: + values: |- + {{ .Values | toJson }} + + config: |- + policy: {{ .Values.global.proxy.autoInject }} + alwaysInjectSelector: +{{ toYaml .Values.sidecarInjectorWebhook.alwaysInjectSelector | trim | indent 6 }} + neverInjectSelector: +{{ toYaml .Values.sidecarInjectorWebhook.neverInjectSelector | trim | indent 6 }} +{{ .Files.Get "files/injection-template.yaml" | trim | indent 4 }} + injectedAnnotations: + {{- range $key, $val := .Values.sidecarInjectorWebhook.injectedAnnotations }} + "{{ $key }}": "{{ $val }}" + {{- end }} + +{{- end }} diff --git a/istio-1.5.0/install/kubernetes/operator/charts/istio-control/istio-autoinject/values.yaml b/istio-1.5.0/install/kubernetes/operator/charts/istio-control/istio-autoinject/values.yaml new file mode 100644 index 0000000..1521f21 --- /dev/null +++ b/istio-1.5.0/install/kubernetes/operator/charts/istio-control/istio-autoinject/values.yaml @@ -0,0 +1,89 @@ +sidecarInjectorWebhook: + # sidecar-injector webhook configuration. + # If down, new pods will fail to start or restart for a short time, but they will + # retry. + replicaCount: 1 + rollingMaxSurge: 100% + rollingMaxUnavailable: 25% + + hub: "" + tag: "" + image: sidecar_injector + + # This enables injection of sidecar in all namespaces, + # with the exception of namespaces with "istio-injection:disabled" annotation + # Only one environment should have this enabled. + enableNamespacesByDefault: false + + # If true, webhook or istioctl injector will rewrite PodSpec for liveness + # health check to redirect request to sidecar. This makes liveness check work + # even when mTLS is enabled. + rewriteAppHTTPProbe: false + + # If true, a self-signed CA will created in order to issue a certificate that + # will be used to authenticate the workload respondible for handling + # the sidecar-injector webhook. + selfSigned: false + + nodeSelector: {} + tolerations: [] + podAnnotations: {} + + # injectedAnnotations are additional annotations that will be added to the pod spec after injection + # This is primarily to support PSP annotations. For example, if you defined a PSP with the annotations: + # + # annotations: + # apparmor.security.beta.kubernetes.io/allowedProfileNames: runtime/default + # apparmor.security.beta.kubernetes.io/defaultProfileName: runtime/default + # + # The PSP controller would add corresponding annotations to the pod spec for each container. However, this happens before + # the inject adds additional containers, so we must specify them explicitly here. With the above example, we could specify: + # injectedAnnotations: + # container.apparmor.security.beta.kubernetes.io/istio-init: runtime/default + # container.apparmor.security.beta.kubernetes.io/istio-proxy: runtime/default + injectedAnnotations: {} + lifecycle: {} + + # If set, will use the value as injection label. The value must match the 'release' label of the injector, + # except when 1.2 istio-injection label is used, which must be set to "enabled". + injectLabel: istio-injection + + # Specify the pod anti-affinity that allows you to constrain which nodes + # your pod is eligible to be scheduled based on labels on pods that are + # already running on the node rather than based on labels on nodes. + # There are currently two types of anti-affinity: + # "requiredDuringSchedulingIgnoredDuringExecution" + # "preferredDuringSchedulingIgnoredDuringExecution" + # which denote "hard" vs. "soft" requirements, you can define your values + # in "podAntiAffinityLabelSelector" and "podAntiAffinityTermLabelSelector" + # correspondingly. + # For example: + # podAntiAffinityLabelSelector: + # - key: security + # operator: In + # values: S1,S2 + # topologyKey: "kubernetes.io/hostname" + # This pod anti-affinity rule says that the pod requires not to be scheduled + # onto a node if that node is already running a pod with label having key + # "security" and value "S1". + podAntiAffinityLabelSelector: [] + podAntiAffinityTermLabelSelector: [] + + # You can use the field called alwaysInjectSelector and neverInjectSelector which will always inject the sidecar or + # always skip the injection on pods that match that label selector, regardless of the global policy. + # See https://istio.io/docs/setup/kubernetes/additional-setup/sidecar-injection/#more-control-adding-exceptions + neverInjectSelector: [] + alwaysInjectSelector: [] + + resources: {} + + # Enable objectSelector to filter out pods with no need for sidecar before calling istio-sidecar-injector. + # It is disabled by default since this function will only work after k8s v1.15. + objectSelector: + enabled: false + autoInject: true + +# If set, no iptable init will be added. It assumes CNI is installed. +# TODO: rename to 'enableIptables' or add 'interceptionMode: CNI' +istio_cni: + enabled: false diff --git a/istio-1.5.0/install/kubernetes/operator/charts/istio-control/istio-config/Chart.yaml b/istio-1.5.0/install/kubernetes/operator/charts/istio-control/istio-config/Chart.yaml new file mode 100644 index 0000000..22b3d23 --- /dev/null +++ b/istio-1.5.0/install/kubernetes/operator/charts/istio-control/istio-config/Chart.yaml @@ -0,0 +1,13 @@ +apiVersion: v1 +name: istio-config +version: 1.1.0 +appVersion: 1.1.0 +tillerVersion: ">=2.7.2" +description: Helm chart for galley deployment +keywords: + - istio + - galley +sources: + - http://github.com/istio/istio +engine: gotpl +icon: https://istio.io/favicons/android-192x192.png diff --git a/istio-1.5.0/install/kubernetes/operator/charts/istio-control/istio-config/OWNERS b/istio-1.5.0/install/kubernetes/operator/charts/istio-control/istio-config/OWNERS new file mode 100644 index 0000000..d6a0e1b --- /dev/null +++ b/istio-1.5.0/install/kubernetes/operator/charts/istio-control/istio-config/OWNERS @@ -0,0 +1,5 @@ +approvers: + - cmluciano + - geeknoid + - ozevren + - ayj diff --git a/istio-1.5.0/install/kubernetes/operator/charts/istio-control/istio-config/README.md b/istio-1.5.0/install/kubernetes/operator/charts/istio-control/istio-config/README.md new file mode 100644 index 0000000..7153c5d --- /dev/null +++ b/istio-1.5.0/install/kubernetes/operator/charts/istio-control/istio-config/README.md @@ -0,0 +1,27 @@ +# Istio Config + +This component handles the configuration, exposing an MCP server. + +The default implementation is Galley, using the K8S apiserver for storage - other MCP providers may be configured. + +It is recommended to run only one production config server - it registers a validation webhook which will apply +to all Istio configs. It is possible to run a second staging/canary config server in a different namespace. + +## Installation + +Galley relies on DNS certificates. Before installing it in a custom namespace you should update Citadel or +create a custom certificate. + +## Validation + +A cluster should have a single galley with validation enabled - usually the prod environment. +It is possible to enable validation on other environments as well - but each Galley will do its own +validation, and a staging version may impact production validation. + +```yamml +security: + ... + dnsCerts: + ... + istio-galley-service-account.MY_NAMESPACE: istio-galley.MY_NAMESPACE.svc +``` diff --git a/istio-1.5.0/install/kubernetes/operator/charts/istio-control/istio-config/templates/_affinity.tpl b/istio-1.5.0/install/kubernetes/operator/charts/istio-control/istio-config/templates/_affinity.tpl new file mode 100644 index 0000000..c2a39d0 --- /dev/null +++ b/istio-1.5.0/install/kubernetes/operator/charts/istio-control/istio-config/templates/_affinity.tpl @@ -0,0 +1,93 @@ +{{/* affinity - https://kubernetes.io/docs/concepts/configuration/assign-pod-node/ */}} + +{{- define "nodeaffinity" }} + nodeAffinity: + requiredDuringSchedulingIgnoredDuringExecution: + {{- include "nodeAffinityRequiredDuringScheduling" . }} + preferredDuringSchedulingIgnoredDuringExecution: + {{- include "nodeAffinityPreferredDuringScheduling" . }} +{{- end }} + +{{- define "nodeAffinityRequiredDuringScheduling" }} + nodeSelectorTerms: + - matchExpressions: + - key: beta.kubernetes.io/arch + operator: In + values: + {{- range $key, $val := .Values.global.arch }} + {{- if gt ($val | int) 0 }} + - {{ $key | quote }} + {{- end }} + {{- end }} + {{- $nodeSelector := default .Values.global.defaultNodeSelector .Values.galley.nodeSelector -}} + {{- range $key, $val := $nodeSelector }} + - key: {{ $key }} + operator: In + values: + - {{ $val | quote }} + {{- end }} +{{- end }} + +{{- define "nodeAffinityPreferredDuringScheduling" }} + {{- range $key, $val := .Values.global.arch }} + {{- if gt ($val | int) 0 }} + - weight: {{ $val | int }} + preference: + matchExpressions: + - key: beta.kubernetes.io/arch + operator: In + values: + - {{ $key | quote }} + {{- end }} + {{- end }} +{{- end }} + +{{- define "podAntiAffinity" }} +{{- if or .Values.galley.podAntiAffinityLabelSelector .Values.galley.podAntiAffinityTermLabelSelector}} + podAntiAffinity: + {{- if .Values.galley.podAntiAffinityLabelSelector }} + requiredDuringSchedulingIgnoredDuringExecution: + {{- include "podAntiAffinityRequiredDuringScheduling" . }} + {{- end }} + {{- if .Values.galley.podAntiAffinityTermLabelSelector }} + preferredDuringSchedulingIgnoredDuringExecution: + {{- include "podAntiAffinityPreferredDuringScheduling" . }} + {{- end }} +{{- end }} +{{- end }} + +{{- define "podAntiAffinityRequiredDuringScheduling" }} + {{- range $index, $item := .Values.galley.podAntiAffinityLabelSelector }} + - labelSelector: + matchExpressions: + - key: {{ $item.key }} + operator: {{ $item.operator }} + {{- if $item.values }} + values: + {{- $vals := split "," $item.values }} + {{- range $i, $v := $vals }} + - {{ $v | quote }} + {{- end }} + {{- end }} + topologyKey: {{ $item.topologyKey }} + {{- end }} +{{- end }} + +{{- define "podAntiAffinityPreferredDuringScheduling" }} + {{- range $index, $item := .Values.galley.podAntiAffinityTermLabelSelector }} + - podAffinityTerm: + labelSelector: + matchExpressions: + - key: {{ $item.key }} + operator: {{ $item.operator }} + {{- if $item.values }} + values: + {{- $vals := split "," $item.values }} + {{- range $i, $v := $vals }} + - {{ $v | quote }} + {{- end }} + {{- end }} + topologyKey: {{ $item.topologyKey }} + weight: 100 + {{- end }} +{{- end }} diff --git a/istio-1.5.0/install/kubernetes/operator/charts/istio-control/istio-config/templates/_helpers.tpl b/istio-1.5.0/install/kubernetes/operator/charts/istio-control/istio-config/templates/_helpers.tpl new file mode 100644 index 0000000..e3167c2 --- /dev/null +++ b/istio-1.5.0/install/kubernetes/operator/charts/istio-control/istio-config/templates/_helpers.tpl @@ -0,0 +1,36 @@ +{{/* vim: set filetype=mustache: */}} +{{/* +Expand the name of the chart. +*/}} +{{- define "pilot.name" -}} +{{- default .Chart.Name .Values.galley.nameOverride | trunc 63 | trimSuffix "-" -}} +{{- end -}} + +{{/* +Create a default fully qualified app name. +We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). +If release name contains chart name it will be used as a full name. +*/}} +{{- define "pilot.fullname" -}} +{{- if .Values.galley.fullnameOverride -}} +{{- .Values.galley.fullnameOverride | trunc 63 | trimSuffix "-" -}} +{{- else -}} +{{- $name := default .Chart.Name .Values.galley.nameOverride -}} +{{- if contains $name .Release.Name -}} +{{- .Release.Name | trunc 63 | trimSuffix "-" -}} +{{- else -}} +{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" -}} +{{- end -}} +{{- end -}} +{{- end -}} + +{{/* +Create chart name and version as used by the chart label. +*/}} +{{- define "pilot.chart" -}} +{{- .Chart.Name | trunc 63 | trimSuffix "-" -}} +{{- end -}} + +{{- define "istio.configmap.checksum" -}} +{{- print $.Template.BasePath "/configmap.yaml" | sha256sum -}} +{{- end -}} diff --git a/istio-1.5.0/install/kubernetes/operator/charts/istio-control/istio-config/templates/clusterrole.yaml b/istio-1.5.0/install/kubernetes/operator/charts/istio-control/istio-config/templates/clusterrole.yaml new file mode 100644 index 0000000..c82d409 --- /dev/null +++ b/istio-1.5.0/install/kubernetes/operator/charts/istio-control/istio-config/templates/clusterrole.yaml @@ -0,0 +1,57 @@ +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: istio-galley-{{ .Release.Namespace }} + labels: + release: {{ .Release.Name }} +rules: + # For reading Istio resources + - apiGroups: [ + "authentication.istio.io", + "config.istio.io", + "networking.istio.io", + "rbac.istio.io", + "security.istio.io"] + resources: ["*"] + verbs: ["get", "list", "watch"] + # For updating Istio resource statuses + - apiGroups: [ + "authentication.istio.io", + "config.istio.io", + "networking.istio.io", + "rbac.istio.io", + "security.istio.io"] + resources: ["*/status"] + verbs: ["update"] + # Remove galley's permissions to reconcile the validation config when istiod is present. +{{- if not (or .Values.global.operatorManageWebhooks .Values.global.istiod.enabled) }} + - apiGroups: ["admissionregistration.k8s.io"] + resources: ["validatingwebhookconfigurations"] + verbs: ["*"] + # permissions to verify the webhook is ready and rejecting + # invalid config. We use --server-dry-run so no config is persisted. + - apiGroups: ["networking.istio.io"] + verbs: ["create"] + resources: ["gateways"] +{{- end }} + - apiGroups: ["extensions","apps"] + resources: ["deployments"] + resourceNames: ["istio-galley"] + verbs: ["get"] + - apiGroups: [""] + resources: ["pods", "nodes", "services", "endpoints", "namespaces"] + verbs: ["get", "list", "watch"] + - apiGroups: ["extensions"] + resources: ["ingresses"] + verbs: ["get", "list", "watch"] + - apiGroups: ["extensions"] + resources: ["deployments/finalizers"] + resourceNames: ["istio-galley"] + verbs: ["update"] + - apiGroups: ["apiextensions.k8s.io"] + resources: ["customresourcedefinitions"] + verbs: ["get", "list", "watch"] + - apiGroups: ["rbac.authorization.k8s.io"] + resources: ["clusterroles"] + verbs: ["get", "list", "watch"] +--- diff --git a/istio-1.5.0/install/kubernetes/operator/charts/istio-control/istio-config/templates/clusterrolebinding.yaml b/istio-1.5.0/install/kubernetes/operator/charts/istio-control/istio-config/templates/clusterrolebinding.yaml new file mode 100644 index 0000000..a291f80 --- /dev/null +++ b/istio-1.5.0/install/kubernetes/operator/charts/istio-control/istio-config/templates/clusterrolebinding.yaml @@ -0,0 +1,15 @@ +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: istio-galley-admin-role-binding-{{ .Release.Namespace }} + labels: + release: {{ .Release.Name }} +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: istio-galley-{{ .Release.Namespace }} +subjects: + - kind: ServiceAccount + name: istio-galley-service-account + namespace: {{ .Release.Namespace }} +--- diff --git a/istio-1.5.0/install/kubernetes/operator/charts/istio-control/istio-config/templates/configmap-envoy.yaml b/istio-1.5.0/install/kubernetes/operator/charts/istio-control/istio-config/templates/configmap-envoy.yaml new file mode 100644 index 0000000..c3103a6 --- /dev/null +++ b/istio-1.5.0/install/kubernetes/operator/charts/istio-control/istio-config/templates/configmap-envoy.yaml @@ -0,0 +1,92 @@ +{{- if .Values.global.controlPlaneSecurityEnabled }} +apiVersion: v1 +kind: ConfigMap +metadata: + namespace: {{ .Release.Namespace }} + name: galley-envoy-config + labels: + app: galley + istio: galley + release: {{ .Release.Name }} +data: + envoy.yaml.tmpl: |- + admin: + access_log_path: /dev/null + address: + socket_address: + address: 127.0.0.1 + port_value: 15000 + + static_resources: + + clusters: + - name: in.9901 + http2_protocol_options: {} + connect_timeout: 1.000s + + hosts: + - socket_address: + address: 127.0.0.1 + port_value: 9901 + + circuit_breakers: + thresholds: + - max_connections: 100000 + max_pending_requests: 100000 + max_requests: 100000 + max_retries: 3 + + listeners: + - name: "15019" + address: + socket_address: + address: 0.0.0.0 + port_value: 15019 + filter_chains: + - filters: + - name: envoy.http_connection_manager + config: + codec_type: HTTP2 + stat_prefix: "15010" + stream_idle_timeout: 0s + http2_protocol_options: + max_concurrent_streams: 1073741824 + + access_log: + - name: envoy.file_access_log + config: + path: /dev/stdout + + http_filters: + - name: envoy.router + + route_config: + name: "15019" + + virtual_hosts: + - name: istio-galley + + domains: + - '*' + + routes: + - match: + prefix: / + route: + cluster: in.9901 + timeout: 0.000s + tls_context: + common_tls_context: + alpn_protocols: + - h2 + tls_certificates: + - certificate_chain: + filename: /etc/certs/cert-chain.pem + private_key: + filename: /etc/certs/key.pem + validation_context: + trusted_ca: + filename: /etc/certs/root-cert.pem + require_client_certificate: true +{{- end }} +--- diff --git a/istio-1.5.0/install/kubernetes/operator/charts/istio-control/istio-config/templates/configmap-mesh.yaml b/istio-1.5.0/install/kubernetes/operator/charts/istio-control/istio-config/templates/configmap-mesh.yaml new file mode 100644 index 0000000..3a25928 --- /dev/null +++ b/istio-1.5.0/install/kubernetes/operator/charts/istio-control/istio-config/templates/configmap-mesh.yaml @@ -0,0 +1,11 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: istio-mesh-galley + namespace: {{ .Release.Namespace }} + labels: + release: {{ .Release.Name }} +data: + mesh: |- +{{ toYaml .Values.galley.mesh | indent 4 }} +--- diff --git a/istio-1.5.0/install/kubernetes/operator/charts/istio-control/istio-config/templates/configmap.yaml b/istio-1.5.0/install/kubernetes/operator/charts/istio-control/istio-config/templates/configmap.yaml new file mode 100644 index 0000000..e05340c --- /dev/null +++ b/istio-1.5.0/install/kubernetes/operator/charts/istio-control/istio-config/templates/configmap.yaml @@ -0,0 +1,13 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: istio-galley-configuration + namespace: {{ .Release.Namespace }} + labels: + release: {{ .Release.Name }} +data: +{{- if .Values.global.configValidation }} + validatingwebhookconfiguration.yaml: |- + {{- include "validatingwebhookconfiguration.yaml.tpl" . | indent 4}} +{{- end}} +--- diff --git a/istio-1.5.0/install/kubernetes/operator/charts/istio-control/istio-config/templates/deployment.yaml b/istio-1.5.0/install/kubernetes/operator/charts/istio-control/istio-config/templates/deployment.yaml new file mode 100644 index 0000000..b72c141 --- /dev/null +++ b/istio-1.5.0/install/kubernetes/operator/charts/istio-control/istio-config/templates/deployment.yaml @@ -0,0 +1,229 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: istio-galley + namespace: {{ .Release.Namespace }} + labels: + app: galley + istio: galley + release: {{ .Release.Name }} +spec: + replicas: {{ .Values.galley.replicaCount }} + selector: + matchLabels: + istio: galley + strategy: + rollingUpdate: + maxSurge: {{ .Values.galley.rollingMaxSurge }} + maxUnavailable: {{ .Values.galley.rollingMaxUnavailable }} + template: + metadata: + labels: + app: galley + istio: galley +{{- if eq .Release.Namespace "istio-system"}} + heritage: Tiller + release: istio + chart: galley +{{- end }} + annotations: + sidecar.istio.io/inject: "false" + {{- if .Values.galley.podAnnotations }} +{{ toYaml .Values.galley.podAnnotations | indent 8 }} + {{- end }} + spec: + serviceAccountName: istio-galley-service-account +{{- if .Values.global.priorityClassName }} + priorityClassName: "{{ .Values.global.priorityClassName }}" +{{- end }} + containers: + - name: galley +{{- if contains "/" .Values.galley.image }} + image: "{{ .Values.galley.image }}" +{{- else }} + image: "{{ .Values.galley.hub | default .Values.global.hub }}/{{ .Values.galley.image | default "galley" }}:{{ .Values.galley.tag | default .Values.global.tag }}" +{{- end }} + imagePullPolicy: {{ .Values.global.imagePullPolicy | default "Always" }} + ports: + - containerPort: 9443 + - containerPort: 15014 + - containerPort: 15019 + - containerPort: 9901 + command: + - /usr/local/bin/galley + - server + - --meshConfigFile=/etc/mesh-config/mesh + - --livenessProbeInterval=1s + - --livenessProbePath=/tmp/healthliveness + - --readinessProbePath=/tmp/healthready + - --readinessProbeInterval=1s + - --insecure=true + {{- if and .Values.global.configValidation (not .Values.global.istiod.enabled) }} + - --enable-validation=true + {{- else }} + - --enable-validation=false + {{- end }} + {{- if or .Values.global.operatorManageWebhooks .Values.global.istiod.enabled }} + - --enable-reconcileWebhookConfiguration=false + {{- else }} + - --enable-reconcileWebhookConfiguration=true + {{- end }} + {{- if .Values.galley.enableServiceDiscovery }} + - --enableServiceDiscovery=true + {{- end }} + - --enable-server=true + {{- if .Values.galley.enableAnalysis }} + - --enableAnalysis=true + {{- end }} + - --deployment-namespace={{ .Release.Namespace }} + - --monitoringPort=15014 + - --validation-port=9443 +{{- if $.Values.global.logging.level }} + - --log_output_level={{ $.Values.global.logging.level }} +{{- end}} +{{- if .Values.global.certificates }} + - --validation.tls.clientCertificate=/etc/dnscerts/cert-chain.pem + - --validation.tls.privateKey=/etc/dnscerts/key.pem + - --validation.tls.caCertificates=/etc/dnscerts/root-cert.pem +{{- end }} + securityContext: + runAsUser: 1337 + runAsGroup: 1337 + runAsNonRoot: true + capabilities: + drop: + - ALL + volumeMounts: + {{- if and .Values.global.configValidation (not .Values.global.istiod.enabled) }} + - name: istio-certs + mountPath: /etc/certs + readOnly: true + {{- end }} + {{- if .Values.global.certificates }} + - name: dnscerts + mountPath: /etc/dnscerts + readOnly: true + {{- end }} + - name: config + mountPath: /etc/config + readOnly: true + - name: mesh-config + mountPath: /etc/mesh-config + readOnly: true + livenessProbe: + exec: + command: + - /usr/local/bin/galley + - probe + - --probe-path=/tmp/healthliveness + - --interval=10s + initialDelaySeconds: 5 + periodSeconds: 5 + readinessProbe: + exec: + command: + - /usr/local/bin/galley + - probe + - --probe-path=/tmp/healthready + - --interval=10s + initialDelaySeconds: 5 + periodSeconds: 5 + resources: +{{- if .Values.galley.resources }} +{{ toYaml .Values.galley.resources | indent 12 }} +{{- else }} +{{ toYaml .Values.global.defaultResources | indent 12 }} +{{- end }} + +{{- if .Values.global.controlPlaneSecurityEnabled }} + - name: istio-proxy +{{- if contains "/" .Values.global.proxy.image }} + image: "{{ .Values.global.proxy.image }}" +{{- else }} + image: "{{ .Values.global.hub | default "gcr.io/istio-release" }}/{{ .Values.global.proxy.image | default "proxyv2" }}:{{ .Values.global.tag | default "release-1.1-latest-daily" }}" +{{- end }} + imagePullPolicy: {{ .Values.global.imagePullPolicy | default "Always" }} + ports: + - containerPort: 9902 + args: + - proxy + - --serviceCluster + - istio-galley + - --templateFile + - /var/lib/istio/galley/envoy/envoy.yaml.tmpl + - --controlPlaneAuthPolicy + - MUTUAL_TLS + {{- if .Values.global.trustDomain }} + - --trust-domain={{ .Values.global.trustDomain }} + {{- end }} + {{- if .Values.global.logAsJson }} + - --log_as_json + {{- end }} + env: + - name: POD_NAME + valueFrom: + fieldRef: + apiVersion: v1 + fieldPath: metadata.name + - name: POD_NAMESPACE + valueFrom: + fieldRef: + apiVersion: v1 + fieldPath: metadata.namespace + - name: INSTANCE_IP + valueFrom: + fieldRef: + apiVersion: v1 + fieldPath: status.podIP + resources: +{{- if .Values.global.proxy.resources }} +{{ toYaml .Values.global.proxy.resources | indent 12 }} +{{- else }} +{{ toYaml .Values.global.defaultResources | indent 12 }} +{{- end }} + volumeMounts: + - name: istio-certs + mountPath: /etc/certs + readOnly: true + - name: envoy-config + mountPath: /var/lib/istio/galley/envoy +{{- end }} + securityContext: + fsGroup: 1337 + volumes: + {{- if or .Values.global.controlPlaneSecurityEnabled (and .Values.global.configValidation (not .Values.global.istiod.enabled)) }} + - name: istio-certs + secret: + secretName: istio.istio-galley-service-account + {{- end }} + {{- if .Values.global.certificates }} + - name: dnscerts + secret: + secretName: dns.istio-galley-service-account + {{- end }} + {{- if .Values.global.controlPlaneSecurityEnabled }} + - name: envoy-config + configMap: + name: galley-envoy-config + {{- end }} + # galley expects /etc/config to exist even though it doesn't include any files. + - name: config + emptyDir: + medium: Memory + # Different config map from pilot, to allow independent config and rollout. + # Both are derived from values.yaml. + - name: mesh-config + configMap: + name: istio-mesh-galley + + affinity: + {{- include "nodeaffinity" . | indent 6 }} + {{- include "podAntiAffinity" . | indent 6 }} +{{- if .Values.galley.tolerations }} + tolerations: +{{ toYaml .Values.galley.tolerations | indent 6 }} +{{- else if .Values.global.defaultTolerations }} + tolerations: +{{ toYaml .Values.global.defaultTolerations | indent 6 }} +{{- end }} +--- diff --git a/istio-1.5.0/install/kubernetes/operator/charts/istio-control/istio-config/templates/poddisruptionbudget.yaml b/istio-1.5.0/install/kubernetes/operator/charts/istio-control/istio-config/templates/poddisruptionbudget.yaml new file mode 100644 index 0000000..9b9bec9 --- /dev/null +++ b/istio-1.5.0/install/kubernetes/operator/charts/istio-control/istio-config/templates/poddisruptionbudget.yaml @@ -0,0 +1,20 @@ +{{- if .Values.global.defaultPodDisruptionBudget.enabled }} +apiVersion: policy/v1beta1 +kind: PodDisruptionBudget +metadata: + name: istio-galley + namespace: {{ .Release.Namespace }} + labels: + app: galley + release: {{ .Release.Name }} + istio: galley +spec: + minAvailable: 1 + selector: + matchLabels: + app: galley + release: {{ .Release.Name }} + istio: galley +--- + +{{- end }} diff --git a/istio-1.5.0/install/kubernetes/operator/charts/istio-control/istio-config/templates/service.yaml b/istio-1.5.0/install/kubernetes/operator/charts/istio-control/istio-config/templates/service.yaml new file mode 100644 index 0000000..dd5d056 --- /dev/null +++ b/istio-1.5.0/install/kubernetes/operator/charts/istio-control/istio-config/templates/service.yaml @@ -0,0 +1,23 @@ +apiVersion: v1 +kind: Service +metadata: + name: istio-galley + namespace: {{ .Release.Namespace }} + labels: + app: galley + istio: galley + release: {{ .Release.Name }} +spec: + ports: + - port: 443 + name: https-validation + targetPort: 9443 + - port: 15014 + name: http-monitoring + - port: 9901 + name: grpc-mcp + - port: 15019 + name: grpc-tls-mcp + selector: + istio: galley +--- diff --git a/istio-1.5.0/install/kubernetes/operator/charts/istio-control/istio-config/templates/serviceaccount.yaml b/istio-1.5.0/install/kubernetes/operator/charts/istio-control/istio-config/templates/serviceaccount.yaml new file mode 100644 index 0000000..d4cf8ff --- /dev/null +++ b/istio-1.5.0/install/kubernetes/operator/charts/istio-control/istio-config/templates/serviceaccount.yaml @@ -0,0 +1,15 @@ +apiVersion: v1 +kind: ServiceAccount +{{- if .Values.global.imagePullSecrets }} +imagePullSecrets: +{{- range .Values.global.imagePullSecrets }} + - name: {{ . }} +{{- end }} +{{- end }} +metadata: + name: istio-galley-service-account + namespace: {{ .Release.Namespace }} + labels: + app: galley + release: {{ .Release.Name }} +--- diff --git a/istio-1.5.0/install/kubernetes/operator/charts/istio-control/istio-config/templates/validatingwebhookconfiguration.yaml b/istio-1.5.0/install/kubernetes/operator/charts/istio-control/istio-config/templates/validatingwebhookconfiguration.yaml new file mode 100644 index 0000000..04e148c --- /dev/null +++ b/istio-1.5.0/install/kubernetes/operator/charts/istio-control/istio-config/templates/validatingwebhookconfiguration.yaml @@ -0,0 +1,90 @@ +{{/* +This version of the validatingwebhookconfiguration is applied directly by +istio/operator. Galley only patches the caBundle and failurePolicy. +*/}} +{{- if .Values.global.istiod.enabled }} +apiVersion: admissionregistration.k8s.io/v1beta1 +kind: ValidatingWebhookConfiguration +metadata: + name: istio-galley + labels: + app: galley + release: {{ .Release.Name }} + istio: galley +webhooks: +{{- else }} +apiVersion: admissionregistration.k8s.io/v1beta1 +kind: ValidatingWebhookConfiguration +metadata: + name: istio-galley + labels: + app: galley + release: {{ .Release.Name }} + istio: galley +webhooks: + - name: pilot.validation.istio.io + clientConfig: + service: + name: istio-galley + namespace: {{ .Release.Namespace }} + path: "/admitpilot" + caBundle: "" + rules: + - operations: + - CREATE + - UPDATE + apiGroups: + - config.istio.io + apiVersions: + - v1alpha2 + resources: + - httpapispecs + - httpapispecbindings + - quotaspecs + - quotaspecbindings + - operations: + - CREATE + - UPDATE + apiGroups: + - rbac.istio.io + - security.istio.io + - authentication.istio.io + - networking.istio.io + apiVersions: + - "*" + resources: + - "*" + # Fail open until the validation webhook is ready. The webhook controller + # will update this to `Fail` and patch in the `caBundle` when the webhook + # endpoint is ready. + failurePolicy: Ignore + sideEffects: None + - name: mixer.validation.istio.io + clientConfig: + service: + name: istio-galley + namespace: {{ .Release.Namespace }} + path: "/admitmixer" + caBundle: "" + rules: + - operations: + - CREATE + - UPDATE + apiGroups: + - config.istio.io + apiVersions: + - v1alpha2 + resources: + - rules + - attributemanifests + - adapters + - handlers + - instances + - templates + # Fail open until the validation webhook is ready. The webhook controller + # will update this to `Fail` and patch in the `caBundle` when the webhook + # endpoint is ready. + failurePolicy: Ignore + sideEffects: None +{{- end }} +--- diff --git a/istio-1.5.0/install/kubernetes/operator/charts/istio-control/istio-config/templates/validatingwebhookconfiguration.yaml.tpl b/istio-1.5.0/install/kubernetes/operator/charts/istio-control/istio-config/templates/validatingwebhookconfiguration.yaml.tpl new file mode 100644 index 0000000..23f0986 --- /dev/null +++ b/istio-1.5.0/install/kubernetes/operator/charts/istio-control/istio-config/templates/validatingwebhookconfiguration.yaml.tpl @@ -0,0 +1,93 @@ +{{/* +This version of the validatingwebhookconfiguration is applied indirectly +by galley. This exists to support a smoother upgrade path from istio +Rversions < 1.4 +*/}} +{{ define "validatingwebhookconfiguration.yaml.tpl" }} +{{- if .Values.global.istiod.enabled }} +apiVersion: admissionregistration.k8s.io/v1beta1 +kind: ValidatingWebhookConfiguration +metadata: + name: istio-galley + labels: + app: galley + release: {{ .Release.Name }} + istio: galley +webhooks: +{{- else }} +apiVersion: admissionregistration.k8s.io/v1beta1 +kind: ValidatingWebhookConfiguration +metadata: + name: istio-galley + labels: + app: galley + release: {{ .Release.Name }} + istio: galley +webhooks: + - name: pilot.validation.istio.io + clientConfig: + service: + name: istio-galley + namespace: {{ .Release.Namespace }} + path: "/admitpilot" + caBundle: "" + rules: + - operations: + - CREATE + - UPDATE + apiGroups: + - config.istio.io + apiVersions: + - v1alpha2 + resources: + - httpapispecs + - httpapispecbindings + - quotaspecs + - quotaspecbindings + - operations: + - CREATE + - UPDATE + apiGroups: + - rbac.istio.io + - security.istio.io + - authentication.istio.io + - networking.istio.io + apiVersions: + - "*" + resources: + - "*" + # Fail open until the validation webhook is ready. The webhook controller + # will update this to `Fail` and patch in the `caBundle` when the webhook + # endpoint is ready. + failurePolicy: Ignore + sideEffects: None + - name: mixer.validation.istio.io + clientConfig: + service: + name: istio-galley + namespace: {{ .Release.Namespace }} + path: "/admitmixer" + caBundle: "" + rules: + - operations: + - CREATE + - UPDATE + apiGroups: + - config.istio.io + apiVersions: + - v1alpha2 + resources: + - rules + - attributemanifests + - adapters + - handlers + - instances + - templates + # Fail open until the validation webhook is ready. The webhook controller + # will update this to `Fail` and patch in the `caBundle` when the webhook + # endpoint is ready. + failurePolicy: Ignore + sideEffects: None +{{- end }} +{{- end }} +--- diff --git a/istio-1.5.0/install/kubernetes/operator/charts/istio-control/istio-config/values.yaml b/istio-1.5.0/install/kubernetes/operator/charts/istio-control/istio-config/values.yaml new file mode 100644 index 0000000..939673d --- /dev/null +++ b/istio-1.5.0/install/kubernetes/operator/charts/istio-control/istio-config/values.yaml @@ -0,0 +1,48 @@ +galley: + hub: "" + tag: "" + image: galley + replicaCount: 1 + rollingMaxSurge: 100% + rollingMaxUnavailable: 25% + + enableServiceDiscovery: false + + resources: + requests: + cpu: 100m + # memory: 128Mi + # limits: + # cpu: 100m + # memory: 128Mi + + # TODO: Galley appears to use the mesh config - need to find which fields are used and need to be configured. + mesh: {} + + nodeSelector: {} + tolerations: [] + podAnnotations: {} + + # Specify the pod anti-affinity that allows you to constrain which nodes + # your pod is eligible to be scheduled based on labels on pods that are + # already running on the node rather than based on labels on nodes. + # There are currently two types of anti-affinity: + # "requiredDuringSchedulingIgnoredDuringExecution" + # "preferredDuringSchedulingIgnoredDuringExecution" + # which denote "hard" vs. "soft" requirements, you can define your values + # in "podAntiAffinityLabelSelector" and "podAntiAffinityTermLabelSelector" + # correspondingly. + # For example: + # podAntiAffinityLabelSelector: + # - key: security + # operator: In + # values: S1,S2 + # topologyKey: "kubernetes.io/hostname" + # This pod anti-affinity rule says that the pod requires not to be scheduled + # onto a node if that node is already running a pod with label having key + # "security" and value "S1". + podAntiAffinityLabelSelector: [] + podAntiAffinityTermLabelSelector: [] + + # Enable analysis and status update in Galley + enableAnalysis: false diff --git a/istio-1.5.0/install/kubernetes/operator/charts/istio-control/istio-discovery/Chart.yaml b/istio-1.5.0/install/kubernetes/operator/charts/istio-control/istio-discovery/Chart.yaml new file mode 100644 index 0000000..4f50841 --- /dev/null +++ b/istio-1.5.0/install/kubernetes/operator/charts/istio-control/istio-discovery/Chart.yaml @@ -0,0 +1,12 @@ +apiVersion: v1 +name: istio-discovery +version: 1.1.0 +appVersion: 1.1.0 +tillerVersion: ">=2.7.2" +description: Helm chart for istio control plane +keywords: + - istio +sources: + - http://github.com/istio/istio +engine: gotpl +icon: https://istio.io/favicons/android-192x192.png diff --git a/istio-1.5.0/install/kubernetes/operator/charts/istio-control/istio-discovery/NOTES.txt b/istio-1.5.0/install/kubernetes/operator/charts/istio-control/istio-discovery/NOTES.txt new file mode 100644 index 0000000..997f4ac --- /dev/null +++ b/istio-1.5.0/install/kubernetes/operator/charts/istio-control/istio-discovery/NOTES.txt @@ -0,0 +1,5 @@ +Minimal control plane for Istio. Pilot and mesh config are included. + +MCP and injector should optionally be installed in the same namespace. Alternatively remote +address of an MCP server can be set. + diff --git a/istio-1.5.0/install/kubernetes/operator/charts/istio-control/istio-discovery/files/injection-template.yaml b/istio-1.5.0/install/kubernetes/operator/charts/istio-control/istio-discovery/files/injection-template.yaml new file mode 100644 index 0000000..fd0447b --- /dev/null +++ b/istio-1.5.0/install/kubernetes/operator/charts/istio-control/istio-discovery/files/injection-template.yaml @@ -0,0 +1,477 @@ +# Configmap optimized for Istiod. Please DO NOT MERGE all changes from istio - in particular those dependent on +# Values.yaml, which should not be used by istiod. + +# Istiod only uses SDS based config ( files will mapped/handled by SDS). + +template: | + rewriteAppHTTPProbe: {{ valueOrDefault .Values.sidecarInjectorWebhook.rewriteAppHTTPProbe false }} + initContainers: + {{ if ne (annotation .ObjectMeta `sidecar.istio.io/interceptionMode` .ProxyConfig.InterceptionMode) `NONE` }} + {{ if .Values.istio_cni.enabled -}} + - name: istio-validation + {{ else -}} + - name: istio-init + {{ end -}} + {{- if contains "/" .Values.global.proxy_init.image }} + image: "{{ .Values.global.proxy_init.image }}" + {{- else }} + image: "{{ .Values.global.hub }}/{{ .Values.global.proxy_init.image }}:{{ .Values.global.tag }}" + {{- end }} + command: + - istio-iptables + - "-p" + - 15001 + - "-z" + - "15006" + - "-u" + - 1337 + - "-m" + - "{{ annotation .ObjectMeta `sidecar.istio.io/interceptionMode` .ProxyConfig.InterceptionMode }}" + - "-i" + - "{{ annotation .ObjectMeta `traffic.sidecar.istio.io/includeOutboundIPRanges` .Values.global.proxy.includeIPRanges }}" + - "-x" + - "{{ annotation .ObjectMeta `traffic.sidecar.istio.io/excludeOutboundIPRanges` .Values.global.proxy.excludeIPRanges }}" + - "-b" + - "{{ annotation .ObjectMeta `traffic.sidecar.istio.io/includeInboundPorts` `*` }}" + - "-d" + - "15090,{{ excludeInboundPort (annotation .ObjectMeta `status.sidecar.istio.io/port` .Values.global.proxy.statusPort) (annotation .ObjectMeta `traffic.sidecar.istio.io/excludeInboundPorts` .Values.global.proxy.excludeInboundPorts) }}" + {{ if or (isset .ObjectMeta.Annotations `traffic.sidecar.istio.io/excludeOutboundPorts`) (ne (valueOrDefault .Values.global.proxy.excludeOutboundPorts "") "") -}} + - "-o" + - "{{ annotation .ObjectMeta `traffic.sidecar.istio.io/excludeOutboundPorts` .Values.global.proxy.excludeOutboundPorts }}" + {{ end -}} + {{ if (isset .ObjectMeta.Annotations `traffic.sidecar.istio.io/kubevirtInterfaces`) -}} + - "-k" + - "{{ index .ObjectMeta.Annotations `traffic.sidecar.istio.io/kubevirtInterfaces` }}" + {{ end -}} + {{ if .Values.istio_cni.enabled -}} + - "--run-validation" + - "--skip-rule-apply" + {{ end -}} + imagePullPolicy: "{{ valueOrDefault .Values.global.imagePullPolicy `Always` }}" + {{- if .Values.global.proxy_init.resources }} + resources: + {{ toYaml .Values.global.proxy_init.resources | indent 4 }} + {{- else }} + resources: {} + {{- end }} + securityContext: + allowPrivilegeEscalation: {{ .Values.global.proxy.privileged }} + privileged: {{ .Values.global.proxy.privileged }} + capabilities: + {{- if not .Values.istio_cni.enabled }} + add: + - NET_ADMIN + - NET_RAW + {{- end }} + drop: + - ALL + readOnlyRootFilesystem: false + {{- if not .Values.istio_cni.enabled }} + runAsGroup: 0 + runAsNonRoot: false + runAsUser: 0 + {{- else }} + runAsGroup: 1337 + runAsUser: 1337 + runAsNonRoot: true + {{- end }} + restartPolicy: Always + {{ end -}} + {{- if eq .Values.global.proxy.enableCoreDump true }} + - name: enable-core-dump + args: + - -c + - sysctl -w kernel.core_pattern=/var/lib/istio/core.proxy && ulimit -c unlimited + command: + - /bin/sh + {{- if contains "/" .Values.global.proxy_init.image }} + image: "{{ .Values.global.proxy_init.image }}" + {{- else }} + image: "{{ .Values.global.hub }}/{{ .Values.global.proxy_init.image }}:{{ .Values.global.tag }}" + {{- end }} + imagePullPolicy: "{{ valueOrDefault .Values.global.imagePullPolicy `Always` }}" + resources: {} + securityContext: + allowPrivilegeEscalation: true + capabilities: + add: + - SYS_ADMIN + drop: + - ALL + privileged: true + readOnlyRootFilesystem: false + runAsGroup: 0 + runAsNonRoot: false + runAsUser: 0 + {{ end }} + containers: + - name: istio-proxy + {{- if contains "/" (annotation .ObjectMeta `sidecar.istio.io/proxyImage` .Values.global.proxy.image) }} + image: "{{ annotation .ObjectMeta `sidecar.istio.io/proxyImage` .Values.global.proxy.image }}" + {{- else }} + image: "{{ .Values.global.hub }}/{{ .Values.global.proxy.image }}:{{ .Values.global.tag }}" + {{- end }} + ports: + - containerPort: 15090 + protocol: TCP + name: http-envoy-prom + args: + - proxy + - sidecar + - --domain + - $(POD_NAMESPACE).svc.{{ .Values.global.proxy.clusterDomain }} + - --configPath + - "/etc/istio/proxy" + - --binaryPath + - "/usr/local/bin/envoy" + - --serviceCluster + {{ if ne "" (index .ObjectMeta.Labels "app") -}} + - "{{ index .ObjectMeta.Labels `app` }}.$(POD_NAMESPACE)" + {{ else -}} + - "{{ valueOrDefault .DeploymentMeta.Name `istio-proxy` }}.{{ valueOrDefault .DeploymentMeta.Namespace `default` }}" + {{ end -}} + - --drainDuration + - "{{ formatDuration .ProxyConfig.DrainDuration }}" + - --parentShutdownDuration + - "{{ formatDuration .ProxyConfig.ParentShutdownDuration }}" + - --discoveryAddress + - "{{ annotation .ObjectMeta `sidecar.istio.io/discoveryAddress` .ProxyConfig.DiscoveryAddress }}" + {{- if eq .Values.global.proxy.tracer "lightstep" }} + - --lightstepAddress + - "{{ .ProxyConfig.GetTracing.GetLightstep.GetAddress }}" + - --lightstepAccessToken + - "{{ .ProxyConfig.GetTracing.GetLightstep.GetAccessToken }}" + - --lightstepSecure={{ .ProxyConfig.GetTracing.GetLightstep.GetSecure }} + - --lightstepCacertPath + - "{{ .ProxyConfig.GetTracing.GetLightstep.GetCacertPath }}" + {{- else if eq .Values.global.proxy.tracer "zipkin" }} + - --zipkinAddress + - "{{ .ProxyConfig.GetTracing.GetZipkin.GetAddress }}" + {{- else if eq .Values.global.proxy.tracer "datadog" }} + - --datadogAgentAddress + - "{{ .ProxyConfig.GetTracing.GetDatadog.GetAddress }}" + {{- end }} + - --proxyLogLevel={{ annotation .ObjectMeta `sidecar.istio.io/logLevel` .Values.global.proxy.logLevel}} + - --proxyComponentLogLevel={{ annotation .ObjectMeta `sidecar.istio.io/componentLogLevel` .Values.global.proxy.componentLogLevel}} + - --connectTimeout + - "{{ formatDuration .ProxyConfig.ConnectTimeout }}" + {{- if .Values.global.proxy.envoyStatsd.enabled }} + - --statsdUdpAddress + - "{{ .ProxyConfig.StatsdUdpAddress }}" + {{- end }} + {{- if .Values.global.proxy.envoyMetricsService.enabled }} + - --envoyMetricsService + - '{{ protoToJSON .ProxyConfig.EnvoyMetricsService }}' + {{- end }} + {{- if .Values.global.proxy.envoyAccessLogService.enabled }} + - --envoyAccessLogService + - '{{ protoToJSON .ProxyConfig.EnvoyAccessLogService }}' + {{- end }} + - --proxyAdminPort + - "{{ .ProxyConfig.ProxyAdminPort }}" + {{ if gt .ProxyConfig.Concurrency 0 -}} + - --concurrency + - "{{ .ProxyConfig.Concurrency }}" + {{ end -}} + {{- if .Values.global.istiod.enabled }} + - --controlPlaneAuthPolicy + - NONE + {{- else if .Values.global.controlPlaneSecurityEnabled }} + - --controlPlaneAuthPolicy + - MUTUAL_TLS + {{- else }} + - --controlPlaneAuthPolicy + - NONE + {{- end }} + - --dnsRefreshRate + - {{ valueOrDefault .Values.global.proxy.dnsRefreshRate "300s" }} + {{- if (ne (annotation .ObjectMeta "status.sidecar.istio.io/port" .Values.global.proxy.statusPort) "0") }} + - --statusPort + - "{{ annotation .ObjectMeta `status.sidecar.istio.io/port` .Values.global.proxy.statusPort }}" + {{- end }} + {{- if .Values.global.sts.servicePort }} + - --stsPort={{ .Values.global.sts.servicePort }} + {{- end }} + {{- if .Values.global.trustDomain }} + - --trust-domain={{ .Values.global.trustDomain }} + {{- end }} + {{- if .Values.global.logAsJson }} + - --log_as_json + {{- end }} + - --controlPlaneBootstrap=false + {{- if .Values.global.proxy.lifecycle }} + lifecycle: + {{ toYaml .Values.global.proxy.lifecycle | indent 4 }} + {{- end }} + env: + - name: JWT_POLICY + value: {{ .Values.global.jwtPolicy }} + - name: PILOT_CERT_PROVIDER + value: {{ .Values.global.pilotCertProvider }} + # Temp, pending PR to make it default or based on the istiodAddr env + - name: CA_ADDR + {{- if .Values.global.configNamespace }} + value: istio-pilot.{{ .Values.global.configNamespace }}.svc:15012 + {{- else }} + value: istio-pilot.istio-system.svc:15012 + {{- end }} + - name: POD_NAME + valueFrom: + fieldRef: + fieldPath: metadata.name + - name: POD_NAMESPACE + valueFrom: + fieldRef: + fieldPath: metadata.namespace + - name: INSTANCE_IP + valueFrom: + fieldRef: + fieldPath: status.podIP + - name: SERVICE_ACCOUNT + valueFrom: + fieldRef: + fieldPath: spec.serviceAccountName + - name: HOST_IP + valueFrom: + fieldRef: + fieldPath: status.hostIP + {{- if eq .Values.global.proxy.tracer "datadog" }} + {{- if isset .ObjectMeta.Annotations `apm.datadoghq.com/env` }} + {{- range $key, $value := fromJSON (index .ObjectMeta.Annotations `apm.datadoghq.com/env`) }} + - name: {{ $key }} + value: "{{ $value }}" + {{- end }} + {{- end }} + {{- end }} + - name: ISTIO_META_POD_PORTS + value: |- + [ + {{- $first := true }} + {{- range $index1, $c := .Spec.Containers }} + {{- range $index2, $p := $c.Ports }} + {{- if (structToJSON $p) }} + {{if not $first}},{{end}}{{ structToJSON $p }} + {{- $first = false }} + {{- end }} + {{- end}} + {{- end}} + ] + - name: ISTIO_META_CLUSTER_ID + value: "{{ valueOrDefault .Values.global.multiCluster.clusterName `Kubernetes` }}" + - name: ISTIO_META_POD_NAME + valueFrom: + fieldRef: + fieldPath: metadata.name + - name: ISTIO_META_CONFIG_NAMESPACE + valueFrom: + fieldRef: + fieldPath: metadata.namespace + - name: ISTIO_META_INTERCEPTION_MODE + value: "{{ or (index .ObjectMeta.Annotations `sidecar.istio.io/interceptionMode`) .ProxyConfig.InterceptionMode.String }}" + {{- if .Values.global.network }} + - name: ISTIO_META_NETWORK + value: "{{ .Values.global.network }}" + {{- end }} + {{ if .ObjectMeta.Annotations }} + - name: ISTIO_METAJSON_ANNOTATIONS + value: | + {{ toJSON .ObjectMeta.Annotations }} + {{ end }} + {{- if .DeploymentMeta.Name }} + - name: ISTIO_META_WORKLOAD_NAME + value: {{ .DeploymentMeta.Name }} + {{ end }} + {{- if and .TypeMeta.APIVersion .DeploymentMeta.Name }} + - name: ISTIO_META_OWNER + value: kubernetes://apis/{{ .TypeMeta.APIVersion }}/namespaces/{{ valueOrDefault .DeploymentMeta.Namespace `default` }}/{{ toLower .TypeMeta.Kind}}s/{{ .DeploymentMeta.Name }} + {{- end}} + {{- if (isset .ObjectMeta.Annotations `sidecar.istio.io/bootstrapOverride`) }} + - name: ISTIO_BOOTSTRAP_OVERRIDE + value: "/etc/istio/custom-bootstrap/custom_bootstrap.json" + {{- end }} + {{- if .Values.global.meshID }} + - name: ISTIO_META_MESH_ID + value: "{{ .Values.global.meshID }}" + {{- else if .Values.global.trustDomain }} + - name: ISTIO_META_MESH_ID + value: "{{ .Values.global.trustDomain }}" + {{- end }} + {{- if eq .Values.global.proxy.tracer "stackdriver" }} + - name: STACKDRIVER_TRACING_ENABLED + value: "true" + - name: STACKDRIVER_TRACING_DEBUG + value: "{{ .ProxyConfig.GetTracing.GetStackdriver.GetDebug }}" + - name: STACKDRIVER_TRACING_MAX_NUMBER_OF_ANNOTATIONS + value: "{{ .ProxyConfig.GetTracing.GetStackdriver.GetMaxNumberOfAnnotations.Value }}" + - name: STACKDRIVER_TRACING_MAX_NUMBER_OF_ATTRIBUTES + value: "{{ .ProxyConfig.GetTracing.GetStackdriver.GetMaxNumberOfAttributes.Value }}" + - name: STACKDRIVER_TRACING_MAX_NUMBER_OF_MESSAGE_EVENTS + value: "{{ .ProxyConfig.GetTracing.GetStackdriver.GetMaxNumberOfMessageEvents.Value }}" + {{- end }} + {{- if and (eq .Values.global.proxy.tracer "datadog") (isset .ObjectMeta.Annotations `apm.datadoghq.com/env`) }} + {{- range $key, $value := fromJSON (index .ObjectMeta.Annotations `apm.datadoghq.com/env`) }} + - name: {{ $key }} + value: "{{ $value }}" + {{- end }} + {{- end }} + {{- range $key, $value := .ProxyConfig.ProxyMetadata }} + - name: {{ $key }} + value: "{{ $value }}" + {{- end }} + imagePullPolicy: "{{ valueOrDefault .Values.global.imagePullPolicy `Always` }}" + {{ if ne (annotation .ObjectMeta `status.sidecar.istio.io/port` .Values.global.proxy.statusPort) `0` }} + readinessProbe: + httpGet: + path: /healthz/ready + port: {{ annotation .ObjectMeta `status.sidecar.istio.io/port` .Values.global.proxy.statusPort }} + initialDelaySeconds: {{ annotation .ObjectMeta `readiness.status.sidecar.istio.io/initialDelaySeconds` .Values.global.proxy.readinessInitialDelaySeconds }} + periodSeconds: {{ annotation .ObjectMeta `readiness.status.sidecar.istio.io/periodSeconds` .Values.global.proxy.readinessPeriodSeconds }} + failureThreshold: {{ annotation .ObjectMeta `readiness.status.sidecar.istio.io/failureThreshold` .Values.global.proxy.readinessFailureThreshold }} + {{ end -}} + securityContext: + allowPrivilegeEscalation: {{ .Values.global.proxy.privileged }} + capabilities: + {{ if or (eq (annotation .ObjectMeta `sidecar.istio.io/interceptionMode` .ProxyConfig.InterceptionMode) `TPROXY`) (eq (annotation .ObjectMeta `sidecar.istio.io/capNetBindService` .Values.global.proxy.capNetBindService) `true`) -}} + add: + {{ if eq (annotation .ObjectMeta `sidecar.istio.io/interceptionMode` .ProxyConfig.InterceptionMode) `TPROXY` -}} + - NET_ADMIN + {{- end }} + {{ if eq (annotation .ObjectMeta `sidecar.istio.io/capNetBindService` .Values.global.proxy.capNetBindService) `true` -}} + - NET_BIND_SERVICE + {{- end }} + {{- end }} + drop: + - ALL + privileged: {{ .Values.global.proxy.privileged }} + readOnlyRootFilesystem: {{ not .Values.global.proxy.enableCoreDump }} + runAsGroup: 1337 + fsGroup: 1337 + {{ if or (eq (annotation .ObjectMeta `sidecar.istio.io/interceptionMode` .ProxyConfig.InterceptionMode) `TPROXY`) (eq (annotation .ObjectMeta `sidecar.istio.io/capNetBindService` .Values.global.proxy.capNetBindService) `true`) -}} + runAsNonRoot: false + runAsUser: 0 + {{- else -}} + runAsNonRoot: true + runAsUser: 1337 + {{- end }} + resources: + {{ if or (isset .ObjectMeta.Annotations `sidecar.istio.io/proxyCPU`) (isset .ObjectMeta.Annotations `sidecar.istio.io/proxyMemory`) -}} + requests: + {{ if (isset .ObjectMeta.Annotations `sidecar.istio.io/proxyCPU`) -}} + cpu: "{{ index .ObjectMeta.Annotations `sidecar.istio.io/proxyCPU` }}" + {{ end}} + {{ if (isset .ObjectMeta.Annotations `sidecar.istio.io/proxyMemory`) -}} + memory: "{{ index .ObjectMeta.Annotations `sidecar.istio.io/proxyMemory` }}" + {{ end }} + {{ else -}} + {{- if .Values.global.proxy.resources }} + {{ toYaml .Values.global.proxy.resources | indent 4 }} + {{- end }} + {{ end -}} + volumeMounts: + {{- if eq .Values.global.pilotCertProvider "istiod" }} + - mountPath: /var/run/secrets/istio + name: istiod-ca-cert + {{- end }} + {{ if (isset .ObjectMeta.Annotations `sidecar.istio.io/bootstrapOverride`) }} + - mountPath: /etc/istio/custom-bootstrap + name: custom-bootstrap-volume + {{- end }} + # SDS channel between istioagent and Envoy + - mountPath: /etc/istio/proxy + name: istio-envoy + {{- if eq .Values.global.jwtPolicy "third-party-jwt" }} + - mountPath: /var/run/secrets/tokens + name: istio-token + {{- end }} + {{- if .Values.global.mountMtlsCerts }} + # Use the key and cert mounted to /etc/certs/ for the in-cluster mTLS communications. + - mountPath: /etc/certs/ + name: istio-certs + readOnly: true + {{- end }} + - name: podinfo + mountPath: /etc/istio/pod + {{- if and (eq .Values.global.proxy.tracer "lightstep") .Values.global.tracer.lightstep.cacertPath }} + - mountPath: {{ directory .ProxyConfig.GetTracing.GetLightstep.GetCacertPath }} + name: lightstep-certs + readOnly: true + {{- end }} + {{- if isset .ObjectMeta.Annotations `sidecar.istio.io/userVolumeMount` }} + {{ range $index, $value := fromJSON (index .ObjectMeta.Annotations `sidecar.istio.io/userVolumeMount`) }} + - name: "{{ $index }}" + {{ toYaml $value | indent 4 }} + {{ end }} + {{- end }} + volumes: + {{- if (isset .ObjectMeta.Annotations `sidecar.istio.io/bootstrapOverride`) }} + - name: custom-bootstrap-volume + configMap: + name: {{ annotation .ObjectMeta `sidecar.istio.io/bootstrapOverride` "" }} + {{- end }} + # SDS channel between istioagent and Envoy + - emptyDir: + medium: Memory + name: istio-envoy + - name: podinfo + downwardAPI: + items: + - path: "labels" + fieldRef: + fieldPath: metadata.labels + - path: "annotations" + fieldRef: + fieldPath: metadata.annotations + {{- if eq .Values.global.jwtPolicy "third-party-jwt" }} + - name: istio-token + projected: + sources: + - serviceAccountToken: + path: istio-token + expirationSeconds: 43200 + audience: {{ .Values.global.sds.token.aud }} + {{- end }} + {{- if eq .Values.global.pilotCertProvider "istiod" }} + - name: istiod-ca-cert + configMap: + name: istio-ca-root-cert + {{- end }} + {{- if .Values.global.mountMtlsCerts }} + # Use the key and cert mounted to /etc/certs/ for the in-cluster mTLS communications. + - name: istio-certs + secret: + optional: true + {{ if eq .Spec.ServiceAccountName "" }} + secretName: istio.default + {{ else -}} + secretName: {{ printf "istio.%s" .Spec.ServiceAccountName }} + {{ end -}} + {{- end }} + {{- if isset .ObjectMeta.Annotations `sidecar.istio.io/userVolume` }} + {{range $index, $value := fromJSON (index .ObjectMeta.Annotations `sidecar.istio.io/userVolume`) }} + - name: "{{ $index }}" + {{ toYaml $value | indent 2 }} + {{ end }} + {{ end }} + {{- if and (eq .Values.global.proxy.tracer "lightstep") .Values.global.tracer.lightstep.cacertPath }} + - name: lightstep-certs + secret: + optional: true + secretName: lightstep.cacert + {{- end }} + {{- if .Values.global.podDNSSearchNamespaces }} + dnsConfig: + searches: + {{- range .Values.global.podDNSSearchNamespaces }} + - {{ render . }} + {{- end }} + {{- end }} + podRedirectAnnot: + sidecar.istio.io/interceptionMode: "{{ annotation .ObjectMeta `sidecar.istio.io/interceptionMode` .ProxyConfig.InterceptionMode }}" + traffic.sidecar.istio.io/includeOutboundIPRanges: "{{ annotation .ObjectMeta `traffic.sidecar.istio.io/includeOutboundIPRanges` .Values.global.proxy.includeIPRanges }}" + traffic.sidecar.istio.io/excludeOutboundIPRanges: "{{ annotation .ObjectMeta `traffic.sidecar.istio.io/excludeOutboundIPRanges` .Values.global.proxy.excludeIPRanges }}" + traffic.sidecar.istio.io/includeInboundPorts: "{{ annotation .ObjectMeta `traffic.sidecar.istio.io/includeInboundPorts` (includeInboundPorts .Spec.Containers) }}" + traffic.sidecar.istio.io/excludeInboundPorts: "{{ excludeInboundPort (annotation .ObjectMeta `status.sidecar.istio.io/port` .Values.global.proxy.statusPort) (annotation .ObjectMeta `traffic.sidecar.istio.io/excludeInboundPorts` .Values.global.proxy.excludeInboundPorts) }}" + {{ if or (isset .ObjectMeta.Annotations `traffic.sidecar.istio.io/excludeOutboundPorts`) (ne .Values.global.proxy.excludeOutboundPorts "") }} + traffic.sidecar.istio.io/excludeOutboundPorts: "{{ annotation .ObjectMeta `traffic.sidecar.istio.io/excludeOutboundPorts` .Values.global.proxy.excludeOutboundPorts }}" + {{- end }} + traffic.sidecar.istio.io/kubevirtInterfaces: "{{ index .ObjectMeta.Annotations `traffic.sidecar.istio.io/kubevirtInterfaces` }}" diff --git a/istio-1.5.0/install/kubernetes/operator/charts/istio-control/istio-discovery/templates/_affinity.tpl b/istio-1.5.0/install/kubernetes/operator/charts/istio-control/istio-discovery/templates/_affinity.tpl new file mode 100644 index 0000000..ef2c7c0 --- /dev/null +++ b/istio-1.5.0/install/kubernetes/operator/charts/istio-control/istio-discovery/templates/_affinity.tpl @@ -0,0 +1,93 @@ +{{/* affinity - https://kubernetes.io/docs/concepts/configuration/assign-pod-node/ */}} + +{{- define "nodeaffinity" }} + nodeAffinity: + requiredDuringSchedulingIgnoredDuringExecution: + {{- include "nodeAffinityRequiredDuringScheduling" . }} + preferredDuringSchedulingIgnoredDuringExecution: + {{- include "nodeAffinityPreferredDuringScheduling" . }} +{{- end }} + +{{- define "nodeAffinityRequiredDuringScheduling" }} + nodeSelectorTerms: + - matchExpressions: + - key: beta.kubernetes.io/arch + operator: In + values: + {{- range $key, $val := .Values.global.arch }} + {{- if gt ($val | int) 0 }} + - {{ $key | quote }} + {{- end }} + {{- end }} + {{- $nodeSelector := default .Values.global.defaultNodeSelector .Values.pilot.nodeSelector -}} + {{- range $key, $val := $nodeSelector }} + - key: {{ $key }} + operator: In + values: + - {{ $val | quote }} + {{- end }} +{{- end }} + +{{- define "nodeAffinityPreferredDuringScheduling" }} + {{- range $key, $val := .Values.global.arch }} + {{- if gt ($val | int) 0 }} + - weight: {{ $val | int }} + preference: + matchExpressions: + - key: beta.kubernetes.io/arch + operator: In + values: + - {{ $key | quote }} + {{- end }} + {{- end }} +{{- end }} + +{{- define "podAntiAffinity" }} +{{- if or .Values.pilot.podAntiAffinityLabelSelector .Values.pilot.podAntiAffinityTermLabelSelector}} + podAntiAffinity: + {{- if .Values.pilot.podAntiAffinityLabelSelector }} + requiredDuringSchedulingIgnoredDuringExecution: + {{- include "podAntiAffinityRequiredDuringScheduling" . }} + {{- end }} + {{- if .Values.pilot.podAntiAffinityTermLabelSelector }} + preferredDuringSchedulingIgnoredDuringExecution: + {{- include "podAntiAffinityPreferredDuringScheduling" . }} + {{- end }} +{{- end }} +{{- end }} + +{{- define "podAntiAffinityRequiredDuringScheduling" }} + {{- range $index, $item := .Values.pilot.podAntiAffinityLabelSelector }} + - labelSelector: + matchExpressions: + - key: {{ $item.key }} + operator: {{ $item.operator }} + {{- if $item.values }} + values: + {{- $vals := split "," $item.values }} + {{- range $i, $v := $vals }} + - {{ $v | quote }} + {{- end }} + {{- end }} + topologyKey: {{ $item.topologyKey }} + {{- end }} +{{- end }} + +{{- define "podAntiAffinityPreferredDuringScheduling" }} + {{- range $index, $item := .Values.pilot.podAntiAffinityTermLabelSelector }} + - podAffinityTerm: + labelSelector: + matchExpressions: + - key: {{ $item.key }} + operator: {{ $item.operator }} + {{- if $item.values }} + values: + {{- $vals := split "," $item.values }} + {{- range $i, $v := $vals }} + - {{ $v | quote }} + {{- end }} + {{- end }} + topologyKey: {{ $item.topologyKey }} + weight: 100 + {{- end }} +{{- end }} diff --git a/istio-1.5.0/install/kubernetes/operator/charts/istio-control/istio-discovery/templates/_helpers.tpl b/istio-1.5.0/install/kubernetes/operator/charts/istio-control/istio-discovery/templates/_helpers.tpl new file mode 100644 index 0000000..e69de29 diff --git a/istio-1.5.0/install/kubernetes/operator/charts/istio-control/istio-discovery/templates/autoscale.yaml b/istio-1.5.0/install/kubernetes/operator/charts/istio-control/istio-discovery/templates/autoscale.yaml new file mode 100644 index 0000000..d8b1176 --- /dev/null +++ b/istio-1.5.0/install/kubernetes/operator/charts/istio-control/istio-discovery/templates/autoscale.yaml @@ -0,0 +1,25 @@ +{{ if or (eq .Values.revision "") (not .Values.clusterResources) }} +{{- if and .Values.pilot.autoscaleEnabled .Values.pilot.autoscaleMin .Values.pilot.autoscaleMax }} +apiVersion: autoscaling/v2beta1 +kind: HorizontalPodAutoscaler +metadata: + name: istiod{{- if not (eq .Values.revision "") }}-{{ .Values.revision }}{{- end }} + namespace: {{ .Release.Namespace }} + labels: + app: istiod + release: {{ .Release.Name }} +spec: + maxReplicas: {{ .Values.pilot.autoscaleMax }} + minReplicas: {{ .Values.pilot.autoscaleMin }} + scaleTargetRef: + apiVersion: apps/v1 + kind: Deployment + name: istiod{{- if not (eq .Values.revision "") }}-{{ .Values.revision }}{{- end }} + metrics: + - type: Resource + resource: + name: cpu + targetAverageUtilization: {{ .Values.pilot.cpu.targetAverageUtilization }} +--- +{{- end }} +{{- end }} diff --git a/istio-1.5.0/install/kubernetes/operator/charts/istio-control/istio-discovery/templates/clusterrole-galley-disable-webhook.yaml b/istio-1.5.0/install/kubernetes/operator/charts/istio-control/istio-discovery/templates/clusterrole-galley-disable-webhook.yaml new file mode 100644 index 0000000..bdc27ad --- /dev/null +++ b/istio-1.5.0/install/kubernetes/operator/charts/istio-control/istio-discovery/templates/clusterrole-galley-disable-webhook.yaml @@ -0,0 +1,57 @@ +{{ if .Values.clusterResources }} +{{/* If we have Istiod enabled and Galley disabled, we may run into issues during upgrade. */}} +{{/* The old Galley will continuely try to patch its webhook, when we actually want to remove it. */}} +{{/* This will disable Galley's permission to do so, if galley is disabled. */}} +{{- if and .Values.global.istiod.enabled (not .Values.galley.enabled) }} +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: istio-galley-{{ .Release.Namespace }} + labels: + release: {{ .Release.Name }} +rules: + # For reading Istio resources + - apiGroups: [ + "authentication.istio.io", + "config.istio.io", + "networking.istio.io", + "rbac.istio.io", + "security.istio.io"] + resources: ["*"] + verbs: ["get", "list", "watch"] + # For updating Istio resource statuses + - apiGroups: [ + "authentication.istio.io", + "config.istio.io", + "networking.istio.io", + "rbac.istio.io", + "security.istio.io"] + resources: ["*/status"] + verbs: ["update"] + + # Remove galley's permissions to reconcile the validation config when istiod is present. + # Notably missing here is the permission to modify webhooks. + + - apiGroups: ["extensions","apps"] + resources: ["deployments"] + resourceNames: ["istio-galley"] + verbs: ["get"] + - apiGroups: [""] + resources: ["pods", "nodes", "services", "endpoints", "namespaces"] + verbs: ["get", "list", "watch"] + - apiGroups: ["extensions"] + resources: ["ingresses"] + verbs: ["get", "list", "watch"] + - apiGroups: ["extensions"] + resources: ["deployments/finalizers"] + resourceNames: ["istio-galley"] + verbs: ["update"] + - apiGroups: ["apiextensions.k8s.io"] + resources: ["customresourcedefinitions"] + verbs: ["get", "list", "watch"] + - apiGroups: ["rbac.authorization.k8s.io"] + resources: ["clusterroles"] + verbs: ["get", "list", "watch"] +--- +{{- end }} +{{- end }} diff --git a/istio-1.5.0/install/kubernetes/operator/charts/istio-control/istio-discovery/templates/clusterrole.yaml b/istio-1.5.0/install/kubernetes/operator/charts/istio-control/istio-discovery/templates/clusterrole.yaml new file mode 100644 index 0000000..e378cae --- /dev/null +++ b/istio-1.5.0/install/kubernetes/operator/charts/istio-control/istio-discovery/templates/clusterrole.yaml @@ -0,0 +1,128 @@ +{{ if .Values.clusterResources }} +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: istio-pilot-{{ .Release.Namespace }} + labels: + app: pilot + release: {{ .Release.Name }} +rules: +- apiGroups: ["config.istio.io", "rbac.istio.io", "security.istio.io", "networking.istio.io", "authentication.istio.io"] + verbs: ["get", "watch", "list"] + resources: ["*"] +- apiGroups: ["apiextensions.k8s.io"] + resources: ["customresourcedefinitions"] + verbs: ["get", "watch", "list"] +- apiGroups: ["extensions"] + resources: ["ingresses"] + verbs: ["get", "list", "watch"] +- apiGroups: ["extensions"] + resources: ["ingresses/status"] + verbs: ["*"] + # TODO: remove, too broad permission, should be namespace only +- apiGroups: [""] + resources: ["configmaps"] + # Create and update needed for ingress election + verbs: ["get", "list", "watch", "create", "update"] +- apiGroups: [""] + resources: ["endpoints", "pods", "services", "namespaces", "nodes", "secrets"] + verbs: ["get", "list", "watch"] +- apiGroups: [""] + resources: ["secrets"] + verbs: ["create", "get", "watch", "list", "update", "delete"] +- apiGroups: ["certificates.k8s.io"] + resources: + - "certificatesigningrequests" + - "certificatesigningrequests/approval" + - "certificatesigningrequests/status" + verbs: ["update", "create", "get", "delete", "watch"] +- apiGroups: ["discovery.k8s.io"] + resources: ["endpointslices"] + verbs: ["get", "list", "watch"] +--- +# Dedicated cluster role - istiod will use fewer dangerous permissions ( secret access in particular ). +# TODO: separate cluster role with the minimal set of permissions needed for a 'tenant' Istiod +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: istiod-{{ .Release.Namespace }} + labels: + app: istiod + release: {{ .Release.Name }} +rules: +{{- if .Values.global.istiod.enabled }} + # Remove permissions to reconcile webhook configuration. This address the downgrade case + # where istiod will be uninstalled. Removing the permissions reduces + # the likelihood that istiod will reconcile something it shouldn't. + + # sidecar injection controller + - apiGroups: ["admissionregistration.k8s.io"] + resources: ["mutatingwebhookconfigurations"] + verbs: ["get", "list", "watch", "patch"] + + # configuration validation webhook controller + - apiGroups: ["admissionregistration.k8s.io"] + resources: ["validatingwebhookconfigurations"] + verbs: ["get", "list", "watch", "update"] +{{ end }} + + # permissions to verify the webhook is ready and rejecting + # invalid config. We use --server-dry-run so no config is persisted. + - apiGroups: ["networking.istio.io"] + verbs: ["create"] + resources: ["gateways"] + + # istio configuration + - apiGroups: ["config.istio.io", "rbac.istio.io", "security.istio.io", "networking.istio.io", "authentication.istio.io"] + verbs: ["get", "watch", "list"] + resources: ["*"] + + # auto-detect installed CRD definitions + - apiGroups: ["apiextensions.k8s.io"] + resources: ["customresourcedefinitions"] + verbs: ["get", "list", "watch"] + + # discovery and routing + - apiGroups: ["extensions","apps"] + resources: ["deployments"] + verbs: ["get", "list", "watch"] + - apiGroups: [""] + resources: ["pods", "nodes", "services", "namespaces", "endpoints"] + verbs: ["get", "list", "watch"] + - apiGroups: ["discovery.k8s.io"] + resources: ["endpointslices"] + verbs: ["get", "list", "watch"] + + # ingress controller + - apiGroups: ["extensions"] + resources: ["ingresses"] + verbs: ["get", "list", "watch"] + - apiGroups: ["extensions"] + resources: ["ingresses/status"] + verbs: ["*"] + + # required for CA's namespace controller + - apiGroups: [""] + resources: ["configmaps"] + verbs: ["create", "get", "list", "watch", "update"] + + # Istiod and bootstrap. + - apiGroups: ["certificates.k8s.io"] + resources: + - "certificatesigningrequests" + - "certificatesigningrequests/approval" + - "certificatesigningrequests/status" + verbs: ["update", "create", "get", "delete", "watch"] + # Used by Istiod to verify the JWT tokens + - apiGroups: ["authentication.k8s.io"] + resources: ["tokenreviews"] + verbs: ["create"] + + # TODO: remove, no longer needed at cluster + - apiGroups: [""] + resources: ["secrets"] + verbs: ["create", "get", "watch", "list", "update", "delete"] + - apiGroups: [""] + resources: ["serviceaccounts"] + verbs: ["get", "watch", "list"] +{{ end }} \ No newline at end of file diff --git a/istio-1.5.0/install/kubernetes/operator/charts/istio-control/istio-discovery/templates/clusterrolebinding.yaml b/istio-1.5.0/install/kubernetes/operator/charts/istio-control/istio-discovery/templates/clusterrolebinding.yaml new file mode 100644 index 0000000..25748ac --- /dev/null +++ b/istio-1.5.0/install/kubernetes/operator/charts/istio-control/istio-discovery/templates/clusterrolebinding.yaml @@ -0,0 +1,37 @@ +{{ if .Values.clusterResources }} +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: istio-pilot-{{ .Release.Namespace }} + labels: + app: pilot + release: {{ .Release.Name }} +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: istio-pilot-{{ .Release.Namespace }} +subjects: + - kind: ServiceAccount + name: istiod-service-account + namespace: {{ .Release.Namespace }} +--- +{{ if .Values.global.istiod.enabled }} +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: istiod-{{ .Release.Namespace }} + labels: + app: istiod + release: {{ .Release.Name }} +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: istiod-{{ .Release.Namespace }} +subjects: + - kind: ServiceAccount + name: istiod-service-account + namespace: {{ .Release.Namespace }} + +--- +{{ end }} +{{ end }} diff --git a/istio-1.5.0/install/kubernetes/operator/charts/istio-control/istio-discovery/templates/configmap-envoy.yaml b/istio-1.5.0/install/kubernetes/operator/charts/istio-control/istio-discovery/templates/configmap-envoy.yaml new file mode 100644 index 0000000..4282ea6 --- /dev/null +++ b/istio-1.5.0/install/kubernetes/operator/charts/istio-control/istio-discovery/templates/configmap-envoy.yaml @@ -0,0 +1,173 @@ +{{ if or (eq .Values.revision "") (not .Values.clusterResources) }} +apiVersion: v1 +kind: ConfigMap +metadata: + namespace: {{ .Release.Namespace }} + name: pilot-envoy-config{{- if not (eq .Values.revision "") }}-{{ .Values.revision }}{{- end }} + labels: + release: {{ .Release.Name }} +data: + envoy.yaml.tmpl: |- + admin: + access_log_path: /dev/null + address: + socket_address: + address: 127.0.0.1 + port_value: 15000 + + static_resources: + clusters: + - name: in.15010 + http2_protocol_options: {} + connect_timeout: 1.000s + + hosts: + - socket_address: + address: 127.0.0.1 + port_value: 15010 + + circuit_breakers: + thresholds: + - max_connections: 100000 + max_pending_requests: 100000 + max_requests: 100000 + max_retries: 3 + + # TODO: telemetry using EDS + # TODO: other pilots using EDS, load balancing + # TODO: galley using EDS + + - name: out.galley.15019 + http2_protocol_options: {} + connect_timeout: 1.000s + type: STRICT_DNS + + circuit_breakers: + thresholds: + - max_connections: 100000 + max_pending_requests: 100000 + max_requests: 100000 + max_retries: 3 + + tls_context: + common_tls_context: + tls_certificates: + - certificate_chain: + filename: /etc/certs/cert-chain.pem + private_key: + filename: /etc/certs/key.pem + validation_context: + trusted_ca: + filename: /etc/certs/root-cert.pem + verify_subject_alt_name: + - spiffe://{{ .Values.global.trustDomain }}/ns/{{ .Values.global.configNamespace }}/sa/istio-galley-service-account + + hosts: + - socket_address: + address: istio-galley.{{ .Values.global.configNamespace }} + port_value: 15019 + + + listeners: + - name: "in.15011" + address: + socket_address: + address: 0.0.0.0 + port_value: 15011 + filter_chains: + - filters: + - name: envoy.http_connection_manager + #typed_config + #"@type": "type.googleapis.com/", + config: + codec_type: HTTP2 + stat_prefix: "15011" + stream_idle_timeout: 0s + http2_protocol_options: + max_concurrent_streams: 1073741824 + + access_log: + - name: envoy.file_access_log + config: + path: /dev/stdout + + http_filters: + - name: envoy.router + + route_config: + name: "15011" + + virtual_hosts: + - name: istio-pilot + + domains: + - '*' + + routes: + - match: + prefix: / + route: + cluster: in.15010 + timeout: 0.000s + decorator: + operation: xDS + + tls_context: + require_client_certificate: true + common_tls_context: + validation_context: + trusted_ca: + filename: /etc/certs/root-cert.pem + + alpn_protocols: + - h2 + + tls_certificates: + - certificate_chain: + filename: /etc/certs/cert-chain.pem + private_key: + filename: /etc/certs/key.pem + + + # Manual 'whitebox' mode + - name: "local.15019" + address: + socket_address: + address: 127.0.0.1 + port_value: 15019 + filter_chains: + - filters: + - name: envoy.http_connection_manager + config: + codec_type: HTTP2 + stat_prefix: "15019" + stream_idle_timeout: 0s + http2_protocol_options: + max_concurrent_streams: 1073741824 + + access_log: + - name: envoy.file_access_log + config: + path: /dev/stdout + + http_filters: + - name: envoy.router + + route_config: + name: "15019" + + virtual_hosts: + - name: istio-galley + + domains: + - '*' + + routes: + - match: + prefix: / + route: + cluster: out.galley.15019 + timeout: 0.000s + +--- +{{- end }} diff --git a/istio-1.5.0/install/kubernetes/operator/charts/istio-control/istio-discovery/templates/configmap-jwks.yaml b/istio-1.5.0/install/kubernetes/operator/charts/istio-control/istio-discovery/templates/configmap-jwks.yaml new file mode 100644 index 0000000..6815bc5 --- /dev/null +++ b/istio-1.5.0/install/kubernetes/operator/charts/istio-control/istio-discovery/templates/configmap-jwks.yaml @@ -0,0 +1,13 @@ +{{ if or (eq .Values.revision "") (not .Values.clusterResources) }} +{{- if .Values.pilot.jwksResolverExtraRootCA }} +apiVersion: v1 +kind: ConfigMap +metadata: + name: pilot-jwks-extra-cacerts{{- if not (eq .Values.revision "") }}-{{ .Values.revision }}{{- end }} + namespace: {{ .Release.Namespace }} + labels: + release: {{ .Release.Name }} +data: + extra.pem: {{ .Values.pilot.jwksResolverExtraRootCA | quote }} +{{- end }} +{{- end }} diff --git a/istio-1.5.0/install/kubernetes/operator/charts/istio-control/istio-discovery/templates/configmap.yaml b/istio-1.5.0/install/kubernetes/operator/charts/istio-control/istio-discovery/templates/configmap.yaml new file mode 100644 index 0000000..f25ea84 --- /dev/null +++ b/istio-1.5.0/install/kubernetes/operator/charts/istio-control/istio-discovery/templates/configmap.yaml @@ -0,0 +1,349 @@ +{{ if or (eq .Values.revision "") (not .Values.clusterResources) }} +{{- if .Values.pilot.configMap }} +apiVersion: v1 +kind: ConfigMap +metadata: + name: istio{{- if not (eq .Values.revision "") }}-{{ .Values.revision }}{{- end }} + namespace: {{ .Release.Namespace }} + labels: + release: {{ .Release.Name }} +data: + + # Configuration file for the mesh networks to be used by the Split Horizon EDS. + meshNetworks: |- + {{- if .Values.global.meshNetworks }} + networks: +{{ toYaml .Values.global.meshNetworks | trim | indent 6 }} + {{- else }} + networks: {} + {{- end }} + + values.yaml: |- +{{ toYaml .Values.pilot | trim | indent 4 }} + + mesh: |- + {{- if .Values.global.enableTracing }} + # Set enableTracing to false to disable request tracing. + enableTracing: {{ .Values.global.enableTracing }} + {{- end }} + + # Set accessLogFile to empty string to disable access log. + accessLogFile: "{{ .Values.global.proxy.accessLogFile }}" + + accessLogFormat: {{ .Values.global.proxy.accessLogFormat | quote }} + + accessLogEncoding: '{{ .Values.global.proxy.accessLogEncoding }}' + + enableEnvoyAccessLogService: {{ .Values.global.proxy.envoyAccessLogService.enabled }} + + {{- if .Values.global.istioRemote }} + + {{- if .Values.global.remotePolicyAddress }} + {{- if .Values.global.createRemoteSvcEndpoints }} + mixerCheckServer: istio-policy.{{ .Release.Namespace }}:15004 + {{- else }} + mixerCheckServer: {{ .Values.global.remotePolicyAddress }}:15004 + {{- end }} + {{- end }} + {{- if .Values.global.remoteTelemetryAddress }} + {{- if .Values.global.createRemoteSvcEndpoints }} + mixerReportServer: istio-telemetry.{{ .Release.Namespace }}:15004 + {{- else }} + mixerReportServer: {{ .Values.global.remoteTelemetryAddress }}:15004 + {{- end }} + {{- end }} + + {{- else }} + + {{- if .Values.mixer.policy.enabled }} + {{- if .Values.global.controlPlaneSecurityEnabled }} + mixerCheckServer: istio-policy.{{ .Values.global.policyNamespace }}.svc.{{ .Values.global.proxy.clusterDomain }}:15004 + {{- else }} + mixerCheckServer: istio-policy.{{ .Values.global.policyNamespace }}.svc.{{ .Values.global.proxy.clusterDomain }}:9091 + {{- end }} + {{- end }} + + {{- if and .Values.telemetry.v1.enabled .Values.telemetry.enabled }} + {{- if .Values.global.controlPlaneSecurityEnabled }} + mixerReportServer: istio-telemetry.{{ .Values.global.telemetryNamespace }}.svc.{{ .Values.global.proxy.clusterDomain }}:15004 + {{- else }} + mixerReportServer: istio-telemetry.{{ .Values.global.telemetryNamespace }}.svc.{{ .Values.global.proxy.clusterDomain }}:9091 + {{- end }} + {{- end }} + + {{- end }} + + {{- if or .Values.mixer.policy.enabled (and .Values.global.istioRemote .Values.global.remotePolicyAddress) }} + # policyCheckFailOpen allows traffic in cases when the mixer policy service cannot be reached. + # Default is false which means the traffic is denied when the client is unable to connect to Mixer. + policyCheckFailOpen: {{ .Values.global.policyCheckFailOpen }} + {{- end }} + + {{- if .Values.mixer.telemetry.reportBatchMaxEntries }} + # reportBatchMaxEntries is the number of requests that are batched before telemetry data is sent to the mixer server + reportBatchMaxEntries: {{ .Values.mixer.telemetry.reportBatchMaxEntries }} + {{- end }} + + {{- if .Values.mixer.telemetry.reportBatchMaxTime }} + # reportBatchMaxTime is the max waiting time before the telemetry data of a request is sent to the mixer server + reportBatchMaxTime: {{ .Values.mixer.telemetry.reportBatchMaxTime }} + {{- end }} + + {{- if .Values.mixer.telemetry.sessionAffinityEnabled }} + # sidecarToTelemetrySessionAffinity will create a STRICT_DNS type cluster for istio-telemetry. + sidecarToTelemetrySessionAffinity: {{ .Values.mixer.telemetry.sessionAffinityEnabled }} + {{- end }} + + {{- if .Values.telemetry.v2.enabled }} + disableMixerHttpReports: true + {{- else }} + disableMixerHttpReports: false + {{- end }} + + # Set the following variable to true to disable policy checks by the Mixer. + # Note that metrics will still be reported to the Mixer. + {{- if .Values.mixer.policy.enabled }} + disablePolicyChecks: {{ .Values.global.disablePolicyChecks }} + {{- else }} + disablePolicyChecks: true + {{- end }} + + # Automatic protocol detection uses a set of heuristics to + # determine whether the connection is using TLS or not (on the + # server side), as well as the application protocol being used + # (e.g., http vs tcp). These heuristics rely on the client sending + # the first bits of data. For server first protocols like MySQL, + # MongoDB, etc., Envoy will timeout on the protocol detection after + # the specified period, defaulting to non mTLS plain TCP + # traffic. Set this field to tweak the period that Envoy will wait + # for the client to send the first bits of data. (MUST BE >=1ms) + protocolDetectionTimeout: {{ .Values.global.proxy.protocolDetectionTimeout }} + + # This is the k8s ingress service name, update if you used a different name + {{- if .Values.pilot.ingress }} + {{- if .Values.pilot.ingress.ingressService }} + ingressService: "{{ .Values.pilot.ingress.ingressService }}" + ingressControllerMode: "{{ .Values.pilot.ingress.ingressControllerMode }}" + ingressClass: "{{ .Values.pilot.ingress.ingressClass }}" + {{- end }} + {{- end }} + + # The trust domain corresponds to the trust root of a system. + # Refer to https://github.com/spiffe/spiffe/blob/master/standards/SPIFFE-ID.md#21-trust-domain + trustDomain: {{ .Values.global.trustDomain | quote }} + + # The trust domain aliases represent the aliases of trust_domain. + # For example, if we have + # trustDomain: td1 + # trustDomainAliases: [“td2”, "td3"] + # Any service with the identity "td1/ns/foo/sa/a-service-account", "td2/ns/foo/sa/a-service-account", + # or "td3/ns/foo/sa/a-service-account" will be treated the same in the Istio mesh. + trustDomainAliases: + {{- range .Values.global.trustDomainAliases }} + - {{ . | quote }} + {{- end }} + + {{- if .Values.global.istiod.enabled }} + + # Used by pilot-agent + sdsUdsPath: "unix:/etc/istio/proxy/SDS" + + {{- else }} + + # Set expected values when SDS is disabled + # Unix Domain Socket through which envoy communicates with NodeAgent SDS to get + # key/cert for mTLS. Use secret-mount files instead of SDS if set to empty. + sdsUdsPath: "" + + # This flag is used by secret discovery service(SDS). + # If set to true(prerequisite: https://kubernetes.io/docs/concepts/storage/volumes/#projected), Istio will inject volumes mount + # for k8s service account JWT, so that K8s API server mounts k8s service account JWT to envoy container, which + # will be used to generate key/cert eventually. This isn't supported for non-k8s case. + enableSdsTokenMount: false + + # This flag is used by secret discovery service(SDS). + # If set to true, envoy will fetch normal k8s service account JWT from '/var/run/secrets/kubernetes.io/serviceaccount/token' + # (https://kubernetes.io/docs/tasks/access-application-cluster/access-cluster/#accessing-the-api-from-a-pod) + # and pass to sds server, which will be used to request key/cert eventually. + # this flag is ignored if enableSdsTokenMount is set. + # This isn't supported for non-k8s case. + sdsUseK8sSaJwt: false + {{- end }} + + # If true, automatically configure client side mTLS settings to match the corresponding service's + # server side mTLS authentication policy, when destination rule for that service does not specify + # TLS settings. + enableAutoMtls: {{ .Values.global.mtls.auto }} + + {{- if .Values.global.useMCP }} + configSources: + {{- if .Values.global.controlPlaneSecurityEnabled }} + - address: localhost:15019 + {{- else }} + - address: istio-galley.{{ .Values.global.configNamespace }}:9901 + {{- end }} + {{- if .Values.pilot.configSource.subscribedResources }} + subscribedResources: + {{- range .Values.pilot.configSource.subscribedResources }} + - {{ . }} + {{- end }} + {{- end}} + {{- end }} + + outboundTrafficPolicy: + mode: {{ .Values.global.outboundTrafficPolicy.mode }} + + {{- if .Values.global.localityLbSetting.enabled }} + localityLbSetting: +{{ toYaml .Values.global.localityLbSetting | trim | indent 6 }} + {{- end }} + + # Configures DNS certificates provisioned through Chiron linked into Pilot. + # The DNS certificate provisioning is enabled by default now so it get tested. + # TODO (lei-tang): we'll decide whether enable it by default or not before Istio 1.4 Release. + certificates: +{{ toYaml .Values.global.certificates | trim | indent 6 }} + + defaultConfig: + # + # TCP connection timeout between Envoy & the application, and between Envoys. + connectTimeout: 10s + # + ### ADVANCED SETTINGS ############# + # Where should envoy's configuration be stored in the istio-proxy container + configPath: "/etc/istio/proxy" + # The pseudo service name used for Envoy. + serviceCluster: istio-proxy + # These settings that determine how long an old Envoy + # process should be kept alive after an occasional reload. + drainDuration: 45s + parentShutdownDuration: 1m0s + # + # Port where Envoy listens (on local host) for admin commands + # You can exec into the istio-proxy container in a pod and + # curl the admin port (curl http://localhost:15000/) to obtain + # diagnostic information from Envoy. See + # https://lyft.github.io/envoy/docs/operations/admin.html + # for more details + proxyAdminPort: 15000 + # + # Set concurrency to a specific number to control the number of Proxy worker threads. + # If set to 0 (default), then start worker thread for each CPU thread/core. + concurrency: {{ .Values.global.proxy.concurrency }} + # + {{- if eq .Values.global.proxy.tracer "lightstep" }} + tracing: + lightstep: + # Address of the LightStep Satellite pool + address: {{ .Values.global.tracer.lightstep.address }} + # Access Token used to communicate with the Satellite pool + accessToken: {{ .Values.global.tracer.lightstep.accessToken }} + # Whether communication with the Satellite pool should be secure + secure: {{ .Values.global.tracer.lightstep.secure }} + # Path to the file containing the cacert to use when verifying TLS + cacertPath: {{ .Values.global.tracer.lightstep.cacertPath }} + {{- else if eq .Values.global.proxy.tracer "zipkin" }} + tracing: + zipkin: + # Address of the Zipkin collector + {{- if .Values.global.tracer.zipkin.address }} + address: {{ .Values.global.tracer.zipkin.address }} + {{- else }} + address: zipkin.{{ .Values.global.telemetryNamespace }}:9411 + {{- end }} + {{- else if eq .Values.global.proxy.tracer "datadog" }} + tracing: + datadog: + # Address of the Datadog Agent + address: {{ .Values.global.tracer.datadog.address }} + {{- else if eq .Values.global.proxy.tracer "stackdriver" }} + tracing: + stackdriver: + # enables trace output to stdout. + {{- if $.Values.global.tracer.stackdriver.debug }} + debug: {{ $.Values.global.tracer.stackdriver.debug }} + {{- end }} + {{- if $.Values.global.tracer.stackdriver.maxNumberOfAttributes }} + # The global default max number of attributes per span. + maxNumberOfAttributes: {{ $.Values.global.tracer.stackdriver.maxNumberOfAttributes }} + {{- end }} + {{- if $.Values.global.tracer.stackdriver.maxNumberOfAnnotations }} + # The global default max number of annotation events per span. + maxNumberOfAnnotations: {{ $.Values.global.tracer.stackdriver.maxNumberOfAnnotations }} + {{- end }} + {{- if $.Values.global.tracer.stackdriver.maxNumberOfMessageEvents }} + # The global default max number of message events per span. + maxNumberOfMessageEvents: {{ $.Values.global.tracer.stackdriver.maxNumberOfMessageEvents }} + {{- end }} + {{- end }} + + {{- $defPilotHostname := printf "istio-pilot.%s" .Release.Namespace }} + {{- $pilotAddress := .Values.global.remotePilotAddress | default $defPilotHostname }} + {{- if .Values.global.istiod.enabled }} + # If port is 15012, will use SDS. + # controlPlaneAuthPolicy is for mounted secrets, will wait for the files. + controlPlaneAuthPolicy: NONE + {{- if .Values.global.remotePilotAddress }} + discoveryAddress: {{ .Values.global.remotePilotAddress }} + {{- else }} + discoveryAddress: istiod{{- if not (eq .Values.revision "") }}-{{ .Values.revision }}{{- end }}.{{.Release.Namespace}}.svc:15012 + {{- end }} + + {{- else if .Values.global.controlPlaneSecurityEnabled }} + # + # Mutual TLS authentication between sidecars and istio control plane. + controlPlaneAuthPolicy: MUTUAL_TLS + # + # Address where istio Pilot service is running + {{- if or .Values.global.remotePilotCreateSvcEndpoint .Values.global.createRemoteSvcEndpoints }} + discoveryAddress: istio-pilot.{{ .Release.Namespace }}:15011 + {{- else }} + discoveryAddress: {{ $pilotAddress }}:15011 + {{- end }} + {{- else }} + # + # Mutual TLS authentication between sidecars and istio control plane. + controlPlaneAuthPolicy: NONE + # + # Address where istio Pilot service is running + {{- if or .Values.global.remotePilotCreateSvcEndpoint .Values.global.createRemoteSvcEndpoints }} + discoveryAddress: istio-pilot.{{ .Release.Namespace }}:15010 + {{- else }} + discoveryAddress: {{ $pilotAddress }}:15010 + {{- end }} + {{- end }} + + {{- if .Values.global.proxy.envoyMetricsService.enabled }} + # + # Envoy's Metrics Service stats sink pushes Envoy metrics to a remote collector via the Metrics Service gRPC API. + envoyMetricsService: + address: {{ .Values.global.proxy.envoyMetricsService.host }}:{{ .Values.global.proxy.envoyMetricsService.port }} + {{- if .Values.global.proxy.envoyMetricsService.tlsSettings }} + tlsSettings: +{{ toYaml .Values.global.proxy.envoyMetricsService.tlsSettings | trim | indent 10 }} + {{- end}} + {{- if .Values.global.proxy.envoyMetricsService.tcpKeepalive }} + tcpKeepalive: +{{ toYaml .Values.global.proxy.envoyMetricsService.tcpKeepalive | trim | indent 10 }} + {{- end}} + {{- end}} + + + {{- if .Values.global.proxy.envoyAccessLogService.enabled }} + # + # Envoy's AccessLog Service pushes access logs to a remote collector via the Access Log Service gRPC API. + envoyAccessLogService: + address: {{ .Values.global.proxy.envoyAccessLogService.host }}:{{ .Values.global.proxy.envoyAccessLogService.port }} + {{- if .Values.global.proxy.envoyAccessLogService.tlsSettings }} + tlsSettings: +{{ toYaml .Values.global.proxy.envoyAccessLogService.tlsSettings | trim | indent 10 }} + {{- end}} + {{- if .Values.global.proxy.envoyAccessLogService.tcpKeepalive }} + tcpKeepalive: +{{ toYaml .Values.global.proxy.envoyAccessLogService.tcpKeepalive | trim | indent 10 }} + {{- end}} + {{- end}} + +--- +{{- end }} +{{- end }} diff --git a/istio-1.5.0/install/kubernetes/operator/charts/istio-control/istio-discovery/templates/deployment.yaml b/istio-1.5.0/install/kubernetes/operator/charts/istio-control/istio-discovery/templates/deployment.yaml new file mode 100644 index 0000000..e9ef555 --- /dev/null +++ b/istio-1.5.0/install/kubernetes/operator/charts/istio-control/istio-discovery/templates/deployment.yaml @@ -0,0 +1,323 @@ +{{ if or (eq .Values.revision "") (not .Values.clusterResources) }} +apiVersion: apps/v1 +kind: Deployment +metadata: + name: istiod{{- if not (eq .Values.revision "") }}-{{ .Values.revision }}{{- end }} + namespace: {{ .Release.Namespace }} + labels: + app: istiod + istio: pilot + release: {{ .Release.Name }} + {{- if ne .Values.revision ""}} + version: {{ .Values.revision }} + {{- end }} +{{- range $key, $val := .Values.pilot.deploymentLabels }} + {{ $key }}: "{{ $val }}" +{{- end }} +spec: +{{- if not .Values.pilot.autoscaleEnabled }} +{{- if .Values.pilot.replicaCount }} + replicas: {{ .Values.pilot.replicaCount }} +{{- end }} +{{- end }} + strategy: + rollingUpdate: + maxSurge: {{ .Values.pilot.rollingMaxSurge }} + maxUnavailable: {{ .Values.pilot.rollingMaxUnavailable }} + selector: + matchLabels: + {{- if ne .Values.revision ""}} + app: istiod + version: {{ .Values.revision }} + {{- end }} + istio: pilot + template: + metadata: + labels: + app: istiod + {{- if ne .Values.revision ""}} + version: {{ .Values.revision }} + {{- end }} + # Label used by the 'default' service. For versioned deployments we match with app and version. + # This avoids default deployment picking the canary + istio: pilot + annotations: + sidecar.istio.io/inject: "false" + {{- if .Values.pilot.podAnnotations }} +{{ toYaml .Values.pilot.podAnnotations | indent 8 }} + {{- end }} + spec: + serviceAccountName: istiod-service-account +{{- if .Values.global.priorityClassName }} + priorityClassName: "{{ .Values.global.priorityClassName }}" +{{- end }} + securityContext: + fsGroup: 1337 + containers: + - name: discovery +{{- if contains "/" .Values.pilot.image }} + image: "{{ .Values.pilot.image }}" +{{- else }} + image: "{{ .Values.pilot.hub | default .Values.global.hub }}/{{ .Values.pilot.image | default "pilot" }}:{{ .Values.pilot.tag | default .Values.global.tag }}" +{{- end }} + imagePullPolicy: {{ .Values.global.imagePullPolicy | default "Always" }} + args: + - "discovery" + - --monitoringAddr=:15014 +{{- if .Values.global.logging.level }} + - --log_output_level={{ .Values.global.logging.level }} +{{- end}} +{{- if .Values.global.logAsJson }} + - --log_as_json +{{- end }} + - --domain + - {{ .Values.global.proxy.clusterDomain }} +{{- if .Values.global.oneNamespace }} + - "-a" + - {{ .Release.Namespace }} +{{- end }} + +{{- if and .Values.global.controlPlaneSecurityEnabled .Values.global.istiod.enabled }} + - --secureGrpcAddr=:15011 +{{- else }} + - --secureGrpcAddr= +{{- end }} +{{- if .Values.global.trustDomain }} + - --trust-domain={{ .Values.global.trustDomain }} +{{- end }} +{{- if .Values.pilot.plugins }} + - --plugins={{ .Values.pilot.plugins }} +{{- end }} + - --keepaliveMaxServerConnectionAge + - "{{ .Values.pilot.keepaliveMaxServerConnectionAge }}" + # TODO: make default + - --disable-install-crds=true + ports: + - containerPort: 8080 + - containerPort: 15010 + - containerPort: 15017 + readinessProbe: + httpGet: + path: /ready + port: 8080 + initialDelaySeconds: 5 + periodSeconds: 5 + timeoutSeconds: 5 + envFrom: + # Allow an istiod configmap injecting user-specified env. + - configMapRef: + name: istiod + optional: true + env: + - name: JWT_POLICY + value: {{ .Values.global.jwtPolicy }} + - name: PILOT_CERT_PROVIDER + value: {{ .Values.global.pilotCertProvider }} + - name: POD_NAME + valueFrom: + fieldRef: + apiVersion: v1 + fieldPath: metadata.name + - name: POD_NAMESPACE + valueFrom: + fieldRef: + apiVersion: v1 + fieldPath: metadata.namespace + - name: SERVICE_ACCOUNT + valueFrom: + fieldRef: + apiVersion: v1 + fieldPath: spec.serviceAccountName + {{- if .Values.pilot.env }} + {{- range $key, $val := .Values.pilot.env }} + - name: {{ $key }} + value: "{{ $val }}" + {{- end }} + {{- end }} +{{- if .Values.pilot.traceSampling }} + - name: PILOT_TRACE_SAMPLING + value: "{{ .Values.pilot.traceSampling }}" +{{- end }} + - name: CONFIG_NAMESPACE + value: {{ .Values.pilot.configNamespace }} +{{- if .Values.pilot.appNamespaces }} + - name: APP_NAMESPACE + value: {{ join "," .Values.pilot.appNamespaces }} +{{- end }} + - name: PILOT_ENABLE_PROTOCOL_SNIFFING_FOR_OUTBOUND + value: "{{ .Values.pilot.enableProtocolSniffingForOutbound }}" + - name: PILOT_ENABLE_PROTOCOL_SNIFFING_FOR_INBOUND + value: "{{ .Values.pilot.enableProtocolSniffingForInbound }}" +{{- if .Values.global.istiod.enabled }} + - name: INJECTION_WEBHOOK_CONFIG_NAME + value: istio-sidecar-injector{{- if not (eq .Values.revision "") }}-{{ .Values.revision }}{{- end }} + - name: ISTIOD_ADDR + value: istiod{{- if not (eq .Values.revision "") }}-{{ .Values.revision }}{{- end }}.{{ .Release.Namespace }}.svc:15012 + - name: PILOT_EXTERNAL_GALLEY + value: "false" +{{- end }} + resources: +{{- if .Values.pilot.resources }} +{{ toYaml .Values.pilot.resources | trim | indent 12 }} +{{- else }} +{{ toYaml .Values.global.defaultResources | trim | indent 12 }} +{{- end }} + securityContext: + runAsUser: 1337 + runAsGroup: 1337 + runAsNonRoot: true + capabilities: + drop: + - ALL + volumeMounts: + - name: config-volume + mountPath: /etc/istio/config + {{- if .Values.global.istiod.enabled }} + {{- if eq .Values.global.jwtPolicy "third-party-jwt" }} + - name: istio-token + mountPath: /var/run/secrets/tokens + readOnly: true + {{- end }} + - name: local-certs + mountPath: /var/run/secrets/istio-dns + - name: cacerts + mountPath: /etc/cacerts + readOnly: true + - name: inject + mountPath: /var/lib/istio/inject + readOnly: true + - name: istiod + mountPath: /var/lib/istio/local + readOnly: true + {{- end }} +{{- if and .Values.global.controlPlaneSecurityEnabled (not .Values.global.istiod.enabled) }} + - name: istio-proxy +{{- if contains "/" .Values.global.proxy.image }} + image: "{{ .Values.global.proxy.image }}" +{{- else }} + image: "{{ .Values.global.hub }}/{{ .Values.global.proxy.image }}:{{ .Values.global.tag }}" +{{- end }} + imagePullPolicy: {{ .Values.global.imagePullPolicy | default "Always" }} + ports: + - containerPort: 15011 + args: + - proxy + - --domain + - $(POD_NAMESPACE).svc.{{ .Values.global.proxy.clusterDomain }} + - --serviceCluster + - istio-pilot + - --templateFile + - /var/lib/envoy/envoy.yaml.tmpl + {{- if .Values.global.controlPlaneSecurityEnabled}} + - --controlPlaneAuthPolicy + - MUTUAL_TLS + {{- else }} + - --controlPlaneAuthPolicy + - NONE + {{- end }} + {{- if .Values.global.trustDomain }} + - --trust-domain={{ .Values.global.trustDomain }} + {{- end }} + {{- if .Values.global.logAsJson }} + - --log_as_json + {{- end }} + env: + - name: JWT_POLICY + value: {{ .Values.global.jwtPolicy }} + - name: PILOT_CERT_PROVIDER + value: {{ .Values.global.pilotCertProvider }} + - name: POD_NAME + valueFrom: + fieldRef: + apiVersion: v1 + fieldPath: metadata.name + - name: POD_NAMESPACE + valueFrom: + fieldRef: + apiVersion: v1 + fieldPath: metadata.namespace + - name: INSTANCE_IP + valueFrom: + fieldRef: + apiVersion: v1 + fieldPath: status.podIP + resources: +{{- if .Values.global.proxy.resources }} +{{ toYaml .Values.global.proxy.resources | trim | indent 12 }} +{{- else }} +{{ toYaml .Values.global.defaultResources | trim | indent 12 }} +{{- end }} + volumeMounts: +{{- if and .Values.global.controlPlaneSecurityEnabled .Values.global.mountMtlsCerts }} + - name: istio-certs + mountPath: /etc/certs + readOnly: true +{{- end }} +{{- if .Values.pilot.jwksResolverExtraRootCA }} + - name: extracacerts + mountPath: /cacerts +{{- end }} + - name: pilot-envoy-config + mountPath: /var/lib/envoy +{{- end }} + volumes: + {{- if .Values.global.istiod.enabled }} + # Technically not needed on this pod - but it helps debugging/testing SDS + # Should be removed after everything works. + - emptyDir: + medium: Memory + name: local-certs + {{- if eq .Values.global.jwtPolicy "third-party-jwt" }} + - name: istio-token + projected: + sources: + - serviceAccountToken: + audience: {{ .Values.global.sds.token.aud }} + expirationSeconds: 43200 + path: istio-token + {{- end }} + - name: istiod + configMap: + name: istiod + optional: true + # Optional: user-generated root + - name: cacerts + secret: + secretName: cacerts + optional: true + # Optional - image should have + - name: inject + configMap: + name: istio-sidecar-injector + optional: true + {{- end }} + + - name: config-volume + configMap: + name: istio{{- if not (eq .Values.revision "") }}-{{ .Values.revision }}{{- end }} + - name: pilot-envoy-config + configMap: + name: pilot-envoy-config{{- if not (eq .Values.revision "") }}-{{ .Values.revision }}{{- end }} + {{- if and .Values.global.controlPlaneSecurityEnabled .Values.global.mountMtlsCerts }} + - name: istio-certs + secret: + secretName: istio.istio-pilot-service-account + optional: true + {{- end }} + {{- if .Values.pilot.jwksResolverExtraRootCA }} + - name: extracacerts + configMap: + name: pilot-jwks-extra-cacerts{{- if not (eq .Values.revision "") }}-{{ .Values.revision }}{{- end }} + {{- end }} + affinity: + {{- include "nodeaffinity" . | indent 6 }} + {{- include "podAntiAffinity" . | indent 6 }} +{{- if .Values.pilot.tolerations }} + tolerations: +{{ toYaml .Values.pilot.tolerations | indent 6 }} +{{- else if .Values.global.defaultTolerations }} + tolerations: +{{ toYaml .Values.global.defaultTolerations | indent 6 }} +{{- end }} +--- +{{- end }} diff --git a/istio-1.5.0/install/kubernetes/operator/charts/istio-control/istio-discovery/templates/enable-mesh-mtls.yaml b/istio-1.5.0/install/kubernetes/operator/charts/istio-control/istio-discovery/templates/enable-mesh-mtls.yaml new file mode 100644 index 0000000..5ce0083 --- /dev/null +++ b/istio-1.5.0/install/kubernetes/operator/charts/istio-control/istio-discovery/templates/enable-mesh-mtls.yaml @@ -0,0 +1,51 @@ +{{- /* + +TODO(https://github.com/istio/istio/issues/18199) remove this configuration from charts once the operator starts managing it + +*/ -}} + +{{ if .Values.clusterResources }} +{{- if .Values.global.mtls.enabled }} + +# Authentication policy to enable mutual TLS for all services (that have sidecar) in the mesh. +apiVersion: "authentication.istio.io/v1alpha1" +kind: "MeshPolicy" +metadata: + name: "default" + labels: + release: {{ .Release.Name }} +spec: + peers: + - mtls: {} +--- +{{- if not .Values.global.mtls.auto }} +# We only need explicit destination rule with ISITO_MUTUAL when auto mTLS is not enabled. +apiVersion: networking.istio.io/v1alpha3 +kind: DestinationRule +metadata: + name: "default" + namespace: {{ .Release.Namespace }} + labels: + release: {{ .Release.Name }} +spec: + host: "*.local" + trafficPolicy: + tls: + mode: ISTIO_MUTUAL +--- +{{ end }} +apiVersion: networking.istio.io/v1alpha3 +kind: DestinationRule +metadata: + name: "api-server" + namespace: {{ .Release.Namespace }} + labels: + release: {{ .Release.Name }} +spec: + host: "kubernetes.default.svc.{{ .Values.global.proxy.clusterDomain }}" + trafficPolicy: + tls: + mode: DISABLE +--- +{{ end }} +{{ end }} diff --git a/istio-1.5.0/install/kubernetes/operator/charts/istio-control/istio-discovery/templates/istiod-injector-configmap.yaml b/istio-1.5.0/install/kubernetes/operator/charts/istio-control/istio-discovery/templates/istiod-injector-configmap.yaml new file mode 100644 index 0000000..82becc6 --- /dev/null +++ b/istio-1.5.0/install/kubernetes/operator/charts/istio-control/istio-discovery/templates/istiod-injector-configmap.yaml @@ -0,0 +1,34 @@ +{{ if or (eq .Values.revision "") (not .Values.clusterResources) }} +{{- if and (not .Values.global.omitSidecarInjectorConfigMap) .Values.global.istiod.enabled }} +apiVersion: v1 +kind: ConfigMap +metadata: + name: istio-sidecar-injector{{- if not (eq .Values.revision "") }}-{{ .Values.revision }}{{- end }} + namespace: {{ .Release.Namespace }} + labels: + release: {{ .Release.Name }} +data: +{{/* Scope the values to just top level fields used in the template, to reduce the size. */}} + values: |- +{{ pick .Values "global" "istio_cni" "sidecarInjectorWebhook" | toPrettyJson | indent 4 }} + + # To disable injection: use omitSidecarInjectorConfigMap, which disables the webhook patching + # and istiod webhook functionality. + # + # New fields should not use Values - it is a 'primary' config object, users should be able + # to fine tune it or use it with kube-inject. + config: |- + policy: {{ .Values.global.proxy.autoInject }} + alwaysInjectSelector: + {{ toYaml .Values.sidecarInjectorWebhook.alwaysInjectSelector | trim | indent 6 }} + neverInjectSelector: + {{ toYaml .Values.sidecarInjectorWebhook.neverInjectSelector | trim | indent 6 }} + injectedAnnotations: + {{- range $key, $val := .Values.sidecarInjectorWebhook.injectedAnnotations }} + "{{ $key }}": "{{ $val }}" + {{- end }} + +{{ .Files.Get "files/injection-template.yaml" | trim | indent 4 }} + +{{- end }} +{{- end }} diff --git a/istio-1.5.0/install/kubernetes/operator/charts/istio-control/istio-discovery/templates/mutatingwebhook.yaml b/istio-1.5.0/install/kubernetes/operator/charts/istio-control/istio-discovery/templates/mutatingwebhook.yaml new file mode 100644 index 0000000..48a3fa4 --- /dev/null +++ b/istio-1.5.0/install/kubernetes/operator/charts/istio-control/istio-discovery/templates/mutatingwebhook.yaml @@ -0,0 +1,75 @@ +# Installed for each revision - not installed for cluster resources ( cluster roles, bindings, crds) +{{- if .Values.global.istiod.enabled }} +{{- if and (not .Values.global.operatorManageWebhooks) .Values.global.istiod.enabled }} +apiVersion: admissionregistration.k8s.io/v1beta1 +kind: MutatingWebhookConfiguration +metadata: +{{- if eq .Release.Namespace "istio-system"}} + name: istio-sidecar-injector{{- if not (eq .Values.revision "") }}-{{ .Values.revision }}{{- end }} +{{ else }} + name: istio-sidecar-injector{{- if not (eq .Values.revision "") }}-{{ .Values.revision }}{{- end }}-{{ .Release.Namespace }} +{{- end }} + labels: + app: sidecar-injector + release: {{ .Release.Name }} +webhooks: + - name: sidecar-injector.istio.io + clientConfig: + service: + name: istiod{{- if not (eq .Values.revision "") }}-{{ .Values.revision }}{{- end }} + namespace: {{ .Release.Namespace }} + path: "/inject" + caBundle: "" + rules: + - operations: [ "CREATE" ] + apiGroups: [""] + apiVersions: ["v1"] + resources: ["pods"] + failurePolicy: Fail + namespaceSelector: +{{- if .Values.sidecarInjectorWebhook.enableNamespacesByDefault }} + matchExpressions: + - key: name + operator: NotIn + values: + - {{ .Release.Namespace }} + - key: istio-injection + operator: NotIn + values: + - disabled + - key: istio-env + operator: DoesNotExist + - key: istio.io/rev + operator: DoesNotExist +{{- else if .Values.revision }} + matchExpressions: + - key: istio-injection + operator: NotIn + values: + - disabled + - key: istio.io/rev + operator: In + values: + - {{ .Values.revision }} +{{- else if eq .Values.sidecarInjectorWebhook.injectLabel "istio-injection" }} + matchLabels: + istio-injection: enabled +{{- else }} + matchLabels: + istio-env: {{ .Release.Namespace }} +{{- end }} +{{- if .Values.sidecarInjectorWebhook.objectSelector.enabled }} + objectSelector: +{{- if .Values.sidecarInjectorWebhook.objectSelector.autoInject }} + matchExpressions: + - key: "sidecar.istio.io/inject" + operator: NotIn + values: + - "false" +{{- else }} + matchLabels: + "sidecar.istio.io/inject": "true" +{{- end }} +{{- end }} +{{- end }} +{{- end }} \ No newline at end of file diff --git a/istio-1.5.0/install/kubernetes/operator/charts/istio-control/istio-discovery/templates/poddisruptionbudget.yaml b/istio-1.5.0/install/kubernetes/operator/charts/istio-control/istio-discovery/templates/poddisruptionbudget.yaml new file mode 100644 index 0000000..08171c1 --- /dev/null +++ b/istio-1.5.0/install/kubernetes/operator/charts/istio-control/istio-discovery/templates/poddisruptionbudget.yaml @@ -0,0 +1,24 @@ +{{ if or (eq .Values.revision "") (not .Values.clusterResources) }} +{{- if .Values.global.defaultPodDisruptionBudget.enabled }} +apiVersion: policy/v1beta1 +kind: PodDisruptionBudget +metadata: + name: istiod{{- if not (eq .Values.revision "") }}-{{ .Values.revision }}{{- end }} + namespace: {{ .Release.Namespace }} + labels: + app: istiod + release: {{ .Release.Name }} + istio: pilot +spec: + minAvailable: 1 + selector: + matchLabels: + app: istiod + {{- if ne .Values.revision ""}} + version: {{ .Values.revision }} + {{- end }} + release: {{ .Release.Name }} + istio: pilot +--- +{{- end }} +{{- end }} diff --git a/istio-1.5.0/install/kubernetes/operator/charts/istio-control/istio-discovery/templates/service.yaml b/istio-1.5.0/install/kubernetes/operator/charts/istio-control/istio-discovery/templates/service.yaml new file mode 100644 index 0000000..47259f0 --- /dev/null +++ b/istio-1.5.0/install/kubernetes/operator/charts/istio-control/istio-discovery/templates/service.yaml @@ -0,0 +1,63 @@ +{{ if or (eq .Values.revision "") (not .Values.clusterResources) }} +apiVersion: v1 +kind: Service +metadata: + name: istio-pilot{{- if not (eq .Values.revision "") }}-{{ .Values.revision }}{{- end }} + namespace: {{ .Release.Namespace }} + labels: + app: pilot + release: {{ .Release.Name }} + istio: pilot +spec: + ports: + - port: 15010 + name: grpc-xds # direct + - port: 15011 + name: https-xds # mTLS + - port: 15012 + name: https-dns # mTLS with k8s-signed cert + - port: 8080 + name: http-legacy-discovery # direct + - port: 15014 + name: http-monitoring +{{- if .Values.global.istiod.enabled }} + - port: 443 + name: https-webhook # validation and injection + targetPort: 15017 +{{- end }} + selector: + {{- if ne .Values.revision ""}} + app: istiod + version: {{ .Values.revision }} + {{ else }} + istio: pilot + {{- end }} +--- +{{- if .Values.global.istiod.enabled }} +apiVersion: v1 +kind: Service +metadata: + name: istiod{{- if not (eq .Values.revision "") }}-{{ .Values.revision }}{{- end }} + namespace: {{ .Release.Namespace }} + labels: + app: istiod + release: {{ .Release.Name }} +spec: + ports: + - port: 15012 + name: https-dns # mTLS with k8s-signed cert + - port: 443 + name: https-webhook # validation and injection + targetPort: 15017 + selector: + app: istiod + {{- if ne .Values.revision ""}} + version: {{ .Values.revision }} + {{- else }} + # Label used by the 'default' service. For versioned deployments we match with app and version. + # This avoids default deployment picking the canary + istio: pilot + {{- end }} +{{- end }} +--- +{{- end }} diff --git a/istio-1.5.0/install/kubernetes/operator/charts/istio-control/istio-discovery/templates/serviceaccount.yaml b/istio-1.5.0/install/kubernetes/operator/charts/istio-control/istio-discovery/templates/serviceaccount.yaml new file mode 100644 index 0000000..65e1d15 --- /dev/null +++ b/istio-1.5.0/install/kubernetes/operator/charts/istio-control/istio-discovery/templates/serviceaccount.yaml @@ -0,0 +1,17 @@ +{{ if .Values.clusterResources }} +apiVersion: v1 +kind: ServiceAccount +{{- if .Values.global.imagePullSecrets }} +imagePullSecrets: +{{- range .Values.global.imagePullSecrets }} + - name: {{ . }} +{{- end }} +{{- end }} +metadata: + name: istiod-service-account + namespace: {{ .Release.Namespace }} + labels: + app: istiod + release: {{ .Release.Name }} +--- +{{ end }} diff --git a/istio-1.5.0/install/kubernetes/operator/charts/istio-control/istio-discovery/templates/telemetryv2_1.4.yaml b/istio-1.5.0/install/kubernetes/operator/charts/istio-control/istio-discovery/templates/telemetryv2_1.4.yaml new file mode 100644 index 0000000..fc7d825 --- /dev/null +++ b/istio-1.5.0/install/kubernetes/operator/charts/istio-control/istio-discovery/templates/telemetryv2_1.4.yaml @@ -0,0 +1,235 @@ +{{ if or (eq .Values.revision "") (not .Values.clusterResources) }} +{{- if and .Values.telemetry.enabled .Values.telemetry.v2.enabled }} +apiVersion: networking.istio.io/v1alpha3 +kind: EnvoyFilter +metadata: + name: metadata-exchange-1.4 + {{- if .Values.global.configRootNamespace }} + namespace: {{ .Values.global.configRootNamespace }} + {{- else }} + namespace: {{ .Release.Namespace }} + {{- end }} +spec: + configPatches: + - applyTo: HTTP_FILTER + match: + context: ANY # inbound, outbound, and gateway + proxy: + proxyVersion: '^1\.4.*' + listener: + filterChain: + filter: + name: "envoy.http_connection_manager" + patch: + operation: INSERT_BEFORE + value: + name: envoy.filters.http.wasm + config: + config: + configuration: envoy.wasm.metadata_exchange + vm_config: + runtime: envoy.wasm.runtime.null + code: + inline_string: envoy.wasm.metadata_exchange +--- +{{- if .Values.telemetry.v2.prometheus.enabled }} +apiVersion: networking.istio.io/v1alpha3 +kind: EnvoyFilter +metadata: + name: stats-filter-1.4 + {{- if .Values.global.configRootNamespace }} + namespace: {{ .Values.global.configRootNamespace }} + {{- else }} + namespace: {{ .Release.Namespace }} + {{- end }} +spec: + configPatches: + - applyTo: HTTP_FILTER + match: + context: SIDECAR_OUTBOUND + proxy: + proxyVersion: '^1\.4.*' + listener: + filterChain: + filter: + name: "envoy.http_connection_manager" + subFilter: + name: "envoy.router" + patch: + operation: INSERT_BEFORE + value: + name: envoy.filters.http.wasm + config: + config: + root_id: stats_outbound + configuration: | + { + "debug": "false", + "stat_prefix": "istio", + } + vm_config: + vm_id: stats_outbound + runtime: envoy.wasm.runtime.null + code: + inline_string: envoy.wasm.stats + - applyTo: HTTP_FILTER + match: + context: SIDECAR_INBOUND + proxy: + proxyVersion: '^1\.4.*' + listener: + filterChain: + filter: + name: "envoy.http_connection_manager" + subFilter: + name: "envoy.router" + patch: + operation: INSERT_BEFORE + value: + name: envoy.filters.http.wasm + config: + config: + root_id: stats_inbound + configuration: | + { + "debug": "false", + "stat_prefix": "istio", + } + vm_config: + vm_id: stats_inbound + runtime: envoy.wasm.runtime.null + code: + inline_string: envoy.wasm.stats + - applyTo: HTTP_FILTER + match: + context: GATEWAY + proxy: + proxyVersion: '^1\.4.*' + listener: + filterChain: + filter: + name: "envoy.http_connection_manager" + subFilter: + name: "envoy.router" + patch: + operation: INSERT_BEFORE + value: + name: envoy.filters.http.wasm + config: + config: + root_id: stats_outbound + configuration: | + { + "debug": "false", + "stat_prefix": "istio", + } + vm_config: + vm_id: stats_outbound + runtime: envoy.wasm.runtime.null + code: + inline_string: envoy.wasm.stats +--- +{{- end }} +{{- if .Values.telemetry.v2.stackdriver.enabled }} +apiVersion: networking.istio.io/v1alpha3 +kind: EnvoyFilter +metadata: + name: stackdriver-filter-1.4 + {{- if .Values.global.configRootNamespace }} + namespace: {{ .Values.global.configRootNamespace }} + {{- else }} + namespace: {{ .Release.Namespace }} + {{- end }} +spec: + configPatches: + - applyTo: HTTP_FILTER + match: + context: SIDECAR_OUTBOUND + proxy: + proxyVersion: '^1\.4.*' + listener: + filterChain: + filter: + name: "envoy.http_connection_manager" + subFilter: + name: "envoy.router" + patch: + operation: INSERT_BEFORE + value: + name: envoy.filters.http.wasm + config: + config: + root_id: stackdriver_outbound + configuration: | + {{- if not .Values.telemetry.v2.stackdriver.configOverride }} + {"enable_mesh_edges_reporting": {{ .Values.telemetry.v2.stackdriver.topology }}, "disable_server_access_logging": {{ not .Values.telemetry.v2.stackdriver.logging }}, "meshEdgesReportingDuration": "600s"} + {{- else }} + {{ toJson .Values.telemetry.v2.stackdriver.configOverride | indent 8 }} + {{- end }} + vm_config: + vm_id: stackdriver_outbound + runtime: envoy.wasm.runtime.null + code: + inline_string: envoy.wasm.null.stackdriver + - applyTo: HTTP_FILTER + match: + context: SIDECAR_INBOUND + proxy: + proxyVersion: '^1\.4.*' + listener: + filterChain: + filter: + name: "envoy.http_connection_manager" + subFilter: + name: "envoy.router" + patch: + operation: INSERT_BEFORE + value: + name: envoy.filters.http.wasm + config: + config: + root_id: stackdriver_inbound + configuration: | + {{- if not .Values.telemetry.v2.stackdriver.configOverride }} + {"enable_mesh_edges_reporting": {{ .Values.telemetry.v2.stackdriver.topology }}, "disable_server_access_logging": {{ not .Values.telemetry.v2.stackdriver.logging }}, "meshEdgesReportingDuration": "600s"} + {{- else }} + {{ toJson .Values.telemetry.v2.stackdriver.configOverride | indent 16 }} + {{- end }} + vm_config: + vm_id: stackdriver_inbound + runtime: envoy.wasm.runtime.null + code: + inline_string: envoy.wasm.null.stackdriver + - applyTo: HTTP_FILTER + match: + context: GATEWAY + proxy: + proxyVersion: '^1\.4.*' + listener: + filterChain: + filter: + name: "envoy.http_connection_manager" + subFilter: + name: "envoy.router" + patch: + operation: INSERT_BEFORE + value: + name: envoy.filters.http.wasm + config: + config: + root_id: stackdriver_outbound + configuration: | + {{- if not .Values.telemetry.v2.stackdriver.configOverride }} + {"enable_mesh_edges_reporting": {{ .Values.telemetry.v2.stackdriver.topology }}, "disable_server_access_logging": {{ not .Values.telemetry.v2.stackdriver.logging }}, "meshEdgesReportingDuration": "600s", "disable_host_header_fallback": true} + {{- else }} + {{ toJson .Values.telemetry.v2.stackdriver.configOverride | indent 16 }} + {{- end }} + vm_config: + vm_id: stackdriver_outbound + runtime: envoy.wasm.runtime.null + code: + inline_string: envoy.wasm.null.stackdriver +--- +{{- end}} +{{- end}} +{{- end }} diff --git a/istio-1.5.0/install/kubernetes/operator/charts/istio-control/istio-discovery/templates/telemetryv2_1.5.yaml b/istio-1.5.0/install/kubernetes/operator/charts/istio-control/istio-discovery/templates/telemetryv2_1.5.yaml new file mode 100644 index 0000000..b441d8f --- /dev/null +++ b/istio-1.5.0/install/kubernetes/operator/charts/istio-control/istio-discovery/templates/telemetryv2_1.5.yaml @@ -0,0 +1,419 @@ +{{ if or (eq .Values.revision "") (not .Values.clusterResources) }} +{{- if and .Values.telemetry.enabled .Values.telemetry.v2.enabled }} +apiVersion: networking.istio.io/v1alpha3 +kind: EnvoyFilter +metadata: + name: metadata-exchange-1.5 + {{- if .Values.global.configRootNamespace }} + namespace: {{ .Values.global.configRootNamespace }} + {{- else }} + namespace: {{ .Release.Namespace }} + {{- end }} +spec: + configPatches: + - applyTo: HTTP_FILTER + match: + context: ANY # inbound, outbound, and gateway + proxy: + proxyVersion: '^1\.5.*' + listener: + filterChain: + filter: + name: "envoy.http_connection_manager" + patch: + operation: INSERT_BEFORE + value: + name: envoy.filters.http.wasm + typed_config: + "@type": type.googleapis.com/udpa.type.v1.TypedStruct + type_url: type.googleapis.com/envoy.config.filter.http.wasm.v2.Wasm + value: + config: + configuration: envoy.wasm.metadata_exchange + vm_config: + runtime: envoy.wasm.runtime.null + code: + local: + inline_string: envoy.wasm.metadata_exchange +--- +apiVersion: networking.istio.io/v1alpha3 +kind: EnvoyFilter +metadata: + name: tcp-metadata-exchange-1.5 + {{- if .Values.global.configRootNamespace }} + namespace: {{ .Values.global.configRootNamespace }} + {{- else }} + namespace: {{ .Release.Namespace }} + {{- end }} +spec: + configPatches: + - applyTo: NETWORK_FILTER + match: + context: SIDECAR_INBOUND + proxy: + proxyVersion: '^1\.5.*' + listener: {} + patch: + operation: INSERT_BEFORE + value: + name: envoy.filters.network.metadata_exchange + config: + protocol: istio-peer-exchange + - applyTo: CLUSTER + match: + context: SIDECAR_OUTBOUND + proxy: + proxyVersion: '^1\.5.*' + cluster: {} + patch: + operation: MERGE + value: + filters: + - name: envoy.filters.network.upstream.metadata_exchange + typed_config: + "@type": type.googleapis.com/udpa.type.v1.TypedStruct + type_url: type.googleapis.com/envoy.tcp.metadataexchange.config.MetadataExchange + value: + protocol: istio-peer-exchange + - applyTo: CLUSTER + match: + context: GATEWAY + proxy: + proxyVersion: '^1\.5.*' + cluster: {} + patch: + operation: MERGE + value: + filters: + - name: envoy.filters.network.upstream.metadata_exchange + typed_config: + "@type": type.googleapis.com/udpa.type.v1.TypedStruct + type_url: type.googleapis.com/envoy.tcp.metadataexchange.config.MetadataExchange + value: + protocol: istio-peer-exchange +--- +{{- if .Values.telemetry.v2.prometheus.enabled }} +apiVersion: networking.istio.io/v1alpha3 +kind: EnvoyFilter +metadata: + name: stats-filter-1.5 + {{- if .Values.global.configRootNamespace }} + namespace: {{ .Values.global.configRootNamespace }} + {{- else }} + namespace: {{ .Release.Namespace }} + {{- end }} +spec: + configPatches: + - applyTo: HTTP_FILTER + match: + context: SIDECAR_OUTBOUND + proxy: + proxyVersion: '^1\.5.*' + listener: + filterChain: + filter: + name: "envoy.http_connection_manager" + subFilter: + name: "envoy.router" + patch: + operation: INSERT_BEFORE + value: + name: envoy.filters.http.wasm + typed_config: + "@type": type.googleapis.com/udpa.type.v1.TypedStruct + type_url: type.googleapis.com/envoy.config.filter.http.wasm.v2.Wasm + value: + config: + root_id: stats_outbound + configuration: | + { + "debug": "false", + "stat_prefix": "istio", + } + vm_config: + vm_id: stats_outbound + runtime: envoy.wasm.runtime.null + code: + local: + inline_string: envoy.wasm.stats + - applyTo: HTTP_FILTER + match: + context: SIDECAR_INBOUND + proxy: + proxyVersion: '^1\.5.*' + listener: + filterChain: + filter: + name: "envoy.http_connection_manager" + subFilter: + name: "envoy.router" + patch: + operation: INSERT_BEFORE + value: + name: envoy.filters.http.wasm + typed_config: + "@type": type.googleapis.com/udpa.type.v1.TypedStruct + type_url: type.googleapis.com/envoy.config.filter.http.wasm.v2.Wasm + value: + config: + root_id: stats_inbound + configuration: | + { + "debug": "false", + "stat_prefix": "istio", + } + vm_config: + vm_id: stats_inbound + runtime: envoy.wasm.runtime.null + code: + local: + inline_string: envoy.wasm.stats + - applyTo: HTTP_FILTER + match: + context: GATEWAY + proxy: + proxyVersion: '^1\.5.*' + listener: + filterChain: + filter: + name: "envoy.http_connection_manager" + subFilter: + name: "envoy.router" + patch: + operation: INSERT_BEFORE + value: + name: envoy.filters.http.wasm + typed_config: + "@type": type.googleapis.com/udpa.type.v1.TypedStruct + type_url: type.googleapis.com/envoy.config.filter.http.wasm.v2.Wasm + value: + config: + root_id: stats_outbound + configuration: | + { + "debug": "false", + "stat_prefix": "istio", + } + vm_config: + vm_id: stats_outbound + runtime: envoy.wasm.runtime.null + code: + local: + inline_string: envoy.wasm.stats +--- +apiVersion: networking.istio.io/v1alpha3 +kind: EnvoyFilter +metadata: + name: tcp-stats-filter-1.5 + {{- if .Values.global.configRootNamespace }} + namespace: {{ .Values.global.configRootNamespace }} + {{- else }} + namespace: {{ .Release.Namespace }} + {{- end }} +spec: + configPatches: + - applyTo: NETWORK_FILTER + match: + context: SIDECAR_INBOUND + proxy: + proxyVersion: '^1\.5.*' + listener: + filterChain: + filter: + name: "envoy.tcp_proxy" + patch: + operation: INSERT_BEFORE + value: + name: envoy.filters.network.wasm + typed_config: + "@type": type.googleapis.com/udpa.type.v1.TypedStruct + type_url: type.googleapis.com/envoy.config.filter.network.wasm.v2.Wasm + value: + config: + root_id: stats_inbound + configuration: | + { + "debug": "false", + "stat_prefix": "istio", + } + vm_config: + vm_id: stats_inbound + runtime: envoy.wasm.runtime.null + code: + local: + inline_string: "envoy.wasm.stats" + - applyTo: NETWORK_FILTER + match: + context: SIDECAR_OUTBOUND + proxy: + proxyVersion: '^1\.5.*' + listener: + filterChain: + filter: + name: "envoy.tcp_proxy" + patch: + operation: INSERT_BEFORE + value: + name: envoy.filters.network.wasm + typed_config: + "@type": type.googleapis.com/udpa.type.v1.TypedStruct + type_url: type.googleapis.com/envoy.config.filter.network.wasm.v2.Wasm + value: + config: + root_id: stats_outbound + configuration: | + { + "debug": "false", + "stat_prefix": "istio", + } + vm_config: + vm_id: stats_outbound + runtime: envoy.wasm.runtime.null + code: + local: + inline_string: "envoy.wasm.stats" + - applyTo: NETWORK_FILTER + match: + context: GATEWAY + proxy: + proxyVersion: '^1\.5.*' + listener: + filterChain: + filter: + name: "envoy.tcp_proxy" + patch: + operation: INSERT_BEFORE + value: + name: envoy.filters.network.wasm + typed_config: + "@type": type.googleapis.com/udpa.type.v1.TypedStruct + type_url: type.googleapis.com/envoy.config.filter.network.wasm.v2.Wasm + value: + config: + root_id: stats_outbound + configuration: | + { + "debug": "false", + "stat_prefix": "istio", + } + vm_config: + vm_id: stats_outbound + runtime: envoy.wasm.runtime.null + code: + local: + inline_string: "envoy.wasm.stats" +--- +{{- end }} + +{{- if .Values.telemetry.v2.stackdriver.enabled }} +apiVersion: networking.istio.io/v1alpha3 +kind: EnvoyFilter +metadata: + name: stackdriver-filter-1.5 + {{- if .Values.global.configRootNamespace }} + namespace: {{ .Values.global.configRootNamespace }} + {{- else }} + namespace: {{ .Release.Namespace }} + {{- end }} +spec: + configPatches: + - applyTo: HTTP_FILTER + match: + context: SIDECAR_OUTBOUND + proxy: + proxyVersion: '^1\.5.*' + listener: + filterChain: + filter: + name: "envoy.http_connection_manager" + subFilter: + name: "envoy.router" + patch: + operation: INSERT_BEFORE + value: + name: envoy.filters.http.wasm + typed_config: + "@type": type.googleapis.com/udpa.type.v1.TypedStruct + type_url: type.googleapis.com/envoy.config.filter.http.wasm.v2.Wasm + value: + config: + root_id: stackdriver_outbound + configuration: | + {{- if not .Values.telemetry.v2.stackdriver.configOverride }} + {"enable_mesh_edges_reporting": {{ .Values.telemetry.v2.stackdriver.topology }}, "disable_server_access_logging": {{ not .Values.telemetry.v2.stackdriver.logging }}, "meshEdgesReportingDuration": "600s"} + {{- else }} + {{ toJson .Values.telemetry.v2.stackdriver.configOverride | indent 18 }} + {{- end }} + vm_config: + vm_id: stackdriver_outbound + runtime: envoy.wasm.runtime.null + code: + local: { inline_string: envoy.wasm.null.stackdriver } + - applyTo: HTTP_FILTER + match: + context: SIDECAR_INBOUND + proxy: + proxyVersion: '^1\.5.*' + listener: + filterChain: + filter: + name: "envoy.http_connection_manager" + subFilter: + name: "envoy.router" + patch: + operation: INSERT_BEFORE + value: + name: envoy.filters.http.wasm + typed_config: + "@type": type.googleapis.com/udpa.type.v1.TypedStruct + type_url: type.googleapis.com/envoy.config.filter.http.wasm.v2.Wasm + value: + config: + root_id: stackdriver_inbound + configuration: | + {{- if not .Values.telemetry.v2.stackdriver.configOverride }} + {"enable_mesh_edges_reporting": {{ .Values.telemetry.v2.stackdriver.topology }}, "disable_server_access_logging": {{ not .Values.telemetry.v2.stackdriver.logging }}, "meshEdgesReportingDuration": "600s"} + {{- else }} + {{ toJson .Values.telemetry.v2.stackdriver.configOverride | indent 18 }} + {{- end }} + vm_config: + vm_id: stackdriver_inbound + runtime: envoy.wasm.runtime.null + code: + local: { inline_string: envoy.wasm.null.stackdriver } + - applyTo: HTTP_FILTER + match: + context: GATEWAY + proxy: + proxyVersion: '^1\.5.*' + listener: + filterChain: + filter: + name: "envoy.http_connection_manager" + subFilter: + name: "envoy.router" + patch: + operation: INSERT_BEFORE + value: + name: envoy.filters.http.wasm + typed_config: + "@type": type.googleapis.com/udpa.type.v1.TypedStruct + type_url: type.googleapis.com/envoy.config.filter.http.wasm.v2.Wasm + value: + config: + root_id: stackdriver_outbound + configuration: | + {{- if not .Values.telemetry.v2.stackdriver.configOverride }} + {"enable_mesh_edges_reporting": {{ .Values.telemetry.v2.stackdriver.topology }}, "disable_server_access_logging": {{ not .Values.telemetry.v2.stackdriver.logging }}, "meshEdgesReportingDuration": "600s", "disable_host_header_fallback": true} + {{- else }} + {{ toJson .Values.telemetry.v2.stackdriver.configOverride | indent 18 }} + {{- end }} + vm_config: + vm_id: stackdriver_outbound + runtime: envoy.wasm.runtime.null + code: + local: { inline_string: envoy.wasm.null.stackdriver } +--- +{{- end}} +{{- end}} +{{- end }} diff --git a/istio-1.5.0/install/kubernetes/operator/charts/istio-control/istio-discovery/templates/validatingwebhookconfiguration.yaml b/istio-1.5.0/install/kubernetes/operator/charts/istio-control/istio-discovery/templates/validatingwebhookconfiguration.yaml new file mode 100644 index 0000000..32b16ba --- /dev/null +++ b/istio-1.5.0/install/kubernetes/operator/charts/istio-control/istio-discovery/templates/validatingwebhookconfiguration.yaml @@ -0,0 +1,60 @@ +{{- if .Values.clusterResources }} +{{- if .Values.global.istiod.enabled }} +apiVersion: admissionregistration.k8s.io/v1beta1 +kind: ValidatingWebhookConfiguration +metadata: + name: istiod-{{ .Release.Namespace }} + labels: + app: istiod + release: {{ .Release.Name }} + istio: istiod +webhooks: + - name: validation.istio.io + clientConfig: + service: + name: istiod + namespace: {{ .Release.Namespace }} + path: "/validate" + caBundle: "" # patched at runtime when the webhook is ready. + rules: + - operations: + - CREATE + - UPDATE + apiGroups: + - config.istio.io + - rbac.istio.io + - security.istio.io + - authentication.istio.io + - networking.istio.io + apiVersions: + - "*" + resources: + - "*" + # Fail open until the validation webhook is ready. The webhook controller + # will update this to `Fail` and patch in the `caBundle` when the webhook + # endpoint is ready. + failurePolicy: Ignore + sideEffects: None +--- +apiVersion: admissionregistration.k8s.io/v1beta1 +kind: ValidatingWebhookConfiguration +metadata: + name: istio-galley + labels: + app: galley + release: {{ .Release.Name }} + istio: galley +webhooks: +--- +{{- else }} +apiVersion: admissionregistration.k8s.io/v1beta1 +kind: ValidatingWebhookConfiguration +metadata: + name: istiod-{{ .Release.Namespace }} + labels: + app: istiod + release: {{ .Release.Name }} + istio: istiod +webhooks: +{{- end }} +{{- end }} diff --git a/istio-1.5.0/install/kubernetes/operator/charts/istio-control/istio-discovery/values.yaml b/istio-1.5.0/install/kubernetes/operator/charts/istio-control/istio-discovery/values.yaml new file mode 100644 index 0000000..0a16acf --- /dev/null +++ b/istio-1.5.0/install/kubernetes/operator/charts/istio-control/istio-discovery/values.yaml @@ -0,0 +1,197 @@ +#.Values.pilot for discovery and mesh wide config + +## Discovery Settings +pilot: + autoscaleEnabled: true + autoscaleMin: 1 + autoscaleMax: 5 + replicaCount: 1 + rollingMaxSurge: 100% + rollingMaxUnavailable: 25% + + hub: "" + tag: "" + + # Can be a full hub/image:tag + image: pilot + traceSampling: 1.0 + + # Resources for a small pilot install + resources: + requests: + cpu: 500m + memory: 2048Mi + + # Namespace for Istio config + configNamespace: istio-config + + # Applications namespace list pilot manages + appNamespaces: [] + + env: {} + + cpu: + targetAverageUtilization: 80 + + # if protocol sniffing is enabled for outbound + enableProtocolSniffingForOutbound: true + # if protocol sniffing is enabled for inbound + enableProtocolSniffingForInbound: false + + nodeSelector: {} + tolerations: [] + podAnnotations: {} + + # You can use jwksResolverExtraRootCA to provide a root certificate + # in PEM format. This will then be trusted by pilot when resolving + # JWKS URIs. + jwksResolverExtraRootCA: "" + + # This is used to set the source of configuration for + # the associated address in configSource, if nothing is specificed + # the default MCP is assumed. The alternative option is SERVICE_REGISTRY + # which describes the source is only forwarding synthetic service entries + configSource: + subscribedResources: [] + + plugins: [] + + # Specify the pod anti-affinity that allows you to constrain which nodes + # your pod is eligible to be scheduled based on labels on pods that are + # already running on the node rather than based on labels on nodes. + # There are currently two types of anti-affinity: + # "requiredDuringSchedulingIgnoredDuringExecution" + # "preferredDuringSchedulingIgnoredDuringExecution" + # which denote "hard" vs. "soft" requirements, you can define your values + # in "podAntiAffinityLabelSelector" and "podAntiAffinityTermLabelSelector" + # correspondingly. + # For example: + # podAntiAffinityLabelSelector: + # - key: security + # operator: In + # values: S1,S2 + # topologyKey: "kubernetes.io/hostname" + # This pod anti-affinity rule says that the pod requires not to be scheduled + # onto a node if that node is already running a pod with label having key + # "security" and value "S1". + podAntiAffinityLabelSelector: [] + podAntiAffinityTermLabelSelector: [] + + # The following is used to limit how long a sidecar can be connected + # to a pilot. It balances out load across pilot instances at the cost of + # increasing system churn. + keepaliveMaxServerConnectionAge: 30m + + # Additional labels to apply to the deployment. + deploymentLabels: {} + + + ## Mesh config settings + + # Install the mesh config map, generated from values.yaml. + # If false, pilot wil use default values (by default) or user-supplied values. + configMap: true + + # Controls legacy k8s ingress + # Only one pilot profile should enable ingress support !!! + ingress: + # If empty, node-port is assumed. + ingressService: istio-ingressgateway + # DEFAULT: all Ingress resources without annotation or with istio annotation + # STRICT: only with istio annotation + # OFF: no ingress or sync. + ingressControllerMode: "STRICT" + + # Value to set on "kubernetes.io/ingress.class" annotations to activate, if mode is STRICT + # This is required to be different than 'istio' if multiple ingresses are present. + ingressClass: istio + + policy: + # Will not define mixerCheckServer and mixerReportServer + enabled: false + +## Mixer settings +mixer: + telemetry: + # Set reportBatchMaxEntries to 0 to use the default batching behavior (i.e., every 100 requests). + # A positive value indicates the number of requests that are batched before telemetry data + # is sent to the mixer server + reportBatchMaxEntries: 100 + + # Set reportBatchMaxTime to 0 to use the default batching behavior (i.e., every 1 second). + # A positive time value indicates the maximum wait time since the last request will telemetry data + # be batched before being sent to the mixer server + reportBatchMaxTime: 1s + + sessionAffinityEnabled: false + policy: + enabled: false + +sidecarInjectorWebhook: + # You can use the field called alwaysInjectSelector and neverInjectSelector which will always inject the sidecar or + # always skip the injection on pods that match that label selector, regardless of the global policy. + # See https://istio.io/docs/setup/kubernetes/additional-setup/sidecar-injection/#more-control-adding-exceptions + neverInjectSelector: [] + alwaysInjectSelector: [] + + # injectedAnnotations are additional annotations that will be added to the pod spec after injection + # This is primarily to support PSP annotations. For example, if you defined a PSP with the annotations: + # + # annotations: + # apparmor.security.beta.kubernetes.io/allowedProfileNames: runtime/default + # apparmor.security.beta.kubernetes.io/defaultProfileName: runtime/default + # + # The PSP controller would add corresponding annotations to the pod spec for each container. However, this happens before + # the inject adds additional containers, so we must specify them explicitly here. With the above example, we could specify: + # injectedAnnotations: + # container.apparmor.security.beta.kubernetes.io/istio-init: runtime/default + # container.apparmor.security.beta.kubernetes.io/istio-proxy: runtime/default + injectedAnnotations: {} + + # This enables injection of sidecar in all namespaces, + # with the exception of namespaces with "istio-injection:disabled" annotation + # Only one environment should have this enabled. + enableNamespacesByDefault: false + + # If set, will use the value as injection label. The value must match the 'release' label of the injector, + # except when 1.2 istio-injection label is used, which must be set to "enabled". + injectLabel: istio-injection + + # Enable objectSelector to filter out pods with no need for sidecar before calling istio-sidecar-injector. + # It is disabled by default since this function will only work after k8s v1.15. + objectSelector: + enabled: false + autoInject: true + +galley: + enabled: false + +telemetry: + enabled: true + v1: + # Set true to enable Mixer based telemetry + enabled: false + v2: + # For Null VM case now. If enabled, will set disableMixerHttpReports to true and not define mixerReportServer + # also enable metadata exchange and stats filter. + enabled: true + # Indicate if prometheus stats filter is enabled or not + prometheus: + enabled: true + # stackdriver filter settings. + stackdriver: + enabled: false + logging: false + monitoring: false + topology: false + # configOverride parts give you the ability to override the low level configuration params passed to envoy filter. + + configOverride: {} + # e.g. + # enable_mesh_edges_reporting: true + # disable_server_access_logging: false + # meshEdgesReportingDuration: 500s + # disable_host_header_fallback: true + +# Revision is set as 'version' label and part of the resource names when installing multiple control planes. +revision: "" diff --git a/istio-1.5.0/install/kubernetes/operator/charts/istio-policy/Chart.yaml b/istio-1.5.0/install/kubernetes/operator/charts/istio-policy/Chart.yaml new file mode 100644 index 0000000..f811d74 --- /dev/null +++ b/istio-1.5.0/install/kubernetes/operator/charts/istio-policy/Chart.yaml @@ -0,0 +1,13 @@ +apiVersion: v1 +name: istio-policy +version: 1.1.0 +appVersion: 1.1.0 +tillerVersion: ">=2.7.2" +description: Helm chart for mixer policy deployment +keywords: + - istio + - mixer +sources: + - http://github.com/istio/istio +engine: gotpl +icon: https://istio.io/favicons/android-192x192.png diff --git a/istio-1.5.0/install/kubernetes/operator/charts/istio-policy/templates/_affinity.tpl b/istio-1.5.0/install/kubernetes/operator/charts/istio-policy/templates/_affinity.tpl new file mode 100644 index 0000000..fb68308 --- /dev/null +++ b/istio-1.5.0/install/kubernetes/operator/charts/istio-policy/templates/_affinity.tpl @@ -0,0 +1,93 @@ +{{/* affinity - https://kubernetes.io/docs/concepts/configuration/assign-pod-node/ */}} + +{{- define "nodeaffinity" }} + nodeAffinity: + requiredDuringSchedulingIgnoredDuringExecution: + {{- include "nodeAffinityRequiredDuringScheduling" . }} + preferredDuringSchedulingIgnoredDuringExecution: + {{- include "nodeAffinityPreferredDuringScheduling" . }} +{{- end }} + +{{- define "nodeAffinityRequiredDuringScheduling" }} + nodeSelectorTerms: + - matchExpressions: + - key: beta.kubernetes.io/arch + operator: In + values: + {{- range $key, $val := .Values.global.arch }} + {{- if gt ($val | int) 0 }} + - {{ $key | quote }} + {{- end }} + {{- end }} + {{- $nodeSelector := default .Values.global.defaultNodeSelector .Values.mixer.policy.nodeSelector -}} + {{- range $key, $val := $nodeSelector }} + - key: {{ $key }} + operator: In + values: + - {{ $val | quote }} + {{- end }} +{{- end }} + +{{- define "nodeAffinityPreferredDuringScheduling" }} + {{- range $key, $val := .Values.global.arch }} + {{- if gt ($val | int) 0 }} + - weight: {{ $val | int }} + preference: + matchExpressions: + - key: beta.kubernetes.io/arch + operator: In + values: + - {{ $key | quote }} + {{- end }} + {{- end }} +{{- end }} + +{{- define "podAntiAffinity" }} +{{- if or .Values.mixer.policy.podAntiAffinityLabelSelector .Values.mixer.policy.podAntiAffinityTermLabelSelector}} + podAntiAffinity: + {{- if .Values.mixer.policy.podAntiAffinityLabelSelector }} + requiredDuringSchedulingIgnoredDuringExecution: + {{- include "podAntiAffinityRequiredDuringScheduling" . }} + {{- end }} + {{- if .Values.mixer.policy.podAntiAffinityTermLabelSelector }} + preferredDuringSchedulingIgnoredDuringExecution: + {{- include "podAntiAffinityPreferredDuringScheduling" . }} + {{- end }} +{{- end }} +{{- end }} + +{{- define "podAntiAffinityRequiredDuringScheduling" }} + {{- range $index, $item := .Values.mixer.policy.podAntiAffinityLabelSelector }} + - labelSelector: + matchExpressions: + - key: {{ $item.key }} + operator: {{ $item.operator }} + {{- if $item.values }} + values: + {{- $vals := split "," $item.values }} + {{- range $i, $v := $vals }} + - {{ $v | quote }} + {{- end }} + {{- end }} + topologyKey: {{ $item.topologyKey }} + {{- end }} +{{- end }} + +{{- define "podAntiAffinityPreferredDuringScheduling" }} + {{- range $index, $item := .Values.mixer.policy.podAntiAffinityTermLabelSelector }} + - podAffinityTerm: + labelSelector: + matchExpressions: + - key: {{ $item.key }} + operator: {{ $item.operator }} + {{- if $item.values }} + values: + {{- $vals := split "," $item.values }} + {{- range $i, $v := $vals }} + - {{ $v | quote }} + {{- end }} + {{- end }} + topologyKey: {{ $item.topologyKey }} + weight: 100 + {{- end }} +{{- end }} diff --git a/istio-1.5.0/install/kubernetes/operator/charts/istio-policy/templates/_helpers.tpl b/istio-1.5.0/install/kubernetes/operator/charts/istio-policy/templates/_helpers.tpl new file mode 100644 index 0000000..236e347 --- /dev/null +++ b/istio-1.5.0/install/kubernetes/operator/charts/istio-policy/templates/_helpers.tpl @@ -0,0 +1,32 @@ +{{/* vim: set filetype=mustache: */}} +{{/* +Expand the name of the chart. +*/}} +{{- define "mixer.name" -}} +{{- default .Chart.Name .Values.mixer.policy.nameOverride | trunc 63 | trimSuffix "-" -}} +{{- end -}} + +{{/* +Create a default fully qualified app name. +We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). +If release name contains chart name it will be used as a full name. +*/}} +{{- define "mixer.fullname" -}} +{{- if .Values.mixer.policy.fullnameOverride -}} +{{- .Values.mixer.policy.fullnameOverride | trunc 63 | trimSuffix "-" -}} +{{- else -}} +{{- $name := default .Chart.Name .Values.mixer.policy.nameOverride -}} +{{- if contains $name .Release.Name -}} +{{- .Release.Name | trunc 63 | trimSuffix "-" -}} +{{- else -}} +{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" -}} +{{- end -}} +{{- end -}} +{{- end -}} + +{{/* +Create chart name and version as used by the chart label. +*/}} +{{- define "mixer.chart" -}} +{{- .Chart.Name | trunc 63 | trimSuffix "-" -}} +{{- end -}} diff --git a/istio-1.5.0/install/kubernetes/operator/charts/istio-policy/templates/autoscale.yaml b/istio-1.5.0/install/kubernetes/operator/charts/istio-policy/templates/autoscale.yaml new file mode 100644 index 0000000..00f7422 --- /dev/null +++ b/istio-1.5.0/install/kubernetes/operator/charts/istio-policy/templates/autoscale.yaml @@ -0,0 +1,23 @@ +{{- if and .Values.mixer.policy.autoscaleEnabled .Values.mixer.policy.autoscaleMin .Values.mixer.policy.autoscaleMax }} +apiVersion: autoscaling/v2beta1 +kind: HorizontalPodAutoscaler +metadata: + name: istio-policy + namespace: {{ .Release.Namespace }} + labels: + app: mixer + release: {{ .Release.Name }} +spec: + maxReplicas: {{ .Values.mixer.policy.autoscaleMax }} + minReplicas: {{ .Values.mixer.policy.autoscaleMin }} + scaleTargetRef: + apiVersion: apps/v1 + kind: Deployment + name: istio-policy + metrics: + - type: Resource + resource: + name: cpu + targetAverageUtilization: {{ .Values.mixer.policy.cpu.targetAverageUtilization }} +--- +{{- end }} diff --git a/istio-1.5.0/install/kubernetes/operator/charts/istio-policy/templates/clusterrole.yaml b/istio-1.5.0/install/kubernetes/operator/charts/istio-policy/templates/clusterrole.yaml new file mode 100644 index 0000000..b04cf13 --- /dev/null +++ b/istio-1.5.0/install/kubernetes/operator/charts/istio-policy/templates/clusterrole.yaml @@ -0,0 +1,21 @@ +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: istio-policy + labels: + release: {{ .Release.Name }} + app: istio-policy +rules: +- apiGroups: ["config.istio.io"] # istio CRD watcher + resources: ["*"] + verbs: ["create", "get", "list", "watch", "patch"] +- apiGroups: ["apiextensions.k8s.io"] + resources: ["customresourcedefinitions"] + verbs: ["get", "list", "watch"] +- apiGroups: [""] + resources: ["configmaps", "endpoints", "pods", "services", "namespaces", "secrets", "replicationcontrollers"] + verbs: ["get", "list", "watch"] +- apiGroups: ["extensions", "apps"] + resources: ["replicasets"] + verbs: ["get", "list", "watch"] +--- diff --git a/istio-1.5.0/install/kubernetes/operator/charts/istio-policy/templates/clusterrolebinding.yaml b/istio-1.5.0/install/kubernetes/operator/charts/istio-policy/templates/clusterrolebinding.yaml new file mode 100644 index 0000000..6683425 --- /dev/null +++ b/istio-1.5.0/install/kubernetes/operator/charts/istio-policy/templates/clusterrolebinding.yaml @@ -0,0 +1,16 @@ +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: istio-policy-admin-role-binding-{{ .Release.Namespace }} + labels: + app: istio-policy + release: {{ .Release.Name }} +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: istio-policy +subjects: + - kind: ServiceAccount + name: istio-policy-service-account + namespace: {{ .Release.Namespace }} +--- diff --git a/istio-1.5.0/install/kubernetes/operator/charts/istio-policy/templates/config.yaml b/istio-1.5.0/install/kubernetes/operator/charts/istio-policy/templates/config.yaml new file mode 100644 index 0000000..c9f970e --- /dev/null +++ b/istio-1.5.0/install/kubernetes/operator/charts/istio-policy/templates/config.yaml @@ -0,0 +1,330 @@ +{{ if not (eq .Release.Namespace "istio-system") }} +apiVersion: "config.istio.io/v1alpha2" +kind: attributemanifest +metadata: + name: istioproxy + namespace: {{ .Release.Namespace }} + labels: + app: istio-policy + release: {{ .Release.Name }} +spec: + attributes: + origin.ip: + valueType: IP_ADDRESS + origin.uid: + valueType: STRING + origin.user: + valueType: STRING + request.headers: + valueType: STRING_MAP + request.id: + valueType: STRING + request.host: + valueType: STRING + request.method: + valueType: STRING + request.path: + valueType: STRING + request.url_path: + valueType: STRING + request.query_params: + valueType: STRING_MAP + request.reason: + valueType: STRING + request.referer: + valueType: STRING + request.scheme: + valueType: STRING + request.total_size: + valueType: INT64 + request.size: + valueType: INT64 + request.time: + valueType: TIMESTAMP + request.useragent: + valueType: STRING + response.code: + valueType: INT64 + response.duration: + valueType: DURATION + response.headers: + valueType: STRING_MAP + response.total_size: + valueType: INT64 + response.size: + valueType: INT64 + response.time: + valueType: TIMESTAMP + response.grpc_status: + valueType: STRING + response.grpc_message: + valueType: STRING + source.uid: + valueType: STRING + source.user: # DEPRECATED + valueType: STRING + source.principal: + valueType: STRING + destination.uid: + valueType: STRING + destination.principal: + valueType: STRING + destination.port: + valueType: INT64 + connection.event: + valueType: STRING + connection.id: + valueType: STRING + connection.received.bytes: + valueType: INT64 + connection.received.bytes_total: + valueType: INT64 + connection.sent.bytes: + valueType: INT64 + connection.sent.bytes_total: + valueType: INT64 + connection.duration: + valueType: DURATION + connection.mtls: + valueType: BOOL + connection.requested_server_name: + valueType: STRING + context.protocol: + valueType: STRING + context.proxy_error_code: + valueType: STRING + context.timestamp: + valueType: TIMESTAMP + context.time: + valueType: TIMESTAMP + # Deprecated, kept for compatibility + context.reporter.local: + valueType: BOOL + context.reporter.kind: + valueType: STRING + context.reporter.uid: + valueType: STRING + context.proxy_version: + valueType: STRING + api.service: + valueType: STRING + api.version: + valueType: STRING + api.operation: + valueType: STRING + api.protocol: + valueType: STRING + request.auth.principal: + valueType: STRING + request.auth.audiences: + valueType: STRING + request.auth.presenter: + valueType: STRING + request.auth.claims: + valueType: STRING_MAP + request.auth.raw_claims: + valueType: STRING + request.api_key: + valueType: STRING + rbac.permissive.response_code: + valueType: STRING + rbac.permissive.effective_policy_id: + valueType: STRING + check.error_code: + valueType: INT64 + check.error_message: + valueType: STRING + check.cache_hit: + valueType: BOOL + quota.cache_hit: + valueType: BOOL + +--- +apiVersion: "config.istio.io/v1alpha2" +kind: attributemanifest +metadata: + name: kubernetes + namespace: {{ .Release.Namespace }} + labels: + app: istio-policy + release: {{ .Release.Name }} +spec: + attributes: + source.ip: + valueType: IP_ADDRESS + source.labels: + valueType: STRING_MAP + source.metadata: + valueType: STRING_MAP + source.name: + valueType: STRING + source.namespace: + valueType: STRING + source.owner: + valueType: STRING + source.serviceAccount: + valueType: STRING + source.services: + valueType: STRING + source.workload.uid: + valueType: STRING + source.workload.name: + valueType: STRING + source.workload.namespace: + valueType: STRING + destination.ip: + valueType: IP_ADDRESS + destination.labels: + valueType: STRING_MAP + destination.metadata: + valueType: STRING_MAP + destination.owner: + valueType: STRING + destination.name: + valueType: STRING + destination.container.name: + valueType: STRING + destination.namespace: + valueType: STRING + destination.service.uid: + valueType: STRING + destination.service.name: + valueType: STRING + destination.service.namespace: + valueType: STRING + destination.service.host: + valueType: STRING + destination.serviceAccount: + valueType: STRING + destination.workload.uid: + valueType: STRING + destination.workload.name: + valueType: STRING + destination.workload.namespace: + valueType: STRING +--- +{{- if .Values.mixer.policy.adapters.kubernetesenv.enabled }} +apiVersion: "config.istio.io/v1alpha2" +kind: handler +metadata: + name: kubernetesenv + namespace: {{ .Release.Namespace }} + labels: + app: istio-policy + release: {{ .Release.Name }} +spec: + compiledAdapter: kubernetesenv + params: + # when running from mixer root, use the following config after adding a + # symbolic link to a kubernetes config file via: + # + # $ ln -s ~/.kube/config mixer/adapter/kubernetes/kubeconfig + # + # kubeconfig_path: "mixer/adapter/kubernetes/kubeconfig" + +--- +apiVersion: "config.istio.io/v1alpha2" +kind: rule +metadata: + name: kubeattrgenrulerule + namespace: {{ .Release.Namespace }} + labels: + app: istio-policy + release: {{ .Release.Name }} +spec: + actions: + - handler: kubernetesenv + instances: + - attributes +--- +apiVersion: "config.istio.io/v1alpha2" +kind: rule +metadata: + name: tcpkubeattrgenrulerule + namespace: {{ .Release.Namespace }} + labels: + app: istio-policy + release: {{ .Release.Name }} +spec: + match: context.protocol == "tcp" + actions: + - handler: kubernetesenv + instances: + - attributes +--- +apiVersion: "config.istio.io/v1alpha2" +kind: instance +metadata: + name: attributes + namespace: {{ .Release.Namespace }} + labels: + app: istio-policy + release: {{ .Release.Name }} +spec: + compiledTemplate: kubernetes + params: + # Pass the required attribute data to the adapter + source_uid: source.uid | "" + source_ip: source.ip | ip("0.0.0.0") # default to unspecified ip addr + destination_uid: destination.uid | "" + destination_port: destination.port | 0 + attributeBindings: + # Fill the new attributes from the adapter produced output. + # $out refers to an instance of OutputTemplate message + source.ip: $out.source_pod_ip | ip("0.0.0.0") + source.uid: $out.source_pod_uid | "unknown" + source.labels: $out.source_labels | emptyStringMap() + source.name: $out.source_pod_name | "unknown" + source.namespace: $out.source_namespace | "default" + source.owner: $out.source_owner | "unknown" + source.serviceAccount: $out.source_service_account_name | "unknown" + source.workload.uid: $out.source_workload_uid | "unknown" + source.workload.name: $out.source_workload_name | "unknown" + source.workload.namespace: $out.source_workload_namespace | "unknown" + destination.ip: $out.destination_pod_ip | ip("0.0.0.0") + destination.uid: $out.destination_pod_uid | "unknown" + destination.labels: $out.destination_labels | emptyStringMap() + destination.name: $out.destination_pod_name | "unknown" + destination.container.name: $out.destination_container_name | "unknown" + destination.namespace: $out.destination_namespace | "default" + destination.owner: $out.destination_owner | "unknown" + destination.serviceAccount: $out.destination_service_account_name | "unknown" + destination.workload.uid: $out.destination_workload_uid | "unknown" + destination.workload.name: $out.destination_workload_name | "unknown" + destination.workload.namespace: $out.destination_workload_namespace | "unknown" +{{- end }} +{{- end }} + +--- +# Configuration needed by Mixer. +# Mixer cluster is delivered via CDS +# Specify mixer cluster settings +apiVersion: networking.istio.io/v1alpha3 +kind: DestinationRule +metadata: + name: istio-policy + namespace: {{ .Release.Namespace }} + labels: + app: istio-policy + release: {{ .Release.Name }} +spec: + host: istio-policy.{{ .Release.Namespace }}.svc.{{ .Values.global.proxy.clusterDomain }} + {{- if .Values.global.defaultConfigVisibilitySettings }} + exportTo: + - '*' + {{- end }} + trafficPolicy: + portLevelSettings: + - port: + number: 15004 # grpc-mixer-mtls + tls: + mode: ISTIO_MUTUAL + - port: + number: 9091 # grpc-mixer + tls: + mode: DISABLE + connectionPool: + http: + http2MaxRequests: 10000 + maxRequestsPerConnection: 10000 +--- diff --git a/istio-1.5.0/install/kubernetes/operator/charts/istio-policy/templates/deployment.yaml b/istio-1.5.0/install/kubernetes/operator/charts/istio-policy/templates/deployment.yaml new file mode 100644 index 0000000..9ebb383 --- /dev/null +++ b/istio-1.5.0/install/kubernetes/operator/charts/istio-policy/templates/deployment.yaml @@ -0,0 +1,215 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: istio-policy + namespace: {{ .Release.Namespace }} + labels: + app: istio-policy + istio: mixer + release: {{ .Release.Name }} +spec: +{{- if not .Values.mixer.policy.autoscaleEnabled }} +{{- if .Values.mixer.policy.replicaCount }} + replicas: {{ .Values.mixer.policy.replicaCount }} +{{- end }} +{{- end }} + strategy: + rollingUpdate: + maxSurge: {{ .Values.mixer.policy.rollingMaxSurge }} + maxUnavailable: {{ .Values.mixer.policy.rollingMaxUnavailable }} + selector: + matchLabels: + istio: mixer + istio-mixer-type: policy + template: + metadata: + labels: + app: policy + istio: mixer + istio-mixer-type: policy + annotations: + sidecar.istio.io/inject: "false" +{{- with .Values.mixer.policy.podAnnotations }} +{{ toYaml . | indent 8 }} +{{- end }} + spec: + serviceAccountName: istio-policy-service-account +{{- if .Values.global.priorityClassName }} + priorityClassName: "{{ .Values.global.priorityClassName }}" +{{- end }} + securityContext: + fsGroup: 1337 + volumes: + - name: istio-certs + secret: + secretName: istio.istio-policy-service-account + optional: true + - name: uds-socket + emptyDir: {} + - name: policy-adapter-secret + secret: + secretName: policy-adapter-secret + optional: true + affinity: + {{- include "nodeaffinity" . | indent 6 }} + {{- include "podAntiAffinity" . | indent 6 }} +{{- if .Values.mixer.policy.tolerations }} + tolerations: +{{ toYaml .Values.mixer.policy.tolerations | indent 6 }} +{{- else if .Values.global.defaultTolerations }} + tolerations: +{{ toYaml .Values.global.defaultTolerations | indent 6 }} +{{- end }} + containers: + - name: mixer +{{- if contains "/" .Values.mixer.policy.image }} + image: "{{ .Values.mixer.policy.image }}" +{{- else }} + image: "{{ .Values.mixer.policy.hub | default .Values.global.hub }}/{{ .Values.mixer.policy.image }}:{{ .Values.mixer.policy.tag | default .Values.global.tag }}" +{{- end }} + imagePullPolicy: {{ .Values.global.imagePullPolicy | default "Always" }} + ports: + - containerPort: 9091 + - containerPort: 15014 + - containerPort: 42422 + args: + - --monitoringPort=15014 + - --address +{{- if .Values.global.controlPlaneSecurityEnabled }} + - unix:///sock/mixer.socket +{{- else }} + - tcp://0.0.0.0:9091 +{{- end }} +{{- if .Values.global.logging.level }} + - --log_output_level={{ .Values.global.logging.level }} +{{- end}} +{{- if .Values.global.logAsJson }} + - --log_as_json +{{- end }} +{{- if .Values.global.useMCP }} + {{- if .Values.global.controlPlaneSecurityEnabled}} + - --configStoreURL=mcps://istio-galley.{{ .Values.global.configNamespace }}.svc:15019 + {{- else }} + - --configStoreURL=mcp://istio-galley.{{ .Values.global.configNamespace }}.svc:9901 + {{- end }} +{{- else }} + - --configStoreURL=k8s:// +{{- end }} + - --configDefaultNamespace={{ .Values.global.configNamespace }} + {{- if .Values.mixer.policy.adapters.useAdapterCRDs }} + - --useAdapterCRDs=true + {{- else }} + - --useAdapterCRDs=false + {{- end }} + - --useTemplateCRDs=false + {{- if .Values.global.tracer.zipkin.address }} + - --trace_zipkin_url=http://{{- .Values.global.tracer.zipkin.address }}/api/v1/spans + {{- else }} + - --trace_zipkin_url=http://zipkin.{{ .Values.global.telemetryNamespace }}:9411/api/v1/spans + {{- end }} + env: + - name: POD_NAMESPACE + valueFrom: + fieldRef: + apiVersion: v1 + fieldPath: metadata.namespace + {{- if .Values.mixer.policy.env }} + {{- range $key, $val := .Values.mixer.policy.env }} + - name: {{ $key }} + value: "{{ $val }}" + {{- end }} + {{- end }} + resources: +{{- if .Values.mixer.policy.resources }} +{{ toYaml .Values.mixer.policy.resources | indent 10 }} +{{- else }} +{{ toYaml .Values.global.defaultResources | indent 10 }} +{{- end }} + securityContext: + runAsUser: 1337 + runAsGroup: 1337 + runAsNonRoot: true + capabilities: + drop: + - ALL + volumeMounts: +{{- if .Values.global.useMCP }} + - name: istio-certs + mountPath: /etc/certs + readOnly: true +{{- end }} + - name: uds-socket + mountPath: /sock + - name: policy-adapter-secret + mountPath: /var/run/secrets/istio.io/policy/adapter + readOnly: true + livenessProbe: + httpGet: + path: /version + port: 15014 + initialDelaySeconds: 5 + periodSeconds: 5 +{{- if .Values.global.controlPlaneSecurityEnabled }} + - name: istio-proxy +{{- if contains "/" .Values.global.proxy.image }} + image: "{{ .Values.global.proxy.image }}" +{{- else }} + image: "{{ .Values.global.hub }}/{{ .Values.global.proxy.image }}:{{ .Values.global.tag }}" +{{- end }} + imagePullPolicy: {{ .Values.global.imagePullPolicy | default "Always" }} + ports: + - containerPort: 15004 + - containerPort: 15090 + protocol: TCP + name: http-envoy-prom + args: + - proxy + - --domain + - $(POD_NAMESPACE).svc.{{ .Values.global.proxy.clusterDomain }} + - --serviceCluster + - istio-policy + - --templateFile + - /etc/istio/proxy/envoy_policy.yaml.tmpl + {{- if .Values.global.controlPlaneSecurityEnabled }} + - --controlPlaneAuthPolicy + - MUTUAL_TLS + {{- else }} + - --controlPlaneAuthPolicy + - NONE + {{- end }} + {{- if .Values.global.trustDomain }} + - --trust-domain={{ .Values.global.trustDomain }} + {{- end }} + {{- if .Values.global.logAsJson }} + - --log_as_json + {{- end }} + env: + - name: POD_NAME + valueFrom: + fieldRef: + apiVersion: v1 + fieldPath: metadata.name + - name: POD_NAMESPACE + valueFrom: + fieldRef: + apiVersion: v1 + fieldPath: metadata.namespace + - name: INSTANCE_IP + valueFrom: + fieldRef: + apiVersion: v1 + fieldPath: status.podIP + resources: +{{- if .Values.global.proxy.resources }} +{{ toYaml .Values.global.proxy.resources | indent 10 }} +{{- else }} +{{ toYaml .Values.global.defaultResources | indent 10 }} +{{- end }} + volumeMounts: + - name: istio-certs + mountPath: /etc/certs + readOnly: true + - name: uds-socket + mountPath: /sock +{{- end }} +--- diff --git a/istio-1.5.0/install/kubernetes/operator/charts/istio-policy/templates/poddisruptionbudget.yaml b/istio-1.5.0/install/kubernetes/operator/charts/istio-policy/templates/poddisruptionbudget.yaml new file mode 100644 index 0000000..cc6a3d7 --- /dev/null +++ b/istio-1.5.0/install/kubernetes/operator/charts/istio-policy/templates/poddisruptionbudget.yaml @@ -0,0 +1,21 @@ +{{- if .Values.global.defaultPodDisruptionBudget.enabled }} +apiVersion: policy/v1beta1 +kind: PodDisruptionBudget +metadata: + name: istio-policy + namespace: {{ .Release.Namespace }} + labels: + app: policy + release: {{ .Release.Name }} + istio: mixer + istio-mixer-type: policy +spec: + minAvailable: 1 + selector: + matchLabels: + app: policy + istio: mixer + istio-mixer-type: policy +--- + +{{- end }} diff --git a/istio-1.5.0/install/kubernetes/operator/charts/istio-policy/templates/service.yaml b/istio-1.5.0/install/kubernetes/operator/charts/istio-policy/templates/service.yaml new file mode 100644 index 0000000..70f664d --- /dev/null +++ b/istio-1.5.0/install/kubernetes/operator/charts/istio-policy/templates/service.yaml @@ -0,0 +1,25 @@ +apiVersion: v1 +kind: Service +metadata: + name: istio-policy + namespace: {{ .Release.Namespace }} + labels: + app: mixer + istio: mixer + release: {{ .Release.Name }} +spec: + ports: + - name: grpc-mixer + port: 9091 + - name: grpc-mixer-mtls + port: 15004 + - name: http-policy-monitoring + port: 15014 + selector: + istio: mixer + istio-mixer-type: policy +{{- if .Values.mixer.policy.sessionAffinityEnabled }} + sessionAffinity: ClientIP +{{- end }} +--- + diff --git a/istio-1.5.0/install/kubernetes/operator/charts/istio-policy/templates/serviceaccount.yaml b/istio-1.5.0/install/kubernetes/operator/charts/istio-policy/templates/serviceaccount.yaml new file mode 100644 index 0000000..988aba8 --- /dev/null +++ b/istio-1.5.0/install/kubernetes/operator/charts/istio-policy/templates/serviceaccount.yaml @@ -0,0 +1,15 @@ +apiVersion: v1 +kind: ServiceAccount +{{- if .Values.global.imagePullSecrets }} +imagePullSecrets: +{{- range .Values.global.imagePullSecrets }} + - name: {{ . }} +{{- end }} +{{- end }} +metadata: + name: istio-policy-service-account + namespace: {{ .Release.Namespace }} + labels: + app: istio-policy + release: {{ .Release.Name }} +--- diff --git a/istio-1.5.0/install/kubernetes/operator/charts/istio-policy/values.yaml b/istio-1.5.0/install/kubernetes/operator/charts/istio-policy/values.yaml new file mode 100644 index 0000000..4826889 --- /dev/null +++ b/istio-1.5.0/install/kubernetes/operator/charts/istio-policy/values.yaml @@ -0,0 +1,47 @@ +mixer: + policy: + hub: "" + tag: "" + image: mixer + + replicaCount: 1 + rollingMaxSurge: 100% + rollingMaxUnavailable: 25% + autoscaleEnabled: true + autoscaleMin: 1 + autoscaleMax: 5 + cpu: + targetAverageUtilization: 80 + sessionAffinityEnabled: false + podAnnotations: {} + + env: {} + + adapters: + useAdapterCRDs: false + kubernetesenv: + enabled: true + resources: {} + nodeSelector: {} + tolerations: [] + + # Specify the pod anti-affinity that allows you to constrain which nodes + # your pod is eligible to be scheduled based on labels on pods that are + # already running on the node rather than based on labels on nodes. + # There are currently two types of anti-affinity: + # "requiredDuringSchedulingIgnoredDuringExecution" + # "preferredDuringSchedulingIgnoredDuringExecution" + # which denote "hard" vs. "soft" requirements, you can define your values + # in "podAntiAffinityLabelSelector" and "podAntiAffinityTermLabelSelector" + # correspondingly. + # For example: + # podAntiAffinityLabelSelector: + # - key: security + # operator: In + # values: S1,S2 + # topologyKey: "kubernetes.io/hostname" + # This pod anti-affinity rule says that the pod requires not to be scheduled + # onto a node if that node is already running a pod with label having key + # "security" and value "S1". + podAntiAffinityLabelSelector: [] + podAntiAffinityTermLabelSelector: [] diff --git a/istio-1.5.0/install/kubernetes/operator/charts/istio-telemetry/grafana/Chart.yaml b/istio-1.5.0/install/kubernetes/operator/charts/istio-telemetry/grafana/Chart.yaml new file mode 100644 index 0000000..8ed3469 --- /dev/null +++ b/istio-1.5.0/install/kubernetes/operator/charts/istio-telemetry/grafana/Chart.yaml @@ -0,0 +1,6 @@ +apiVersion: v1 +description: A Helm chart for Kubernetes +name: grafana +version: 1.1.0 +appVersion: 1.1.0 +tillerVersion: ">=2.7.2" diff --git a/istio-1.5.0/install/kubernetes/operator/charts/istio-telemetry/grafana/dashboards/citadel-dashboard.json b/istio-1.5.0/install/kubernetes/operator/charts/istio-telemetry/grafana/dashboards/citadel-dashboard.json new file mode 100644 index 0000000..7cb8e5b --- /dev/null +++ b/istio-1.5.0/install/kubernetes/operator/charts/istio-telemetry/grafana/dashboards/citadel-dashboard.json @@ -0,0 +1,1089 @@ +{ + "annotations": { + "list": [ + { + "builtIn": 1, + "datasource": "-- Grafana --", + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations & Alerts", + "type": "dashboard" + } + ] + }, + "description": "", + "editable": true, + "gnetId": null, + "graphTooltip": 0, + "links": [], + "panels": [ + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 0 + }, + "id": 8, + "panels": [], + "title": "Performance", + "type": "row" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "description": "CPU usage across Citadel instances.", + "fill": 1, + "gridPos": { + "h": 6, + "w": 8, + "x": 0, + "y": 1 + }, + "id": 10, + "legend": { + "alignAsTable": false, + "avg": false, + "current": false, + "max": false, + "min": false, + "rightSide": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(rate(container_cpu_usage_seconds_total{job=\"kubernetes-cadvisor\",container=~\"citadel\", pod=~\"istio-citadel-.*\"}[1m]))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Citadel CPU usage rate", + "refId": "A" + }, + { + "expr": "irate(process_cpu_seconds_total{job=\"citadel\"}[1m])", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Citadel CPU usage irate", + "refId": "C" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "CPU", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": "", + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "description": "Citadel process memory statistics.", + "fill": 1, + "gridPos": { + "h": 6, + "w": 8, + "x": 8, + "y": 1 + }, + "id": 12, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "process_virtual_memory_bytes{job=\"citadel\"}", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Virtual Memory", + "refId": "A" + }, + { + "expr": "process_resident_memory_bytes{job=\"citadel\"}", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Resident Memory", + "refId": "B" + }, + { + "expr": "go_memstats_heap_sys_bytes{job=\"citadel\"}", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Heap Memory Total", + "refId": "C" + }, + { + "expr": "go_memstats_alloc_bytes{job=\"citadel\"}", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Heap Memory Allocated", + "refId": "E" + }, + { + "expr": "go_memstats_heap_inuse_bytes{job=\"citadel\"}", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Heap Inuse", + "refId": "F" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Memory", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "fill": 1, + "gridPos": { + "h": 6, + "w": 8, + "x": 16, + "y": 1 + }, + "id": 14, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "go_goroutines{job=\"citadel\"}", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Goroutines", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Goroutines", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 7 + }, + "id": 28, + "panels": [], + "title": "General", + "type": "row" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "description": "Total number of CSR requests made to Citadel.", + "fill": 1, + "gridPos": { + "h": 5, + "w": 12, + "x": 0, + "y": 8 + }, + "id": 30, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "citadel_server_csr_count{job=\"citadel\"}", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "CSR Request Count", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "CSR Requests", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "description": "The number of certificates issuances that have succeeded.", + "fill": 1, + "gridPos": { + "h": 5, + "w": 12, + "x": 12, + "y": 8 + }, + "id": 32, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "citadel_server_success_cert_issuance_count{job=\"citadel\"}", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Certificates Issued", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Certificates Issued", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 13 + }, + "id": 23, + "panels": [], + "title": "Errors", + "type": "row" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "description": "The number of errors occurred when creating the CSR.", + "fill": 1, + "gridPos": { + "h": 5, + "w": 8, + "x": 0, + "y": 14 + }, + "id": 20, + "legend": { + "alignAsTable": false, + "avg": false, + "current": false, + "max": false, + "min": false, + "rightSide": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "citadel_secret_controller_csr_err_count{job=\"citadel\"}", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "CSR Creation Error Count", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "CSR Creation Errors", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": "", + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "fill": 1, + "gridPos": { + "h": 5, + "w": 8, + "x": 8, + "y": 14 + }, + "id": 24, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "citadel_server_csr_parsing_err_count{job=\"citadel\"}", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "CSR Parse Error Count", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "CSR Parse Errors", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "description": "The number of authentication failures.", + "fill": 1, + "gridPos": { + "h": 5, + "w": 8, + "x": 16, + "y": 14 + }, + "id": 26, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "citadel_server_authentication_failure_count{job=\"citadel\"}", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Authentication Failure Count", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Authentication Failures", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 19 + }, + "id": 4, + "panels": [], + "title": "Secret Controller", + "type": "row" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "description": "The number of certificates created due to service account creation.", + "fill": 1, + "gridPos": { + "h": 5, + "w": 8, + "x": 0, + "y": 20 + }, + "id": 2, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": true, + "targets": [ + { + "expr": "citadel_secret_controller_svc_acc_created_cert_count{job=\"citadel\"}", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "SA Secrets Created", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Service Account Secrets Created (due to SA creation)", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "decimals": null, + "format": "short", + "label": "Certs Created", + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "description": "The number of certificates deleted due to service account deletion.", + "fill": 1, + "gridPos": { + "h": 5, + "w": 8, + "x": 8, + "y": 20 + }, + "id": 16, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": true, + "targets": [ + { + "expr": "citadel_secret_controller_svc_acc_deleted_cert_count{job=\"citadel\"}", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "SA Secrets Deleted", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Service Account Secrets Deleted (due to SA deletion)", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "decimals": null, + "format": "short", + "label": "Certs Created", + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "description": "The number of certificates recreated due to secret deletion (service account still exists).", + "fill": 1, + "gridPos": { + "h": 5, + "w": 8, + "x": 16, + "y": 20 + }, + "id": 6, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": true, + "targets": [ + { + "expr": "citadel_secret_controller_secret_deleted_cert_count{job=\"citadel\"}", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "SA Secrets Recreated", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Service Account Secrets Recreated (due to errant deletion)", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "decimals": null, + "format": "short", + "label": "Certs Created", + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + } + ], + "refresh": "5s", + "schemaVersion": 18, + "style": "dark", + "tags": [], + "templating": { + "list": [] + }, + "time": { + "from": "now-5m", + "to": "now" + }, + "timepicker": { + "refresh_intervals": [ + "5s", + "10s", + "30s", + "1m", + "5m", + "15m", + "30m", + "1h", + "2h", + "1d" + ], + "time_options": [ + "5m", + "15m", + "1h", + "6h", + "12h", + "24h", + "2d", + "7d", + "30d" + ] + }, + "timezone": "", + "title": "Istio Citadel Dashboard", + "uid": "OOyOqb4Wz", + "version": 1 +} \ No newline at end of file diff --git a/istio-1.5.0/install/kubernetes/operator/charts/istio-telemetry/grafana/dashboards/galley-dashboard.json b/istio-1.5.0/install/kubernetes/operator/charts/istio-telemetry/grafana/dashboards/galley-dashboard.json new file mode 100644 index 0000000..0a1d809 --- /dev/null +++ b/istio-1.5.0/install/kubernetes/operator/charts/istio-telemetry/grafana/dashboards/galley-dashboard.json @@ -0,0 +1,1734 @@ +{ + "__inputs": [ + { + "name": "DS_PROMETHEUS", + "label": "Prometheus", + "description": "", + "type": "datasource", + "pluginId": "prometheus", + "pluginName": "Prometheus" + } + ], + "annotations": { + "list": [ + { + "builtIn": 1, + "datasource": "-- Grafana --", + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations & Alerts", + "type": "dashboard" + } + ] + }, + "editable": false, + "gnetId": null, + "graphTooltip": 0, + "links": [], + "panels": [ + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 5, + "w": 24, + "x": 0, + "y": 0 + }, + "id": 46, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(istio_build{component=\"galley\"}) by (tag)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{ tag }}", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Galley Versions", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 5 + }, + "id": 40, + "panels": [], + "title": "Resource Usage", + "type": "row" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 8, + "w": 6, + "x": 0, + "y": 6 + }, + "id": 36, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "process_virtual_memory_bytes{job=\"galley\"}", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "Virtual Memory", + "refId": "A" + }, + { + "expr": "process_resident_memory_bytes{job=\"galley\"}", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "Resident Memory", + "refId": "B" + }, + { + "expr": "go_memstats_heap_sys_bytes{job=\"galley\"}", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "heap sys", + "refId": "C" + }, + { + "expr": "go_memstats_heap_alloc_bytes{job=\"galley\"}", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "heap alloc", + "refId": "D" + }, + { + "expr": "go_memstats_alloc_bytes{job=\"galley\"}", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "Alloc", + "refId": "F" + }, + { + "expr": "go_memstats_heap_inuse_bytes{job=\"galley\"}", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "Heap in-use", + "refId": "G" + }, + { + "expr": "go_memstats_stack_inuse_bytes{job=\"galley\"}", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "Stack in-use", + "refId": "H" + }, + { + "expr": "sum(container_memory_usage_bytes{job=\"kubernetes-cadvisor\",container=~\"galley\", pod=~\"istio-galley-.*\"})", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Total (kis)", + "refId": "E" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Memory", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 8, + "w": 6, + "x": 6, + "y": 6 + }, + "id": 38, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(rate(container_cpu_usage_seconds_total{job=\"kubernetes-cadvisor\",container=~\"galley\", pod=~\"istio-galley-.*\"}[1m]))", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "Total (k8s)", + "refId": "A" + }, + { + "expr": "sum(rate(container_cpu_usage_seconds_total{job=\"kubernetes-cadvisor\",container=~\"galley\", pod=~\"istio-galley-.*\"}[1m])) by (container)", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "{{ container }} (k8s)", + "refId": "B" + }, + { + "expr": "irate(process_cpu_seconds_total{job=\"galley\"}[1m])", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "galley (self-reported)", + "refId": "C" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "CPU", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 8, + "w": 6, + "x": 12, + "y": 6 + }, + "id": 42, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "process_open_fds{job=\"galley\"}", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "Open FDs (galley)", + "refId": "A" + }, + { + "expr": "container_fs_usage_bytes{job=\"kubernetes-cadvisor\",container=~\"galley\", pod=~\"istio-galley-.*\"}", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "{{ container }} ", + "refId": "B" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Disk", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 8, + "w": 6, + "x": 18, + "y": 6 + }, + "id": 44, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "go_goroutines{job=\"galley\"}", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "goroutines_total", + "refId": "A" + }, + { + "expr": "istio_mcp_clients_total{component=\"galley\"}", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "clients_total", + "refId": "B" + }, + { + "expr": "go_goroutines{job=\"galley\"}/sum(istio_mcp_clients_total{component=\"galley\"}) without (component)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "avg_goroutines_per_client", + "refId": "C" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Goroutines", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 14 + }, + "id": 10, + "panels": [], + "title": "Runtime", + "type": "row" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 6, + "w": 8, + "x": 0, + "y": 15 + }, + "id": 2, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(rate(galley_runtime_strategy_on_change_total[1m])) * 60", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Strategy Change Events", + "refId": "A" + }, + { + "expr": "sum(rate(galley_runtime_processor_events_processed_total[1m])) * 60", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Processed Events", + "refId": "B" + }, + { + "expr": "sum(rate(galley_runtime_processor_snapshots_published_total[1m])) * 60", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Snapshot Published", + "refId": "C" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Event Rates", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": "Events/min", + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": "", + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 6, + "w": 8, + "x": 8, + "y": 15 + }, + "id": 4, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(rate(galley_runtime_strategy_timer_max_time_reached_total[1m])) * 60", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Max Time Reached", + "refId": "A" + }, + { + "expr": "sum(rate(galley_runtime_strategy_timer_quiesce_reached_total[1m])) * 60", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Quiesce Reached", + "refId": "B" + }, + { + "expr": "sum(rate(galley_runtime_strategy_timer_resets_total[1m])) * 60", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Timer Resets", + "refId": "C" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Timer Rates", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": "Events/min", + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 6, + "w": 8, + "x": 16, + "y": 15 + }, + "id": 8, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 3, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": true, + "steppedLine": false, + "targets": [ + { + "expr": "histogram_quantile(0.50, sum by (le) (galley_runtime_processor_snapshot_events_total_bucket))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "P50", + "refId": "A" + }, + { + "expr": "histogram_quantile(0.90, sum by (le) (galley_runtime_processor_snapshot_events_total_bucket))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "P90", + "refId": "B" + }, + { + "expr": "histogram_quantile(0.95, sum by (le) (galley_runtime_processor_snapshot_events_total_bucket))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "P95", + "refId": "C" + }, + { + "expr": "histogram_quantile(0.99, sum by (le) (galley_runtime_processor_snapshot_events_total_bucket))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "P99", + "refId": "D" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Events Per Snapshot", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 6, + "w": 8, + "x": 8, + "y": 21 + }, + "id": 6, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum by (collection) (galley_runtime_state_type_instances_total)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{ collection }}", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "State Type Instances", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": "Count", + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 27 + }, + "id": 34, + "panels": [], + "title": "Validation", + "type": "row" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 6, + "w": 8, + "x": 0, + "y": 28 + }, + "id": 28, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "galley_validation_cert_key_updates{}", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Key Updates", + "refId": "A" + }, + { + "expr": "galley_validation_cert_key_update_errors{}", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Key Update Errors: {{ error }}", + "refId": "B" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Validation Webhook Certificate", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 6, + "w": 8, + "x": 8, + "y": 28 + }, + "id": 30, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(galley_validation_passed{}) by (group, version, resource)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Passed: {{ group }}/{{ version }}/{{resource}}", + "refId": "A" + }, + { + "expr": "sum(galley_validation_failed{}) by (group, version, resource, reason)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Failed: {{ group }}/{{ version }}/{{resource}} ({{ reason}})", + "refId": "B" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Resource Validation", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 6, + "w": 8, + "x": 16, + "y": 28 + }, + "id": 32, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(galley_validation_http_error{}) by (status)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{ status }}", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Validation HTTP Errors", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 34 + }, + "id": 12, + "panels": [], + "title": "Kubernetes Source", + "type": "row" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 6, + "w": 8, + "x": 0, + "y": 35 + }, + "id": 14, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "rate(galley_source_kube_event_success_total[1m]) * 60", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Success", + "refId": "A" + }, + { + "expr": "rate(galley_source_kube_event_error_total[1m]) * 60", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Error", + "refId": "B" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Source Event Rate", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": "Events/min", + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 6, + "w": 8, + "x": 16, + "y": 35 + }, + "id": 24, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "rate(galley_source_kube_dynamic_converter_failure_total[1m]) * 60", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Error", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Kubernetes Object Conversion Failures", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": "Failures/min", + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 41 + }, + "id": 18, + "panels": [], + "title": "Mesh Configuration Protocol", + "type": "row" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 6, + "w": 8, + "x": 0, + "y": 42 + }, + "id": 20, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(istio_mcp_clients_total{component=\"galley\"})", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Clients", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Connected Clients", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 6, + "w": 8, + "x": 8, + "y": 42 + }, + "id": 22, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum by(collection)(irate(istio_mcp_request_acks_total{component=\"galley\"}[1m]) * 60)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Request ACKs", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": "ACKs/min", + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 6, + "w": 8, + "x": 16, + "y": 42 + }, + "id": 26, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "rate(istio_mcp_request_nacks_total{component=\"galley\"}[1m]) * 60", + "format": "time_series", + "intervalFactor": 1, + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Request NACKs", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": "NACKs/min", + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + } + ], + "refresh": "5s", + "schemaVersion": 16, + "style": "dark", + "tags": [], + "templating": { + "list": [] + }, + "time": { + "from": "now-5m", + "to": "now" + }, + "timepicker": { + "refresh_intervals": [ + "5s", + "10s", + "30s", + "1m", + "5m", + "15m", + "30m", + "1h", + "2h", + "1d" + ], + "time_options": [ + "5m", + "15m", + "1h", + "6h", + "12h", + "24h", + "2d", + "7d", + "30d" + ] + }, + "timezone": "", + "title": "Istio Galley Dashboard", + "uid": "TSEY6jLmk", + "version": 1 +} diff --git a/istio-1.5.0/install/kubernetes/operator/charts/istio-telemetry/grafana/dashboards/istio-mesh-dashboard.json b/istio-1.5.0/install/kubernetes/operator/charts/istio-telemetry/grafana/dashboards/istio-mesh-dashboard.json new file mode 100644 index 0000000..2ae9a3e --- /dev/null +++ b/istio-1.5.0/install/kubernetes/operator/charts/istio-telemetry/grafana/dashboards/istio-mesh-dashboard.json @@ -0,0 +1,1225 @@ +{ + "annotations": { + "list": [ + { + "builtIn": 1, + "datasource": "-- Grafana --", + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations & Alerts", + "type": "dashboard" + } + ] + }, + "editable": false, + "gnetId": null, + "graphTooltip": 0, + "id": null, + "links": [], + "panels": [ + { + "content": "
\n
\n Istio\n
\n
\n Istio is an open platform that provides a uniform way to connect,\n manage, and \n secure microservices.\n
\n Need help? Join the Istio community.\n
\n
", + "gridPos": { + "h": 3, + "w": 24, + "x": 0, + "y": 0 + }, + "height": "50px", + "id": 13, + "links": [], + "mode": "html", + "style": { + "font-size": "18pt" + }, + "title": "", + "transparent": true, + "type": "text" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "datasource": "Prometheus", + "format": "ops", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "gridPos": { + "h": 3, + "w": 6, + "x": 0, + "y": 3 + }, + "id": 20, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": true, + "lineColor": "rgb(31, 120, 193)", + "show": true + }, + "tableColumn": "", + "targets": [ + { + "expr": "round(sum(irate(istio_requests_total{reporter=\"destination\"}[1m])), 0.001)", + "intervalFactor": 1, + "refId": "A", + "step": 4 + } + ], + "thresholds": "", + "title": "Global Request Volume", + "type": "singlestat", + "valueFontSize": "80%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "avg" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "datasource": "Prometheus", + "format": "percentunit", + "gauge": { + "maxValue": 100, + "minValue": 80, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": false + }, + "gridPos": { + "h": 3, + "w": 6, + "x": 6, + "y": 3 + }, + "id": 21, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": true, + "lineColor": "rgb(31, 120, 193)", + "show": true + }, + "tableColumn": "", + "targets": [ + { + "expr": "sum(rate(istio_requests_total{reporter=\"destination\", response_code!~\"5.*\"}[1m])) / sum(rate(istio_requests_total{reporter=\"destination\"}[1m]))", + "format": "time_series", + "intervalFactor": 1, + "refId": "A", + "step": 4 + } + ], + "thresholds": "95, 99, 99.5", + "title": "Global Success Rate (non-5xx responses)", + "type": "singlestat", + "valueFontSize": "80%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "avg" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "datasource": "Prometheus", + "format": "ops", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "gridPos": { + "h": 3, + "w": 6, + "x": 12, + "y": 3 + }, + "id": 22, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": true, + "lineColor": "rgb(31, 120, 193)", + "show": true + }, + "tableColumn": "", + "targets": [ + { + "expr": "sum(irate(istio_requests_total{reporter=\"destination\", response_code=~\"4.*\"}[1m])) ", + "format": "time_series", + "intervalFactor": 1, + "refId": "A", + "step": 4 + } + ], + "thresholds": "", + "title": "4xxs", + "type": "singlestat", + "valueFontSize": "80%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "avg" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "datasource": "Prometheus", + "format": "ops", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "gridPos": { + "h": 3, + "w": 6, + "x": 18, + "y": 3 + }, + "id": 23, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": true, + "lineColor": "rgb(31, 120, 193)", + "show": true + }, + "tableColumn": "", + "targets": [ + { + "expr": "sum(irate(istio_requests_total{reporter=\"destination\", response_code=~\"5.*\"}[1m])) ", + "format": "time_series", + "intervalFactor": 1, + "refId": "A", + "step": 4 + } + ], + "thresholds": "", + "title": "5xxs", + "type": "singlestat", + "valueFontSize": "80%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "avg" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "#299c46", + "rgba(237, 129, 40, 0.89)", + "#d44a3a" + ], + "format": "none", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "gridPos": { + "h": 3, + "w": 6, + "x": 0, + "y": 6 + }, + "id": 113, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": false, + "lineColor": "rgb(31, 120, 193)", + "show": true + }, + "tableColumn": "", + "targets": [ + { + "expr": "avg(galley_istio_networking_virtualservices)", + "format": "time_series", + "intervalFactor": 1, + "refId": "A" + } + ], + "thresholds": "", + "timeFrom": null, + "timeShift": null, + "title": "Virtual Services", + "type": "singlestat", + "valueFontSize": "80%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "current" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "#299c46", + "rgba(237, 129, 40, 0.89)", + "#d44a3a" + ], + "format": "none", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "gridPos": { + "h": 3, + "w": 6, + "x": 6, + "y": 6 + }, + "id": 114, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": false, + "lineColor": "rgb(31, 120, 193)", + "show": true + }, + "tableColumn": "", + "targets": [ + { + "expr": "avg(galley_istio_networking_destinationrules)", + "format": "time_series", + "intervalFactor": 1, + "refId": "A" + } + ], + "thresholds": "", + "timeFrom": null, + "timeShift": null, + "title": "Destination Rules", + "type": "singlestat", + "valueFontSize": "80%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "current" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "#299c46", + "rgba(237, 129, 40, 0.89)", + "#d44a3a" + ], + "format": "none", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "gridPos": { + "h": 3, + "w": 6, + "x": 12, + "y": 6 + }, + "id": 115, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": false, + "lineColor": "rgb(31, 120, 193)", + "show": true + }, + "tableColumn": "", + "targets": [ + { + "expr": "avg(galley_istio_networking_gateways)", + "format": "time_series", + "intervalFactor": 1, + "refId": "A" + } + ], + "thresholds": "", + "timeFrom": null, + "timeShift": null, + "title": "Gateways", + "type": "singlestat", + "valueFontSize": "80%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "current" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "#299c46", + "rgba(237, 129, 40, 0.89)", + "#d44a3a" + ], + "format": "none", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "gridPos": { + "h": 3, + "w": 6, + "x": 18, + "y": 6 + }, + "id": 116, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": false, + "lineColor": "rgb(31, 120, 193)", + "show": true + }, + "tableColumn": "", + "targets": [ + { + "expr": "avg(galley_istio_authentication_meshpolicies)", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "refId": "A" + } + ], + "thresholds": "", + "timeFrom": null, + "timeShift": null, + "title": "Authentication Mesh Policies", + "type": "singlestat", + "valueFontSize": "80%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "current" + }, + { + "columns": [], + "datasource": "Prometheus", + "fontSize": "100%", + "gridPos": { + "h": 21, + "w": 24, + "x": 0, + "y": 9 + }, + "hideTimeOverride": false, + "id": 73, + "links": [], + "pageSize": null, + "repeat": null, + "repeatDirection": "v", + "scroll": true, + "showHeader": true, + "sort": { + "col": 4, + "desc": true + }, + "styles": [ + { + "alias": "Workload", + "colorMode": null, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "link": false, + "linkTargetBlank": false, + "linkTooltip": "Workload dashboard", + "linkUrl": "/dashboard/db/istio-workload-dashboard?var-namespace=$__cell_2&var-workload=$__cell_", + "pattern": "destination_workload", + "preserveFormat": false, + "sanitize": false, + "thresholds": [], + "type": "hidden", + "unit": "short" + }, + { + "alias": "", + "colorMode": null, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "pattern": "Time", + "thresholds": [], + "type": "hidden", + "unit": "short" + }, + { + "alias": "Requests", + "colorMode": null, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "pattern": "Value #A", + "thresholds": [], + "type": "number", + "unit": "ops" + }, + { + "alias": "P50 Latency", + "colorMode": null, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "pattern": "Value #B", + "thresholds": [], + "type": "number", + "unit": "s" + }, + { + "alias": "P90 Latency", + "colorMode": null, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "pattern": "Value #D", + "thresholds": [], + "type": "number", + "unit": "s" + }, + { + "alias": "P99 Latency", + "colorMode": null, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "pattern": "Value #E", + "thresholds": [], + "type": "number", + "unit": "s" + }, + { + "alias": "Success Rate", + "colorMode": "cell", + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "pattern": "Value #F", + "thresholds": [ + ".95", + " 1.00" + ], + "type": "number", + "unit": "percentunit" + }, + { + "alias": "Workload", + "colorMode": null, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "link": true, + "linkTooltip": "$__cell dashboard", + "linkUrl": "/dashboard/db/istio-workload-dashboard?var-workload=$__cell_2&var-namespace=$__cell_3", + "pattern": "destination_workload_var", + "thresholds": [], + "type": "number", + "unit": "short" + }, + { + "alias": "Service", + "colorMode": null, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "link": true, + "linkTooltip": "$__cell dashboard", + "linkUrl": "/dashboard/db/istio-service-dashboard?var-service=$__cell", + "pattern": "destination_service", + "thresholds": [], + "type": "string", + "unit": "short" + }, + { + "alias": "", + "colorMode": null, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "pattern": "destination_workload_namespace", + "thresholds": [], + "type": "hidden", + "unit": "short" + } + ], + "targets": [ + { + "expr": "label_join(sum(rate(istio_requests_total{reporter=\"destination\", response_code=\"200\"}[1m])) by (destination_workload, destination_workload_namespace, destination_service), \"destination_workload_var\", \".\", \"destination_workload\", \"destination_workload_namespace\")", + "format": "table", + "hide": false, + "instant": true, + "intervalFactor": 1, + "legendFormat": "{{ destination_workload}}.{{ destination_workload_namespace }}", + "refId": "A" + }, + { + "expr": "label_join((histogram_quantile(0.50, sum(rate(istio_request_duration_milliseconds_bucket{reporter=\"destination\"}[1m])) by (le, destination_workload, destination_workload_namespace)) / 1000) or histogram_quantile(0.50, sum(rate(istio_request_duration_seconds_bucket{reporter=\"destination\"}[1m])) by (le, destination_workload, destination_workload_namespace)), \"destination_workload_var\", \".\", \"destination_workload\", \"destination_workload_namespace\")", + "format": "table", + "hide": false, + "instant": true, + "intervalFactor": 1, + "legendFormat": "{{ destination_workload}}.{{ destination_workload_namespace }}", + "refId": "B" + }, + { + "expr": "label_join((histogram_quantile(0.90, sum(rate(istio_request_duration_milliseconds_bucket{reporter=\"destination\"}[1m])) by (le, destination_workload, destination_workload_namespace)) / 1000) or histogram_quantile(0.90, sum(rate(istio_request_duration_seconds_bucket{reporter=\"destination\"}[1m])) by (le, destination_workload, destination_workload_namespace)), \"destination_workload_var\", \".\", \"destination_workload\", \"destination_workload_namespace\")", + "format": "table", + "hide": false, + "instant": true, + "intervalFactor": 1, + "legendFormat": "{{ destination_workload }}.{{ destination_workload_namespace }}", + "refId": "D" + }, + { + "expr": "label_join((histogram_quantile(0.99, sum(rate(istio_request_duration_milliseconds_bucket{reporter=\"destination\"}[1m])) by (le, destination_workload, destination_workload_namespace)) / 1000) or histogram_quantile(0.99, sum(rate(istio_request_duration_seconds_bucket{reporter=\"destination\"}[1m])) by (le, destination_workload, destination_workload_namespace)), \"destination_workload_var\", \".\", \"destination_workload\", \"destination_workload_namespace\")", + "format": "table", + "hide": false, + "instant": true, + "intervalFactor": 1, + "legendFormat": "{{ destination_workload }}.{{ destination_workload_namespace }}", + "refId": "E" + }, + { + "expr": "label_join((sum(rate(istio_requests_total{reporter=\"destination\", response_code!~\"5.*\"}[1m])) by (destination_workload, destination_workload_namespace) / sum(rate(istio_requests_total{reporter=\"destination\"}[1m])) by (destination_workload, destination_workload_namespace)), \"destination_workload_var\", \".\", \"destination_workload\", \"destination_workload_namespace\")", + "format": "table", + "hide": false, + "instant": true, + "interval": "", + "intervalFactor": 1, + "legendFormat": "{{ destination_workload }}.{{ destination_workload_namespace }}", + "refId": "F" + } + ], + "timeFrom": null, + "title": "HTTP/GRPC Workloads", + "transform": "table", + "type": "table" + }, + { + "columns": [], + "datasource": "Prometheus", + "fontSize": "100%", + "gridPos": { + "h": 18, + "w": 24, + "x": 0, + "y": 30 + }, + "hideTimeOverride": false, + "id": 109, + "links": [], + "pageSize": null, + "repeatDirection": "v", + "scroll": true, + "showHeader": true, + "sort": { + "col": 2, + "desc": true + }, + "styles": [ + { + "alias": "Workload", + "colorMode": null, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "link": false, + "linkTargetBlank": false, + "linkTooltip": "$__cell dashboard", + "linkUrl": "/dashboard/db/istio-tcp-workload-dashboard?var-namespace=$__cell_2&&var-workload=$__cell", + "pattern": "destination_workload", + "preserveFormat": false, + "sanitize": false, + "thresholds": [], + "type": "hidden", + "unit": "short" + }, + { + "alias": "Bytes Sent", + "colorMode": null, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "pattern": "Value #A", + "thresholds": [ + "" + ], + "type": "number", + "unit": "Bps" + }, + { + "alias": "Bytes Received", + "colorMode": null, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "pattern": "Value #C", + "thresholds": [], + "type": "number", + "unit": "Bps" + }, + { + "alias": "", + "colorMode": null, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "pattern": "Time", + "thresholds": [], + "type": "hidden", + "unit": "short" + }, + { + "alias": "Workload", + "colorMode": null, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "link": true, + "linkTooltip": "$__cell dashboard", + "linkUrl": "/dashboard/db/istio-workload-dashboard?var-namespace=$__cell_3&var-workload=$__cell_2", + "pattern": "destination_workload_var", + "thresholds": [], + "type": "string", + "unit": "short" + }, + { + "alias": "", + "colorMode": null, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "pattern": "destination_workload_namespace", + "thresholds": [], + "type": "hidden", + "unit": "short" + }, + { + "alias": "Service", + "colorMode": null, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "link": true, + "linkTooltip": "$__cell dashboard", + "linkUrl": "/dashboard/db/istio-service-dashboard?var-service=$__cell", + "pattern": "destination_service", + "thresholds": [], + "type": "number", + "unit": "short" + } + ], + "targets": [ + { + "expr": "label_join(sum(rate(istio_tcp_received_bytes_total{reporter=\"source\"}[1m])) by (destination_workload, destination_workload_namespace, destination_service), \"destination_workload_var\", \".\", \"destination_workload\", \"destination_workload_namespace\")", + "format": "table", + "hide": false, + "instant": true, + "intervalFactor": 1, + "legendFormat": "{{ destination_workload }}", + "refId": "C" + }, + { + "expr": "label_join(sum(rate(istio_tcp_sent_bytes_total{reporter=\"source\"}[1m])) by (destination_workload, destination_workload_namespace, destination_service), \"destination_workload_var\", \".\", \"destination_workload\", \"destination_workload_namespace\")", + "format": "table", + "hide": false, + "instant": true, + "intervalFactor": 1, + "legendFormat": "{{ destination_workload }}", + "refId": "A" + } + ], + "timeFrom": null, + "title": "TCP Workloads", + "transform": "table", + "type": "table" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 9, + "w": 24, + "x": 0, + "y": 48 + }, + "id": 111, + "legend": { + "alignAsTable": false, + "avg": false, + "current": false, + "max": false, + "min": false, + "rightSide": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(istio_build) by (component, tag)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{ component }}: {{ tag }}", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Istio Components by Version", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + } + ], + "refresh": "5s", + "schemaVersion": 18, + "style": "dark", + "tags": [], + "templating": { + "list": [] + }, + "time": { + "from": "now-5m", + "to": "now" + }, + "timepicker": { + "refresh_intervals": [ + "5s", + "10s", + "30s", + "1m", + "5m", + "15m", + "30m", + "1h", + "2h", + "1d" + ], + "time_options": [ + "5m", + "15m", + "1h", + "6h", + "12h", + "24h", + "2d", + "7d", + "30d" + ] + }, + "timezone": "browser", + "title": "Istio Mesh Dashboard", + "uid": "G8wLrJIZk", + "version": 5 +} diff --git a/istio-1.5.0/install/kubernetes/operator/charts/istio-telemetry/grafana/dashboards/istio-performance-dashboard.json b/istio-1.5.0/install/kubernetes/operator/charts/istio-telemetry/grafana/dashboards/istio-performance-dashboard.json new file mode 100644 index 0000000..dbb6c71 --- /dev/null +++ b/istio-1.5.0/install/kubernetes/operator/charts/istio-telemetry/grafana/dashboards/istio-performance-dashboard.json @@ -0,0 +1,1822 @@ +{ + "annotations": { + "list": [ + { + "builtIn": 1, + "datasource": "-- Grafana --", + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations & Alerts", + "type": "dashboard" + } + ] + }, + "editable": false, + "gnetId": null, + "graphTooltip": 0, + "id": 9, + "links": [], + "panels": [ + { + "collapsed": true, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 0 + }, + "id": 21, + "panels": [ + { + "content": "The charts on this dashboard are intended to show Istio main components cost in terms resources utilization under steady load.\n\n- **vCPU/1k rps:** shows vCPU utilization by the main Istio components normalized by 1000 requests/second. When idle or low traffic, this chart will be blank. The curve for istio-proxy refers to the services sidecars only.\n- **vCPU:** vCPU utilization by Istio components, not normalized.\n- **Memory:** memory footprint for the components. Telemetry and policy are normalized by 1k rps, and no data is shown when there is no traffic. For ingress and istio-proxy, the data is per instance.\n- **Bytes transferred/ sec:** shows the number of bytes flowing through each Istio component.\n\n\n", + "gridPos": { + "h": 6, + "w": 24, + "x": 0, + "y": 1 + }, + "id": 19, + "links": [], + "mode": "markdown", + "timeFrom": null, + "timeShift": null, + "title": "Performance Dashboard README", + "transparent": true, + "type": "text" + } + ], + "title": "Performance Dashboard Notes", + "type": "row" + }, + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 1 + }, + "id": 6, + "panels": [], + "title": "vCPU Usage", + "type": "row" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "fill": 1, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 2 + }, + "id": 4, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "(sum(irate(container_cpu_usage_seconds_total{job=\"kubernetes-cadvisor\",pod=~\"istio-telemetry-.*\",container=~\"mixer|istio-proxy\"}[1m]))/ (round(sum(irate(istio_requests_total[1m])), 0.001)/1000))/ (sum(irate(istio_requests_total{source_workload=\"istio-ingressgateway\"}[1m])) >bool 10)", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "istio-telemetry", + "refId": "A" + }, + { + "expr": "(sum(irate(container_cpu_usage_seconds_total{job=\"kubernetes-cadvisor\",pod=~\"istio-ingressgateway-.*\",container=\"istio-proxy\"}[1m])) / (round(sum(irate(istio_requests_total{source_workload=\"istio-ingressgateway\", reporter=\"source\"}[1m])), 0.001)/1000))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "istio-ingressgateway", + "refId": "B" + }, + { + "expr": "(sum(irate(container_cpu_usage_seconds_total{job=\"kubernetes-cadvisor\",namespace!=\"istio-system\",container=\"istio-proxy\"}[1m]))/ (round(sum(irate(istio_requests_total[1m])), 0.001)/1000))/ (sum(irate(istio_requests_total{source_workload=\"istio-ingressgateway\"}[1m])) >bool 10)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "istio-proxy", + "refId": "C" + }, + { + "expr": "(sum(irate(container_cpu_usage_seconds_total{job=\"kubernetes-cadvisor\",pod=~\"istio-policy-.*\",container=~\"mixer|istio-proxy\"}[1m]))/ (round(sum(irate(istio_requests_total[1m])), 0.001)/1000))/ (sum(irate(istio_requests_total{source_workload=\"istio-ingressgateway\"}[1m])) >bool 10)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "istio-policy", + "refId": "D" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "vCPU / 1k rps", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "fill": 1, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 2 + }, + "id": 7, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(rate(container_cpu_usage_seconds_total{job=\"kubernetes-cadvisor\",pod=~\"istio-telemetry-.*\",container=~\"mixer|istio-proxy\"}[1m]))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "istio-telemetry", + "refId": "A" + }, + { + "expr": "sum(rate(container_cpu_usage_seconds_total{job=\"kubernetes-cadvisor\",pod=~\"istio-ingressgateway-.*\",container=\"istio-proxy\"}[1m]))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "istio-ingressgateway", + "refId": "B" + }, + { + "expr": "sum(rate(container_cpu_usage_seconds_total{job=\"kubernetes-cadvisor\",namespace!=\"istio-system\",container=\"istio-proxy\"}[1m]))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "istio-proxy", + "refId": "C" + }, + { + "expr": "sum(rate(container_cpu_usage_seconds_total{job=\"kubernetes-cadvisor\",pod=~\"istio-policy-.*\",container=~\"mixer|istio-proxy\"}[1m]))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "istio-policy", + "refId": "D" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "vCPU", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 10 + }, + "id": 13, + "panels": [], + "title": "Memory and Data Rates", + "type": "row" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "fill": 1, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 11 + }, + "id": 902, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "(sum(container_memory_usage_bytes{job=\"kubernetes-cadvisor\",pod=~\"istio-telemetry-.*\"}) / (sum(irate(istio_requests_total[1m])) / 1000)) / (sum(irate(istio_requests_total{source_workload=\"istio-ingressgateway\"}[1m])) >bool 10)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "istio-telemetry / 1k rps", + "refId": "A" + }, + { + "expr": "sum(container_memory_usage_bytes{job=\"kubernetes-cadvisor\",pod=~\"istio-ingressgateway-.*\"}) / count(container_memory_usage_bytes{job=\"kubernetes-cadvisor\",pod=~\"istio-ingressgateway-.*\",container!=\"POD\"})", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "per istio-ingressgateway", + "refId": "B" + }, + { + "expr": "sum(container_memory_usage_bytes{job=\"kubernetes-cadvisor\",namespace!=\"istio-system\",container=\"istio-proxy\"}) / count(container_memory_usage_bytes{job=\"kubernetes-cadvisor\",namespace!=\"istio-system\",container=\"istio-proxy\"})", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "per istio proxy", + "refId": "C" + }, + { + "expr": "(sum(container_memory_usage_bytes{job=\"kubernetes-cadvisor\",pod=~\"istio-policy-.*\"}) / (sum(irate(istio_requests_total[1m])) / 1000))/ (sum(irate(istio_requests_total{source_workload=\"istio-ingressgateway\"}[1m])) >bool 10)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "istio-policy / 1k rps", + "refId": "D" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Memory Usage", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "bytes", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "fill": 1, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 11 + }, + "id": 11, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(irate(istio_response_bytes_sum{destination_workload=\"istio-telemetry\"}[1m])) + sum(irate(istio_request_bytes_sum{destination_workload=\"istio-telemetry\"}[1m]))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "istio-telemetry", + "refId": "A" + }, + { + "expr": "sum(irate(istio_response_bytes_sum{source_workload=\"istio-ingressgateway\", reporter=\"source\"}[1m]))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "istio-ingressgateway", + "refId": "B" + }, + { + "expr": "sum(irate(istio_response_bytes_sum{source_workload_namespace!=\"istio-system\", reporter=\"source\"}[1m])) + sum(irate(istio_response_bytes_sum{destination_workload_namespace!=\"istio-system\", reporter=\"destination\"}[1m])) + sum(irate(istio_request_bytes_sum{source_workload_namespace!=\"istio-system\", reporter=\"source\"}[1m])) + sum(irate(istio_request_bytes_sum{destination_workload_namespace!=\"istio-system\", reporter=\"destination\"}[1m]))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "istio-proxy", + "refId": "C" + }, + { + "expr": "sum(irate(istio_response_bytes_sum{destination_workload=\"istio-policy\"}[1m])) + sum(irate(istio_request_bytes_sum{destination_workload=\"istio-policy\"}[1m]))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "istio_policy", + "refId": "D" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Bytes transferred / sec", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "Bps", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 19 + }, + "id": 17, + "panels": [], + "title": "Istio Component Versions", + "type": "row" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "fill": 1, + "gridPos": { + "h": 8, + "w": 24, + "x": 0, + "y": 20 + }, + "id": 15, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(istio_build) by (component, tag)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{ component }}: {{ tag }}", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Istio Components by Version", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 31 + }, + "id": 71, + "panels": [], + "title": "Proxy Resource Usage", + "type": "row" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 7, + "w": 6, + "x": 0, + "y": 32 + }, + "id": 72, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(container_memory_usage_bytes{job=\"kubernetes-cadvisor\",container=\"istio-proxy\"})", + "format": "time_series", + "hide": false, + "intervalFactor": 2, + "legendFormat": "{{ container }} (k8s)", + "refId": "B", + "step": 2 + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Memory", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "bytes", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 7, + "w": 6, + "x": 6, + "y": 32 + }, + "id": 73, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(rate(container_cpu_usage_seconds_total{job=\"kubernetes-cadvisor\",container=\"istio-proxy\"}[1m]))", + "format": "time_series", + "hide": false, + "intervalFactor": 2, + "legendFormat": "Total (k8s)", + "refId": "A", + "step": 2 + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "vCPU", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 7, + "w": 6, + "x": 12, + "y": 32 + }, + "id": 702, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(container_fs_usage_bytes{job=\"kubernetes-cadvisor\", container=\"istio-proxy\"})", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "{{ container }}", + "refId": "B", + "step": 2 + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Disk", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "bytes", + "label": "", + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "decimals": null, + "format": "none", + "label": "", + "logBase": 1024, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 39 + }, + "id": 69, + "panels": [], + "title": "Pilot Resource Usage", + "type": "row" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 7, + "w": 6, + "x": 0, + "y": 40 + }, + "id": 5, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "process_virtual_memory_bytes{job=\"pilot\"}", + "format": "time_series", + "instant": false, + "intervalFactor": 2, + "legendFormat": "Virtual Memory", + "refId": "I", + "step": 2 + }, + { + "expr": "process_resident_memory_bytes{job=\"pilot\"}", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "Resident Memory", + "refId": "H", + "step": 2 + }, + { + "expr": "go_memstats_heap_sys_bytes{job=\"pilot\"}", + "format": "time_series", + "hide": true, + "intervalFactor": 2, + "legendFormat": "heap sys", + "refId": "A" + }, + { + "expr": "go_memstats_heap_alloc_bytes{job=\"pilot\"}", + "format": "time_series", + "hide": true, + "intervalFactor": 2, + "legendFormat": "heap alloc", + "refId": "D" + }, + { + "expr": "go_memstats_alloc_bytes{job=\"pilot\"}", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "Alloc", + "refId": "F", + "step": 2 + }, + { + "expr": "go_memstats_heap_inuse_bytes{job=\"pilot\"}", + "format": "time_series", + "hide": false, + "intervalFactor": 2, + "legendFormat": "Heap in-use", + "refId": "E", + "step": 2 + }, + { + "expr": "go_memstats_stack_inuse_bytes{job=\"pilot\"}", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "Stack in-use", + "refId": "G", + "step": 2 + }, + { + "expr": "sum(container_memory_usage_bytes{job=\"kubernetes-cadvisor\",container=~\"discovery|istio-proxy\", pod=~\"istiod-.*\"})", + "format": "time_series", + "hide": false, + "intervalFactor": 2, + "legendFormat": "Total (k8s)", + "refId": "C", + "step": 2 + }, + { + "expr": "container_memory_usage_bytes{job=\"kubernetes-cadvisor\",container=~\"discovery|istio-proxy\", pod=~\"istiod-.*\"}", + "format": "time_series", + "hide": false, + "intervalFactor": 2, + "legendFormat": "{{ container }} (k8s)", + "refId": "B", + "step": 2 + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Memory", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "bytes", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 7, + "w": 6, + "x": 6, + "y": 40 + }, + "id": 602, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(rate(container_cpu_usage_seconds_total{job=\"kubernetes-cadvisor\",container=~\"discovery|istio-proxy\", pod=~\"istiod-.*\"}[1m]))", + "format": "time_series", + "hide": false, + "intervalFactor": 2, + "legendFormat": "Total (k8s)", + "refId": "A", + "step": 2 + }, + { + "expr": "sum(rate(container_cpu_usage_seconds_total{job=\"kubernetes-cadvisor\",container=~\"discovery|istio-proxy\", pod=~\"istiod-.*\"}[1m])) by (container)", + "format": "time_series", + "hide": false, + "intervalFactor": 2, + "legendFormat": "{{ container }} (k8s)", + "refId": "B", + "step": 2 + }, + { + "expr": "irate(process_cpu_seconds_total{job=\"pilot\"}[1m])", + "format": "time_series", + "hide": false, + "intervalFactor": 2, + "legendFormat": "pilot (self-reported)", + "refId": "C", + "step": 2 + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "vCPU", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 7, + "w": 6, + "x": 12, + "y": 40 + }, + "id": 74, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "process_open_fds{job=\"pilot\"}", + "format": "time_series", + "hide": true, + "instant": false, + "interval": "", + "intervalFactor": 2, + "legendFormat": "Open FDs (pilot)", + "refId": "A" + }, + { + "expr": "container_fs_usage_bytes{job=\"kubernetes-cadvisor\", container=~\"discovery|istio-proxy\", pod=~\"istiod-.*\"}", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "{{ container }}", + "refId": "B", + "step": 2 + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Disk", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "bytes", + "label": "", + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "decimals": null, + "format": "none", + "label": "", + "logBase": 1024, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 7, + "w": 6, + "x": 18, + "y": 40 + }, + "id": 402, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": false, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "go_goroutines{job=\"pilot\"}", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "Number of Goroutines", + "refId": "A", + "step": 2 + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Goroutines", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": "", + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 47 + }, + "id": 93, + "panels": [], + "title": "Mixer Resource Usage", + "type": "row" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 7, + "w": 6, + "x": 0, + "y": 48 + }, + "id": 94, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "process_virtual_memory_bytes{job=~\"istio-telemetry|istio-policy\"}", + "format": "time_series", + "instant": false, + "intervalFactor": 2, + "legendFormat": "Virtual Memory", + "refId": "I", + "step": 2 + }, + { + "expr": "process_resident_memory_bytes{job=~\"istio-telemetry|istio-policy\"}", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "Resident Memory", + "refId": "H", + "step": 2 + }, + { + "expr": "go_memstats_heap_sys_bytes{job=~\"istio-telemetry|istio-policy\"}", + "format": "time_series", + "hide": true, + "intervalFactor": 2, + "legendFormat": "heap sys", + "refId": "A" + }, + { + "expr": "go_memstats_heap_alloc_bytes{job=~\"istio-telemetry|istio-policy\"}", + "format": "time_series", + "hide": true, + "intervalFactor": 2, + "legendFormat": "heap alloc", + "refId": "D" + }, + { + "expr": "go_memstats_alloc_bytes{job=~\"istio-telemetry|istio-policy\"}", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "Alloc", + "refId": "F", + "step": 2 + }, + { + "expr": "go_memstats_heap_inuse_bytes{job=~\"istio-telemetry|istio-policy\"}", + "format": "time_series", + "hide": false, + "intervalFactor": 2, + "legendFormat": "Heap in-use", + "refId": "E", + "step": 2 + }, + { + "expr": "go_memstats_stack_inuse_bytes{job=~\"istio-policy|istio-telemetry\"}", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "Stack in-use", + "refId": "G", + "step": 2 + }, + { + "expr": "sum(container_memory_usage_bytes{job=\"kubernetes-cadvisor\",container=~\"mixer|istio-proxy\", pod=~\"istio-telemetry-.*\"})", + "format": "time_series", + "hide": false, + "intervalFactor": 2, + "legendFormat": "Total (k8s)", + "refId": "C", + "step": 2 + }, + { + "expr": "container_memory_usage_bytes{job=\"kubernetes-cadvisor\",container=~\"mixer|istio-proxy\", pod=~\"istio-telemetry-.*\"}", + "format": "time_series", + "hide": false, + "intervalFactor": 2, + "legendFormat": "{{ container }} (k8s)", + "refId": "B", + "step": 2 + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Memory", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "bytes", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 7, + "w": 6, + "x": 6, + "y": 48 + }, + "id": 95, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(rate(container_cpu_usage_seconds_total{job=\"kubernetes-cadvisor\",container=~\"mixer|istio-proxy\", pod=~\"istio-telemetry-.*\"}[1m]))", + "format": "time_series", + "hide": false, + "intervalFactor": 2, + "legendFormat": "Total (k8s)", + "refId": "A", + "step": 2 + }, + { + "expr": "sum(rate(container_cpu_usage_seconds_total{job=\"kubernetes-cadvisor\",container=~\"mixer|istio-proxy\", pod=~\"istio-telemetry-.*\"}[1m])) by (container)", + "format": "time_series", + "hide": false, + "intervalFactor": 2, + "legendFormat": "{{ container }} (k8s)", + "refId": "B", + "step": 2 + }, + { + "expr": "irate(process_cpu_seconds_total{job=~\"istio-policy|istio-telemetry\"}[1m])", + "format": "time_series", + "hide": false, + "intervalFactor": 2, + "legendFormat": "mixer (self-reported)", + "refId": "C", + "step": 2 + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "vCPU", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 7, + "w": 6, + "x": 12, + "y": 48 + }, + "id": 96, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "process_open_fds{job=~\"istio-policy|istio-telemetry\"}", + "format": "time_series", + "hide": true, + "instant": false, + "interval": "", + "intervalFactor": 2, + "legendFormat": "Open FDs (pilot)", + "refId": "A" + }, + { + "expr": "container_fs_usage_bytes{job=\"kubernetes-cadvisor\", container=~\"mixer|istio-proxy\", pod=~\"istio-telemetry-.*\"}", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "{{ container }}", + "refId": "B", + "step": 2 + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Disk", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "bytes", + "label": "", + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "decimals": null, + "format": "none", + "label": "", + "logBase": 1024, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 7, + "w": 6, + "x": 18, + "y": 48 + }, + "id": 97, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": false, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "go_goroutines{job=\"istio-telemetry\"}", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "Number of Goroutines", + "refId": "A", + "step": 2 + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Goroutines", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": "", + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + } + ], + "refresh": "10s", + "schemaVersion": 18, + "style": "dark", + "tags": [], + "templating": { + "list": [] + }, + "time": { + "from": "now-5m", + "to": "now" + }, + "timepicker": { + "refresh_intervals": [ + "5s", + "10s", + "30s", + "1m", + "5m", + "15m", + "30m", + "1h", + "2h", + "1d" + ], + "time_options": [ + "5m", + "15m", + "1h", + "6h", + "12h", + "24h", + "2d", + "7d", + "30d" + ] + }, + "timezone": "", + "title": "Istio Performance Dashboard", + "uid": "vu8e0VWZk", + "version": 22 +} diff --git a/istio-1.5.0/install/kubernetes/operator/charts/istio-telemetry/grafana/dashboards/istio-service-dashboard.json b/istio-1.5.0/install/kubernetes/operator/charts/istio-telemetry/grafana/dashboards/istio-service-dashboard.json new file mode 100644 index 0000000..f4d58a2 --- /dev/null +++ b/istio-1.5.0/install/kubernetes/operator/charts/istio-telemetry/grafana/dashboards/istio-service-dashboard.json @@ -0,0 +1,2601 @@ +{ + "annotations": { + "list": [ + { + "builtIn": 1, + "datasource": "-- Grafana --", + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations & Alerts", + "type": "dashboard" + } + ] + }, + "editable": false, + "gnetId": null, + "graphTooltip": 0, + "iteration": 1536442501501, + "links": [], + "panels": [ + { + "content": "
\nSERVICE: $service\n
", + "gridPos": { + "h": 3, + "w": 24, + "x": 0, + "y": 0 + }, + "id": 89, + "links": [], + "mode": "html", + "title": "", + "transparent": true, + "type": "text" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "datasource": "Prometheus", + "format": "ops", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "gridPos": { + "h": 4, + "w": 6, + "x": 0, + "y": 3 + }, + "id": 12, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": true, + "lineColor": "rgb(31, 120, 193)", + "show": true + }, + "tableColumn": "", + "targets": [ + { + "expr": "round(sum(irate(istio_requests_total{reporter=\"source\",destination_service=~\"$service\"}[5m])), 0.001)", + "format": "time_series", + "intervalFactor": 1, + "refId": "A", + "step": 4 + } + ], + "thresholds": "", + "title": "Client Request Volume", + "transparent": false, + "type": "singlestat", + "valueFontSize": "80%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "current" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "rgba(50, 172, 45, 0.97)", + "rgba(237, 129, 40, 0.89)", + "rgba(245, 54, 54, 0.9)" + ], + "datasource": "Prometheus", + "decimals": null, + "format": "percentunit", + "gauge": { + "maxValue": 100, + "minValue": 80, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": false + }, + "gridPos": { + "h": 4, + "w": 6, + "x": 6, + "y": 3 + }, + "id": 14, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": true, + "lineColor": "rgb(31, 120, 193)", + "show": true + }, + "tableColumn": "", + "targets": [ + { + "expr": "sum(irate(istio_requests_total{reporter=\"source\",destination_service=~\"$service\",response_code!~\"5.*\"}[5m])) / sum(irate(istio_requests_total{reporter=\"source\",destination_service=~\"$service\"}[5m]))", + "format": "time_series", + "intervalFactor": 1, + "refId": "B" + } + ], + "thresholds": "95, 99, 99.5", + "title": "Client Success Rate (non-5xx responses)", + "transparent": false, + "type": "singlestat", + "valueFontSize": "80%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "avg" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 4, + "w": 6, + "x": 12, + "y": 3 + }, + "id": 87, + "legend": { + "alignAsTable": false, + "avg": false, + "current": false, + "hideEmpty": false, + "hideZero": false, + "max": false, + "min": false, + "rightSide": true, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "(histogram_quantile(0.50, sum(irate(istio_request_duration_milliseconds_bucket{reporter=\"source\",destination_service=~\"$service\"}[1m])) by (le)) / 1000) or histogram_quantile(0.50, sum(irate(istio_request_duration_seconds_bucket{reporter=\"source\",destination_service=~\"$service\"}[1m])) by (le))", + "format": "time_series", + "interval": "", + "intervalFactor": 1, + "legendFormat": "P50", + "refId": "A" + }, + { + "expr": "(histogram_quantile(0.90, sum(irate(istio_request_duration_milliseconds_bucket{reporter=\"source\",destination_service=~\"$service\"}[1m])) by (le)) / 1000) or histogram_quantile(0.90, sum(irate(istio_request_duration_seconds_bucket{reporter=\"source\",destination_service=~\"$service\"}[1m])) by (le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "P90", + "refId": "B" + }, + { + "expr": "(histogram_quantile(0.99, sum(irate(istio_request_duration_milliseconds_bucket{reporter=\"source\",destination_service=~\"$service\"}[1m])) by (le)) / 1000) or histogram_quantile(0.99, sum(irate(istio_request_duration_seconds_bucket{reporter=\"source\",destination_service=~\"$service\"}[1m])) by (le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "P99", + "refId": "C" + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Client Request Duration", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "s", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "#299c46", + "rgba(237, 129, 40, 0.89)", + "#d44a3a" + ], + "datasource": "Prometheus", + "format": "Bps", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "gridPos": { + "h": 4, + "w": 6, + "x": 18, + "y": 3 + }, + "id": 84, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": true, + "lineColor": "rgb(31, 120, 193)", + "show": true + }, + "tableColumn": "", + "targets": [ + { + "expr": "sum(irate(istio_tcp_received_bytes_total{reporter=\"source\", destination_service=~\"$service\"}[1m]))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "", + "refId": "A" + } + ], + "thresholds": "", + "title": "TCP Received Bytes", + "transparent": false, + "type": "singlestat", + "valueFontSize": "80%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "avg" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "datasource": "Prometheus", + "format": "ops", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "gridPos": { + "h": 4, + "w": 6, + "x": 0, + "y": 7 + }, + "id": 97, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": true, + "lineColor": "rgb(31, 120, 193)", + "show": true + }, + "tableColumn": "", + "targets": [ + { + "expr": "round(sum(irate(istio_requests_total{reporter=\"destination\",destination_service=~\"$service\"}[5m])), 0.001)", + "format": "time_series", + "intervalFactor": 1, + "refId": "A", + "step": 4 + } + ], + "thresholds": "", + "title": "Server Request Volume", + "transparent": false, + "type": "singlestat", + "valueFontSize": "80%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "current" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "rgba(50, 172, 45, 0.97)", + "rgba(237, 129, 40, 0.89)", + "rgba(245, 54, 54, 0.9)" + ], + "datasource": "Prometheus", + "decimals": null, + "format": "percentunit", + "gauge": { + "maxValue": 100, + "minValue": 80, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": false + }, + "gridPos": { + "h": 4, + "w": 6, + "x": 6, + "y": 7 + }, + "id": 98, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": true, + "lineColor": "rgb(31, 120, 193)", + "show": true + }, + "tableColumn": "", + "targets": [ + { + "expr": "sum(irate(istio_requests_total{reporter=\"destination\",destination_service=~\"$service\",response_code!~\"5.*\"}[5m])) / sum(irate(istio_requests_total{reporter=\"destination\",destination_service=~\"$service\"}[5m]))", + "format": "time_series", + "intervalFactor": 1, + "refId": "B" + } + ], + "thresholds": "95, 99, 99.5", + "title": "Server Success Rate (non-5xx responses)", + "transparent": false, + "type": "singlestat", + "valueFontSize": "80%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "avg" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 4, + "w": 6, + "x": 12, + "y": 7 + }, + "id": 99, + "legend": { + "alignAsTable": false, + "avg": false, + "current": false, + "hideEmpty": false, + "hideZero": false, + "max": false, + "min": false, + "rightSide": true, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "(histogram_quantile(0.50, sum(irate(istio_request_duration_milliseconds_bucket{reporter=\"destination\",destination_service=~\"$service\"}[1m])) by (le)) / 1000) or histogram_quantile(0.50, sum(irate(istio_request_duration_seconds_bucket{reporter=\"destination\",destination_service=~\"$service\"}[1m])) by (le))", + "format": "time_series", + "interval": "", + "intervalFactor": 1, + "legendFormat": "P50", + "refId": "A" + }, + { + "expr": "(histogram_quantile(0.90, sum(irate(istio_request_duration_milliseconds_bucket{reporter=\"destination\",destination_service=~\"$service\"}[1m])) by (le)) / 1000) or histogram_quantile(0.90, sum(irate(istio_request_duration_seconds_bucket{reporter=\"destination\",destination_service=~\"$service\"}[1m])) by (le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "P90", + "refId": "B" + }, + { + "expr": "(histogram_quantile(0.99, sum(irate(istio_request_duration_milliseconds_bucket{reporter=\"destination\",destination_service=~\"$service\"}[1m])) by (le)) / 1000) or histogram_quantile(0.99, sum(irate(istio_request_duration_seconds_bucket{reporter=\"destination\",destination_service=~\"$service\"}[1m])) by (le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "P99", + "refId": "C" + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Server Request Duration", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "s", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "#299c46", + "rgba(237, 129, 40, 0.89)", + "#d44a3a" + ], + "datasource": "Prometheus", + "format": "Bps", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "gridPos": { + "h": 4, + "w": 6, + "x": 18, + "y": 7 + }, + "id": 100, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": true, + "lineColor": "rgb(31, 120, 193)", + "show": true + }, + "tableColumn": "", + "targets": [ + { + "expr": "sum(irate(istio_tcp_sent_bytes_total{reporter=\"source\", destination_service=~\"$service\"}[1m])) ", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "", + "refId": "A" + } + ], + "thresholds": "", + "title": "TCP Sent Bytes", + "transparent": false, + "type": "singlestat", + "valueFontSize": "80%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "avg" + }, + { + "content": "
\nCLIENT WORKLOADS\n
", + "gridPos": { + "h": 3, + "w": 24, + "x": 0, + "y": 11 + }, + "id": 45, + "links": [], + "mode": "html", + "title": "", + "transparent": true, + "type": "text" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 0, + "gridPos": { + "h": 6, + "w": 12, + "x": 0, + "y": 14 + }, + "id": 25, + "legend": { + "avg": false, + "current": false, + "hideEmpty": true, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null as zero", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "round(sum(irate(istio_requests_total{connection_security_policy=\"mutual_tls\",destination_service=~\"$service\",reporter=\"source\",source_workload=~\"$srcwl\",source_workload_namespace=~\"$srcns\"}[5m])) by (source_workload, source_workload_namespace, response_code), 0.001)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{ source_workload }}.{{ source_workload_namespace }} : {{ response_code }} (🔐mTLS)", + "refId": "B", + "step": 2 + }, + { + "expr": "round(sum(irate(istio_requests_total{connection_security_policy!=\"mutual_tls\", destination_service=~\"$service\", reporter=\"source\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[5m])) by (source_workload, source_workload_namespace, response_code), 0.001)", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ source_workload }}.{{ source_workload_namespace }} : {{ response_code }}", + "refId": "A", + "step": 2 + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Incoming Requests by Source And Response Code", + "tooltip": { + "shared": false, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [ + "total" + ] + }, + "yaxes": [ + { + "format": "ops", + "label": null, + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 6, + "w": 12, + "x": 12, + "y": 14 + }, + "id": 26, + "legend": { + "avg": false, + "current": false, + "hideEmpty": true, + "hideZero": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(irate(istio_requests_total{reporter=\"source\", connection_security_policy=\"mutual_tls\", destination_service=~\"$service\",response_code!~\"5.*\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[5m])) by (source_workload, source_workload_namespace) / sum(irate(istio_requests_total{reporter=\"source\", connection_security_policy=\"mutual_tls\", destination_service=~\"$service\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[5m])) by (source_workload, source_workload_namespace)", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ source_workload }}.{{ source_workload_namespace }} (🔐mTLS)", + "refId": "A", + "step": 2 + }, + { + "expr": "sum(irate(istio_requests_total{reporter=\"source\", connection_security_policy!=\"mutual_tls\", destination_service=~\"$service\",response_code!~\"5.*\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[5m])) by (source_workload, source_workload_namespace) / sum(irate(istio_requests_total{reporter=\"source\", connection_security_policy!=\"mutual_tls\", destination_service=~\"$service\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[5m])) by (source_workload, source_workload_namespace)", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ source_workload }}.{{ source_workload_namespace }}", + "refId": "B", + "step": 2 + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Incoming Success Rate (non-5xx responses) By Source", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "percentunit", + "label": null, + "logBase": 1, + "max": "1.01", + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "description": "", + "fill": 1, + "gridPos": { + "h": 6, + "w": 8, + "x": 0, + "y": 20 + }, + "id": 27, + "legend": { + "alignAsTable": false, + "avg": false, + "current": false, + "hideEmpty": true, + "hideZero": false, + "max": false, + "min": false, + "rightSide": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "(histogram_quantile(0.50, sum(irate(istio_request_duration_milliseconds_bucket{reporter=\"source\", connection_security_policy=\"mutual_tls\", destination_service=~\"$service\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le)) / 1000) or histogram_quantile(0.50, sum(irate(istio_request_duration_seconds_bucket{reporter=\"source\", connection_security_policy=\"mutual_tls\", destination_service=~\"$service\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{source_workload}}.{{source_workload_namespace}} P50 (🔐mTLS)", + "refId": "D", + "step": 2 + }, + { + "expr": "(histogram_quantile(0.90, sum(irate(istio_request_duration_milliseconds_bucket{reporter=\"source\", connection_security_policy=\"mutual_tls\", destination_service=~\"$service\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le)) / 1000) or histogram_quantile(0.90, sum(irate(istio_request_duration_seconds_bucket{reporter=\"source\", connection_security_policy=\"mutual_tls\", destination_service=~\"$service\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{source_workload}}.{{source_workload_namespace}} P90 (🔐mTLS)", + "refId": "A", + "step": 2 + }, + { + "expr": "(histogram_quantile(0.95, sum(irate(istio_request_duration_milliseconds_bucket{reporter=\"source\", connection_security_policy=\"mutual_tls\", destination_service=~\"$service\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le)) / 1000) or histogram_quantile(0.95, sum(irate(istio_request_duration_seconds_bucket{reporter=\"source\", connection_security_policy=\"mutual_tls\", destination_service=~\"$service\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{source_workload}}.{{source_workload_namespace}} P95 (🔐mTLS)", + "refId": "B", + "step": 2 + }, + { + "expr": "(histogram_quantile(0.99, sum(irate(istio_request_duration_milliseconds_bucket{reporter=\"source\", connection_security_policy=\"mutual_tls\", destination_service=~\"$service\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le)) / 1000) or histogram_quantile(0.99, sum(irate(istio_request_duration_seconds_bucket{reporter=\"source\", connection_security_policy=\"mutual_tls\", destination_service=~\"$service\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{source_workload}}.{{source_workload_namespace}} P99 (🔐mTLS)", + "refId": "C", + "step": 2 + }, + { + "expr": "(histogram_quantile(0.50, sum(irate(istio_request_duration_milliseconds_bucket{reporter=\"source\", connection_security_policy!=\"mutual_tls\", destination_service=~\"$service\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le)) / 1000) or histogram_quantile(0.50, sum(irate(istio_request_duration_seconds_bucket{reporter=\"source\", connection_security_policy!=\"mutual_tls\", destination_service=~\"$service\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{source_workload}}.{{source_workload_namespace}} P50", + "refId": "E", + "step": 2 + }, + { + "expr": "(histogram_quantile(0.90, sum(irate(istio_request_duration_milliseconds_bucket{reporter=\"source\", connection_security_policy!=\"mutual_tls\", destination_service=~\"$service\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le)) / 1000) or histogram_quantile(0.90, sum(irate(istio_request_duration_seconds_bucket{reporter=\"source\", connection_security_policy!=\"mutual_tls\", destination_service=~\"$service\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{source_workload}}.{{source_workload_namespace}} P90", + "refId": "F", + "step": 2 + }, + { + "expr": "(histogram_quantile(0.95, sum(irate(istio_request_duration_milliseconds_bucket{reporter=\"source\", connection_security_policy!=\"mutual_tls\", destination_service=~\"$service\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le)) / 1000) or histogram_quantile(0.95, sum(irate(istio_request_duration_seconds_bucket{reporter=\"source\", connection_security_policy!=\"mutual_tls\", destination_service=~\"$service\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{source_workload}}.{{source_workload_namespace}} P95", + "refId": "G", + "step": 2 + }, + { + "expr": "(histogram_quantile(0.99, sum(irate(istio_request_duration_milliseconds_bucket{reporter=\"source\", connection_security_policy!=\"mutual_tls\", destination_service=~\"$service\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le)) / 1000) or histogram_quantile(0.99, sum(irate(istio_request_duration_seconds_bucket{reporter=\"source\", connection_security_policy!=\"mutual_tls\", destination_service=~\"$service\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{source_workload}}.{{source_workload_namespace}} P99", + "refId": "H", + "step": 2 + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Incoming Request Duration by Source", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "s", + "label": null, + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 6, + "w": 8, + "x": 8, + "y": 20 + }, + "id": 28, + "legend": { + "alignAsTable": false, + "avg": false, + "current": false, + "hideEmpty": true, + "max": false, + "min": false, + "rightSide": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "histogram_quantile(0.50, sum(irate(istio_request_bytes_bucket{reporter=\"source\", connection_security_policy=\"mutual_tls\", destination_service=~\"$service\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{source_workload}}.{{source_workload_namespace}} P50 (🔐mTLS)", + "refId": "D", + "step": 2 + }, + { + "expr": "histogram_quantile(0.90, sum(irate(istio_request_bytes_bucket{reporter=\"source\", connection_security_policy=\"mutual_tls\", destination_service=~\"$service\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{source_workload}}.{{source_workload_namespace}} P90 (🔐mTLS)", + "refId": "A", + "step": 2 + }, + { + "expr": "histogram_quantile(0.95, sum(irate(istio_request_bytes_bucket{reporter=\"source\", connection_security_policy=\"mutual_tls\", destination_service=~\"$service\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{source_workload}}.{{source_workload_namespace}} P95 (🔐mTLS)", + "refId": "B", + "step": 2 + }, + { + "expr": "histogram_quantile(0.99, sum(irate(istio_request_bytes_bucket{reporter=\"source\", connection_security_policy=\"mutual_tls\", destination_service=~\"$service\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{source_workload}}.{{source_workload_namespace}} P99 (🔐mTLS)", + "refId": "C", + "step": 2 + }, + { + "expr": "histogram_quantile(0.50, sum(irate(istio_request_bytes_bucket{reporter=\"source\", connection_security_policy!=\"mutual_tls\", destination_service=~\"$service\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{source_workload}}.{{source_workload_namespace}} P50", + "refId": "E", + "step": 2 + }, + { + "expr": "histogram_quantile(0.90, sum(irate(istio_request_bytes_bucket{reporter=\"source\", connection_security_policy!=\"mutual_tls\", destination_service=~\"$service\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{source_workload}}.{{source_workload_namespace}} P90", + "refId": "F", + "step": 2 + }, + { + "expr": "histogram_quantile(0.95, sum(irate(istio_request_bytes_bucket{reporter=\"source\", connection_security_policy!=\"mutual_tls\", destination_service=~\"$service\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{source_workload}}.{{source_workload_namespace}} P95", + "refId": "G", + "step": 2 + }, + { + "expr": "histogram_quantile(0.99, sum(irate(istio_request_bytes_bucket{reporter=\"source\", connection_security_policy!=\"mutual_tls\", destination_service=~\"$service\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{source_workload}}.{{source_workload_namespace}} P99", + "refId": "H", + "step": 2 + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Incoming Request Size By Source", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "decbytes", + "label": null, + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 6, + "w": 8, + "x": 16, + "y": 20 + }, + "id": 68, + "legend": { + "alignAsTable": false, + "avg": false, + "current": false, + "hideEmpty": true, + "max": false, + "min": false, + "rightSide": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "histogram_quantile(0.50, sum(irate(istio_response_bytes_bucket{reporter=\"source\", connection_security_policy=\"mutual_tls\", destination_service=~\"$service\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{source_workload}}.{{source_workload_namespace}} P50 (🔐mTLS)", + "refId": "D", + "step": 2 + }, + { + "expr": "histogram_quantile(0.90, sum(irate(istio_response_bytes_bucket{reporter=\"source\", connection_security_policy=\"mutual_tls\", destination_service=~\"$service\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{source_workload}}.{{source_workload_namespace}} P90 (🔐mTLS)", + "refId": "A", + "step": 2 + }, + { + "expr": "histogram_quantile(0.95, sum(irate(istio_response_bytes_bucket{reporter=\"source\", connection_security_policy=\"mutual_tls\", destination_service=~\"$service\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{source_workload}}.{{source_workload_namespace}} P95 (🔐mTLS)", + "refId": "B", + "step": 2 + }, + { + "expr": "histogram_quantile(0.99, sum(irate(istio_response_bytes_bucket{reporter=\"source\", connection_security_policy=\"mutual_tls\", destination_service=~\"$service\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{source_workload}}.{{source_workload_namespace}} P99 (🔐mTLS)", + "refId": "C", + "step": 2 + }, + { + "expr": "histogram_quantile(0.50, sum(irate(istio_response_bytes_bucket{reporter=\"source\", connection_security_policy!=\"mutual_tls\", destination_service=~\"$service\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{source_workload}}.{{source_workload_namespace}} P50", + "refId": "E", + "step": 2 + }, + { + "expr": "histogram_quantile(0.90, sum(irate(istio_response_bytes_bucket{reporter=\"source\", connection_security_policy!=\"mutual_tls\", destination_service=~\"$service\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{source_workload}}.{{source_workload_namespace}} P90", + "refId": "F", + "step": 2 + }, + { + "expr": "histogram_quantile(0.95, sum(irate(istio_response_bytes_bucket{reporter=\"source\", connection_security_policy!=\"mutual_tls\", destination_service=~\"$service\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{source_workload}}.{{source_workload_namespace}} P95", + "refId": "G", + "step": 2 + }, + { + "expr": "histogram_quantile(0.99, sum(irate(istio_response_bytes_bucket{reporter=\"source\", connection_security_policy!=\"mutual_tls\", destination_service=~\"$service\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{source_workload}}.{{source_workload_namespace}} P99", + "refId": "H", + "step": 2 + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Response Size By Source", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "decbytes", + "label": null, + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 6, + "w": 12, + "x": 0, + "y": 26 + }, + "id": 80, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "round(sum(irate(istio_tcp_received_bytes_total{reporter=\"source\", connection_security_policy=\"mutual_tls\", destination_service=~\"$service\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace), 0.001)", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ source_workload }}.{{ source_workload_namespace}} (🔐mTLS)", + "refId": "A", + "step": 2 + }, + { + "expr": "round(sum(irate(istio_tcp_received_bytes_total{reporter=\"source\", connection_security_policy!=\"mutual_tls\", destination_service=~\"$service\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace), 0.001)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{ source_workload }}.{{ source_workload_namespace}}", + "refId": "B", + "step": 2 + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Bytes Received from Incoming TCP Connection", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "Bps", + "label": null, + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 6, + "w": 12, + "x": 12, + "y": 26 + }, + "id": 82, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "round(sum(irate(istio_tcp_sent_bytes_total{connection_security_policy=\"mutual_tls\", reporter=\"source\", destination_service=~\"$service\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace), 0.001)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{ source_workload }}.{{ source_workload_namespace}} (🔐mTLS)", + "refId": "A", + "step": 2 + }, + { + "expr": "round(sum(irate(istio_tcp_sent_bytes_total{connection_security_policy!=\"mutual_tls\", reporter=\"source\", destination_service=~\"$service\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace), 0.001)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{ source_workload }}.{{ source_workload_namespace}}", + "refId": "B", + "step": 2 + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Bytes Sent to Incoming TCP Connection", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "Bps", + "label": null, + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "content": "
\nSERVICE WORKLOADS\n
", + "gridPos": { + "h": 3, + "w": 24, + "x": 0, + "y": 32 + }, + "id": 69, + "links": [], + "mode": "html", + "title": "", + "transparent": true, + "type": "text" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 0, + "gridPos": { + "h": 6, + "w": 12, + "x": 0, + "y": 35 + }, + "id": 90, + "legend": { + "avg": false, + "current": false, + "hideEmpty": true, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null as zero", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "round(sum(irate(istio_requests_total{connection_security_policy=\"mutual_tls\",destination_service=~\"$service\",reporter=\"destination\",destination_workload=~\"$dstwl\",destination_workload_namespace=~\"$dstns\"}[5m])) by (destination_workload, destination_workload_namespace, response_code), 0.001)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{ destination_workload }}.{{ destination_workload_namespace }} : {{ response_code }} (🔐mTLS)", + "refId": "B", + "step": 2 + }, + { + "expr": "round(sum(irate(istio_requests_total{connection_security_policy!=\"mutual_tls\", destination_service=~\"$service\", reporter=\"destination\", destination_workload=~\"$dstwl\", destination_workload_namespace=~\"$dstns\"}[5m])) by (destination_workload, destination_workload_namespace, response_code), 0.001)", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_workload }}.{{ destination_workload_namespace }} : {{ response_code }}", + "refId": "A", + "step": 2 + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Incoming Requests by Destination And Response Code", + "tooltip": { + "shared": false, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [ + "total" + ] + }, + "yaxes": [ + { + "format": "ops", + "label": null, + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 6, + "w": 12, + "x": 12, + "y": 35 + }, + "id": 91, + "legend": { + "avg": false, + "current": false, + "hideEmpty": true, + "hideZero": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(irate(istio_requests_total{reporter=\"destination\", connection_security_policy=\"mutual_tls\", destination_service=~\"$service\",response_code!~\"5.*\", destination_workload=~\"$dstwl\", destination_workload_namespace=~\"$dstns\"}[5m])) by (destination_workload, destination_workload_namespace) / sum(irate(istio_requests_total{reporter=\"destination\", connection_security_policy=\"mutual_tls\", destination_service=~\"$service\", destination_workload=~\"$dstwl\", destination_workload_namespace=~\"$dstns\"}[5m])) by (destination_workload, destination_workload_namespace)", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_workload }}.{{ destination_workload_namespace }} (🔐mTLS)", + "refId": "A", + "step": 2 + }, + { + "expr": "sum(irate(istio_requests_total{reporter=\"destination\", connection_security_policy!=\"mutual_tls\", destination_service=~\"$service\",response_code!~\"5.*\", destination_workload=~\"$dstwl\", destination_workload_namespace=~\"$dstns\"}[5m])) by (destination_workload, destination_workload_namespace) / sum(irate(istio_requests_total{reporter=\"destination\", connection_security_policy!=\"mutual_tls\", destination_service=~\"$service\", destination_workload=~\"$dstwl\", destination_workload_namespace=~\"$dstns\"}[5m])) by (destination_workload, destination_workload_namespace)", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_workload }}.{{ destination_workload_namespace }}", + "refId": "B", + "step": 2 + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Incoming Success Rate (non-5xx responses) By Source", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "percentunit", + "label": null, + "logBase": 1, + "max": "1.01", + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "description": "", + "fill": 1, + "gridPos": { + "h": 6, + "w": 8, + "x": 0, + "y": 41 + }, + "id": 94, + "legend": { + "alignAsTable": false, + "avg": false, + "current": false, + "hideEmpty": true, + "hideZero": false, + "max": false, + "min": false, + "rightSide": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "(histogram_quantile(0.50, sum(irate(istio_request_duration_milliseconds_bucket{reporter=\"destination\", connection_security_policy=\"mutual_tls\", destination_service=~\"$service\", destination_workload=~\"$dstwl\", destination_workload_namespace=~\"$dstns\"}[1m])) by (destination_workload, destination_workload_namespace, le)) / 1000) or histogram_quantile(0.50, sum(irate(istio_request_duration_seconds_bucket{reporter=\"destination\", connection_security_policy=\"mutual_tls\", destination_service=~\"$service\", destination_workload=~\"$dstwl\", destination_workload_namespace=~\"$dstns\"}[1m])) by (destination_workload, destination_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_workload }}.{{ destination_workload_namespace }} P50 (🔐mTLS)", + "refId": "D", + "step": 2 + }, + { + "expr": "(histogram_quantile(0.90, sum(irate(istio_request_duration_milliseconds_bucket{reporter=\"destination\", connection_security_policy=\"mutual_tls\", destination_service=~\"$service\", destination_workload=~\"$dstwl\", destination_workload_namespace=~\"$dstns\"}[1m])) by (destination_workload, destination_workload_namespace, le)) / 1000) or histogram_quantile(0.90, sum(irate(istio_request_duration_seconds_bucket{reporter=\"destination\", connection_security_policy=\"mutual_tls\", destination_service=~\"$service\", destination_workload=~\"$dstwl\", destination_workload_namespace=~\"$dstns\"}[1m])) by (destination_workload, destination_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_workload }}.{{ destination_workload_namespace }} P90 (🔐mTLS)", + "refId": "A", + "step": 2 + }, + { + "expr": "(histogram_quantile(0.95, sum(irate(istio_request_duration_milliseconds_bucket{reporter=\"destination\", connection_security_policy=\"mutual_tls\", destination_service=~\"$service\", destination_workload=~\"$dstwl\", destination_workload_namespace=~\"$dstns\"}[1m])) by (destination_workload, destination_workload_namespace, le)) / 1000) or histogram_quantile(0.95, sum(irate(istio_request_duration_seconds_bucket{reporter=\"destination\", connection_security_policy=\"mutual_tls\", destination_service=~\"$service\", destination_workload=~\"$dstwl\", destination_workload_namespace=~\"$dstns\"}[1m])) by (destination_workload, destination_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_workload }}.{{ destination_workload_namespace }} P95 (🔐mTLS)", + "refId": "B", + "step": 2 + }, + { + "expr": "(histogram_quantile(0.99, sum(irate(istio_request_duration_milliseconds_bucket{reporter=\"destination\", connection_security_policy=\"mutual_tls\", destination_service=~\"$service\", destination_workload=~\"$dstwl\", destination_workload_namespace=~\"$dstns\"}[1m])) by (destination_workload, destination_workload_namespace, le)) / 1000) or histogram_quantile(0.99, sum(irate(istio_request_duration_seconds_bucket{reporter=\"destination\", connection_security_policy=\"mutual_tls\", destination_service=~\"$service\", destination_workload=~\"$dstwl\", destination_workload_namespace=~\"$dstns\"}[1m])) by (destination_workload, destination_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_workload }}.{{ destination_workload_namespace }} P99 (🔐mTLS)", + "refId": "C", + "step": 2 + }, + { + "expr": "(histogram_quantile(0.50, sum(irate(istio_request_duration_milliseconds_bucket{reporter=\"destination\", connection_security_policy!=\"mutual_tls\", destination_service=~\"$service\", destination_workload=~\"$dstwl\", destination_workload_namespace=~\"$dstns\"}[1m])) by (destination_workload, destination_workload_namespace, le)) / 1000) or histogram_quantile(0.50, sum(irate(istio_request_duration_seconds_bucket{reporter=\"destination\", connection_security_policy!=\"mutual_tls\", destination_service=~\"$service\", destination_workload=~\"$dstwl\", destination_workload_namespace=~\"$dstns\"}[1m])) by (destination_workload, destination_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_workload }}.{{ destination_workload_namespace }} P50", + "refId": "E", + "step": 2 + }, + { + "expr": "(histogram_quantile(0.90, sum(irate(istio_request_duration_milliseconds_bucket{reporter=\"destination\", connection_security_policy!=\"mutual_tls\", destination_service=~\"$service\", destination_workload=~\"$dstwl\", destination_workload_namespace=~\"$dstns\"}[1m])) by (destination_workload, destination_workload_namespace, le)) / 1000) or histogram_quantile(0.90, sum(irate(istio_request_duration_seconds_bucket{reporter=\"destination\", connection_security_policy!=\"mutual_tls\", destination_service=~\"$service\", destination_workload=~\"$dstwl\", destination_workload_namespace=~\"$dstns\"}[1m])) by (destination_workload, destination_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_workload }}.{{ destination_workload_namespace }} P90", + "refId": "F", + "step": 2 + }, + { + "expr": "(histogram_quantile(0.95, sum(irate(istio_request_duration_milliseconds_bucket{reporter=\"destination\", connection_security_policy!=\"mutual_tls\", destination_service=~\"$service\", destination_workload=~\"$dstwl\", destination_workload_namespace=~\"$dstns\"}[1m])) by (destination_workload, destination_workload_namespace, le)) / 1000) or histogram_quantile(0.95, sum(irate(istio_request_duration_seconds_bucket{reporter=\"destination\", connection_security_policy!=\"mutual_tls\", destination_service=~\"$service\", destination_workload=~\"$dstwl\", destination_workload_namespace=~\"$dstns\"}[1m])) by (destination_workload, destination_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_workload }}.{{ destination_workload_namespace }} P95", + "refId": "G", + "step": 2 + }, + { + "expr": "(histogram_quantile(0.99, sum(irate(istio_request_duration_milliseconds_bucket{reporter=\"destination\", connection_security_policy!=\"mutual_tls\", destination_service=~\"$service\", destination_workload=~\"$dstwl\", destination_workload_namespace=~\"$dstns\"}[1m])) by (destination_workload, destination_workload_namespace, le)) / 1000) or histogram_quantile(0.99, sum(irate(istio_request_duration_seconds_bucket{reporter=\"destination\", connection_security_policy!=\"mutual_tls\", destination_service=~\"$service\", destination_workload=~\"$dstwl\", destination_workload_namespace=~\"$dstns\"}[1m])) by (destination_workload, destination_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_workload }}.{{ destination_workload_namespace }} P99", + "refId": "H", + "step": 2 + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Incoming Request Duration by Source", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "s", + "label": null, + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 6, + "w": 8, + "x": 8, + "y": 41 + }, + "id": 95, + "legend": { + "alignAsTable": false, + "avg": false, + "current": false, + "hideEmpty": true, + "max": false, + "min": false, + "rightSide": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "histogram_quantile(0.50, sum(irate(istio_request_bytes_bucket{reporter=\"destination\", connection_security_policy=\"mutual_tls\", destination_service=~\"$service\", destination_workload=~\"$dstwl\", destination_workload_namespace=~\"$dstns\"}[1m])) by (destination_workload, destination_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_workload }}.{{ destination_workload_namespace }} P50 (🔐mTLS)", + "refId": "D", + "step": 2 + }, + { + "expr": "histogram_quantile(0.90, sum(irate(istio_request_bytes_bucket{reporter=\"destination\", connection_security_policy=\"mutual_tls\", destination_service=~\"$service\", destination_workload=~\"$dstwl\", destination_workload_namespace=~\"$dstns\"}[1m])) by (destination_workload, destination_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_workload }}.{{ destination_workload_namespace }} P90 (🔐mTLS)", + "refId": "A", + "step": 2 + }, + { + "expr": "histogram_quantile(0.95, sum(irate(istio_request_bytes_bucket{reporter=\"destination\", connection_security_policy=\"mutual_tls\", destination_service=~\"$service\", destination_workload=~\"$dstwl\", destination_workload_namespace=~\"$dstns\"}[1m])) by (destination_workload, destination_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_workload }}.{{ destination_workload_namespace }} P95 (🔐mTLS)", + "refId": "B", + "step": 2 + }, + { + "expr": "histogram_quantile(0.99, sum(irate(istio_request_bytes_bucket{reporter=\"destination\", connection_security_policy=\"mutual_tls\", destination_service=~\"$service\", destination_workload=~\"$dstwl\", destination_workload_namespace=~\"$dstns\"}[1m])) by (destination_workload, destination_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_workload }}.{{ destination_workload_namespace }} P99 (🔐mTLS)", + "refId": "C", + "step": 2 + }, + { + "expr": "histogram_quantile(0.50, sum(irate(istio_request_bytes_bucket{reporter=\"destination\", connection_security_policy!=\"mutual_tls\", destination_service=~\"$service\", destination_workload=~\"$dstwl\", destination_workload_namespace=~\"$dstns\"}[1m])) by (destination_workload, destination_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_workload }}.{{ destination_workload_namespace }} P50", + "refId": "E", + "step": 2 + }, + { + "expr": "histogram_quantile(0.90, sum(irate(istio_request_bytes_bucket{reporter=\"destination\", connection_security_policy!=\"mutual_tls\", destination_service=~\"$service\", destination_workload=~\"$dstwl\", destination_workload_namespace=~\"$dstns\"}[1m])) by (destination_workload, destination_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_workload }}.{{ destination_workload_namespace }} P90", + "refId": "F", + "step": 2 + }, + { + "expr": "histogram_quantile(0.95, sum(irate(istio_request_bytes_bucket{reporter=\"destination\", connection_security_policy!=\"mutual_tls\", destination_service=~\"$service\", destination_workload=~\"$dstwl\", destination_workload_namespace=~\"$dstns\"}[1m])) by (destination_workload, destination_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_workload }}.{{ destination_workload_namespace }} P95", + "refId": "G", + "step": 2 + }, + { + "expr": "histogram_quantile(0.99, sum(irate(istio_request_bytes_bucket{reporter=\"destination\", connection_security_policy!=\"mutual_tls\", destination_service=~\"$service\", destination_workload=~\"$dstwl\", destination_workload_namespace=~\"$dstns\"}[1m])) by (destination_workload, destination_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_workload }}.{{ destination_workload_namespace }} P99", + "refId": "H", + "step": 2 + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Incoming Request Size By Source", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "decbytes", + "label": null, + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 6, + "w": 8, + "x": 16, + "y": 41 + }, + "id": 96, + "legend": { + "alignAsTable": false, + "avg": false, + "current": false, + "hideEmpty": true, + "max": false, + "min": false, + "rightSide": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "histogram_quantile(0.50, sum(irate(istio_response_bytes_bucket{reporter=\"destination\", connection_security_policy=\"mutual_tls\", destination_service=~\"$service\", destination_workload=~\"$dstwl\", destination_workload_namespace=~\"$dstns\"}[1m])) by (destination_workload, destination_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_workload }}.{{ destination_workload_namespace }} P50 (🔐mTLS)", + "refId": "D", + "step": 2 + }, + { + "expr": "histogram_quantile(0.90, sum(irate(istio_response_bytes_bucket{reporter=\"destination\", connection_security_policy=\"mutual_tls\", destination_service=~\"$service\", destination_workload=~\"$dstwl\", destination_workload_namespace=~\"$dstns\"}[1m])) by (destination_workload, destination_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_workload }}.{{ destination_workload_namespace }} P90 (🔐mTLS)", + "refId": "A", + "step": 2 + }, + { + "expr": "histogram_quantile(0.95, sum(irate(istio_response_bytes_bucket{reporter=\"destination\", connection_security_policy=\"mutual_tls\", destination_service=~\"$service\", destination_workload=~\"$dstwl\", destination_workload_namespace=~\"$dstns\"}[1m])) by (destination_workload, destination_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_workload }}.{{ destination_workload_namespace }} P95 (🔐mTLS)", + "refId": "B", + "step": 2 + }, + { + "expr": "histogram_quantile(0.99, sum(irate(istio_response_bytes_bucket{reporter=\"destination\", connection_security_policy=\"mutual_tls\", destination_service=~\"$service\", destination_workload=~\"$dstwl\", destination_workload_namespace=~\"$dstns\"}[1m])) by (destination_workload, destination_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_workload }}.{{ destination_workload_namespace }} P99 (🔐mTLS)", + "refId": "C", + "step": 2 + }, + { + "expr": "histogram_quantile(0.50, sum(irate(istio_response_bytes_bucket{reporter=\"destination\", connection_security_policy!=\"mutual_tls\", destination_service=~\"$service\", destination_workload=~\"$dstwl\", destination_workload_namespace=~\"$dstns\"}[1m])) by (destination_workload, destination_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_workload }}.{{ destination_workload_namespace }} P50", + "refId": "E", + "step": 2 + }, + { + "expr": "histogram_quantile(0.90, sum(irate(istio_response_bytes_bucket{reporter=\"destination\", connection_security_policy!=\"mutual_tls\", destination_service=~\"$service\", destination_workload=~\"$dstwl\", destination_workload_namespace=~\"$dstns\"}[1m])) by (destination_workload, destination_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_workload }}.{{ destination_workload_namespace }} P90", + "refId": "F", + "step": 2 + }, + { + "expr": "histogram_quantile(0.95, sum(irate(istio_response_bytes_bucket{reporter=\"destination\", connection_security_policy!=\"mutual_tls\", destination_service=~\"$service\", destination_workload=~\"$dstwl\", destination_workload_namespace=~\"$dstns\"}[1m])) by (destination_workload, destination_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_workload }}.{{ destination_workload_namespace }} P95", + "refId": "G", + "step": 2 + }, + { + "expr": "histogram_quantile(0.99, sum(irate(istio_response_bytes_bucket{reporter=\"destination\", connection_security_policy!=\"mutual_tls\", destination_service=~\"$service\", destination_workload=~\"$dstwl\", destination_workload_namespace=~\"$dstns\"}[1m])) by (destination_workload, destination_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_workload }}.{{ destination_workload_namespace }} P99", + "refId": "H", + "step": 2 + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Response Size By Source", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "decbytes", + "label": null, + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 6, + "w": 12, + "x": 0, + "y": 47 + }, + "id": 92, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "round(sum(irate(istio_tcp_received_bytes_total{reporter=\"source\", connection_security_policy=\"mutual_tls\", destination_service=~\"$service\", destination_workload=~\"$dstwl\", destination_workload_namespace=~\"$dstns\"}[1m])) by (destination_workload, destination_workload_namespace), 0.001)", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_workload }}.{{ destination_workload_namespace}} (🔐mTLS)", + "refId": "A", + "step": 2 + }, + { + "expr": "round(sum(irate(istio_tcp_received_bytes_total{reporter=\"source\", connection_security_policy!=\"mutual_tls\", destination_service=~\"$service\", destination_workload=~\"$dstwl\", destination_workload_namespace=~\"$dstns\"}[1m])) by (destination_workload, destination_workload_namespace), 0.001)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{ destination_workload }}.{{ destination_workload_namespace}}", + "refId": "B", + "step": 2 + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Bytes Received from Incoming TCP Connection", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "Bps", + "label": null, + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 6, + "w": 12, + "x": 12, + "y": 47 + }, + "id": 93, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "round(sum(irate(istio_tcp_sent_bytes_total{connection_security_policy=\"mutual_tls\", reporter=\"source\", destination_service=~\"$service\", destination_workload=~\"$dstwl\", destination_workload_namespace=~\"$dstns\"}[1m])) by (destination_workload, destination_workload_namespace), 0.001)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{ destination_workload }}.{{destination_workload_namespace }} (🔐mTLS)", + "refId": "A", + "step": 2 + }, + { + "expr": "round(sum(irate(istio_tcp_sent_bytes_total{connection_security_policy!=\"mutual_tls\", reporter=\"source\", destination_service=~\"$service\", destination_workload=~\"$dstwl\", destination_workload_namespace=~\"$dstns\"}[1m])) by (destination_workload, destination_workload_namespace), 0.001)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{ destination_workload }}.{{destination_workload_namespace }}", + "refId": "B", + "step": 2 + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Bytes Sent to Incoming TCP Connection", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "Bps", + "label": null, + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + } + ], + "refresh": "10s", + "schemaVersion": 16, + "style": "dark", + "tags": [], + "templating": { + "list": [ + { + "allValue": null, + "datasource": "Prometheus", + "hide": 0, + "includeAll": false, + "label": "Service", + "multi": false, + "name": "service", + "options": [], + "query": "label_values(destination_service)", + "refresh": 1, + "regex": "", + "sort": 0, + "tagValuesQuery": "", + "tags": [], + "tagsQuery": "", + "type": "query", + "useTags": false + }, + { + "allValue": null, + "current": { + "text": "All", + "value": "$__all" + }, + "datasource": "Prometheus", + "hide": 0, + "includeAll": true, + "label": "Client Workload Namespace", + "multi": true, + "name": "srcns", + "options": [], + "query": "query_result( sum(istio_requests_total{reporter=\"destination\", destination_service=\"$service\"}) by (source_workload_namespace) or sum(istio_tcp_sent_bytes_total{reporter=\"destination\", destination_service=~\"$service\"}) by (source_workload_namespace))", + "refresh": 1, + "regex": "/.*namespace=\"([^\"]*).*/", + "sort": 2, + "tagValuesQuery": "", + "tags": [], + "tagsQuery": "", + "type": "query", + "useTags": false + }, + { + "allValue": null, + "current": { + "text": "All", + "value": "$__all" + }, + "datasource": "Prometheus", + "hide": 0, + "includeAll": true, + "label": "Client Workload", + "multi": true, + "name": "srcwl", + "options": [], + "query": "query_result( sum(istio_requests_total{reporter=\"destination\", destination_service=~\"$service\", source_workload_namespace=~\"$srcns\"}) by (source_workload) or sum(istio_tcp_sent_bytes_total{reporter=\"destination\", destination_service=~\"$service\", source_workload_namespace=~\"$srcns\"}) by (source_workload))", + "refresh": 1, + "regex": "/.*workload=\"([^\"]*).*/", + "sort": 3, + "tagValuesQuery": "", + "tags": [], + "tagsQuery": "", + "type": "query", + "useTags": false + }, + { + "allValue": null, + "current": { + "text": "All", + "value": "$__all" + }, + "datasource": "Prometheus", + "hide": 0, + "includeAll": true, + "label": "Service Workload Namespace", + "multi": true, + "name": "dstns", + "options": [], + "query": "query_result( sum(istio_requests_total{reporter=\"destination\", destination_service=\"$service\"}) by (destination_workload_namespace) or sum(istio_tcp_sent_bytes_total{reporter=\"destination\", destination_service=~\"$service\"}) by (destination_workload_namespace))", + "refresh": 1, + "regex": "/.*namespace=\"([^\"]*).*/", + "sort": 2, + "tagValuesQuery": "", + "tags": [], + "tagsQuery": "", + "type": "query", + "useTags": false + }, + { + "allValue": null, + "current": { + "text": "All", + "value": "$__all" + }, + "datasource": "Prometheus", + "hide": 0, + "includeAll": true, + "label": "Service Workload", + "multi": true, + "name": "dstwl", + "options": [], + "query": "query_result( sum(istio_requests_total{reporter=\"destination\", destination_service=~\"$service\", destination_workload_namespace=~\"$dstns\"}) by (destination_workload) or sum(istio_tcp_sent_bytes_total{reporter=\"destination\", destination_service=~\"$service\", destination_workload_namespace=~\"$dstns\"}) by (destination_workload))", + "refresh": 1, + "regex": "/.*workload=\"([^\"]*).*/", + "sort": 3, + "tagValuesQuery": "", + "tags": [], + "tagsQuery": "", + "type": "query", + "useTags": false + } + ] + }, + "time": { + "from": "now-5m", + "to": "now" + }, + "timepicker": { + "refresh_intervals": [ + "5s", + "10s", + "30s", + "1m", + "5m", + "15m", + "30m", + "1h", + "2h", + "1d" + ], + "time_options": [ + "5m", + "15m", + "1h", + "6h", + "12h", + "24h", + "2d", + "7d", + "30d" + ] + }, + "timezone": "", + "title": "Istio Service Dashboard", + "uid": "LJ_uJAvmk", + "version": 1 +} diff --git a/istio-1.5.0/install/kubernetes/operator/charts/istio-telemetry/grafana/dashboards/istio-workload-dashboard.json b/istio-1.5.0/install/kubernetes/operator/charts/istio-telemetry/grafana/dashboards/istio-workload-dashboard.json new file mode 100644 index 0000000..62ad1b5 --- /dev/null +++ b/istio-1.5.0/install/kubernetes/operator/charts/istio-telemetry/grafana/dashboards/istio-workload-dashboard.json @@ -0,0 +1,2303 @@ +{ + "__inputs": [ + { + "name": "DS_PROMETHEUS", + "label": "Prometheus", + "description": "", + "type": "datasource", + "pluginId": "prometheus", + "pluginName": "Prometheus" + } + ], + "__requires": [ + { + "type": "grafana", + "id": "grafana", + "name": "Grafana", + "version": "5.0.4" + }, + { + "type": "panel", + "id": "graph", + "name": "Graph", + "version": "5.0.0" + }, + { + "type": "datasource", + "id": "prometheus", + "name": "Prometheus", + "version": "5.0.0" + }, + { + "type": "panel", + "id": "singlestat", + "name": "Singlestat", + "version": "5.0.0" + }, + { + "type": "panel", + "id": "text", + "name": "Text", + "version": "5.0.0" + } + ], + "annotations": { + "list": [ + { + "builtIn": 1, + "datasource": "-- Grafana --", + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations & Alerts", + "type": "dashboard" + } + ] + }, + "editable": false, + "gnetId": null, + "graphTooltip": 0, + "id": null, + "iteration": 1531345461465, + "links": [], + "panels": [ + { + "content": "
\nWORKLOAD: $workload.$namespace\n
", + "gridPos": { + "h": 3, + "w": 24, + "x": 0, + "y": 0 + }, + "id": 89, + "links": [], + "mode": "html", + "title": "", + "transparent": true, + "type": "text" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "datasource": "Prometheus", + "format": "ops", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "gridPos": { + "h": 4, + "w": 8, + "x": 0, + "y": 3 + }, + "id": 12, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": true, + "lineColor": "rgb(31, 120, 193)", + "show": true + }, + "tableColumn": "", + "targets": [ + { + "expr": "round(sum(irate(istio_requests_total{reporter=\"destination\",destination_workload_namespace=~\"$namespace\",destination_workload=~\"$workload\"}[5m])), 0.001)", + "format": "time_series", + "intervalFactor": 1, + "refId": "A", + "step": 4 + } + ], + "thresholds": "", + "title": "Incoming Request Volume", + "transparent": false, + "type": "singlestat", + "valueFontSize": "80%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "current" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "rgba(50, 172, 45, 0.97)", + "rgba(237, 129, 40, 0.89)", + "rgba(245, 54, 54, 0.9)" + ], + "datasource": "Prometheus", + "decimals": null, + "format": "percentunit", + "gauge": { + "maxValue": 100, + "minValue": 80, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": false + }, + "gridPos": { + "h": 4, + "w": 8, + "x": 8, + "y": 3 + }, + "id": 14, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": true, + "lineColor": "rgb(31, 120, 193)", + "show": true + }, + "tableColumn": "", + "targets": [ + { + "expr": "sum(irate(istio_requests_total{reporter=\"destination\",destination_workload_namespace=~\"$namespace\",destination_workload=~\"$workload\",response_code!~\"5.*\"}[5m])) / sum(irate(istio_requests_total{reporter=\"destination\",destination_workload_namespace=~\"$namespace\",destination_workload=~\"$workload\"}[5m]))", + "format": "time_series", + "intervalFactor": 1, + "refId": "B" + } + ], + "thresholds": "95, 99, 99.5", + "title": "Incoming Success Rate (non-5xx responses)", + "transparent": false, + "type": "singlestat", + "valueFontSize": "80%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "avg" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 4, + "w": 8, + "x": 16, + "y": 3 + }, + "id": 87, + "legend": { + "alignAsTable": false, + "avg": false, + "current": false, + "hideEmpty": false, + "hideZero": false, + "max": false, + "min": false, + "rightSide": true, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "(histogram_quantile(0.50, sum(irate(istio_request_duration_milliseconds_bucket{reporter=\"destination\",destination_workload=~\"$workload\", destination_workload_namespace=~\"$namespace\"}[1m])) by (le)) / 1000) or histogram_quantile(0.50, sum(irate(istio_request_duration_seconds_bucket{reporter=\"destination\",destination_workload=~\"$workload\", destination_workload_namespace=~\"$namespace\"}[1m])) by (le))", + "format": "time_series", + "interval": "", + "intervalFactor": 1, + "legendFormat": "P50", + "refId": "A" + }, + { + "expr": "(histogram_quantile(0.50, sum(irate(istio_request_duration_milliseconds_bucket{reporter=\"destination\",destination_workload=~\"$workload\", destination_workload_namespace=~\"$namespace\"}[1m])) by (le)) / 1000) or histogram_quantile(0.90, sum(irate(istio_request_duration_seconds_bucket{reporter=\"destination\",destination_workload=~\"$workload\", destination_workload_namespace=~\"$namespace\"}[1m])) by (le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "P90", + "refId": "B" + }, + { + "expr": "(histogram_quantile(0.50, sum(irate(istio_request_duration_milliseconds_bucket{reporter=\"destination\",destination_workload=~\"$workload\", destination_workload_namespace=~\"$namespace\"}[1m])) by (le)) / 1000) or histogram_quantile(0.99, sum(irate(istio_request_duration_seconds_bucket{reporter=\"destination\",destination_workload=~\"$workload\", destination_workload_namespace=~\"$namespace\"}[1m])) by (le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "P99", + "refId": "C" + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Request Duration", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "s", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ] + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "#299c46", + "rgba(237, 129, 40, 0.89)", + "#d44a3a" + ], + "datasource": "Prometheus", + "format": "Bps", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "gridPos": { + "h": 4, + "w": 12, + "x": 0, + "y": 7 + }, + "id": 84, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": true, + "lineColor": "rgb(31, 120, 193)", + "show": true + }, + "tableColumn": "", + "targets": [ + { + "expr": "sum(irate(istio_tcp_sent_bytes_total{reporter=\"destination\", destination_workload_namespace=~\"$namespace\", destination_workload=~\"$workload\"}[1m])) + sum(irate(istio_tcp_received_bytes_total{reporter=\"destination\", destination_workload_namespace=~\"$namespace\", destination_workload=~\"$workload\"}[1m]))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "", + "refId": "A" + } + ], + "thresholds": "", + "title": "TCP Server Traffic", + "transparent": false, + "type": "singlestat", + "valueFontSize": "80%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "avg" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "#299c46", + "rgba(237, 129, 40, 0.89)", + "#d44a3a" + ], + "datasource": "Prometheus", + "format": "Bps", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "gridPos": { + "h": 4, + "w": 12, + "x": 12, + "y": 7 + }, + "id": 85, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": true, + "lineColor": "rgb(31, 120, 193)", + "show": true + }, + "tableColumn": "", + "targets": [ + { + "expr": "sum(irate(istio_tcp_sent_bytes_total{reporter=\"source\", source_workload_namespace=~\"$namespace\", source_workload=~\"$workload\"}[1m])) + sum(irate(istio_tcp_received_bytes_total{reporter=\"source\", source_workload_namespace=~\"$namespace\", source_workload=~\"$workload\"}[1m]))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "", + "refId": "A" + } + ], + "thresholds": "", + "title": "TCP Client Traffic", + "transparent": false, + "type": "singlestat", + "valueFontSize": "80%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "avg" + }, + { + "content": "
\nINBOUND WORKLOADS\n
", + "gridPos": { + "h": 3, + "w": 24, + "x": 0, + "y": 11 + }, + "id": 45, + "links": [], + "mode": "html", + "title": "", + "transparent": true, + "type": "text" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 0, + "gridPos": { + "h": 6, + "w": 12, + "x": 0, + "y": 14 + }, + "id": 25, + "legend": { + "avg": false, + "current": false, + "hideEmpty": true, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null as zero", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "round(sum(irate(istio_requests_total{connection_security_policy=\"mutual_tls\", destination_workload_namespace=~\"$namespace\", destination_workload=~\"$workload\", reporter=\"destination\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[5m])) by (source_workload, source_workload_namespace, response_code), 0.001)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{ source_workload }}.{{ source_workload_namespace }} : {{ response_code }} (🔐mTLS)", + "refId": "B", + "step": 2 + }, + { + "expr": "round(sum(irate(istio_requests_total{connection_security_policy!=\"mutual_tls\", destination_workload_namespace=~\"$namespace\", destination_workload=~\"$workload\", reporter=\"destination\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[5m])) by (source_workload, source_workload_namespace, response_code), 0.001)", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ source_workload }}.{{ source_workload_namespace }} : {{ response_code }}", + "refId": "A", + "step": 2 + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Incoming Requests by Source And Response Code", + "tooltip": { + "shared": false, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [ + "total" + ] + }, + "yaxes": [ + { + "format": "ops", + "label": null, + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ] + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 6, + "w": 12, + "x": 12, + "y": 14 + }, + "id": 26, + "legend": { + "avg": false, + "current": false, + "hideEmpty": true, + "hideZero": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(irate(istio_requests_total{reporter=\"destination\", connection_security_policy=\"mutual_tls\", destination_workload_namespace=~\"$namespace\", destination_workload=~\"$workload\",response_code!~\"5.*\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[5m])) by (source_workload, source_workload_namespace) / sum(irate(istio_requests_total{reporter=\"destination\", connection_security_policy=\"mutual_tls\", destination_workload_namespace=~\"$namespace\", destination_workload=~\"$workload\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[5m])) by (source_workload, source_workload_namespace)", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ source_workload }}.{{ source_workload_namespace }} (🔐mTLS)", + "refId": "A", + "step": 2 + }, + { + "expr": "sum(irate(istio_requests_total{reporter=\"destination\", connection_security_policy!=\"mutual_tls\", destination_workload_namespace=~\"$namespace\", destination_workload=~\"$workload\",response_code!~\"5.*\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[5m])) by (source_workload, source_workload_namespace) / sum(irate(istio_requests_total{reporter=\"destination\", connection_security_policy!=\"mutual_tls\", destination_workload_namespace=~\"$namespace\", destination_workload=~\"$workload\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[5m])) by (source_workload, source_workload_namespace)", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ source_workload }}.{{ source_workload_namespace }}", + "refId": "B", + "step": 2 + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Incoming Success Rate (non-5xx responses) By Source", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "percentunit", + "label": null, + "logBase": 1, + "max": "1.01", + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ] + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "description": "", + "fill": 1, + "gridPos": { + "h": 6, + "w": 8, + "x": 0, + "y": 20 + }, + "id": 27, + "legend": { + "alignAsTable": false, + "avg": false, + "current": false, + "hideEmpty": true, + "hideZero": false, + "max": false, + "min": false, + "rightSide": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "(histogram_quantile(0.50, sum(irate(istio_request_duration_milliseconds_bucket{reporter=\"destination\", connection_security_policy=\"mutual_tls\", destination_workload=~\"$workload\", destination_workload_namespace=~\"$namespace\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le)) / 1000) or histogram_quantile(0.50, sum(irate(istio_request_duration_seconds_bucket{reporter=\"destination\", connection_security_policy=\"mutual_tls\", destination_workload=~\"$workload\", destination_workload_namespace=~\"$namespace\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{source_workload}}.{{source_workload_namespace}} P50 (🔐mTLS)", + "refId": "D", + "step": 2 + }, + { + "expr": "(histogram_quantile(0.90, sum(irate(istio_request_duration_milliseconds_bucket{reporter=\"destination\", connection_security_policy=\"mutual_tls\", destination_workload=~\"$workload\", destination_workload_namespace=~\"$namespace\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le)) / 1000) or histogram_quantile(0.90, sum(irate(istio_request_duration_seconds_bucket{reporter=\"destination\", connection_security_policy=\"mutual_tls\", destination_workload=~\"$workload\", destination_workload_namespace=~\"$namespace\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{source_workload}}.{{source_workload_namespace}} P90 (🔐mTLS)", + "refId": "A", + "step": 2 + }, + { + "expr": "(histogram_quantile(0.95, sum(irate(istio_request_duration_milliseconds_bucket{reporter=\"destination\", connection_security_policy=\"mutual_tls\", destination_workload=~\"$workload\", destination_workload_namespace=~\"$namespace\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le)) / 1000) or histogram_quantile(0.95, sum(irate(istio_request_duration_seconds_bucket{reporter=\"destination\", connection_security_policy=\"mutual_tls\", destination_workload=~\"$workload\", destination_workload_namespace=~\"$namespace\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{source_workload}}.{{source_workload_namespace}} P95 (🔐mTLS)", + "refId": "B", + "step": 2 + }, + { + "expr": "(histogram_quantile(0.99, sum(irate(istio_request_duration_milliseconds_bucket{reporter=\"destination\", connection_security_policy=\"mutual_tls\", destination_workload=~\"$workload\", destination_workload_namespace=~\"$namespace\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le)) / 1000) or histogram_quantile(0.99, sum(irate(istio_request_duration_seconds_bucket{reporter=\"destination\", connection_security_policy=\"mutual_tls\", destination_workload=~\"$workload\", destination_workload_namespace=~\"$namespace\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{source_workload}}.{{source_workload_namespace}} P99 (🔐mTLS)", + "refId": "C", + "step": 2 + }, + { + "expr": "(histogram_quantile(0.50, sum(irate(istio_request_duration_milliseconds_bucket{reporter=\"destination\", connection_security_policy!=\"mutual_tls\", destination_workload=~\"$workload\", destination_workload_namespace=~\"$namespace\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le)) / 1000) or histogram_quantile(0.50, sum(irate(istio_request_duration_seconds_bucket{reporter=\"destination\", connection_security_policy!=\"mutual_tls\", destination_workload=~\"$workload\", destination_workload_namespace=~\"$namespace\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{source_workload}}.{{source_workload_namespace}} P50", + "refId": "E", + "step": 2 + }, + { + "expr": "(histogram_quantile(0.90, sum(irate(istio_request_duration_milliseconds_bucket{reporter=\"destination\", connection_security_policy!=\"mutual_tls\", destination_workload=~\"$workload\", destination_workload_namespace=~\"$namespace\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le)) / 1000) or histogram_quantile(0.90, sum(irate(istio_request_duration_seconds_bucket{reporter=\"destination\", connection_security_policy!=\"mutual_tls\", destination_workload=~\"$workload\", destination_workload_namespace=~\"$namespace\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{source_workload}}.{{source_workload_namespace}} P90", + "refId": "F", + "step": 2 + }, + { + "expr": "(histogram_quantile(0.95, sum(irate(istio_request_duration_milliseconds_bucket{reporter=\"destination\", connection_security_policy!=\"mutual_tls\", destination_workload=~\"$workload\", destination_workload_namespace=~\"$namespace\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le)) / 1000) or histogram_quantile(0.95, sum(irate(istio_request_duration_seconds_bucket{reporter=\"destination\", connection_security_policy!=\"mutual_tls\", destination_workload=~\"$workload\", destination_workload_namespace=~\"$namespace\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{source_workload}}.{{source_workload_namespace}} P95", + "refId": "G", + "step": 2 + }, + { + "expr": "(histogram_quantile(0.99, sum(irate(istio_request_duration_milliseconds_bucket{reporter=\"destination\", connection_security_policy!=\"mutual_tls\", destination_workload=~\"$workload\", destination_workload_namespace=~\"$namespace\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le)) / 1000) or histogram_quantile(0.99, sum(irate(istio_request_duration_seconds_bucket{reporter=\"destination\", connection_security_policy!=\"mutual_tls\", destination_workload=~\"$workload\", destination_workload_namespace=~\"$namespace\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{source_workload}}.{{source_workload_namespace}} P99", + "refId": "H", + "step": 2 + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Incoming Request Duration by Source", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "s", + "label": null, + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ] + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 6, + "w": 8, + "x": 8, + "y": 20 + }, + "id": 28, + "legend": { + "alignAsTable": false, + "avg": false, + "current": false, + "hideEmpty": true, + "max": false, + "min": false, + "rightSide": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "histogram_quantile(0.50, sum(irate(istio_request_bytes_bucket{reporter=\"destination\", connection_security_policy=\"mutual_tls\", destination_workload=~\"$workload\", destination_workload_namespace=~\"$namespace\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{source_workload}}.{{source_workload_namespace}} P50 (🔐mTLS)", + "refId": "D", + "step": 2 + }, + { + "expr": "histogram_quantile(0.90, sum(irate(istio_request_bytes_bucket{reporter=\"destination\", connection_security_policy=\"mutual_tls\", destination_workload=~\"$workload\", destination_workload_namespace=~\"$namespace\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{source_workload}}.{{source_workload_namespace}} P90 (🔐mTLS)", + "refId": "A", + "step": 2 + }, + { + "expr": "histogram_quantile(0.95, sum(irate(istio_request_bytes_bucket{reporter=\"destination\", connection_security_policy=\"mutual_tls\", destination_workload=~\"$workload\", destination_workload_namespace=~\"$namespace\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{source_workload}}.{{source_workload_namespace}} P95 (🔐mTLS)", + "refId": "B", + "step": 2 + }, + { + "expr": "histogram_quantile(0.99, sum(irate(istio_request_bytes_bucket{reporter=\"destination\", connection_security_policy=\"mutual_tls\", destination_workload=~\"$workload\", destination_workload_namespace=~\"$namespace\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{source_workload}}.{{source_workload_namespace}} P99 (🔐mTLS)", + "refId": "C", + "step": 2 + }, + { + "expr": "histogram_quantile(0.50, sum(irate(istio_request_bytes_bucket{reporter=\"destination\", connection_security_policy!=\"mutual_tls\", destination_workload=~\"$workload\", destination_workload_namespace=~\"$namespace\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{source_workload}}.{{source_workload_namespace}} P50", + "refId": "E", + "step": 2 + }, + { + "expr": "histogram_quantile(0.90, sum(irate(istio_request_bytes_bucket{reporter=\"destination\", connection_security_policy!=\"mutual_tls\", destination_workload=~\"$workload\", destination_workload_namespace=~\"$namespace\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{source_workload}}.{{source_workload_namespace}} P90", + "refId": "F", + "step": 2 + }, + { + "expr": "histogram_quantile(0.95, sum(irate(istio_request_bytes_bucket{reporter=\"destination\", connection_security_policy!=\"mutual_tls\", destination_workload=~\"$workload\", destination_workload_namespace=~\"$namespace\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{source_workload}}.{{source_workload_namespace}} P95", + "refId": "G", + "step": 2 + }, + { + "expr": "histogram_quantile(0.99, sum(irate(istio_request_bytes_bucket{reporter=\"destination\", connection_security_policy!=\"mutual_tls\", destination_workload=~\"$workload\", destination_workload_namespace=~\"$namespace\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{source_workload}}.{{source_workload_namespace}} P99", + "refId": "H", + "step": 2 + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Incoming Request Size By Source", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "decbytes", + "label": null, + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ] + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 6, + "w": 8, + "x": 16, + "y": 20 + }, + "id": 68, + "legend": { + "alignAsTable": false, + "avg": false, + "current": false, + "hideEmpty": true, + "max": false, + "min": false, + "rightSide": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "histogram_quantile(0.50, sum(irate(istio_response_bytes_bucket{reporter=\"destination\", connection_security_policy=\"mutual_tls\", destination_workload=~\"$workload\", destination_workload_namespace=~\"$namespace\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{source_workload}}.{{source_workload_namespace}} P50 (🔐mTLS)", + "refId": "D", + "step": 2 + }, + { + "expr": "histogram_quantile(0.90, sum(irate(istio_response_bytes_bucket{reporter=\"destination\", connection_security_policy=\"mutual_tls\", destination_workload=~\"$workload\", destination_workload_namespace=~\"$namespace\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{source_workload}}.{{source_workload_namespace}} P90 (🔐mTLS)", + "refId": "A", + "step": 2 + }, + { + "expr": "histogram_quantile(0.95, sum(irate(istio_response_bytes_bucket{reporter=\"destination\", connection_security_policy=\"mutual_tls\", destination_workload=~\"$workload\", destination_workload_namespace=~\"$namespace\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{source_workload}}.{{source_workload_namespace}} P95 (🔐mTLS)", + "refId": "B", + "step": 2 + }, + { + "expr": "histogram_quantile(0.99, sum(irate(istio_response_bytes_bucket{reporter=\"destination\", connection_security_policy=\"mutual_tls\", destination_workload=~\"$workload\", destination_workload_namespace=~\"$namespace\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{source_workload}}.{{source_workload_namespace}} P99 (🔐mTLS)", + "refId": "C", + "step": 2 + }, + { + "expr": "histogram_quantile(0.50, sum(irate(istio_response_bytes_bucket{reporter=\"destination\", connection_security_policy!=\"mutual_tls\", destination_workload=~\"$workload\", destination_workload_namespace=~\"$namespace\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{source_workload}}.{{source_workload_namespace}} P50", + "refId": "E", + "step": 2 + }, + { + "expr": "histogram_quantile(0.90, sum(irate(istio_response_bytes_bucket{reporter=\"destination\", connection_security_policy!=\"mutual_tls\", destination_workload=~\"$workload\", destination_workload_namespace=~\"$namespace\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{source_workload}}.{{source_workload_namespace}} P90", + "refId": "F", + "step": 2 + }, + { + "expr": "histogram_quantile(0.95, sum(irate(istio_response_bytes_bucket{reporter=\"destination\", connection_security_policy!=\"mutual_tls\", destination_workload=~\"$workload\", destination_workload_namespace=~\"$namespace\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{source_workload}}.{{source_workload_namespace}} P95", + "refId": "G", + "step": 2 + }, + { + "expr": "histogram_quantile(0.99, sum(irate(istio_response_bytes_bucket{reporter=\"destination\", connection_security_policy!=\"mutual_tls\", destination_workload=~\"$workload\", destination_workload_namespace=~\"$namespace\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{source_workload}}.{{source_workload_namespace}} P99", + "refId": "H", + "step": 2 + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Response Size By Source", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "decbytes", + "label": null, + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ] + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 6, + "w": 12, + "x": 0, + "y": 26 + }, + "id": 80, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "round(sum(irate(istio_tcp_received_bytes_total{reporter=\"destination\", connection_security_policy=\"mutual_tls\", destination_workload_namespace=~\"$namespace\", destination_workload=~\"$workload\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace), 0.001)", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ source_workload }}.{{ source_workload_namespace}} (🔐mTLS)", + "refId": "A", + "step": 2 + }, + { + "expr": "round(sum(irate(istio_tcp_received_bytes_total{reporter=\"destination\", connection_security_policy!=\"mutual_tls\", destination_workload_namespace=~\"$namespace\", destination_workload=~\"$workload\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace), 0.001)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{ source_workload }}.{{ source_workload_namespace}}", + "refId": "B", + "step": 2 + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Bytes Received from Incoming TCP Connection", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "Bps", + "label": null, + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ] + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 6, + "w": 12, + "x": 12, + "y": 26 + }, + "id": 82, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "round(sum(irate(istio_tcp_sent_bytes_total{connection_security_policy=\"mutual_tls\", reporter=\"destination\", destination_workload_namespace=~\"$namespace\", destination_workload=~\"$workload\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace), 0.001)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{ source_workload }}.{{ source_workload_namespace}} (🔐mTLS)", + "refId": "A", + "step": 2 + }, + { + "expr": "round(sum(irate(istio_tcp_sent_bytes_total{connection_security_policy!=\"mutual_tls\", reporter=\"destination\", destination_workload_namespace=~\"$namespace\", destination_workload=~\"$workload\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace), 0.001)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{ source_workload }}.{{ source_workload_namespace}}", + "refId": "B", + "step": 2 + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Bytes Sent to Incoming TCP Connection", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "Bps", + "label": null, + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ] + }, + { + "content": "
\nOUTBOUND SERVICES\n
", + "gridPos": { + "h": 3, + "w": 24, + "x": 0, + "y": 32 + }, + "id": 69, + "links": [], + "mode": "html", + "title": "", + "transparent": true, + "type": "text" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 0, + "gridPos": { + "h": 6, + "w": 12, + "x": 0, + "y": 35 + }, + "id": 70, + "legend": { + "avg": false, + "current": false, + "hideEmpty": true, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null as zero", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "round(sum(irate(istio_requests_total{connection_security_policy=\"mutual_tls\", source_workload_namespace=~\"$namespace\", source_workload=~\"$workload\", reporter=\"source\", destination_service=~\"$dstsvc\"}[5m])) by (destination_service, response_code), 0.001)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{ destination_service }} : {{ response_code }} (🔐mTLS)", + "refId": "B", + "step": 2 + }, + { + "expr": "round(sum(irate(istio_requests_total{connection_security_policy!=\"mutual_tls\", source_workload_namespace=~\"$namespace\", source_workload=~\"$workload\", reporter=\"source\", destination_service=~\"$dstsvc\"}[5m])) by (destination_service, response_code), 0.001)", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_service }} : {{ response_code }}", + "refId": "A", + "step": 2 + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Outgoing Requests by Destination And Response Code", + "tooltip": { + "shared": false, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [ + "total" + ] + }, + "yaxes": [ + { + "format": "ops", + "label": null, + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ] + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 6, + "w": 12, + "x": 12, + "y": 35 + }, + "id": 71, + "legend": { + "avg": false, + "current": false, + "hideEmpty": true, + "hideZero": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(irate(istio_requests_total{reporter=\"source\", connection_security_policy=\"mutual_tls\", source_workload_namespace=~\"$namespace\", source_workload=~\"$workload\",response_code!~\"5.*\", destination_service=~\"$dstsvc\"}[5m])) by (destination_service) / sum(irate(istio_requests_total{reporter=\"source\", connection_security_policy=\"mutual_tls\", source_workload_namespace=~\"$namespace\", source_workload=~\"$workload\", destination_service=~\"$dstsvc\"}[5m])) by (destination_service)", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_service }} (🔐mTLS)", + "refId": "A", + "step": 2 + }, + { + "expr": "sum(irate(istio_requests_total{reporter=\"source\", connection_security_policy!=\"mutual_tls\", source_workload_namespace=~\"$namespace\", source_workload=~\"$workload\",response_code!~\"5.*\", destination_service=~\"$dstsvc\"}[5m])) by (destination_service) / sum(irate(istio_requests_total{reporter=\"source\", connection_security_policy!=\"mutual_tls\", source_workload_namespace=~\"$namespace\", source_workload=~\"$workload\", destination_service=~\"$dstsvc\"}[5m])) by (destination_service)", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{destination_service }}", + "refId": "B", + "step": 2 + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Outgoing Success Rate (non-5xx responses) By Destination", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "percentunit", + "label": null, + "logBase": 1, + "max": "1.01", + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ] + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "description": "", + "fill": 1, + "gridPos": { + "h": 6, + "w": 8, + "x": 0, + "y": 41 + }, + "id": 72, + "legend": { + "alignAsTable": false, + "avg": false, + "current": false, + "hideEmpty": true, + "hideZero": false, + "max": false, + "min": false, + "rightSide": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "(histogram_quantile(0.50, sum(irate(istio_request_duration_milliseconds_bucket{reporter=\"source\", connection_security_policy=\"mutual_tls\", source_workload=~\"$workload\", source_workload_namespace=~\"$namespace\", destination_service=~\"$dstsvc\"}[1m])) by (destination_service, le)) / 1000) or histogram_quantile(0.50, sum(irate(istio_request_duration_seconds_bucket{reporter=\"source\", connection_security_policy=\"mutual_tls\", source_workload=~\"$workload\", source_workload_namespace=~\"$namespace\", destination_service=~\"$dstsvc\"}[1m])) by (destination_service, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_service }} P50 (🔐mTLS)", + "refId": "D", + "step": 2 + }, + { + "expr": "(histogram_quantile(0.90, sum(irate(istio_request_duration_milliseconds_bucket{reporter=\"source\", connection_security_policy=\"mutual_tls\", source_workload=~\"$workload\", source_workload_namespace=~\"$namespace\", destination_service=~\"$dstsvc\"}[1m])) by (destination_service, le)) / 1000) or histogram_quantile(0.90, sum(irate(istio_request_duration_seconds_bucket{reporter=\"source\", connection_security_policy=\"mutual_tls\", source_workload=~\"$workload\", source_workload_namespace=~\"$namespace\", destination_service=~\"$dstsvc\"}[1m])) by (destination_service, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_service }} P90 (🔐mTLS)", + "refId": "A", + "step": 2 + }, + { + "expr": "(histogram_quantile(0.95, sum(irate(istio_request_duration_milliseconds_bucket{reporter=\"source\", connection_security_policy=\"mutual_tls\", source_workload=~\"$workload\", source_workload_namespace=~\"$namespace\", destination_service=~\"$dstsvc\"}[1m])) by (destination_service, le)) / 1000) or histogram_quantile(0.95, sum(irate(istio_request_duration_seconds_bucket{reporter=\"source\", connection_security_policy=\"mutual_tls\", source_workload=~\"$workload\", source_workload_namespace=~\"$namespace\", destination_service=~\"$dstsvc\"}[1m])) by (destination_service, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_service }} P95 (🔐mTLS)", + "refId": "B", + "step": 2 + }, + { + "expr": "(histogram_quantile(0.99, sum(irate(istio_request_duration_milliseconds_bucket{reporter=\"source\", connection_security_policy=\"mutual_tls\", source_workload=~\"$workload\", source_workload_namespace=~\"$namespace\", destination_service=~\"$dstsvc\"}[1m])) by (destination_service, le)) / 1000) or histogram_quantile(0.99, sum(irate(istio_request_duration_seconds_bucket{reporter=\"source\", connection_security_policy=\"mutual_tls\", source_workload=~\"$workload\", source_workload_namespace=~\"$namespace\", destination_service=~\"$dstsvc\"}[1m])) by (destination_service, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_service }} P99 (🔐mTLS)", + "refId": "C", + "step": 2 + }, + { + "expr": "(histogram_quantile(0.50, sum(irate(istio_request_duration_milliseconds_bucket{reporter=\"source\", connection_security_policy!=\"mutual_tls\", source_workload=~\"$workload\", source_workload_namespace=~\"$namespace\", destination_service=~\"$dstsvc\"}[1m])) by (destination_service, le)) / 1000) or histogram_quantile(0.50, sum(irate(istio_request_duration_seconds_bucket{reporter=\"source\", connection_security_policy!=\"mutual_tls\", source_workload=~\"$workload\", source_workload_namespace=~\"$namespace\", destination_service=~\"$dstsvc\"}[1m])) by (destination_service, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_service }} P50", + "refId": "E", + "step": 2 + }, + { + "expr": "(histogram_quantile(0.90, sum(irate(istio_request_duration_milliseconds_bucket{reporter=\"source\", connection_security_policy!=\"mutual_tls\", source_workload=~\"$workload\", source_workload_namespace=~\"$namespace\", destination_service=~\"$dstsvc\"}[1m])) by (destination_service, le)) / 1000) or histogram_quantile(0.90, sum(irate(istio_request_duration_seconds_bucket{reporter=\"source\", connection_security_policy!=\"mutual_tls\", source_workload=~\"$workload\", source_workload_namespace=~\"$namespace\", destination_service=~\"$dstsvc\"}[1m])) by (destination_service, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_service }} P90", + "refId": "F", + "step": 2 + }, + { + "expr": "(histogram_quantile(0.95, sum(irate(istio_request_duration_milliseconds_bucket{reporter=\"source\", connection_security_policy!=\"mutual_tls\", source_workload=~\"$workload\", source_workload_namespace=~\"$namespace\", destination_service=~\"$dstsvc\"}[1m])) by (destination_service, le)) / 1000) or histogram_quantile(0.95, sum(irate(istio_request_duration_seconds_bucket{reporter=\"source\", connection_security_policy!=\"mutual_tls\", source_workload=~\"$workload\", source_workload_namespace=~\"$namespace\", destination_service=~\"$dstsvc\"}[1m])) by (destination_service, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_service }} P95", + "refId": "G", + "step": 2 + }, + { + "expr": "(histogram_quantile(0.99, sum(irate(istio_request_duration_milliseconds_bucket{reporter=\"source\", connection_security_policy!=\"mutual_tls\", source_workload=~\"$workload\", source_workload_namespace=~\"$namespace\", destination_service=~\"$dstsvc\"}[1m])) by (destination_service, le)) / 1000) or histogram_quantile(0.99, sum(irate(istio_request_duration_seconds_bucket{reporter=\"source\", connection_security_policy!=\"mutual_tls\", source_workload=~\"$workload\", source_workload_namespace=~\"$namespace\", destination_service=~\"$dstsvc\"}[1m])) by (destination_service, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_service }} P99", + "refId": "H", + "step": 2 + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Outgoing Request Duration by Destination", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "s", + "label": null, + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ] + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 6, + "w": 8, + "x": 8, + "y": 41 + }, + "id": 73, + "legend": { + "alignAsTable": false, + "avg": false, + "current": false, + "hideEmpty": true, + "max": false, + "min": false, + "rightSide": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "histogram_quantile(0.50, sum(irate(istio_request_bytes_bucket{reporter=\"source\", connection_security_policy=\"mutual_tls\", source_workload=~\"$workload\", source_workload_namespace=~\"$namespace\", destination_service=~\"$dstsvc\"}[1m])) by (destination_service, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_service }} P50 (🔐mTLS)", + "refId": "D", + "step": 2 + }, + { + "expr": "histogram_quantile(0.90, sum(irate(istio_request_bytes_bucket{reporter=\"source\", connection_security_policy=\"mutual_tls\", source_workload=~\"$workload\", source_workload_namespace=~\"$namespace\", destination_service=~\"$dstsvc\"}[1m])) by (destination_service, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_service }} P90 (🔐mTLS)", + "refId": "A", + "step": 2 + }, + { + "expr": "histogram_quantile(0.95, sum(irate(istio_request_bytes_bucket{reporter=\"source\", connection_security_policy=\"mutual_tls\", source_workload=~\"$workload\", source_workload_namespace=~\"$namespace\", destination_service=~\"$dstsvc\"}[1m])) by (destination_service, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_service }} P95 (🔐mTLS)", + "refId": "B", + "step": 2 + }, + { + "expr": "histogram_quantile(0.99, sum(irate(istio_request_bytes_bucket{reporter=\"source\", connection_security_policy=\"mutual_tls\", source_workload=~\"$workload\", source_workload_namespace=~\"$namespace\", destination_service=~\"$dstsvc\"}[1m])) by (destination_service, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_service }} P99 (🔐mTLS)", + "refId": "C", + "step": 2 + }, + { + "expr": "histogram_quantile(0.50, sum(irate(istio_request_bytes_bucket{reporter=\"source\", connection_security_policy!=\"mutual_tls\", source_workload=~\"$workload\", source_workload_namespace=~\"$namespace\", destination_service=~\"$dstsvc\"}[1m])) by (destination_service, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_service }} P50", + "refId": "E", + "step": 2 + }, + { + "expr": "histogram_quantile(0.90, sum(irate(istio_request_bytes_bucket{reporter=\"source\", connection_security_policy!=\"mutual_tls\", source_workload=~\"$workload\", source_workload_namespace=~\"$namespace\", destination_service=~\"$dstsvc\"}[1m])) by (destination_service, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_service }} P90", + "refId": "F", + "step": 2 + }, + { + "expr": "histogram_quantile(0.95, sum(irate(istio_request_bytes_bucket{reporter=\"source\", connection_security_policy!=\"mutual_tls\", source_workload=~\"$workload\", source_workload_namespace=~\"$namespace\", destination_service=~\"$dstsvc\"}[1m])) by (destination_service, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_service }} P95", + "refId": "G", + "step": 2 + }, + { + "expr": "histogram_quantile(0.99, sum(irate(istio_request_bytes_bucket{reporter=\"source\", connection_security_policy!=\"mutual_tls\", source_workload=~\"$workload\", source_workload_namespace=~\"$namespace\", destination_service=~\"$dstsvc\"}[1m])) by (destination_service, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_service }} P99", + "refId": "H", + "step": 2 + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Outgoing Request Size By Destination", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "decbytes", + "label": null, + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ] + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 6, + "w": 8, + "x": 16, + "y": 41 + }, + "id": 74, + "legend": { + "alignAsTable": false, + "avg": false, + "current": false, + "hideEmpty": true, + "max": false, + "min": false, + "rightSide": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "histogram_quantile(0.50, sum(irate(istio_response_bytes_bucket{reporter=\"source\", connection_security_policy=\"mutual_tls\", source_workload=~\"$workload\", source_workload_namespace=~\"$namespace\", destination_service=~\"$dstsvc\"}[1m])) by (destination_service, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_service }} P50 (🔐mTLS)", + "refId": "D", + "step": 2 + }, + { + "expr": "histogram_quantile(0.90, sum(irate(istio_response_bytes_bucket{reporter=\"source\", connection_security_policy=\"mutual_tls\", source_workload=~\"$workload\", source_workload_namespace=~\"$namespace\", destination_service=~\"$dstsvc\"}[1m])) by (destination_service, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_service }} P90 (🔐mTLS)", + "refId": "A", + "step": 2 + }, + { + "expr": "histogram_quantile(0.95, sum(irate(istio_response_bytes_bucket{reporter=\"source\", connection_security_policy=\"mutual_tls\", source_workload=~\"$workload\", source_workload_namespace=~\"$namespace\", destination_service=~\"$dstsvc\"}[1m])) by (destination_service, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_service }} P95 (🔐mTLS)", + "refId": "B", + "step": 2 + }, + { + "expr": "histogram_quantile(0.99, sum(irate(istio_response_bytes_bucket{reporter=\"source\", connection_security_policy=\"mutual_tls\", source_workload=~\"$workload\", source_workload_namespace=~\"$namespace\", destination_service=~\"$dstsvc\"}[1m])) by (destination_service, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_service }} P99 (🔐mTLS)", + "refId": "C", + "step": 2 + }, + { + "expr": "histogram_quantile(0.50, sum(irate(istio_response_bytes_bucket{reporter=\"source\", connection_security_policy!=\"mutual_tls\", source_workload=~\"$workload\", source_workload_namespace=~\"$namespace\", destination_service=~\"$dstsvc\"}[1m])) by (destination_service, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_service }} P50", + "refId": "E", + "step": 2 + }, + { + "expr": "histogram_quantile(0.90, sum(irate(istio_response_bytes_bucket{reporter=\"source\", connection_security_policy!=\"mutual_tls\", source_workload=~\"$workload\", source_workload_namespace=~\"$namespace\", destination_service=~\"$dstsvc\"}[1m])) by (destination_service, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_service }} P90", + "refId": "F", + "step": 2 + }, + { + "expr": "histogram_quantile(0.95, sum(irate(istio_response_bytes_bucket{reporter=\"source\", connection_security_policy!=\"mutual_tls\", source_workload=~\"$workload\", source_workload_namespace=~\"$namespace\", destination_service=~\"$dstsvc\"}[1m])) by (destination_service, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_service }} P95", + "refId": "G", + "step": 2 + }, + { + "expr": "histogram_quantile(0.99, sum(irate(istio_response_bytes_bucket{reporter=\"source\", connection_security_policy!=\"mutual_tls\", source_workload=~\"$workload\", source_workload_namespace=~\"$namespace\", destination_service=~\"$dstsvc\"}[1m])) by (destination_service, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_service }} P99", + "refId": "H", + "step": 2 + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Response Size By Destination", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "decbytes", + "label": null, + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ] + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 6, + "w": 12, + "x": 0, + "y": 47 + }, + "id": 76, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "round(sum(irate(istio_tcp_sent_bytes_total{connection_security_policy=\"mutual_tls\", reporter=\"source\", source_workload_namespace=~\"$namespace\", source_workload=~\"$workload\", destination_service=~\"$dstsvc\"}[1m])) by (destination_service), 0.001)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{ destination_service }} (🔐mTLS)", + "refId": "A", + "step": 2 + }, + { + "expr": "round(sum(irate(istio_tcp_sent_bytes_total{connection_security_policy!=\"mutual_tls\", reporter=\"source\", source_workload_namespace=~\"$namespace\", source_workload=~\"$workload\", destination_service=~\"$dstsvc\"}[1m])) by (destination_service), 0.001)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{ destination_service }}", + "refId": "B", + "step": 2 + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Bytes Sent on Outgoing TCP Connection", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "Bps", + "label": null, + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ] + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 6, + "w": 12, + "x": 12, + "y": 47 + }, + "id": 78, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "round(sum(irate(istio_tcp_received_bytes_total{reporter=\"source\", connection_security_policy=\"mutual_tls\", source_workload_namespace=~\"$namespace\", source_workload=~\"$workload\", destination_service=~\"$dstsvc\"}[1m])) by (destination_service), 0.001)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{ destination_service }} (🔐mTLS)", + "refId": "A", + "step": 2 + }, + { + "expr": "round(sum(irate(istio_tcp_received_bytes_total{reporter=\"source\", connection_security_policy!=\"mutual_tls\", source_workload_namespace=~\"$namespace\", source_workload=~\"$workload\", destination_service=~\"$dstsvc\"}[1m])) by (destination_service), 0.001)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{ destination_service }}", + "refId": "B", + "step": 2 + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Bytes Received from Outgoing TCP Connection", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "Bps", + "label": null, + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ] + } + ], + "refresh": "10s", + "schemaVersion": 16, + "style": "dark", + "tags": [], + "templating": { + "list": [ + { + "allValue": null, + "current": {}, + "datasource": "Prometheus", + "hide": 0, + "includeAll": false, + "label": "Namespace", + "multi": false, + "name": "namespace", + "options": [], + "query": "query_result(sum(istio_requests_total) by (destination_workload_namespace) or sum(istio_tcp_sent_bytes_total) by (destination_workload_namespace))", + "refresh": 1, + "regex": "/.*_namespace=\"([^\"]*).*/", + "sort": 0, + "tagValuesQuery": "", + "tags": [], + "tagsQuery": "", + "type": "query", + "useTags": false + }, + { + "allValue": null, + "current": {}, + "datasource": "Prometheus", + "hide": 0, + "includeAll": false, + "label": "Workload", + "multi": false, + "name": "workload", + "options": [], + "query": "query_result((sum(istio_requests_total{destination_workload_namespace=~\"$namespace\"}) by (destination_workload) or sum(istio_requests_total{source_workload_namespace=~\"$namespace\"}) by (source_workload)) or (sum(istio_tcp_sent_bytes_total{destination_workload_namespace=~\"$namespace\"}) by (destination_workload) or sum(istio_tcp_sent_bytes_total{source_workload_namespace=~\"$namespace\"}) by (source_workload)))", + "refresh": 1, + "regex": "/.*workload=\"([^\"]*).*/", + "sort": 1, + "tagValuesQuery": "", + "tags": [], + "tagsQuery": "", + "type": "query", + "useTags": false + }, + { + "allValue": null, + "current": {}, + "datasource": "Prometheus", + "hide": 0, + "includeAll": true, + "label": "Inbound Workload Namespace", + "multi": true, + "name": "srcns", + "options": [], + "query": "query_result( sum(istio_requests_total{reporter=\"destination\", destination_workload=\"$workload\", destination_workload_namespace=~\"$namespace\"}) by (source_workload_namespace) or sum(istio_tcp_sent_bytes_total{reporter=\"destination\", destination_workload=\"$workload\", destination_workload_namespace=~\"$namespace\"}) by (source_workload_namespace))", + "refresh": 1, + "regex": "/.*namespace=\"([^\"]*).*/", + "sort": 2, + "tagValuesQuery": "", + "tags": [], + "tagsQuery": "", + "type": "query", + "useTags": false + }, + { + "allValue": null, + "current": {}, + "datasource": "Prometheus", + "hide": 0, + "includeAll": true, + "label": "Inbound Workload", + "multi": true, + "name": "srcwl", + "options": [], + "query": "query_result( sum(istio_requests_total{reporter=\"destination\", destination_workload=\"$workload\", destination_workload_namespace=~\"$namespace\", source_workload_namespace=~\"$srcns\"}) by (source_workload) or sum(istio_tcp_sent_bytes_total{reporter=\"destination\", destination_workload=\"$workload\", destination_workload_namespace=~\"$namespace\", source_workload_namespace=~\"$srcns\"}) by (source_workload))", + "refresh": 1, + "regex": "/.*workload=\"([^\"]*).*/", + "sort": 3, + "tagValuesQuery": "", + "tags": [], + "tagsQuery": "", + "type": "query", + "useTags": false + }, + { + "allValue": null, + "current": {}, + "datasource": "Prometheus", + "hide": 0, + "includeAll": true, + "label": "Destination Service", + "multi": true, + "name": "dstsvc", + "options": [], + "query": "query_result( sum(istio_requests_total{reporter=\"source\", source_workload=~\"$workload\", source_workload_namespace=~\"$namespace\"}) by (destination_service) or sum(istio_tcp_sent_bytes_total{reporter=\"source\", source_workload=~\"$workload\", source_workload_namespace=~\"$namespace\"}) by (destination_service))", + "refresh": 1, + "regex": "/.*destination_service=\"([^\"]*).*/", + "sort": 4, + "tagValuesQuery": "", + "tags": [], + "tagsQuery": "", + "type": "query", + "useTags": false + } + ] + }, + "time": { + "from": "now-5m", + "to": "now" + }, + "timepicker": { + "refresh_intervals": [ + "5s", + "10s", + "30s", + "1m", + "5m", + "15m", + "30m", + "1h", + "2h", + "1d" + ], + "time_options": [ + "5m", + "15m", + "1h", + "6h", + "12h", + "24h", + "2d", + "7d", + "30d" + ] + }, + "timezone": "", + "title": "Istio Workload Dashboard", + "uid": "UbsSZTDik", + "version": 1 +} diff --git a/istio-1.5.0/install/kubernetes/operator/charts/istio-telemetry/grafana/dashboards/mixer-dashboard.json b/istio-1.5.0/install/kubernetes/operator/charts/istio-telemetry/grafana/dashboards/mixer-dashboard.json new file mode 100644 index 0000000..6da44ec --- /dev/null +++ b/istio-1.5.0/install/kubernetes/operator/charts/istio-telemetry/grafana/dashboards/mixer-dashboard.json @@ -0,0 +1,1808 @@ +{ + "__inputs": [ + { + "name": "DS_PROMETHEUS", + "label": "Prometheus", + "description": "", + "type": "datasource", + "pluginId": "prometheus", + "pluginName": "Prometheus" + } + ], + "__requires": [ + { + "type": "grafana", + "id": "grafana", + "name": "Grafana", + "version": "5.2.3" + }, + { + "type": "panel", + "id": "graph", + "name": "Graph", + "version": "5.0.0" + }, + { + "type": "datasource", + "id": "prometheus", + "name": "Prometheus", + "version": "5.0.0" + }, + { + "type": "panel", + "id": "text", + "name": "Text", + "version": "5.0.0" + } + ], + "annotations": { + "list": [ + { + "builtIn": 1, + "datasource": "-- Grafana --", + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "limit": 100, + "name": "Annotations & Alerts", + "showIn": 0, + "type": "dashboard" + } + ] + }, + "editable": false, + "gnetId": null, + "graphTooltip": 1, + "id": null, + "iteration": 1543881232533, + "links": [], + "panels": [ + { + "content": "

Deployed Versions

", + "gridPos": { + "h": 3, + "w": 24, + "x": 0, + "y": 0 + }, + "height": "40", + "id": 62, + "links": [], + "mode": "html", + "title": "", + "transparent": true, + "type": "text" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 5, + "w": 24, + "x": 0, + "y": 3 + }, + "id": 64, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(istio_build{component=\"mixer\"}) by (tag)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{ tag }}", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Mixer Versions", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "content": "

Resource Usage

", + "gridPos": { + "h": 3, + "w": 24, + "x": 0, + "y": 8 + }, + "height": "40", + "id": 29, + "links": [], + "mode": "html", + "title": "", + "transparent": true, + "type": "text" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 7, + "w": 6, + "x": 0, + "y": 11 + }, + "id": 5, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(process_virtual_memory_bytes{job=~\"istio-telemetry|istio-policy\"}) by (job)", + "format": "time_series", + "instant": false, + "intervalFactor": 2, + "legendFormat": "Virtual Memory ({{ job }})", + "refId": "I" + }, + { + "expr": "sum(process_resident_memory_bytes{job=~\"istio-telemetry|istio-policy\"}) by (job)", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "Resident Memory ({{ job }})", + "refId": "H" + }, + { + "expr": "sum(go_memstats_heap_sys_bytes{job=~\"istio-telemetry|istio-policy\"}) by (job)", + "format": "time_series", + "hide": true, + "intervalFactor": 2, + "legendFormat": "heap sys ({{ job }})", + "refId": "A" + }, + { + "expr": "sum(go_memstats_heap_alloc_bytes{job=~\"istio-telemetry|istio-policy\"}) by (job)", + "format": "time_series", + "hide": true, + "intervalFactor": 2, + "legendFormat": "heap alloc ({{ job }})", + "refId": "D" + }, + { + "expr": "sum(go_memstats_alloc_bytes{job=~\"istio-telemetry|istio-policy\"}) by (job)", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "Alloc ({{ job }})", + "refId": "F" + }, + { + "expr": "sum(go_memstats_heap_inuse_bytes{job=~\"istio-telemetry|istio-policy\"}) by (job)", + "format": "time_series", + "hide": false, + "intervalFactor": 2, + "legendFormat": "Heap in-use ({{ job }})", + "refId": "E" + }, + { + "expr": "sum(go_memstats_stack_inuse_bytes{job=~\"istio-telemetry|istio-policy\"}) by (job)", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "Stack in-use ({{ job }})", + "refId": "G" + }, + { + "expr": "sum(label_replace(container_memory_usage_bytes{job=\"kubernetes-cadvisor\", container=~\"mixer|istio-proxy\", pod=~\"istio-telemetry-.*|istio-policy-.*\"}, \"service\", \"$1\" , \"pod\", \"(istio-telemetry|istio-policy)-.*\")) by (service)", + "format": "time_series", + "hide": false, + "intervalFactor": 2, + "legendFormat": "{{ service }} total (k8s)", + "refId": "C" + }, + { + "expr": "sum(label_replace(container_memory_usage_bytes{job=\"kubernetes-cadvisor\", container=~\"mixer|istio-proxy\", pod=~\"istio-telemetry-.*|istio-policy-.*\"}, \"service\", \"$1\" , \"pod\", \"(istio-telemetry|istio-policy)-.*\")) by (container, service)", + "format": "time_series", + "hide": false, + "intervalFactor": 2, + "legendFormat": "{{ service }} - {{ container }} (k8s)", + "refId": "B" + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Memory", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "bytes", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 7, + "w": 6, + "x": 6, + "y": 11 + }, + "id": 6, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "label_replace(sum(rate(container_cpu_usage_seconds_total{job=\"kubernetes-cadvisor\",container=~\"mixer|istio-proxy\", pod=~\"istio-telemetry-.*|istio-policy-.*\"}[1m])) by (pod), \"service\", \"$1\" , \"pod\", \"(istio-telemetry|istio-policy)-.*\")", + "format": "time_series", + "hide": false, + "intervalFactor": 2, + "legendFormat": "{{ service }} total (k8s)", + "refId": "A" + }, + { + "expr": "label_replace(sum(rate(container_cpu_usage_seconds_total{job=\"kubernetes-cadvisor\",container=~\"mixer|istio-proxy\", pod=~\"istio-telemetry-.*|istio-policy-.*\"}[1m])) by (container, pod), \"service\", \"$1\" , \"pod\", \"(istio-telemetry|istio-policy)-.*\")", + "format": "time_series", + "hide": false, + "intervalFactor": 2, + "legendFormat": "{{ service }} - {{ container }} (k8s)", + "refId": "B" + }, + { + "expr": "sum(irate(process_cpu_seconds_total{job=~\"istio-telemetry|istio-policy\"}[1m])) by (job)", + "format": "time_series", + "hide": false, + "intervalFactor": 2, + "legendFormat": "{{ job }} (self-reported)", + "refId": "C" + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "CPU", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 7, + "w": 6, + "x": 12, + "y": 11 + }, + "id": 7, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(process_open_fds{job=~\"istio-telemetry|istio-policy\"}) by (job)", + "format": "time_series", + "hide": true, + "instant": false, + "interval": "", + "intervalFactor": 2, + "legendFormat": "Open FDs ({{ job }})", + "refId": "A" + }, + { + "expr": "sum(label_replace(container_fs_usage_bytes{job=\"kubernetes-cadvisor\", container=~\"mixer|istio-proxy\", pod=~\"istio-telemetry-.*|istio-policy-.*\"}, \"service\", \"$1\" , \"pod\", \"(istio-telemetry|istio-policy)-.*\")) by (container, service)", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "{{ service }} - {{ container }}", + "refId": "B" + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Disk", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "bytes", + "label": "", + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "decimals": null, + "format": "none", + "label": "", + "logBase": 1024, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 7, + "w": 6, + "x": 18, + "y": 11 + }, + "id": 4, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": false, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(go_goroutines{job=~\"istio-telemetry|istio-policy\"}) by (job)", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "Number of Goroutines ({{ job }})", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Goroutines", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": "", + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "content": "

Mixer Overview

", + "gridPos": { + "h": 3, + "w": 24, + "x": 0, + "y": 18 + }, + "height": "40px", + "id": 30, + "links": [], + "mode": "html", + "title": "", + "transparent": true, + "type": "text" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 6, + "w": 6, + "x": 0, + "y": 21 + }, + "id": 9, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(rate(grpc_io_server_completed_rpcs[1m]))", + "format": "time_series", + "hide": false, + "intervalFactor": 2, + "legendFormat": "mixer (Total)", + "refId": "B" + }, + { + "expr": "sum(rate(grpc_io_server_completed_rpcs[1m])) by (grpc_server_method)", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "mixer ({{ grpc_server_method }})", + "refId": "C" + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Incoming Requests", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "ops", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 6, + "w": 6, + "x": 6, + "y": 21 + }, + "id": 8, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [ + { + "alias": "{}", + "yaxis": 1 + } + ], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "histogram_quantile(0.5, sum(rate(grpc_io_server_server_latency_bucket{}[1m])) by (grpc_server_method, le))", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "{{ grpc_server_method }} 0.5", + "refId": "B" + }, + { + "expr": "histogram_quantile(0.9, sum(rate(grpc_io_server_server_latency_bucket{}[1m])) by (grpc_server_method, le))", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "{{ grpc_server_method }} 0.9", + "refId": "C" + }, + { + "expr": "histogram_quantile(0.99, sum(rate(grpc_io_server_server_latency_bucket{}[1m])) by (grpc_server_method, le))", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "{{ grpc_server_method }} 0.99", + "refId": "D" + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Response Durations", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "ms", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 6, + "w": 6, + "x": 12, + "y": 21 + }, + "id": 11, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(rate(grpc_server_handled_total{grpc_code=~\"Unknown|Unimplemented|Internal|DataLoss\"}[1m])) by (grpc_method)", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "Mixer {{ grpc_method }}", + "refId": "B" + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Server Error Rate (5xx responses)", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 6, + "w": 6, + "x": 18, + "y": 21 + }, + "id": 12, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(irate(grpc_server_handled_total{grpc_code!=\"OK\",grpc_service=~\".*Mixer\"}[1m])) by (grpc_method)", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "Mixer {{ grpc_method }}", + "refId": "B" + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Non-successes (4xxs)", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "content": "

Adapters and Config

", + "gridPos": { + "h": 3, + "w": 24, + "x": 0, + "y": 27 + }, + "id": 28, + "links": [], + "mode": "html", + "title": "", + "transparent": true, + "type": "text" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 7, + "w": 12, + "x": 0, + "y": 30 + }, + "id": 13, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(irate(mixer_runtime_dispatches_total{adapter=~\"$adapter\"}[1m])) by (adapter)", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "{{ adapter }}", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Adapter Dispatch Count", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 7, + "w": 12, + "x": 12, + "y": 30 + }, + "id": 14, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "histogram_quantile(0.5, sum(irate(mixer_runtime_dispatch_duration_seconds_bucket{adapter=~\"$adapter\"}[1m])) by (adapter, le))", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "{{ adapter }} - p50", + "refId": "A" + }, + { + "expr": "histogram_quantile(0.9, sum(irate(mixer_runtime_dispatch_duration_seconds_bucket{adapter=~\"$adapter\"}[1m])) by (adapter, le))", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "{{ adapter }} - p90 ", + "refId": "B" + }, + { + "expr": "histogram_quantile(0.99, sum(irate(mixer_runtime_dispatch_duration_seconds_bucket{adapter=~\"$adapter\"}[1m])) by (adapter, le))", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "{{ adapter }} - p99", + "refId": "C" + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Adapter Dispatch Duration", + "tooltip": { + "shared": true, + "sort": 1, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "s", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 7, + "w": 6, + "x": 0, + "y": 37 + }, + "id": 60, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "scalar(topk(1, max(mixer_config_rule_config_count) by (configID)))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Rules", + "refId": "A" + }, + { + "expr": "scalar(topk(1, max(mixer_config_rule_config_error_count) by (configID)))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Config Errors", + "refId": "B" + }, + { + "expr": "scalar(topk(1, max(mixer_config_rule_config_match_error_count) by (configID)))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Match Errors", + "refId": "C" + }, + { + "expr": "scalar(topk(1, max(mixer_config_unsatisfied_action_handler_count) by (configID)))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Unsatisfied Actions", + "refId": "D" + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Rules", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 7, + "w": 6, + "x": 6, + "y": 37 + }, + "id": 56, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "scalar(topk(1, max(mixer_config_instance_config_count) by (configID)))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Instances", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Instances in Latest Config", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 7, + "w": 6, + "x": 12, + "y": 37 + }, + "id": 54, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "scalar(topk(1, max(mixer_config_handler_config_count) by (configID)))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Handlers", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Handlers in Latest Config", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 7, + "w": 6, + "x": 18, + "y": 37 + }, + "id": 58, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "scalar(topk(1, max(mixer_config_attribute_count) by (configID)))", + "format": "time_series", + "instant": false, + "intervalFactor": 1, + "legendFormat": "Attributes", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Attributes in Latest Config", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "content": "

Individual Adapters

", + "gridPos": { + "h": 3, + "w": 24, + "x": 0, + "y": 44 + }, + "id": 23, + "links": [], + "mode": "html", + "title": "", + "transparent": true, + "type": "text" + }, + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 47 + }, + "id": 46, + "panels": [], + "repeat": "adapter", + "title": "$adapter Adapter", + "type": "row" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 7, + "w": 12, + "x": 0, + "y": 48 + }, + "id": 17, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "label_replace(irate(mixer_runtime_dispatches_total{adapter=~\"$adapter\"}[1m]),\"handler\", \"$1 ($3)\", \"handler\", \"(.*)\\\\.(.*)\\\\.(.*)\")", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "{{ handler }} (error: {{ error }})", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Dispatch Count By Handler", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 7, + "w": 12, + "x": 12, + "y": 48 + }, + "id": 18, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "label_replace(histogram_quantile(0.5, sum(rate(mixer_runtime_dispatch_duration_seconds_bucket{adapter=~\"$adapter\"}[1m])) by (handler, error, le)), \"handler_short\", \"$1 ($3)\", \"handler\", \"(.*)\\\\.(.*)\\\\.(.*)\")", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "p50 - {{ handler_short }} (error: {{ error }})", + "refId": "A" + }, + { + "expr": "label_replace(histogram_quantile(0.9, sum(irate(mixer_runtime_dispatch_duration_seconds_bucket{adapter=~\"$adapter\"}[1m])) by (handler, error, le)), \"handler_short\", \"$1 ($3)\", \"handler\", \"(.*)\\\\.(.*)\\\\.(.*)\")", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "p90 - {{ handler_short }} (error: {{ error }})", + "refId": "D" + }, + { + "expr": "label_replace(histogram_quantile(0.99, sum(irate(mixer_runtime_dispatch_duration_seconds_bucket{adapter=~\"$adapter\"}[1m])) by (handler, error, le)), \"handler_short\", \"$1 ($3)\", \"handler\", \"(.*)\\\\.(.*)\\\\.(.*)\")", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "p99 - {{ handler_short }} (error: {{ error }})", + "refId": "E" + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Dispatch Duration By Handler", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "s", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + } + ], + "refresh": "5s", + "schemaVersion": 16, + "style": "dark", + "tags": [], + "templating": { + "list": [ + { + "allValue": null, + "current": {}, + "datasource": "Prometheus", + "hide": 0, + "includeAll": true, + "label": "Adapter", + "multi": true, + "name": "adapter", + "options": [], + "query": "label_values(adapter)", + "refresh": 2, + "regex": "", + "sort": 1, + "tagValuesQuery": "", + "tags": [], + "tagsQuery": "", + "type": "query", + "useTags": false + } + ] + }, + "time": { + "from": "now-5m", + "to": "now" + }, + "timepicker": { + "refresh_intervals": [ + "5s", + "10s", + "30s", + "1m", + "5m", + "15m", + "30m", + "1h", + "2h", + "1d" + ], + "time_options": [ + "5m", + "15m", + "1h", + "6h", + "12h", + "24h", + "2d", + "7d", + "30d" + ] + }, + "timezone": "", + "title": "Istio Mixer Dashboard", + "version": 4 +} diff --git a/istio-1.5.0/install/kubernetes/operator/charts/istio-telemetry/grafana/dashboards/pilot-dashboard.json b/istio-1.5.0/install/kubernetes/operator/charts/istio-telemetry/grafana/dashboards/pilot-dashboard.json new file mode 100644 index 0000000..2647a0d --- /dev/null +++ b/istio-1.5.0/install/kubernetes/operator/charts/istio-telemetry/grafana/dashboards/pilot-dashboard.json @@ -0,0 +1,1591 @@ +{ + "annotations": { + "list": [ + { + "builtIn": 1, + "datasource": "-- Grafana --", + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations & Alerts", + "type": "dashboard" + } + ] + }, + "editable": false, + "gnetId": null, + "graphTooltip": 1, + "id": 11, + "links": [], + "panels": [ + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 0 + }, + "id": 60, + "panels": [], + "title": "Deployed Versions", + "type": "row" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 5, + "w": 24, + "x": 0, + "y": 1 + }, + "id": 56, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(istio_build{component=\"pilot\"}) by (tag)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{ tag }}", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Pilot Versions", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 6 + }, + "id": 62, + "panels": [], + "title": "Resource Usage", + "type": "row" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 7, + "w": 6, + "x": 0, + "y": 7 + }, + "id": 5, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "process_virtual_memory_bytes{job=\"pilot\"}", + "format": "time_series", + "instant": false, + "intervalFactor": 2, + "legendFormat": "Virtual Memory", + "refId": "I", + "step": 2 + }, + { + "expr": "process_resident_memory_bytes{job=\"pilot\"}", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "Resident Memory", + "refId": "H", + "step": 2 + }, + { + "expr": "go_memstats_heap_sys_bytes{job=\"pilot\"}", + "format": "time_series", + "hide": true, + "intervalFactor": 2, + "legendFormat": "heap sys", + "refId": "A" + }, + { + "expr": "go_memstats_heap_alloc_bytes{job=\"pilot\"}", + "format": "time_series", + "hide": true, + "intervalFactor": 2, + "legendFormat": "heap alloc", + "refId": "D" + }, + { + "expr": "go_memstats_alloc_bytes{job=\"pilot\"}", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "Alloc", + "refId": "F", + "step": 2 + }, + { + "expr": "go_memstats_heap_inuse_bytes{job=\"pilot\"}", + "format": "time_series", + "hide": false, + "intervalFactor": 2, + "legendFormat": "Heap in-use", + "refId": "E", + "step": 2 + }, + { + "expr": "go_memstats_stack_inuse_bytes{job=\"pilot\"}", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "Stack in-use", + "refId": "G", + "step": 2 + }, + { + "expr": "container_memory_usage_bytes{job=\"kubernetes-cadvisor\", container=~\"discovery\", pod=~\"istiod-.*|istio-pilot-.*\"}", + "format": "time_series", + "hide": false, + "intervalFactor": 2, + "legendFormat": "Discovery (container)", + "refId": "B", + "step": 2 + }, + { + "expr": "container_memory_usage_bytes{job=\"kubernetes-cadvisor\", container=~\"istio-proxy\", pod=~\"istiod-.*|istio-pilot-.*\"}", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Sidecar (container)", + "refId": "C" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Memory", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "bytes", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 7, + "w": 6, + "x": 6, + "y": 7 + }, + "id": 6, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(irate(container_cpu_usage_seconds_total{job=\"kubernetes-cadvisor\",container=\"discovery\", pod=~\"istiod-.*|istio-pilot-.*\"}[1m]))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Discovery (container)", + "refId": "A" + }, + { + "expr": "irate(process_cpu_seconds_total{job=\"pilot\"}[1m])", + "format": "time_series", + "hide": false, + "intervalFactor": 2, + "legendFormat": "Discovery (process)", + "refId": "C", + "step": 2 + }, + { + "expr": "sum(irate(container_cpu_usage_seconds_total{job=\"kubernetes-cadvisor\",container=\"istio-proxy\", pod=~\"istiod-.*|istio-pilot-.*\"}[1m]))", + "format": "time_series", + "hide": false, + "intervalFactor": 2, + "legendFormat": "Sidecar (container)", + "refId": "B", + "step": 2 + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "CPU", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 7, + "w": 6, + "x": 12, + "y": 7 + }, + "id": 7, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "container_fs_usage_bytes{job=\"kubernetes-cadvisor\", container=\"discovery\", pod=~\"istiod-.*|istio-pilot-.*\"}", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "Discovery", + "refId": "B", + "step": 2 + }, + { + "expr": "container_fs_usage_bytes{job=\"kubernetes-cadvisor\", container=\"istio-proxy\", pod=~\"istiod-.*|istio-pilot-.*\"}", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Sidecar", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Disk", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "bytes", + "label": "", + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "decimals": null, + "format": "none", + "label": "", + "logBase": 1024, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 7, + "w": 6, + "x": 18, + "y": 7 + }, + "id": 4, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": false, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "go_goroutines{job=\"pilot\"}", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "Number of Goroutines", + "refId": "A", + "step": 2 + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Goroutines", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": "", + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 14 + }, + "id": 58, + "panels": [], + "title": "Pilot Push Information", + "type": "row" + }, + { + "aliasColors": {}, + "bars": true, + "dashLength": 10, + "dashes": false, + "description": "Shows the rate of pilot pushes", + "fill": 1, + "gridPos": { + "h": 8, + "w": 8, + "x": 0, + "y": 15 + }, + "id": 622, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": false, + "linewidth": 1, + "links": [], + "nullPointMode": "null as zero", + "paceLength": 10, + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": true, + "steppedLine": false, + "targets": [ + { + "expr": "sum(irate(pilot_xds_pushes{type=\"cds\"}[1m]))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Cluster", + "refId": "C" + }, + { + "expr": "sum(irate(pilot_xds_pushes{type=\"eds\"}[1m]))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Endpoints", + "refId": "D" + }, + { + "expr": "sum(irate(pilot_xds_pushes{type=\"lds\"}[1m]))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Listeners", + "refId": "A" + }, + { + "expr": "sum(irate(pilot_xds_pushes{type=\"rds\"}[1m]))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Routes", + "refId": "E" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Pilot Pushes", + "tooltip": { + "shared": false, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [ + "total" + ] + }, + "yaxes": [ + { + "format": "ops", + "label": null, + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "description": "Captures a variety of pilot errors", + "fill": 1, + "gridPos": { + "h": 8, + "w": 8, + "x": 8, + "y": 15 + }, + "id": 67, + "legend": { + "avg": false, + "current": false, + "hideEmpty": true, + "hideZero": true, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(pilot_xds_cds_reject{job=\"pilot\"}) or (absent(pilot_xds_cds_reject{job=\"pilot\"}) - 1)", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "Rejected CDS Configs", + "refId": "C" + }, + { + "expr": "sum(pilot_xds_eds_reject{job=\"pilot\"}) or (absent(pilot_xds_eds_reject{job=\"pilot\"}) - 1)", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "Rejected EDS Configs", + "refId": "D" + }, + { + "expr": "sum(pilot_xds_rds_reject{job=\"pilot\"}) or (absent(pilot_xds_rds_reject{job=\"pilot\"}) - 1)", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "Rejected RDS Configs", + "refId": "A" + }, + { + "expr": "sum(pilot_xds_lds_reject{job=\"pilot\"}) or (absent(pilot_xds_lds_reject{job=\"pilot\"}) - 1)", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "Rejected LDS Configs", + "refId": "B" + }, + { + "expr": "sum(rate(pilot_xds_write_timeout{job=\"pilot\"}[1m]))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Write Timeouts", + "refId": "F" + }, + { + "expr": "sum(rate(pilot_total_xds_internal_errors{job=\"pilot\"}[1m]))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "Internal Errors", + "refId": "H" + }, + { + "expr": "sum(rate(pilot_total_xds_rejects{job=\"pilot\"}[1m]))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "Config Rejection Rate", + "refId": "E" + }, + { + "expr": "sum(rate(pilot_xds_push_context_errors{job=\"pilot\"}[1m]))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "Push Context Errors", + "refId": "K" + }, + { + "expr": "sum(rate(pilot_xds_pushes{type!~\"lds|cds|rds|eds\"}[1m])) by (type)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Push Errors ({{ type }})", + "refId": "L" + }, + { + "expr": "sum(rate(pilot_xds_push_errors{job=\"pilot\"}[1m])) by (type)", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "Push Errors ({{ type }})", + "refId": "I" + }, + { + "expr": "sum(rate(pilot_xds_push_timeout{job=\"pilot\"}[1m]))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Push Timeouts", + "refId": "G" + }, + { + "expr": "sum(rate(pilot_xds_push_timeout_failures{job=\"pilot\"}[1m]))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Push Timeouts Failures", + "refId": "J" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Pilot Errors", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "description": "Shows the total time it takes to push a config update to a proxy", + "fill": 1, + "gridPos": { + "h": 8, + "w": 8, + "x": 16, + "y": 15 + }, + "id": 624, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "histogram_quantile(0.5, sum(rate(pilot_proxy_convergence_time_bucket[1m])) by (le))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "p50 ", + "refId": "A" + }, + { + "expr": "histogram_quantile(0.9, sum(rate(pilot_proxy_convergence_time_bucket[1m])) by (le))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "p90", + "refId": "B" + }, + { + "expr": "histogram_quantile(0.99, sum(rate(pilot_proxy_convergence_time_bucket[1m])) by (le))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "p99", + "refId": "C" + }, + { + "expr": "histogram_quantile(0.999, sum(rate(pilot_proxy_convergence_time_bucket[1m])) by (le))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "p99.9", + "refId": "D" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Proxy Push Time", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "s", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 8, + "w": 8, + "x": 0, + "y": 23 + }, + "id": 45, + "legend": { + "avg": false, + "current": false, + "hideEmpty": true, + "hideZero": true, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null as zero", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "pilot_conflict_inbound_listener{job=\"pilot\"}", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "Inbound Listeners", + "refId": "B" + }, + { + "expr": "pilot_conflict_outbound_listener_http_over_current_tcp{job=\"pilot\"}", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "Outbound Listeners (http over current tcp)", + "refId": "A" + }, + { + "expr": "pilot_conflict_outbound_listener_tcp_over_current_tcp{job=\"pilot\"}", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "Outbound Listeners (tcp over current tcp)", + "refId": "C" + }, + { + "expr": "pilot_conflict_outbound_listener_tcp_over_current_http{job=\"pilot\"}", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "Outbound Listeners (tcp over current http)", + "refId": "D" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Conflicts", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 8, + "w": 8, + "x": 8, + "y": 23 + }, + "id": 47, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "pilot_virt_services{job=\"pilot\"}", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Virtual Services", + "refId": "A" + }, + { + "expr": "pilot_services{job=\"pilot\"}", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Services", + "refId": "B" + }, + { + "expr": "pilot_xds{job=\"pilot\"}", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Connected Endpoints", + "refId": "E" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "ADS Monitoring", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "columns": [], + "datasource": "Prometheus", + "description": "Clusters in this table do not have any endpoints known to pilot. This could be from referencing subsets that do not have any instances, or pods marked as NotReady", + "fontSize": "100%", + "gridPos": { + "h": 8, + "w": 8, + "x": 16, + "y": 23 + }, + "id": 51, + "links": [], + "pageSize": null, + "scroll": true, + "showHeader": true, + "sort": { + "col": null, + "desc": false + }, + "styles": [ + { + "alias": "Time", + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "pattern": "Time", + "type": "date" + }, + { + "alias": "Clusters", + "colorMode": null, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "decimals": 2, + "pattern": "/.*/", + "thresholds": [], + "type": "number", + "unit": "short" + } + ], + "targets": [ + { + "expr": "sum(pilot_xds_eds_instances{job=\"pilot\", cluster=~\".+\\\\|.+\"}) by (cluster) < 1", + "format": "time_series", + "hide": false, + "instant": true, + "intervalFactor": 1, + "legendFormat": "{{cluster}}", + "refId": "B" + } + ], + "timeFrom": null, + "timeShift": null, + "title": "Clusters with no known endpoints", + "transform": "timeseries_aggregations", + "type": "table" + }, + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 31 + }, + "id": 64, + "panels": [], + "title": "Envoy Information", + "type": "row" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "description": "Shows details about Envoy proxies in the mesh", + "fill": 1, + "gridPos": { + "h": 8, + "w": 8, + "x": 0, + "y": 32 + }, + "id": 40, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(irate(envoy_cluster_upstream_cx_total{cluster_name=\"xds-grpc\"}[1m]))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "XDS Connections", + "refId": "C" + }, + { + "expr": "sum(irate(envoy_cluster_upstream_cx_connect_fail{cluster_name=\"xds-grpc\"}[1m]))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "XDS Connection Failures", + "refId": "A" + }, + { + "expr": "sum(increase(envoy_server_hot_restart_epoch[1m]))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Envoy Restarts", + "refId": "B" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Envoy Details", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "ops", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "ops", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 8, + "w": 8, + "x": 8, + "y": 32 + }, + "id": 41, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(envoy_cluster_upstream_cx_active{cluster_name=\"xds-grpc\"})", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "XDS Active Connections", + "refId": "C", + "step": 2 + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "XDS Active Connections", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "description": "Shows the size of XDS requests and responses", + "fill": 1, + "gridPos": { + "h": 8, + "w": 8, + "x": 16, + "y": 32 + }, + "id": 42, + "legend": { + "avg": false, + "current": false, + "hideEmpty": false, + "hideZero": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "max(rate(envoy_cluster_upstream_cx_rx_bytes_total{cluster_name=\"xds-grpc\"}[1m]))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "XDS Response Bytes Max", + "refId": "D" + }, + { + "expr": "quantile(0.5, rate(envoy_cluster_upstream_cx_rx_bytes_total{cluster_name=\"xds-grpc\"}[1m]))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "XDS Response Bytes Average", + "refId": "B" + }, + { + "expr": "max(rate(envoy_cluster_upstream_cx_tx_bytes_total{cluster_name=\"xds-grpc\"}[1m]))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "XDS Request Bytes Max", + "refId": "A" + }, + { + "expr": "quantile(.5, rate(envoy_cluster_upstream_cx_tx_bytes_total{cluster_name=\"xds-grpc\"}[1m]))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "XDS Request Bytes Average", + "refId": "C" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "XDS Requests Size", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "Bps", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "ops", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + } + ], + "refresh": "5s", + "schemaVersion": 18, + "style": "dark", + "tags": [], + "templating": { + "list": [] + }, + "time": { + "from": "now-5m", + "to": "now" + }, + "timepicker": { + "refresh_intervals": [ + "5s", + "10s", + "30s", + "1m", + "5m", + "15m", + "30m", + "1h", + "2h", + "1d" + ], + "time_options": [ + "5m", + "15m", + "1h", + "6h", + "12h", + "24h", + "2d", + "7d", + "30d" + ] + }, + "timezone": "browser", + "title": "Istio Pilot Dashboard", + "uid": "3--MLVZZk", + "version": 11 +} \ No newline at end of file diff --git a/istio-1.5.0/install/kubernetes/operator/charts/istio-telemetry/grafana/fix_datasources.sh b/istio-1.5.0/install/kubernetes/operator/charts/istio-telemetry/grafana/fix_datasources.sh new file mode 100755 index 0000000..0442adf --- /dev/null +++ b/istio-1.5.0/install/kubernetes/operator/charts/istio-telemetry/grafana/fix_datasources.sh @@ -0,0 +1,30 @@ +#!/bin/bash + +# Copyright Istio Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +set -e + +THIS_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" +UX=$(uname) + +for db in "${THIS_DIR}"/dashboards/*.json; do + if [[ ${UX} == "Darwin" ]]; then + # shellcheck disable=SC2016 + sed -i '' 's/${DS_PROMETHEUS}/Prometheus/g' "$db" + else + # shellcheck disable=SC2016 + sed -i 's/${DS_PROMETHEUS}/Prometheus/g' "$db" + fi +done diff --git a/istio-1.5.0/install/kubernetes/operator/charts/istio-telemetry/grafana/templates/_affinity.tpl b/istio-1.5.0/install/kubernetes/operator/charts/istio-telemetry/grafana/templates/_affinity.tpl new file mode 100644 index 0000000..f2707b9 --- /dev/null +++ b/istio-1.5.0/install/kubernetes/operator/charts/istio-telemetry/grafana/templates/_affinity.tpl @@ -0,0 +1,93 @@ +{{/* affinity - https://kubernetes.io/docs/concepts/configuration/assign-pod-node/ */}} + +{{- define "nodeaffinity" }} + nodeAffinity: + requiredDuringSchedulingIgnoredDuringExecution: + {{- include "nodeAffinityRequiredDuringScheduling" . }} + preferredDuringSchedulingIgnoredDuringExecution: + {{- include "nodeAffinityPreferredDuringScheduling" . }} +{{- end }} + +{{- define "nodeAffinityRequiredDuringScheduling" }} + nodeSelectorTerms: + - matchExpressions: + - key: beta.kubernetes.io/arch + operator: In + values: + {{- range $key, $val := .Values.global.arch }} + {{- if gt ($val | int) 0 }} + - {{ $key | quote }} + {{- end }} + {{- end }} + {{- $nodeSelector := default .Values.global.defaultNodeSelector .Values.grafana.nodeSelector -}} + {{- range $key, $val := $nodeSelector }} + - key: {{ $key }} + operator: In + values: + - {{ $val | quote }} + {{- end }} +{{- end }} + +{{- define "nodeAffinityPreferredDuringScheduling" }} + {{- range $key, $val := .Values.global.arch }} + {{- if gt ($val | int) 0 }} + - weight: {{ $val | int }} + preference: + matchExpressions: + - key: beta.kubernetes.io/arch + operator: In + values: + - {{ $key | quote }} + {{- end }} + {{- end }} +{{- end }} + +{{- define "podAntiAffinity" }} +{{- if or .Values.grafana.podAntiAffinityLabelSelector .Values.grafana.podAntiAffinityTermLabelSelector}} + podAntiAffinity: + {{- if .Values.grafana.podAntiAffinityLabelSelector }} + requiredDuringSchedulingIgnoredDuringExecution: + {{- include "podAntiAffinityRequiredDuringScheduling" . }} + {{- end }} + {{- if .Values.grafana.podAntiAffinityTermLabelSelector }} + preferredDuringSchedulingIgnoredDuringExecution: + {{- include "podAntiAffinityPreferredDuringScheduling" . }} + {{- end }} +{{- end }} +{{- end }} + +{{- define "podAntiAffinityRequiredDuringScheduling" }} + {{- range $index, $item := .Values.grafana.podAntiAffinityLabelSelector }} + - labelSelector: + matchExpressions: + - key: {{ $item.key }} + operator: {{ $item.operator }} + {{- if $item.values }} + values: + {{- $vals := split "," $item.values }} + {{- range $i, $v := $vals }} + - {{ $v | quote }} + {{- end }} + {{- end }} + topologyKey: {{ $item.topologyKey }} + {{- end }} +{{- end }} + +{{- define "podAntiAffinityPreferredDuringScheduling" }} + {{- range $index, $item := .Values.grafana.podAntiAffinityTermLabelSelector }} + - podAffinityTerm: + labelSelector: + matchExpressions: + - key: {{ $item.key }} + operator: {{ $item.operator }} + {{- if $item.values }} + values: + {{- $vals := split "," $item.values }} + {{- range $i, $v := $vals }} + - {{ $v | quote }} + {{- end }} + {{- end }} + topologyKey: {{ $item.topologyKey }} + weight: 100 + {{- end }} +{{- end }} diff --git a/istio-1.5.0/install/kubernetes/operator/charts/istio-telemetry/grafana/templates/configmap-dashboards.yaml b/istio-1.5.0/install/kubernetes/operator/charts/istio-telemetry/grafana/templates/configmap-dashboards.yaml new file mode 100644 index 0000000..046dbca --- /dev/null +++ b/istio-1.5.0/install/kubernetes/operator/charts/istio-telemetry/grafana/templates/configmap-dashboards.yaml @@ -0,0 +1,16 @@ +{{- $files := .Files }} +{{- range $path, $bytes := .Files.Glob "dashboards/*.json" }} +{{- $filename := trimSuffix (ext $path) (base $path) }} +apiVersion: v1 +kind: ConfigMap +metadata: + name: istio-grafana-configuration-dashboards-{{ $filename }} + namespace: {{ $.Release.Namespace }} + labels: + app: grafana + release: {{ $.Release.Name }} + istio: grafana +data: + {{ base $path }}: '{{ $files.Get $path }}' +--- +{{- end }} diff --git a/istio-1.5.0/install/kubernetes/operator/charts/istio-telemetry/grafana/templates/configmap.yaml b/istio-1.5.0/install/kubernetes/operator/charts/istio-telemetry/grafana/templates/configmap.yaml new file mode 100644 index 0000000..dde985e --- /dev/null +++ b/istio-1.5.0/install/kubernetes/operator/charts/istio-telemetry/grafana/templates/configmap.yaml @@ -0,0 +1,23 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: istio-grafana + namespace: {{ .Release.Namespace }} + labels: + app: grafana + release: {{ .Release.Name }} + istio: grafana +data: +{{- if .Values.grafana.datasources }} + {{- range $key, $value := .Values.grafana.datasources }} + {{ $key }}: | +{{ toYaml $value | indent 4 }} + {{- end -}} +{{- end -}} + +{{- if .Values.grafana.dashboardProviders }} + {{- range $key, $value := .Values.grafana.dashboardProviders }} + {{ $key }}: | +{{ toYaml $value | indent 4 }} + {{- end -}} +{{- end -}} diff --git a/istio-1.5.0/install/kubernetes/operator/charts/istio-telemetry/grafana/templates/deployment.yaml b/istio-1.5.0/install/kubernetes/operator/charts/istio-telemetry/grafana/templates/deployment.yaml new file mode 100644 index 0000000..8715455 --- /dev/null +++ b/istio-1.5.0/install/kubernetes/operator/charts/istio-telemetry/grafana/templates/deployment.yaml @@ -0,0 +1,138 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: grafana + namespace: {{ .Release.Namespace }} + labels: + app: grafana + release: {{ .Release.Name }} +spec: + replicas: {{ .Values.grafana.replicaCount }} + selector: + matchLabels: + app: grafana + template: + metadata: + labels: + app: grafana + chart: grafana + heritage: Tiller + release: istio-system + annotations: + sidecar.istio.io/inject: "false" + {{- if .Values.grafana.podAnnotations }} +{{ toYaml .Values.grafana.podAnnotations | indent 8 }} + {{- end }} + spec: + securityContext: + runAsUser: 472 + fsGroup: 472 +{{- if .Values.global.priorityClassName }} + priorityClassName: "{{ .Values.global.priorityClassName }}" +{{- end }} +{{- if .Values.global.imagePullSecrets }} + imagePullSecrets: +{{- range .Values.global.imagePullSecrets }} + - name: {{ . }} +{{- end }} +{{- end }} + containers: + - name: {{ .Chart.Name }} + image: "{{ .Values.grafana.image.repository }}:{{ .Values.grafana.image.tag }}" + imagePullPolicy: {{ .Values.global.imagePullPolicy | default "Always" }} + ports: + - containerPort: 3000 + readinessProbe: + httpGet: + path: /api/health + port: 3000 + env: + - name: GRAFANA_PORT + value: "3000" +{{- if .Values.grafana.security.enabled }} + - name: GF_SECURITY_ADMIN_USER + valueFrom: + secretKeyRef: + name: {{ .Values.grafana.security.secretName }} + key: {{ .Values.grafana.security.usernameKey }} + - name: GF_SECURITY_ADMIN_PASSWORD + valueFrom: + secretKeyRef: + name: {{ .Values.grafana.security.secretName }} + key: {{ .Values.grafana.security.passphraseKey }} + - name: GF_AUTH_BASIC_ENABLED + value: "true" + - name: GF_AUTH_ANONYMOUS_ENABLED + value: "false" + - name: GF_AUTH_DISABLE_LOGIN_FORM + value: "false" +{{- else }} + - name: GF_AUTH_BASIC_ENABLED + value: "false" + - name: GF_AUTH_ANONYMOUS_ENABLED + value: "true" + - name: GF_AUTH_ANONYMOUS_ORG_ROLE + value: Admin +{{- end }} + - name: GF_PATHS_DATA + value: /data/grafana + {{- range $key, $value := $.Values.grafana.env }} + - name: {{ $key }} + value: {{ $value | quote }} + {{- end }} + {{- range $key, $secret := $.Values.grafana.envSecrets }} + - name: {{ $key }} + valueFrom: + secretKeyRef: + name: {{ $secret }} + key: {{ $key | quote }} + {{- end }} + resources: +{{- if .Values.grafana.resources }} +{{ toYaml .Values.grafana.resources | indent 12 }} +{{- else }} +{{ toYaml .Values.global.defaultResources | indent 12 }} +{{- end }} + volumeMounts: + - name: data + mountPath: /data/grafana + {{- range $path, $bytes := .Files.Glob "dashboards/*.json" }} + {{- $filename := trimSuffix (ext $path) (base $path) }} + - name: dashboards-istio-{{ $filename }} + mountPath: "/var/lib/grafana/dashboards/istio/{{ base $path }}" + subPath: {{ base $path }} + readOnly: true + {{- end }} + - name: config + mountPath: "/etc/grafana/provisioning/datasources/datasources.yaml" + subPath: datasources.yaml + - name: config + mountPath: "/etc/grafana/provisioning/dashboards/dashboardproviders.yaml" + subPath: dashboardproviders.yaml + affinity: + {{- include "nodeaffinity" . | indent 6 }} + {{- include "podAntiAffinity" . | indent 6 }} +{{- if .Values.grafana.tolerations }} + tolerations: +{{ toYaml .Values.grafana.tolerations | indent 6 }} +{{- else if .Values.global.defaultTolerations }} + tolerations: +{{ toYaml .Values.global.defaultTolerations | indent 6 }} +{{- end }} + volumes: + - name: config + configMap: + name: istio-grafana + - name: data +{{- if .Values.grafana.persist }} + persistentVolumeClaim: + claimName: istio-grafana-pvc +{{- else }} + emptyDir: {} +{{- end }} +{{- range $path, $bytes := .Files.Glob "dashboards/*.json" }} +{{- $filename := trimSuffix (ext $path) (base $path) }} + - name: dashboards-istio-{{ $filename }} + configMap: + name: istio-grafana-configuration-dashboards-{{ $filename }} +{{- end }} diff --git a/istio-1.5.0/install/kubernetes/operator/charts/istio-telemetry/grafana/templates/grafana-policy.yaml b/istio-1.5.0/install/kubernetes/operator/charts/istio-telemetry/grafana/templates/grafana-policy.yaml new file mode 100644 index 0000000..223cccf --- /dev/null +++ b/istio-1.5.0/install/kubernetes/operator/charts/istio-telemetry/grafana/templates/grafana-policy.yaml @@ -0,0 +1,13 @@ +apiVersion: authentication.istio.io/v1alpha1 +kind: Policy +metadata: + name: grafana-ports-mtls-disabled + namespace: {{ .Release.Namespace }} + labels: + app: grafana + release: {{ .Release.Name }} +spec: + targets: + - name: grafana + ports: + - number: {{ .Values.grafana.service.externalPort }} diff --git a/istio-1.5.0/install/kubernetes/operator/charts/istio-telemetry/grafana/templates/pvc.yaml b/istio-1.5.0/install/kubernetes/operator/charts/istio-telemetry/grafana/templates/pvc.yaml new file mode 100644 index 0000000..d2d14ae --- /dev/null +++ b/istio-1.5.0/install/kubernetes/operator/charts/istio-telemetry/grafana/templates/pvc.yaml @@ -0,0 +1,16 @@ +{{- if .Values.grafana.persist }} +kind: PersistentVolumeClaim +apiVersion: v1 +metadata: + name: istio-grafana-pvc + labels: + app: grafana + release: {{ .Release.Name }} +spec: + storageClassName: {{ .Values.grafana.storageClassName }} + accessModes: + - {{ .Values.grafana.accessMode }} + resources: + requests: + storage: 5Gi +{{- end }} diff --git a/istio-1.5.0/install/kubernetes/operator/charts/istio-telemetry/grafana/templates/service.yaml b/istio-1.5.0/install/kubernetes/operator/charts/istio-telemetry/grafana/templates/service.yaml new file mode 100644 index 0000000..644298c --- /dev/null +++ b/istio-1.5.0/install/kubernetes/operator/charts/istio-telemetry/grafana/templates/service.yaml @@ -0,0 +1,30 @@ +apiVersion: v1 +kind: Service +metadata: + name: grafana + namespace: {{ .Release.Namespace }} + annotations: + {{- range $key, $val := .Values.grafana.service.annotations }} + {{ $key }}: {{ $val | quote }} + {{- end }} + labels: + app: grafana + release: {{ .Release.Name }} +spec: + type: {{ .Values.grafana.service.type }} + ports: + - port: {{ .Values.grafana.service.externalPort }} + targetPort: 3000 + protocol: TCP + name: {{ .Values.grafana.service.name }} + selector: + app: grafana +{{- if .Values.grafana.service.loadBalancerIP }} + loadBalancerIP: "{{ .Values.grafana.service.loadBalancerIP }}" +{{- end }} + {{if .Values.grafana.service.loadBalancerSourceRanges}} + loadBalancerSourceRanges: + {{range $rangeList := .Values.grafana.service.loadBalancerSourceRanges}} + - {{ $rangeList }} + {{end}} + {{end}} diff --git a/istio-1.5.0/install/kubernetes/operator/charts/istio-telemetry/grafana/templates/tests/test-grafana-connection.yaml b/istio-1.5.0/install/kubernetes/operator/charts/istio-telemetry/grafana/templates/tests/test-grafana-connection.yaml new file mode 100644 index 0000000..79e3f79 --- /dev/null +++ b/istio-1.5.0/install/kubernetes/operator/charts/istio-telemetry/grafana/templates/tests/test-grafana-connection.yaml @@ -0,0 +1,28 @@ +{{- if .Values.global.enableHelmTest }} +apiVersion: v1 +kind: Pod +metadata: + name: grafana-test + namespace: {{ .Release.Namespace }} + labels: + app: grafana-test + release: {{ .Release.Name }} + istio: grafana + annotations: + sidecar.istio.io/inject: "false" + helm.sh/hook: test-success +spec: +{{- if .Values.global.priorityClassName }} + priorityClassName: "{{ .Values.global.priorityClassName }}" +{{- end }} + containers: + - name: "grafana-test" + image: {{ .Values.global.hub }}/{{ .Values.global.proxy.image }}:{{ .Values.global.tag }} + imagePullPolicy: "{{ .Values.global.imagePullPolicy }}" + command: ['curl'] + args: ['http://grafana:{{ .Values.grafana.service.externalPort }}'] + restartPolicy: Never + affinity: + {{- include "nodeaffinity" . | indent 4 }} + {{- include "podAntiAffinity" . | indent 4 }} +{{- end }} diff --git a/istio-1.5.0/install/kubernetes/operator/charts/istio-telemetry/grafana/values.yaml b/istio-1.5.0/install/kubernetes/operator/charts/istio-telemetry/grafana/values.yaml new file mode 100644 index 0000000..62d0b72 --- /dev/null +++ b/istio-1.5.0/install/kubernetes/operator/charts/istio-telemetry/grafana/values.yaml @@ -0,0 +1,126 @@ +grafana: + enabled: true + replicaCount: 1 + image: + repository: grafana/grafana + tag: 6.5.2 + persist: false + storageClassName: "" + accessMode: ReadWriteMany + security: + enabled: false + secretName: grafana + usernameKey: username + passphraseKey: passphrase + + contextPath: /grafana + service: + annotations: {} + name: http + type: ClusterIP + externalPort: 3000 + loadBalancerIP: "" + loadBalancerSourceRanges: "" + + ingress: + enabled: false + ## Used to create an Ingress record. + hosts: + - grafana.local + annotations: + # kubernetes.io/ingress.class: nginx + # kubernetes.io/tls-acme: "true" + tls: + # Secrets must be manually created in the namespace. + # - secretName: grafana-tls + # hosts: + # - grafana.local + + # Optional: prometheus may be deployed in a different namespace + # prometheusNamespace: istio-telemetry + + # Additional datasources. Prometheus included in the config map. + datasources: + datasources.yaml: + apiVersion: 1 + datasources: + - name: Prometheus + type: prometheus + orgId: 1 + url: http://prometheus:9090 + access: proxy + isDefault: true + jsonData: + timeInterval: 5s + editable: true + + dashboardProviders: + dashboardproviders.yaml: + apiVersion: 1 + providers: + - name: 'istio' + orgId: 1 + folder: 'istio' + type: file + disableDeletion: false + options: + path: /var/lib/grafana/dashboards/istio + + nodeSelector: {} + tolerations: [] + podAnnotations: {} + + env: {} + # Define additional environment variables for configuring grafana. + # @see https://grafana.com/docs/installation/configuration/#using-environment-variables + # Format: env_variable_name: value + # For example: + # GF_SMTP_ENABLED: true + # GF_SMTP_HOST: email-smtp.eu-west-1.amazonaws.com:2587 + # GF_SMTP_FROM_ADDRESS: alerts@mydomain.com + # GF_SMTP_FROM_NAME: Grafana + + envSecrets: {} + # The key name and ENV name must match in the secrets file. + # @see https://grafana.com/docs/installation/configuration/#using-environment-variables + # For example: + # --- + # apiVersion: v1 + # kind: Secret + # metadata: + # name: grafana-secrets + # namespace: istio-system + # data: + # GF_SMTP_USER: bXl1c2Vy + # GF_SMTP_PASSWORD: bXlwYXNzd29yZA== + # type: Opaque + # --- + # env_variable_key_name: secretsName + # --- + # GF_SMTP_USER: grafana-secrets + # GF_SMTP_PASSWORD: grafana-secrets + + resources: {} + + prometheusNamespace: "" + + # Specify the pod anti-affinity that allows you to constrain which nodes + # your pod is eligible to be scheduled based on labels on pods that are + # already running on the node rather than based on labels on nodes. + # There are currently two types of anti-affinity: + # "requiredDuringSchedulingIgnoredDuringExecution" + # "preferredDuringSchedulingIgnoredDuringExecution" + # which denote "hard" vs. "soft" requirements, you can define your values + # in "podAntiAffinityLabelSelector" and "podAntiAffinityTermLabelSelector" + # correspondingly. + # For example: + # podAntiAffinityLabelSelector: + # - key: security + # operator: In + # values: S1,S2 + # topologyKey: "kubernetes.io/hostname" + # This pod anti-affinity rule says that the pod requires not to be scheduled + # onto a node if that node is already running a pod with label having key + # "security" and value "S1". + podAntiAffinityLabelSelector: [] + podAntiAffinityTermLabelSelector: [] diff --git a/istio-1.5.0/install/kubernetes/operator/charts/istio-telemetry/kiali/Chart.yaml b/istio-1.5.0/install/kubernetes/operator/charts/istio-telemetry/kiali/Chart.yaml new file mode 100644 index 0000000..d82ea15 --- /dev/null +++ b/istio-1.5.0/install/kubernetes/operator/charts/istio-telemetry/kiali/Chart.yaml @@ -0,0 +1,6 @@ +apiVersion: v1 +description: Kiali is an open source project for service mesh observability, refer to https://www.kiali.io for details. +name: kiali +version: 1.14.0 +appVersion: 1.14.0 +tillerVersion: ">=2.7.2" diff --git a/istio-1.5.0/install/kubernetes/operator/charts/istio-telemetry/kiali/templates/_affinity.tpl b/istio-1.5.0/install/kubernetes/operator/charts/istio-telemetry/kiali/templates/_affinity.tpl new file mode 100644 index 0000000..09bc893 --- /dev/null +++ b/istio-1.5.0/install/kubernetes/operator/charts/istio-telemetry/kiali/templates/_affinity.tpl @@ -0,0 +1,93 @@ +{{/* affinity - https://kubernetes.io/docs/concepts/configuration/assign-pod-node/ */}} + +{{- define "nodeaffinity" }} + nodeAffinity: + requiredDuringSchedulingIgnoredDuringExecution: + {{- include "nodeAffinityRequiredDuringScheduling" . }} + preferredDuringSchedulingIgnoredDuringExecution: + {{- include "nodeAffinityPreferredDuringScheduling" . }} +{{- end }} + +{{- define "nodeAffinityRequiredDuringScheduling" }} + nodeSelectorTerms: + - matchExpressions: + - key: beta.kubernetes.io/arch + operator: In + values: + {{- range $key, $val := .Values.global.arch }} + {{- if gt ($val | int) 0 }} + - {{ $key | quote }} + {{- end }} + {{- end }} + {{- $nodeSelector := default .Values.global.defaultNodeSelector .Values.kiali.nodeSelector -}} + {{- range $key, $val := $nodeSelector }} + - key: {{ $key }} + operator: In + values: + - {{ $val | quote }} + {{- end }} +{{- end }} + +{{- define "nodeAffinityPreferredDuringScheduling" }} + {{- range $key, $val := .Values.global.arch }} + {{- if gt ($val | int) 0 }} + - weight: {{ $val | int }} + preference: + matchExpressions: + - key: beta.kubernetes.io/arch + operator: In + values: + - {{ $key | quote }} + {{- end }} + {{- end }} +{{- end }} + +{{- define "podAntiAffinity" }} +{{- if or .Values.kiali.podAntiAffinityLabelSelector .Values.kiali.podAntiAffinityTermLabelSelector}} + podAntiAffinity: + {{- if .Values.kiali.podAntiAffinityLabelSelector }} + requiredDuringSchedulingIgnoredDuringExecution: + {{- include "podAntiAffinityRequiredDuringScheduling" . }} + {{- end }} + {{- if or .Values.kiali.podAntiAffinityTermLabelSelector}} + preferredDuringSchedulingIgnoredDuringExecution: + {{- include "podAntiAffinityPreferredDuringScheduling" . }} + {{- end }} +{{- end }} +{{- end }} + +{{- define "podAntiAffinityRequiredDuringScheduling" }} + {{- range $index, $item := .Values.kiali.podAntiAffinityLabelSelector }} + - labelSelector: + matchExpressions: + - key: {{ $item.key }} + operator: {{ $item.operator }} + {{- if $item.values }} + values: + {{- $vals := split "," $item.values }} + {{- range $i, $v := $vals }} + - {{ $v | quote }} + {{- end }} + {{- end }} + topologyKey: {{ $item.topologyKey }} + {{- end }} +{{- end }} + +{{- define "podAntiAffinityPreferredDuringScheduling" }} + {{- range $index, $item := .Values.kiali.podAntiAffinityTermLabelSelector }} + - podAffinityTerm: + labelSelector: + matchExpressions: + - key: {{ $item.key }} + operator: {{ $item.operator }} + {{- if $item.values }} + values: + {{- $vals := split "," $item.values }} + {{- range $i, $v := $vals }} + - {{ $v | quote }} + {{- end }} + {{- end }} + topologyKey: {{ $item.topologyKey }} + weight: 100 + {{- end }} +{{- end }} diff --git a/istio-1.5.0/install/kubernetes/operator/charts/istio-telemetry/kiali/templates/clusterrole.yaml b/istio-1.5.0/install/kubernetes/operator/charts/istio-telemetry/kiali/templates/clusterrole.yaml new file mode 100644 index 0000000..0fe78f8 --- /dev/null +++ b/istio-1.5.0/install/kubernetes/operator/charts/istio-telemetry/kiali/templates/clusterrole.yaml @@ -0,0 +1,130 @@ +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: kiali + labels: + app: kiali + release: {{ .Release.Name }} +rules: + - apiGroups: [""] + resources: + - configmaps + - endpoints + - namespaces + - nodes + - pods + - pods/log + - replicationcontrollers + - services + verbs: + - get + - list + - watch + - apiGroups: ["extensions", "apps"] + resources: + - deployments + - replicasets + - statefulsets + verbs: + - get + - list + - watch + - apiGroups: ["autoscaling"] + resources: + - horizontalpodautoscalers + verbs: + - get + - list + - watch + - apiGroups: ["batch"] + resources: + - cronjobs + - jobs + verbs: + - get + - list + - watch + - apiGroups: + - config.istio.io + - networking.istio.io + - authentication.istio.io + - rbac.istio.io + - security.istio.io + resources: ["*"] + verbs: + - create + - delete + - get + - list + - patch + - watch + - apiGroups: ["monitoring.kiali.io"] + resources: + - monitoringdashboards + verbs: + - get + - list +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: kiali-viewer + labels: + app: kiali + release: {{ .Release.Name }} +rules: + - apiGroups: [""] + resources: + - configmaps + - endpoints + - namespaces + - nodes + - pods + - pods/log + - replicationcontrollers + - services + verbs: + - get + - list + - watch + - apiGroups: ["extensions", "apps"] + resources: + - deployments + - replicasets + - statefulsets + verbs: + - get + - list + - watch + - apiGroups: ["autoscaling"] + resources: + - horizontalpodautoscalers + verbs: + - get + - list + - watch + - apiGroups: ["batch"] + resources: + - cronjobs + - jobs + verbs: + - get + - list + - watch + - apiGroups: + - config.istio.io + - networking.istio.io + - authentication.istio.io + - rbac.istio.io + - security.istio.io + resources: ["*"] + verbs: + - get + - list + - watch + - apiGroups: ["monitoring.kiali.io"] + resources: + - monitoringdashboards + verbs: + - get + - list diff --git a/istio-1.5.0/install/kubernetes/operator/charts/istio-telemetry/kiali/templates/clusterrolebinding.yaml b/istio-1.5.0/install/kubernetes/operator/charts/istio-telemetry/kiali/templates/clusterrolebinding.yaml new file mode 100644 index 0000000..14a1bf3 --- /dev/null +++ b/istio-1.5.0/install/kubernetes/operator/charts/istio-telemetry/kiali/templates/clusterrolebinding.yaml @@ -0,0 +1,33 @@ +{{- if not .Values.kiali.dashboard.viewOnlyMode }} +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: kiali + labels: + app: kiali + release: {{ .Release.Name }} +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: kiali +subjects: + - kind: ServiceAccount + name: kiali-service-account + namespace: {{ .Release.Namespace }} +{{- else }} +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: istio-kiali-viewer-role-binding-{{ .Release.Namespace }} + labels: + app: kiali + release: {{ .Release.Name }} +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: kiali-viewer +subjects: +- kind: ServiceAccount + name: kiali-service-account + namespace: {{ .Release.Namespace }} +{{- end }} diff --git a/istio-1.5.0/install/kubernetes/operator/charts/istio-telemetry/kiali/templates/configmap.yaml b/istio-1.5.0/install/kubernetes/operator/charts/istio-telemetry/kiali/templates/configmap.yaml new file mode 100644 index 0000000..c67c17b --- /dev/null +++ b/istio-1.5.0/install/kubernetes/operator/charts/istio-telemetry/kiali/templates/configmap.yaml @@ -0,0 +1,51 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: kiali + namespace: {{ .Release.Namespace }} + labels: + app: kiali + release: {{ .Release.Name }} +data: + config.yaml: | + istio_component_namespaces: + grafana: {{ .Values.global.telemetryNamespace }} + tracing: {{ .Values.global.telemetryNamespace }} + pilot: {{ .Values.global.configNamespace }} + prometheus: {{ .Values.global.prometheusNamespace }} + istio_namespace: {{ .Values.global.istioNamespace }} + auth: + strategy: {{ .Values.kiali.dashboard.auth.strategy }} +{{- if eq .Values.kiali.dashboard.auth.strategy "ldap" }} + ldap: +{{- with .Values.kiali.dashboard.auth.strategy.ldap }} +{{ toYaml . | indent 8 }} +{{- end }} +{{- end }} + deployment: + accessible_namespaces: ['**'] + server: + port: 20001 +{{- if .Values.kiali.contextPath }} + web_root: {{ .Values.kiali.contextPath }} +{{- end }} + external_services: + istio: + url_service_version: http://istio-pilot.{{ .Values.global.configNamespace }}:8080/version + tracing: + url: {{ .Values.kiali.dashboard.jaegerURL }} + in_cluster_url: {{ .Values.kiali.dashboard.jaegerInClusterURL }} + grafana: + url: {{ .Values.kiali.dashboard.grafanaURL }} + in_cluster_url: {{ .Values.kiali.dashboard.grafanaInClusterURL }} + prometheus: +{{- if .Values.global.prometheusNamespace }} + url: http://prometheus.{{ .Values.global.prometheusNamespace }}:9090 +{{ else }} + url: http://prometheus:9090 +{{- end }} +{{- if .Values.kiali.security.enabled }} + identity: + cert_file: {{ .Values.kiali.security.cert_file }} + private_key_file: {{ .Values.kiali.security.private_key_file }} +{{- end}} diff --git a/istio-1.5.0/install/kubernetes/operator/charts/istio-telemetry/kiali/templates/demosecret.yaml b/istio-1.5.0/install/kubernetes/operator/charts/istio-telemetry/kiali/templates/demosecret.yaml new file mode 100644 index 0000000..efcbdc7 --- /dev/null +++ b/istio-1.5.0/install/kubernetes/operator/charts/istio-telemetry/kiali/templates/demosecret.yaml @@ -0,0 +1,14 @@ +{{- if .Values.kiali.createDemoSecret }} +apiVersion: v1 +kind: Secret +metadata: + name: {{ .Values.kiali.dashboard.secretName }} + namespace: {{ .Release.Namespace }} + labels: + app: kiali + release: {{ .Release.Name }} +type: Opaque +data: + username: YWRtaW4= # admin + passphrase: YWRtaW4= # admin +{{- end }} diff --git a/istio-1.5.0/install/kubernetes/operator/charts/istio-telemetry/kiali/templates/deployment.yaml b/istio-1.5.0/install/kubernetes/operator/charts/istio-telemetry/kiali/templates/deployment.yaml new file mode 100644 index 0000000..270dadc --- /dev/null +++ b/istio-1.5.0/install/kubernetes/operator/charts/istio-telemetry/kiali/templates/deployment.yaml @@ -0,0 +1,99 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: kiali + namespace: {{ .Release.Namespace }} + labels: + app: kiali + release: {{ .Release.Name }} +spec: + replicas: {{ .Values.kiali.replicaCount }} + selector: + matchLabels: + app: kiali + template: + metadata: + name: kiali + labels: + app: kiali + release: {{ .Release.Name }} + annotations: + sidecar.istio.io/inject: "false" + scheduler.alpha.kubernetes.io/critical-pod: "" + prometheus.io/scrape: "true" + prometheus.io/port: "9090" + kiali.io/runtimes: go,kiali + {{- if .Values.kiali.podAnnotations }} +{{ toYaml .Values.kiali.podAnnotations | indent 8 }} + {{- end }} + spec: + serviceAccountName: kiali-service-account +{{- if .Values.global.priorityClassName }} + priorityClassName: "{{ .Values.global.priorityClassName }}" +{{- end }} + containers: + - image: "{{ .Values.kiali.hub }}/{{ .Values.kiali.image }}:{{ .Values.kiali.tag }}" + imagePullPolicy: {{ .Values.global.imagePullPolicy | default "Always" }} + name: kiali + command: + - "/opt/kiali/kiali" + - "-config" + - "/kiali-configuration/config.yaml" + - "-v" + - "3" + readinessProbe: + httpGet: + path: {{ .Values.kiali.contextPath }}/healthz + port: 20001 + scheme: {{ if .Values.kiali.security.enabled }}'HTTPS'{{ else }}'HTTP'{{ end }} + initialDelaySeconds: 5 + periodSeconds: 30 + livenessProbe: + httpGet: + path: {{ .Values.kiali.contextPath }}/healthz + port: 20001 + scheme: {{ if .Values.kiali.security.enabled }}'HTTPS'{{ else }}'HTTP'{{ end }} + initialDelaySeconds: 5 + periodSeconds: 30 + env: + - name: ACTIVE_NAMESPACE + valueFrom: + fieldRef: + fieldPath: metadata.namespace + volumeMounts: + - name: kiali-configuration + mountPath: "/kiali-configuration" + - name: kiali-cert + mountPath: "/kiali-cert" + - name: kiali-secret + mountPath: "/kiali-secret" + resources: +{{- if .Values.kiali.resources }} +{{ toYaml .Values.kiali.resources | indent 10 }} +{{- else }} +{{ toYaml .Values.global.defaultResources | indent 10 }} +{{- end }} + volumes: + - name: kiali-configuration + configMap: + name: kiali + - name: kiali-cert + secret: + secretName: istio.kiali-service-account +{{- if not .Values.kiali.security.enabled }} + optional: true +{{- end }} + - name: kiali-secret + secret: + secretName: {{ .Values.kiali.dashboard.secretName }} + optional: true + affinity: + {{- include "nodeaffinity" . | indent 6 }} + {{- include "podAntiAffinity" . | indent 6 }} +{{- if .Values.kiali.tolerations }} + tolerations: +{{ toYaml .Values.kiali.tolerations | indent 6 }} +{{- else if .Values.global.defaultTolerations }} + tolerations: +{{ toYaml .Values.global.defaultTolerations | indent 6 }} +{{- end }} diff --git a/istio-1.5.0/install/kubernetes/operator/charts/istio-telemetry/kiali/templates/service.yaml b/istio-1.5.0/install/kubernetes/operator/charts/istio-telemetry/kiali/templates/service.yaml new file mode 100644 index 0000000..3b4f9c6 --- /dev/null +++ b/istio-1.5.0/install/kubernetes/operator/charts/istio-telemetry/kiali/templates/service.yaml @@ -0,0 +1,15 @@ +apiVersion: v1 +kind: Service +metadata: + name: kiali + namespace: {{ .Release.Namespace }} + labels: + app: kiali + release: {{ .Release.Name }} +spec: + ports: + - name: http-kiali + protocol: TCP + port: 20001 + selector: + app: kiali diff --git a/istio-1.5.0/install/kubernetes/operator/charts/istio-telemetry/kiali/templates/serviceaccount.yaml b/istio-1.5.0/install/kubernetes/operator/charts/istio-telemetry/kiali/templates/serviceaccount.yaml new file mode 100644 index 0000000..54824ba --- /dev/null +++ b/istio-1.5.0/install/kubernetes/operator/charts/istio-telemetry/kiali/templates/serviceaccount.yaml @@ -0,0 +1,14 @@ +apiVersion: v1 +kind: ServiceAccount + {{- if .Values.global.imagePullSecrets }} +imagePullSecrets: + {{- range .Values.global.imagePullSecrets }} +- name: {{ . }} + {{- end }} + {{- end }} +metadata: + name: kiali-service-account + namespace: {{ .Release.Namespace }} + labels: + app: kiali + release: {{ .Release.Name }} diff --git a/istio-1.5.0/install/kubernetes/operator/charts/istio-telemetry/kiali/values.yaml b/istio-1.5.0/install/kubernetes/operator/charts/istio-telemetry/kiali/values.yaml new file mode 100644 index 0000000..caccaf9 --- /dev/null +++ b/istio-1.5.0/install/kubernetes/operator/charts/istio-telemetry/kiali/values.yaml @@ -0,0 +1,85 @@ +# +# addon kiali +# +kiali: + enabled: false # Note that if using the demo or demo-auth yaml when installing via Helm, this default will be `true`. + replicaCount: 1 + hub: quay.io/kiali + tag: v1.14 + image: kiali + contextPath: /kiali # The root context path to access the Kiali UI. + nodeSelector: {} + tolerations: [] + podAnnotations: {} + + # Specify the pod anti-affinity that allows you to constrain which nodes + # your pod is eligible to be scheduled based on labels on pods that are + # already running on the node rather than based on labels on nodes. + # There are currently two types of anti-affinity: + # "requiredDuringSchedulingIgnoredDuringExecution" + # "preferredDuringSchedulingIgnoredDuringExecution" + # which denote "hard" vs. "soft" requirements, you can define your values + # in "podAntiAffinityLabelSelector" and "podAntiAffinityTermLabelSelector" + # correspondingly. + # For example: + # podAntiAffinityLabelSelector: + # - key: security + # operator: In + # values: S1,S2 + # topologyKey: "kubernetes.io/hostname" + # This pod anti-affinity rule says that the pod requires not to be scheduled + # onto a node if that node is already running a pod with label having key + # "security" and value "S1". + podAntiAffinityLabelSelector: [] + podAntiAffinityTermLabelSelector: [] + + ingress: + enabled: false + ## Used to create an Ingress record. + hosts: + - kiali.local + annotations: {} + # kubernetes.io/ingress.class: nginx + # kubernetes.io/tls-acme: "true" + tls: + # Secrets must be manually created in the namespace. + # - secretName: kiali-tls + # hosts: + # - kiali.local + + dashboard: + auth: + strategy: login # Can be anonymous, login, openshift, or ldap + # ldap: # This is required to use the ldap strategy + # ldap_base: "DC=example,DC=com" + # ldap_bind_dn: "CN={USERID},OU=xyz,OU=Users,OU=Accounts,DC=example,DC=com" + # ldap_group_filter: "(cn=%s)" + # ldap_host: "ldap-service.ldap-namespace" + # ldap_insecure_skip_verify: true + # ldap_mail_id_key: "mail" + # ldap_member_of_key: "memberOf" + # ldap_port: 123 + # ldap_role_filter: ".*xyz.*" + # ldap_search_filter: "(&(name={USERID}))" + # ldap_use_ssl: false + # ldap_user_filter: "(cn=%s)" + # ldap_user_id_key: "cn" + + secretName: kiali # You must create a secret with this name - one is not provided out-of-box unless you've chose to create a demo secret. + usernameKey: username # This is the key name within the secret whose value is the actual username. + passphraseKey: passphrase # This is the key name within the secret whose value is the actual passphrase. + + viewOnlyMode: false # Bind the service account to a role with only read access + + grafanaURL: "" # If you have Grafana installed and it is accessible to client browsers, then set this to its external URL. Kiali will redirect users to this URL when Grafana metrics are to be shown. + grafanaInClusterURL: "http://grafana:3000" # In Kubernetes cluster with ELB in front this option is needed, since public IP of ELB is not reachable from inside the cluster + jaegerURL: "" # If you have Jaeger installed and it is accessible to client browsers, then set this property to its external URL. Kiali will redirect users to this URL when Jaeger tracing is to be shown. + jaegerInClusterURL: "http://tracing/jaeger" # If you have Jaeger installed and accessible from Kiali pod (typically in cluster), then set this property to enable more tracing charts within Kiali. + + createDemoSecret: true # When true, a secret will be created with a default username and password. Useful for demos. + + resources: {} + security: + enabled: false + cert_file: /kiali-cert/cert-chain.pem + private_key_file: /kiali-cert/key.pem diff --git a/istio-1.5.0/install/kubernetes/operator/charts/istio-telemetry/mixer-telemetry/Chart.yaml b/istio-1.5.0/install/kubernetes/operator/charts/istio-telemetry/mixer-telemetry/Chart.yaml new file mode 100644 index 0000000..5356739 --- /dev/null +++ b/istio-1.5.0/install/kubernetes/operator/charts/istio-telemetry/mixer-telemetry/Chart.yaml @@ -0,0 +1,13 @@ +apiVersion: v1 +name: mixer-telemetry +version: 1.1.0 +appVersion: 1.1.0 +tillerVersion: ">=2.7.2" +description: Helm chart for mixer deployment +keywords: + - istio + - mixer +sources: + - http://github.com/istio/istio +engine: gotpl +icon: https://istio.io/favicons/android-192x192.png diff --git a/istio-1.5.0/install/kubernetes/operator/charts/istio-telemetry/mixer-telemetry/templates/_affinity.tpl b/istio-1.5.0/install/kubernetes/operator/charts/istio-telemetry/mixer-telemetry/templates/_affinity.tpl new file mode 100644 index 0000000..d1e1e89 --- /dev/null +++ b/istio-1.5.0/install/kubernetes/operator/charts/istio-telemetry/mixer-telemetry/templates/_affinity.tpl @@ -0,0 +1,93 @@ +{{/* affinity - https://kubernetes.io/docs/concepts/configuration/assign-pod-node/ */}} + +{{- define "nodeaffinity" }} + nodeAffinity: + requiredDuringSchedulingIgnoredDuringExecution: + {{- include "nodeAffinityRequiredDuringScheduling" . }} + preferredDuringSchedulingIgnoredDuringExecution: + {{- include "nodeAffinityPreferredDuringScheduling" . }} +{{- end }} + +{{- define "nodeAffinityRequiredDuringScheduling" }} + nodeSelectorTerms: + - matchExpressions: + - key: beta.kubernetes.io/arch + operator: In + values: + {{- range $key, $val := .Values.global.arch }} + {{- if gt ($val | int) 0 }} + - {{ $key | quote }} + {{- end }} + {{- end }} + {{- $nodeSelector := default .Values.global.defaultNodeSelector .Values.mixer.telemetry.nodeSelector -}} + {{- range $key, $val := $nodeSelector }} + - key: {{ $key }} + operator: In + values: + - {{ $val | quote }} + {{- end }} +{{- end }} + +{{- define "nodeAffinityPreferredDuringScheduling" }} + {{- range $key, $val := .Values.global.arch }} + {{- if gt ($val | int) 0 }} + - weight: {{ $val | int }} + preference: + matchExpressions: + - key: beta.kubernetes.io/arch + operator: In + values: + - {{ $key | quote }} + {{- end }} + {{- end }} +{{- end }} + +{{- define "podAntiAffinity" }} +{{- if or .Values.mixer.telemetry.podAntiAffinityLabelSelector .Values.mixer.telemetry.podAntiAffinityTermLabelSelector}} + podAntiAffinity: + {{- if .Values.mixer.telemetry.podAntiAffinityLabelSelector }} + requiredDuringSchedulingIgnoredDuringExecution: + {{- include "podAntiAffinityRequiredDuringScheduling" . }} + {{- end }} + {{- if .Values.mixer.telemetry.podAntiAffinityTermLabelSelector }} + preferredDuringSchedulingIgnoredDuringExecution: + {{- include "podAntiAffinityPreferredDuringScheduling" . }} + {{- end }} +{{- end }} +{{- end }} + +{{- define "podAntiAffinityRequiredDuringScheduling" }} + {{- range $index, $item := .Values.mixer.telemetry.podAntiAffinityLabelSelector }} + - labelSelector: + matchExpressions: + - key: {{ $item.key }} + operator: {{ $item.operator }} + {{- if $item.values }} + values: + {{- $vals := split "," $item.values }} + {{- range $i, $v := $vals }} + - {{ $v | quote }} + {{- end }} + {{- end }} + topologyKey: {{ $item.topologyKey }} + {{- end }} +{{- end }} + +{{- define "podAntiAffinityPreferredDuringScheduling" }} + {{- range $index, $item := .Values.mixer.telemetry.podAntiAffinityTermLabelSelector }} + - podAffinityTerm: + labelSelector: + matchExpressions: + - key: {{ $item.key }} + operator: {{ $item.operator }} + {{- if $item.values }} + values: + {{- $vals := split "," $item.values }} + {{- range $i, $v := $vals }} + - {{ $v | quote }} + {{- end }} + {{- end }} + topologyKey: {{ $item.topologyKey }} + weight: 100 + {{- end }} +{{- end }} diff --git a/istio-1.5.0/install/kubernetes/operator/charts/istio-telemetry/mixer-telemetry/templates/autoscale.yaml b/istio-1.5.0/install/kubernetes/operator/charts/istio-telemetry/mixer-telemetry/templates/autoscale.yaml new file mode 100644 index 0000000..23fa5ac --- /dev/null +++ b/istio-1.5.0/install/kubernetes/operator/charts/istio-telemetry/mixer-telemetry/templates/autoscale.yaml @@ -0,0 +1,23 @@ +{{- if .Values.mixer.telemetry.autoscaleMin }} +apiVersion: autoscaling/v2beta1 +kind: HorizontalPodAutoscaler +metadata: + name: istio-telemetry + namespace: {{ .Release.Namespace }} + labels: + app: mixer + release: {{ .Release.Name }} +spec: + maxReplicas: {{ .Values.mixer.telemetry.autoscaleMax }} + minReplicas: {{ .Values.mixer.telemetry.autoscaleMin }} + scaleTargetRef: + apiVersion: apps/v1 + kind: Deployment + name: istio-telemetry + metrics: + - type: Resource + resource: + name: cpu + targetAverageUtilization: {{ .Values.mixer.telemetry.cpu.targetAverageUtilization }} +--- +{{- end }} diff --git a/istio-1.5.0/install/kubernetes/operator/charts/istio-telemetry/mixer-telemetry/templates/clusterrole.yaml b/istio-1.5.0/install/kubernetes/operator/charts/istio-telemetry/mixer-telemetry/templates/clusterrole.yaml new file mode 100644 index 0000000..bd10d8d --- /dev/null +++ b/istio-1.5.0/install/kubernetes/operator/charts/istio-telemetry/mixer-telemetry/templates/clusterrole.yaml @@ -0,0 +1,21 @@ +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: istio-mixer-{{ .Release.Namespace }} + labels: + app: istio-telemetry + release: {{ .Release.Name }} +rules: +- apiGroups: ["config.istio.io"] # istio CRD watcher + resources: ["*"] + verbs: ["create", "get", "list", "watch", "patch"] +- apiGroups: ["apiextensions.k8s.io"] + resources: ["customresourcedefinitions"] + verbs: ["get", "list", "watch"] +- apiGroups: [""] + resources: ["configmaps", "endpoints", "pods", "services", "namespaces", "secrets", "replicationcontrollers"] + verbs: ["get", "list", "watch"] +- apiGroups: ["extensions", "apps"] + resources: ["replicasets"] + verbs: ["get", "list", "watch"] +--- diff --git a/istio-1.5.0/install/kubernetes/operator/charts/istio-telemetry/mixer-telemetry/templates/clusterrolebinding.yaml b/istio-1.5.0/install/kubernetes/operator/charts/istio-telemetry/mixer-telemetry/templates/clusterrolebinding.yaml new file mode 100644 index 0000000..5dd8046 --- /dev/null +++ b/istio-1.5.0/install/kubernetes/operator/charts/istio-telemetry/mixer-telemetry/templates/clusterrolebinding.yaml @@ -0,0 +1,16 @@ +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: istio-mixer-admin-role-binding-{{ .Release.Namespace }} + labels: + app: istio-telemetry + release: {{ .Release.Name }} +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: istio-mixer-{{ .Release.Namespace }} +subjects: + - kind: ServiceAccount + name: istio-mixer-service-account + namespace: {{ .Release.Namespace }} +--- diff --git a/istio-1.5.0/install/kubernetes/operator/charts/istio-telemetry/mixer-telemetry/templates/config.yaml b/istio-1.5.0/install/kubernetes/operator/charts/istio-telemetry/mixer-telemetry/templates/config.yaml new file mode 100644 index 0000000..4b2b8b8 --- /dev/null +++ b/istio-1.5.0/install/kubernetes/operator/charts/istio-telemetry/mixer-telemetry/templates/config.yaml @@ -0,0 +1,994 @@ +apiVersion: "config.istio.io/v1alpha2" +kind: attributemanifest +metadata: + name: istioproxy + namespace: {{ .Release.Namespace }} + labels: + app: istio-telemetry + release: {{ .Release.Name }} +spec: + attributes: + origin.ip: + valueType: IP_ADDRESS + origin.uid: + valueType: STRING + origin.user: + valueType: STRING + request.headers: + valueType: STRING_MAP + request.id: + valueType: STRING + request.host: + valueType: STRING + request.method: + valueType: STRING + request.path: + valueType: STRING + request.url_path: + valueType: STRING + request.query_params: + valueType: STRING_MAP + request.reason: + valueType: STRING + request.referer: + valueType: STRING + request.scheme: + valueType: STRING + request.total_size: + valueType: INT64 + request.size: + valueType: INT64 + request.time: + valueType: TIMESTAMP + request.useragent: + valueType: STRING + response.code: + valueType: INT64 + response.duration: + valueType: DURATION + response.headers: + valueType: STRING_MAP + response.total_size: + valueType: INT64 + response.size: + valueType: INT64 + response.time: + valueType: TIMESTAMP + response.grpc_status: + valueType: STRING + response.grpc_message: + valueType: STRING + source.uid: + valueType: STRING + source.user: # DEPRECATED + valueType: STRING + source.principal: + valueType: STRING + destination.uid: + valueType: STRING + destination.principal: + valueType: STRING + destination.port: + valueType: INT64 + connection.event: + valueType: STRING + connection.id: + valueType: STRING + connection.received.bytes: + valueType: INT64 + connection.received.bytes_total: + valueType: INT64 + connection.sent.bytes: + valueType: INT64 + connection.sent.bytes_total: + valueType: INT64 + connection.duration: + valueType: DURATION + connection.mtls: + valueType: BOOL + connection.requested_server_name: + valueType: STRING + context.protocol: + valueType: STRING + context.proxy_error_code: + valueType: STRING + context.timestamp: + valueType: TIMESTAMP + context.time: + valueType: TIMESTAMP + # Deprecated, kept for compatibility + context.reporter.local: + valueType: BOOL + context.reporter.kind: + valueType: STRING + context.reporter.uid: + valueType: STRING + context.proxy_version: + valueType: STRING + api.service: + valueType: STRING + api.version: + valueType: STRING + api.operation: + valueType: STRING + api.protocol: + valueType: STRING + request.auth.principal: + valueType: STRING + request.auth.audiences: + valueType: STRING + request.auth.presenter: + valueType: STRING + request.auth.claims: + valueType: STRING_MAP + request.auth.raw_claims: + valueType: STRING + request.api_key: + valueType: STRING + rbac.permissive.response_code: + valueType: STRING + rbac.permissive.effective_policy_id: + valueType: STRING + check.error_code: + valueType: INT64 + check.error_message: + valueType: STRING + check.cache_hit: + valueType: BOOL + quota.cache_hit: + valueType: BOOL + +--- +apiVersion: "config.istio.io/v1alpha2" +kind: attributemanifest +metadata: + name: kubernetes + namespace: {{ .Release.Namespace }} + labels: + app: istio-telemetry + release: {{ .Release.Name }} +spec: + attributes: + source.ip: + valueType: IP_ADDRESS + source.labels: + valueType: STRING_MAP + source.metadata: + valueType: STRING_MAP + source.name: + valueType: STRING + source.namespace: + valueType: STRING + source.owner: + valueType: STRING + source.serviceAccount: + valueType: STRING + source.services: + valueType: STRING + source.workload.uid: + valueType: STRING + source.workload.name: + valueType: STRING + source.workload.namespace: + valueType: STRING + destination.ip: + valueType: IP_ADDRESS + destination.labels: + valueType: STRING_MAP + destination.metadata: + valueType: STRING_MAP + destination.owner: + valueType: STRING + destination.name: + valueType: STRING + destination.container.name: + valueType: STRING + destination.namespace: + valueType: STRING + destination.service.uid: + valueType: STRING + destination.service.name: + valueType: STRING + destination.service.namespace: + valueType: STRING + destination.service.host: + valueType: STRING + destination.serviceAccount: + valueType: STRING + destination.workload.uid: + valueType: STRING + destination.workload.name: + valueType: STRING + destination.workload.namespace: + valueType: STRING +--- +{{- if .Values.mixer.adapters.stdio.enabled }} +apiVersion: "config.istio.io/v1alpha2" +kind: handler +metadata: + name: stdio + namespace: {{ .Release.Namespace }} + labels: + app: istio-telemetry + release: {{ .Release.Name }} +spec: + compiledAdapter: stdio + params: + outputAsJson: {{ .Values.mixer.adapters.stdio.outputAsJson }} +--- +apiVersion: "config.istio.io/v1alpha2" +kind: instance +metadata: + name: accesslog + namespace: {{ .Release.Namespace }} + labels: + app: istio-telemetry + release: {{ .Release.Name }} +spec: + compiledTemplate: logentry + params: + severity: '"Info"' + timestamp: request.time + variables: + sourceIp: source.ip | ip("0.0.0.0") + sourceApp: source.labels["app"] | "" + sourcePrincipal: source.principal | "" + sourceName: source.name | "" + sourceWorkload: source.workload.name | "" + sourceNamespace: source.namespace | "" + sourceOwner: source.owner | "" + destinationApp: destination.labels["app"] | "" + destinationIp: destination.ip | ip("0.0.0.0") + destinationServiceHost: destination.service.host | request.host | "" + destinationWorkload: destination.workload.name | "" + destinationName: destination.name | "" + destinationNamespace: destination.namespace | "" + destinationOwner: destination.owner | "" + destinationPrincipal: destination.principal | "" + apiClaims: request.auth.raw_claims | "" + apiKey: request.api_key | request.headers["x-api-key"] | "" + protocol: api.protocol | context.protocol | "http" + method: request.method | "" + url: request.path | "" + responseCode: response.code | 0 + responseFlags: context.proxy_error_code | "" + responseSize: response.size | 0 + permissiveResponseCode: rbac.permissive.response_code | "none" + permissiveResponsePolicyID: rbac.permissive.effective_policy_id | "none" + requestSize: request.size | 0 + requestId: request.headers["x-request-id"] | "" + clientTraceId: request.headers["x-client-trace-id"] | "" + latency: response.duration | "0ms" + connection_security_policy: conditional((context.reporter.kind | "inbound") == "outbound", "unknown", conditional(connection.mtls | false, "mutual_tls", "none")) + requestedServerName: connection.requested_server_name | "" + userAgent: request.useragent | "" + responseTimestamp: response.time + receivedBytes: request.total_size | 0 + sentBytes: response.total_size | 0 + referer: request.referer | "" + httpAuthority: request.headers[":authority"] | request.host | "" + xForwardedFor: request.headers["x-forwarded-for"] | "0.0.0.0" + reporter: conditional((context.reporter.kind | "inbound") == "outbound", "source", "destination") + grpcStatus: response.grpc_status | "" + grpcMessage: response.grpc_message | "" + monitored_resource_type: '"global"' +--- +apiVersion: "config.istio.io/v1alpha2" +kind: instance +metadata: + name: tcpaccesslog + namespace: {{ .Release.Namespace }} + labels: + app: istio-telemetry + release: {{ .Release.Name }} +spec: + compiledTemplate: logentry + params: + severity: '"Info"' + timestamp: context.time | timestamp("2017-01-01T00:00:00Z") + variables: + connectionEvent: connection.event | "" + sourceIp: source.ip | ip("0.0.0.0") + sourceApp: source.labels["app"] | "" + sourcePrincipal: source.principal | "" + sourceName: source.name | "" + sourceWorkload: source.workload.name | "" + sourceNamespace: source.namespace | "" + sourceOwner: source.owner | "" + destinationApp: destination.labels["app"] | "" + destinationIp: destination.ip | ip("0.0.0.0") + destinationServiceHost: destination.service.host | "" + destinationWorkload: destination.workload.name | "" + destinationName: destination.name | "" + destinationNamespace: destination.namespace | "" + destinationOwner: destination.owner | "" + destinationPrincipal: destination.principal | "" + protocol: context.protocol | "tcp" + connectionDuration: connection.duration | "0ms" + connection_security_policy: conditional((context.reporter.kind | "inbound") == "outbound", "unknown", conditional(connection.mtls | false, "mutual_tls", "none")) + requestedServerName: connection.requested_server_name | "" + receivedBytes: connection.received.bytes | 0 + sentBytes: connection.sent.bytes | 0 + totalReceivedBytes: connection.received.bytes_total | 0 + totalSentBytes: connection.sent.bytes_total | 0 + reporter: conditional((context.reporter.kind | "inbound") == "outbound", "source", "destination") + responseFlags: context.proxy_error_code | "" + monitored_resource_type: '"global"' +--- +apiVersion: "config.istio.io/v1alpha2" +kind: rule +metadata: + name: stdio + namespace: {{ .Release.Namespace }} + labels: + app: istio-telemetry + release: {{ .Release.Name }} +spec: + match: context.protocol == "http" || context.protocol == "grpc" + actions: + - handler: stdio + instances: + - accesslog +--- +apiVersion: "config.istio.io/v1alpha2" +kind: rule +metadata: + name: stdiotcp + namespace: {{ .Release.Namespace }} + labels: + app: istio-telemetry + release: {{ .Release.Name }} +spec: + match: context.protocol == "tcp" + actions: + - handler: stdio + instances: + - tcpaccesslog +{{- end }} +--- +{{- if .Values.mixer.adapters.prometheus.enabled }} +apiVersion: "config.istio.io/v1alpha2" +kind: instance +metadata: + name: requestcount + namespace: {{ .Release.Namespace }} + labels: + app: istio-telemetry + release: {{ .Release.Name }} +spec: + compiledTemplate: metric + params: + value: "1" + dimensions: + reporter: conditional((context.reporter.kind | "inbound") == "outbound", "source", "destination") + source_workload: source.workload.name | "unknown" + source_workload_namespace: source.workload.namespace | "unknown" + source_principal: source.principal | "unknown" + source_app: source.labels["app"] | "unknown" + source_version: source.labels["version"] | "unknown" + destination_workload: destination.workload.name | "unknown" + destination_workload_namespace: destination.workload.namespace | "unknown" + destination_principal: destination.principal | "unknown" + destination_app: destination.labels["app"] | "unknown" + destination_version: destination.labels["version"] | "unknown" + destination_service: destination.service.host | conditional((destination.service.name | "unknown") == "unknown", "unknown", request.host) + destination_service_name: destination.service.name | "unknown" + destination_service_namespace: destination.service.namespace | "unknown" + request_protocol: api.protocol | context.protocol | "unknown" + response_code: response.code | 200 + grpc_response_status: response.grpc_status | "" + response_flags: context.proxy_error_code | "-" + connection_security_policy: conditional((context.reporter.kind | "inbound") == "outbound", "unknown", conditional(connection.mtls | false, "mutual_tls", "none")) + monitored_resource_type: '"UNSPECIFIED"' +--- +apiVersion: "config.istio.io/v1alpha2" +kind: instance +metadata: + name: requestduration + namespace: {{ .Release.Namespace }} + labels: + app: istio-telemetry + release: {{ .Release.Name }} +spec: + compiledTemplate: metric + params: + value: response.duration | "0ms" + dimensions: + reporter: conditional((context.reporter.kind | "inbound") == "outbound", "source", "destination") + source_workload: source.workload.name | "unknown" + source_workload_namespace: source.workload.namespace | "unknown" + source_principal: source.principal | "unknown" + source_app: source.labels["app"] | "unknown" + source_version: source.labels["version"] | "unknown" + destination_workload: destination.workload.name | "unknown" + destination_workload_namespace: destination.workload.namespace | "unknown" + destination_principal: destination.principal | "unknown" + destination_app: destination.labels["app"] | "unknown" + destination_version: destination.labels["version"] | "unknown" + destination_service: destination.service.host | conditional((destination.service.name | "unknown") == "unknown", "unknown", request.host) + destination_service_name: destination.service.name | "unknown" + destination_service_namespace: destination.service.namespace | "unknown" + request_protocol: api.protocol | context.protocol | "unknown" + response_code: response.code | 200 + grpc_response_status: response.grpc_status | "" + response_flags: context.proxy_error_code | "-" + connection_security_policy: conditional((context.reporter.kind | "inbound") == "outbound", "unknown", conditional(connection.mtls | false, "mutual_tls", "none")) + monitored_resource_type: '"UNSPECIFIED"' +--- +apiVersion: "config.istio.io/v1alpha2" +kind: instance +metadata: + name: requestsize + namespace: {{ .Release.Namespace }} + labels: + app: istio-telemetry + release: {{ .Release.Name }} +spec: + compiledTemplate: metric + params: + value: request.size | 0 + dimensions: + reporter: conditional((context.reporter.kind | "inbound") == "outbound", "source", "destination") + source_workload: source.workload.name | "unknown" + source_workload_namespace: source.workload.namespace | "unknown" + source_principal: source.principal | "unknown" + source_app: source.labels["app"] | "unknown" + source_version: source.labels["version"] | "unknown" + destination_workload: destination.workload.name | "unknown" + destination_workload_namespace: destination.workload.namespace | "unknown" + destination_principal: destination.principal | "unknown" + destination_app: destination.labels["app"] | "unknown" + destination_version: destination.labels["version"] | "unknown" + destination_service: destination.service.host | conditional((destination.service.name | "unknown") == "unknown", "unknown", request.host) + destination_service_name: destination.service.name | "unknown" + destination_service_namespace: destination.service.namespace | "unknown" + request_protocol: api.protocol | context.protocol | "unknown" + response_code: response.code | 200 + grpc_response_status: response.grpc_status | "" + response_flags: context.proxy_error_code | "-" + connection_security_policy: conditional((context.reporter.kind | "inbound") == "outbound", "unknown", conditional(connection.mtls | false, "mutual_tls", "none")) + monitored_resource_type: '"UNSPECIFIED"' +--- +apiVersion: "config.istio.io/v1alpha2" +kind: instance +metadata: + name: responsesize + namespace: {{ .Release.Namespace }} + labels: + app: istio-telemetry + release: {{ .Release.Name }} +spec: + compiledTemplate: metric + params: + value: response.size | 0 + dimensions: + reporter: conditional((context.reporter.kind | "inbound") == "outbound", "source", "destination") + source_workload: source.workload.name | "unknown" + source_workload_namespace: source.workload.namespace | "unknown" + source_principal: source.principal | "unknown" + source_app: source.labels["app"] | "unknown" + source_version: source.labels["version"] | "unknown" + destination_workload: destination.workload.name | "unknown" + destination_workload_namespace: destination.workload.namespace | "unknown" + destination_principal: destination.principal | "unknown" + destination_app: destination.labels["app"] | "unknown" + destination_version: destination.labels["version"] | "unknown" + destination_service: destination.service.host | conditional((destination.service.name | "unknown") == "unknown", "unknown", request.host) + destination_service_name: destination.service.name | "unknown" + destination_service_namespace: destination.service.namespace | "unknown" + request_protocol: api.protocol | context.protocol | "unknown" + response_code: response.code | 200 + grpc_response_status: response.grpc_status | "" + response_flags: context.proxy_error_code | "-" + connection_security_policy: conditional((context.reporter.kind | "inbound") == "outbound", "unknown", conditional(connection.mtls | false, "mutual_tls", "none")) + monitored_resource_type: '"UNSPECIFIED"' +--- +apiVersion: "config.istio.io/v1alpha2" +kind: instance +metadata: + name: tcpbytesent + namespace: {{ .Release.Namespace }} + labels: + app: istio-telemetry + release: {{ .Release.Name }} +spec: + compiledTemplate: metric + params: + value: connection.sent.bytes | 0 + dimensions: + reporter: conditional((context.reporter.kind | "inbound") == "outbound", "source", "destination") + source_workload: source.workload.name | "unknown" + source_workload_namespace: source.workload.namespace | "unknown" + source_principal: source.principal | "unknown" + source_app: source.labels["app"] | "unknown" + source_version: source.labels["version"] | "unknown" + destination_workload: destination.workload.name | "unknown" + destination_workload_namespace: destination.workload.namespace | "unknown" + destination_principal: destination.principal | "unknown" + destination_app: destination.labels["app"] | "unknown" + destination_version: destination.labels["version"] | "unknown" + destination_service: destination.service.host | "unknown" + destination_service_name: destination.service.name | "unknown" + destination_service_namespace: destination.service.namespace | "unknown" + connection_security_policy: conditional((context.reporter.kind | "inbound") == "outbound", "unknown", conditional(connection.mtls | false, "mutual_tls", "none")) + response_flags: context.proxy_error_code | "-" + monitored_resource_type: '"UNSPECIFIED"' +--- +apiVersion: "config.istio.io/v1alpha2" +kind: instance +metadata: + name: tcpbytereceived + namespace: {{ .Release.Namespace }} + labels: + app: istio-telemetry + release: {{ .Release.Name }} +spec: + compiledTemplate: metric + params: + value: connection.received.bytes | 0 + dimensions: + reporter: conditional((context.reporter.kind | "inbound") == "outbound", "source", "destination") + source_workload: source.workload.name | "unknown" + source_workload_namespace: source.workload.namespace | "unknown" + source_principal: source.principal | "unknown" + source_app: source.labels["app"] | "unknown" + source_version: source.labels["version"] | "unknown" + destination_workload: destination.workload.name | "unknown" + destination_workload_namespace: destination.workload.namespace | "unknown" + destination_principal: destination.principal | "unknown" + destination_app: destination.labels["app"] | "unknown" + destination_version: destination.labels["version"] | "unknown" + destination_service: destination.service.host | "unknown" + destination_service_name: destination.service.name | "unknown" + destination_service_namespace: destination.service.namespace | "unknown" + connection_security_policy: conditional((context.reporter.kind | "inbound") == "outbound", "unknown", conditional(connection.mtls | false, "mutual_tls", "none")) + response_flags: context.proxy_error_code | "-" + monitored_resource_type: '"UNSPECIFIED"' +--- +apiVersion: "config.istio.io/v1alpha2" +kind: instance +metadata: + name: tcpconnectionsopened + namespace: {{ .Release.Namespace }} + labels: + app: istio-telemetry + release: {{ .Release.Name }} +spec: + compiledTemplate: metric + params: + value: "1" + dimensions: + reporter: conditional((context.reporter.kind | "inbound") == "outbound", "source", "destination") + source_workload: source.workload.name | "unknown" + source_workload_namespace: source.workload.namespace | "unknown" + source_principal: source.principal | "unknown" + source_app: source.labels["app"] | "unknown" + source_version: source.labels["version"] | "unknown" + destination_workload: destination.workload.name | "unknown" + destination_workload_namespace: destination.workload.namespace | "unknown" + destination_principal: destination.principal | "unknown" + destination_app: destination.labels["app"] | "unknown" + destination_version: destination.labels["version"] | "unknown" + destination_service: destination.service.host | "unknown" + destination_service_name: destination.service.name | "unknown" + destination_service_namespace: destination.service.namespace | "unknown" + connection_security_policy: conditional((context.reporter.kind | "inbound") == "outbound", "unknown", conditional(connection.mtls | false, "mutual_tls", "none")) + response_flags: context.proxy_error_code | "-" + monitored_resource_type: '"UNSPECIFIED"' +--- +apiVersion: "config.istio.io/v1alpha2" +kind: instance +metadata: + name: tcpconnectionsclosed + namespace: {{ .Release.Namespace }} + labels: + app: istio-telemetry + release: {{ .Release.Name }} +spec: + compiledTemplate: metric + params: + value: "1" + dimensions: + reporter: conditional((context.reporter.kind | "inbound") == "outbound", "source", "destination") + source_workload: source.workload.name | "unknown" + source_workload_namespace: source.workload.namespace | "unknown" + source_principal: source.principal | "unknown" + source_app: source.labels["app"] | "unknown" + source_version: source.labels["version"] | "unknown" + destination_workload: destination.workload.name | "unknown" + destination_workload_namespace: destination.workload.namespace | "unknown" + destination_principal: destination.principal | "unknown" + destination_app: destination.labels["app"] | "unknown" + destination_version: destination.labels["version"] | "unknown" + destination_service: destination.service.host | "unknown" + destination_service_name: destination.service.name | "unknown" + destination_service_namespace: destination.service.namespace | "unknown" + connection_security_policy: conditional((context.reporter.kind | "inbound") == "outbound", "unknown", conditional(connection.mtls | false, "mutual_tls", "none")) + response_flags: context.proxy_error_code | "-" + monitored_resource_type: '"UNSPECIFIED"' +--- +apiVersion: "config.istio.io/v1alpha2" +kind: handler +metadata: + name: prometheus + namespace: {{ .Release.Namespace }} + labels: + app: istio-telemetry + release: {{ .Release.Name }} +spec: + compiledAdapter: prometheus + params: + metricsExpirationPolicy: + metricsExpiryDuration: "{{ .Values.mixer.adapters.prometheus.metricsExpiryDuration }}" + metrics: + - name: requests_total + instance_name: requestcount.instance.{{ .Release.Namespace }} + kind: COUNTER + label_names: + - reporter + - source_app + - source_principal + - source_workload + - source_workload_namespace + - source_version + - destination_app + - destination_principal + - destination_workload + - destination_workload_namespace + - destination_version + - destination_service + - destination_service_name + - destination_service_namespace + - request_protocol + - grpc_response_status + - response_code + - response_flags + - connection_security_policy + - name: request_duration_seconds + instance_name: requestduration.instance.{{ .Release.Namespace }} + kind: DISTRIBUTION + label_names: + - reporter + - source_app + - source_principal + - source_workload + - source_workload_namespace + - source_version + - destination_app + - destination_principal + - destination_workload + - destination_workload_namespace + - destination_version + - destination_service + - destination_service_name + - destination_service_namespace + - request_protocol + - response_code + - grpc_response_status + - response_flags + - connection_security_policy + buckets: + explicit_buckets: + bounds: [0.005, 0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 1, 2.5, 5, 10] + - name: request_bytes + instance_name: requestsize.instance.{{ .Release.Namespace }} + kind: DISTRIBUTION + label_names: + - reporter + - source_app + - source_principal + - source_workload + - source_workload_namespace + - source_version + - destination_app + - destination_principal + - destination_workload + - destination_workload_namespace + - destination_version + - destination_service + - destination_service_name + - destination_service_namespace + - request_protocol + - response_code + - grpc_response_status + - response_flags + - connection_security_policy + buckets: + exponentialBuckets: + numFiniteBuckets: 8 + scale: 1 + growthFactor: 10 + - name: response_bytes + instance_name: responsesize.instance.{{ .Release.Namespace }} + kind: DISTRIBUTION + label_names: + - reporter + - source_app + - source_principal + - source_workload + - source_workload_namespace + - source_version + - destination_app + - destination_principal + - destination_workload + - destination_workload_namespace + - destination_version + - destination_service + - destination_service_name + - destination_service_namespace + - request_protocol + - response_code + - grpc_response_status + - response_flags + - connection_security_policy + buckets: + exponentialBuckets: + numFiniteBuckets: 8 + scale: 1 + growthFactor: 10 + - name: tcp_sent_bytes_total + instance_name: tcpbytesent.instance.{{ .Release.Namespace }} + kind: COUNTER + label_names: + - reporter + - source_app + - source_principal + - source_workload + - source_workload_namespace + - source_version + - destination_app + - destination_principal + - destination_workload + - destination_workload_namespace + - destination_version + - destination_service + - destination_service_name + - destination_service_namespace + - connection_security_policy + - response_flags + - name: tcp_received_bytes_total + instance_name: tcpbytereceived.instance.{{ .Release.Namespace }} + kind: COUNTER + label_names: + - reporter + - source_app + - source_principal + - source_workload + - source_workload_namespace + - source_version + - destination_app + - destination_principal + - destination_workload + - destination_workload_namespace + - destination_version + - destination_service + - destination_service_name + - destination_service_namespace + - connection_security_policy + - response_flags + - name: tcp_connections_opened_total + instance_name: tcpconnectionsopened.instance.{{ .Release.Namespace }} + kind: COUNTER + label_names: + - reporter + - source_app + - source_principal + - source_workload + - source_workload_namespace + - source_version + - destination_app + - destination_principal + - destination_workload + - destination_workload_namespace + - destination_version + - destination_service + - destination_service_name + - destination_service_namespace + - connection_security_policy + - response_flags + - name: tcp_connections_closed_total + instance_name: tcpconnectionsclosed.instance.{{ .Release.Namespace }} + kind: COUNTER + label_names: + - reporter + - source_app + - source_principal + - source_workload + - source_workload_namespace + - source_version + - destination_app + - destination_principal + - destination_workload + - destination_workload_namespace + - destination_version + - destination_service + - destination_service_name + - destination_service_namespace + - connection_security_policy + - response_flags +--- +apiVersion: "config.istio.io/v1alpha2" +kind: rule +metadata: + name: promhttp + namespace: {{ .Release.Namespace }} + labels: + app: istio-telemetry + release: {{ .Release.Name }} +spec: + match: (context.protocol == "http" || context.protocol == "grpc") && (match((request.useragent | "-"), "kube-probe*") == false) && (match((request.useragent | "-"), "Prometheus*") == false) + actions: + - handler: prometheus + instances: + - requestcount + - requestduration + - requestsize + - responsesize +--- +apiVersion: "config.istio.io/v1alpha2" +kind: rule +metadata: + name: promtcp + namespace: {{ .Release.Namespace }} + labels: + app: istio-telemetry + release: {{ .Release.Name }} +spec: + match: context.protocol == "tcp" + actions: + - handler: prometheus + instances: + - tcpbytesent + - tcpbytereceived +--- +apiVersion: "config.istio.io/v1alpha2" +kind: rule +metadata: + name: promtcpconnectionopen + namespace: {{ .Release.Namespace }} + labels: + app: istio-telemetry + release: {{ .Release.Name }} +spec: + match: context.protocol == "tcp" && ((connection.event | "na") == "open") + actions: + - handler: prometheus + instances: + - tcpconnectionsopened +--- +apiVersion: "config.istio.io/v1alpha2" +kind: rule +metadata: + name: promtcpconnectionclosed + namespace: {{ .Release.Namespace }} + labels: + app: istio-telemetry + release: {{ .Release.Name }} +spec: + match: context.protocol == "tcp" && ((connection.event | "na") == "close") + actions: + - handler: prometheus + instances: + - tcpconnectionsclosed +{{- end }} +--- +{{- if .Values.mixer.adapters.kubernetesenv.enabled }} +apiVersion: "config.istio.io/v1alpha2" +kind: handler +metadata: + name: kubernetesenv + namespace: {{ .Release.Namespace }} + labels: + app: istio-telemetry + release: {{ .Release.Name }} +spec: + compiledAdapter: kubernetesenv + params: {} + # when running from mixer root, use the following config after adding a + # symbolic link to a kubernetes config file via: + # + # $ ln -s ~/.kube/config mixer/adapter/kubernetes/kubeconfig + # + # kubeconfig_path: "mixer/adapter/kubernetes/kubeconfig" + +--- +apiVersion: "config.istio.io/v1alpha2" +kind: rule +metadata: + name: kubeattrgenrulerule + namespace: {{ .Release.Namespace }} + labels: + app: istio-telemetry + release: {{ .Release.Name }} +spec: + actions: + - handler: kubernetesenv + instances: + - attributes +--- +apiVersion: "config.istio.io/v1alpha2" +kind: rule +metadata: + name: tcpkubeattrgenrulerule + namespace: {{ .Release.Namespace }} + labels: + app: istio-telemetry + release: {{ .Release.Name }} +spec: + match: context.protocol == "tcp" + actions: + - handler: kubernetesenv + instances: + - attributes +--- +apiVersion: "config.istio.io/v1alpha2" +kind: instance +metadata: + name: attributes + namespace: {{ .Release.Namespace }} + labels: + app: istio-telemetry + release: {{ .Release.Name }} +spec: + compiledTemplate: kubernetes + params: + # Pass the required attribute data to the adapter + source_uid: source.uid | "" + source_ip: source.ip | ip("0.0.0.0") # default to unspecified ip addr + destination_uid: destination.uid | "" + destination_port: destination.port | 0 + attributeBindings: + # Fill the new attributes from the adapter produced output. + # $out refers to an instance of OutputTemplate message + source.ip: $out.source_pod_ip | ip("0.0.0.0") + source.uid: $out.source_pod_uid | "unknown" + source.labels: $out.source_labels | emptyStringMap() + source.name: $out.source_pod_name | "unknown" + source.namespace: $out.source_namespace | "default" + source.owner: $out.source_owner | "unknown" + source.serviceAccount: $out.source_service_account_name | "unknown" + source.workload.uid: $out.source_workload_uid | "unknown" + source.workload.name: $out.source_workload_name | "unknown" + source.workload.namespace: $out.source_workload_namespace | "unknown" + destination.ip: $out.destination_pod_ip | ip("0.0.0.0") + destination.uid: $out.destination_pod_uid | "unknown" + destination.labels: $out.destination_labels | emptyStringMap() + destination.name: $out.destination_pod_name | "unknown" + destination.container.name: $out.destination_container_name | "unknown" + destination.namespace: $out.destination_namespace | "default" + destination.owner: $out.destination_owner | "unknown" + destination.serviceAccount: $out.destination_service_account_name | "unknown" + destination.workload.uid: $out.destination_workload_uid | "unknown" + destination.workload.name: $out.destination_workload_name | "unknown" + destination.workload.namespace: $out.destination_workload_namespace | "unknown" +{{- end }} +--- +apiVersion: networking.istio.io/v1alpha3 +kind: DestinationRule +metadata: + name: istio-telemetry + namespace: {{ .Release.Namespace }} + labels: + app: istio-telemetry + release: {{ .Release.Name }} +spec: + host: istio-telemetry.{{ .Release.Namespace }}.svc.{{ .Values.global.proxy.clusterDomain }} + {{- if .Values.global.defaultConfigVisibilitySettings }} + exportTo: + - '*' + {{- end }} + trafficPolicy: + portLevelSettings: + - port: + number: 15004 # grpc-mixer-mtls + tls: + mode: ISTIO_MUTUAL + - port: + number: 9091 # grpc-mixer + tls: + mode: DISABLE + connectionPool: + http: + http2MaxRequests: 10000 + maxRequestsPerConnection: 10000 +--- diff --git a/istio-1.5.0/install/kubernetes/operator/charts/istio-telemetry/mixer-telemetry/templates/configmap-envoy.yaml b/istio-1.5.0/install/kubernetes/operator/charts/istio-telemetry/mixer-telemetry/templates/configmap-envoy.yaml new file mode 100644 index 0000000..ef496ff --- /dev/null +++ b/istio-1.5.0/install/kubernetes/operator/charts/istio-telemetry/mixer-telemetry/templates/configmap-envoy.yaml @@ -0,0 +1,300 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + namespace: {{ .Release.Namespace }} + name: telemetry-envoy-config + labels: + release: {{ .Release.Name }} +data: + # Explicitly defined - moved from istio/istio/pilot/docker. + envoy.yaml.tmpl: |- + admin: + access_log_path: /dev/null + address: + socket_address: + address: 127.0.0.1 + port_value: 15000 + stats_config: + use_all_default_tags: false + stats_tags: + - tag_name: cluster_name + regex: '^cluster\.((.+?(\..+?\.svc\.cluster\.local)?)\.)' + - tag_name: tcp_prefix + regex: '^tcp\.((.*?)\.)\w+?$' + - tag_name: response_code + regex: '_rq(_(\d{3}))$' + - tag_name: response_code_class + regex: '_rq(_(\dxx))$' + - tag_name: http_conn_manager_listener_prefix + regex: '^listener(?=\.).*?\.http\.(((?:[_.[:digit:]]*|[_\[\]aAbBcCdDeEfF[:digit:]]*))\.)' + - tag_name: http_conn_manager_prefix + regex: '^http\.(((?:[_.[:digit:]]*|[_\[\]aAbBcCdDeEfF[:digit:]]*))\.)' + - tag_name: listener_address + regex: '^listener\.(((?:[_.[:digit:]]*|[_\[\]aAbBcCdDeEfF[:digit:]]*))\.)' + + static_resources: + clusters: + - name: prometheus_stats + type: STATIC + connect_timeout: 0.250s + lb_policy: ROUND_ROBIN + hosts: + - socket_address: + protocol: TCP + address: 127.0.0.1 + port_value: 15000 + + - name: inbound_9092 + circuit_breakers: + thresholds: + - max_connections: 100000 + max_pending_requests: 100000 + max_requests: 100000 + max_retries: 3 + connect_timeout: 1.000s + hosts: + - pipe: + path: /sock/mixer.socket + http2_protocol_options: {} + + - name: out.galley.15019 + http2_protocol_options: {} + connect_timeout: 1.000s + type: STRICT_DNS + + circuit_breakers: + thresholds: + - max_connections: 100000 + max_pending_requests: 100000 + max_requests: 100000 + max_retries: 3 + + tls_context: + common_tls_context: + tls_certificates: + - certificate_chain: + filename: /etc/certs/cert-chain.pem + private_key: + filename: /etc/certs/key.pem + validation_context: + trusted_ca: + filename: /etc/certs/root-cert.pem + verify_subject_alt_name: + - spiffe://{{ .Values.global.trustDomain }}/ns/{{ .Values.global.configNamespace }}/sa/istio-galley-service-account + + hosts: + - socket_address: + address: istio-galley.{{ .Values.global.configNamespace }} + port_value: 15019 + + + listeners: + - name: "15090" + address: + socket_address: + protocol: TCP + address: 0.0.0.0 + port_value: 15090 + filter_chains: + - filters: + - name: envoy.http_connection_manager + config: + codec_type: AUTO + stat_prefix: stats + route_config: + virtual_hosts: + - name: backend + domains: + - '*' + routes: + - match: + prefix: /stats/prometheus + route: + cluster: prometheus_stats + http_filters: + - name: envoy.router + + - name: "15004" + address: + socket_address: + address: 0.0.0.0 + port_value: 15004 + filter_chains: + - filters: + - config: + codec_type: HTTP2 + http2_protocol_options: + max_concurrent_streams: 1073741824 + generate_request_id: true + http_filters: + - config: + default_destination_service: istio-telemetry.{{ .Release.Namespace }}.svc.{{ .Values.global.proxy.clusterDomain }} + service_configs: + istio-telemetry.{{ .Release.Namespace }}.svc.{{ .Values.global.proxy.clusterDomain }}: + disable_check_calls: true + {{"{{"}}- if .DisableReportCalls {{"}}"}} + disable_report_calls: true + {{"{{"}}- end {{"}}"}} + mixer_attributes: + attributes: + destination.service.host: + string_value: istio-telemetry.{{ .Release.Namespace }}.svc.{{ .Values.global.proxy.clusterDomain }} + destination.service.uid: + string_value: istio://{{ .Release.Namespace }}/services/istio-telemetry + destination.service.name: + string_value: istio-telemetry + destination.service.namespace: + string_value: {{ .Release.Namespace }} + destination.uid: + string_value: kubernetes://{{"{{"}} .PodName {{"}}"}}.{{ .Release.Namespace }} + destination.namespace: + string_value: {{.Release.Namespace }} + destination.ip: + bytes_value: {{"{{"}} .PodIP {{"}}"}} + destination.port: + int64_value: 15004 + context.reporter.kind: + string_value: inbound + context.reporter.uid: + string_value: kubernetes://{{"{{"}} .PodName {{"}}"}}.{{ .Release.Namespace }} + transport: + check_cluster: mixer_check_server + report_cluster: inbound_9092 + name: mixer + - name: envoy.router + route_config: + name: "15004" + virtual_hosts: + - domains: + - '*' + name: istio-telemetry.{{ .Release.Namespace }}.svc.{{ .Values.global.proxy.clusterDomain }} + routes: + - decorator: + operation: Report + match: + prefix: / + route: + cluster: inbound_9092 + timeout: 0.000s + stat_prefix: "15004" + name: envoy.http_connection_manager + {{- if .Values.global.controlPlaneSecurityEnabled }} + tls_context: + common_tls_context: + alpn_protocols: + - h2 + tls_certificates: + - certificate_chain: + filename: /etc/certs/cert-chain.pem + private_key: + filename: /etc/certs/key.pem + validation_context: + trusted_ca: + filename: /etc/certs/root-cert.pem + require_client_certificate: true + {{- end }} + + - name: "9091" + address: + socket_address: + address: 0.0.0.0 + port_value: 9091 + filter_chains: + - filters: + - config: + codec_type: HTTP2 + http2_protocol_options: + max_concurrent_streams: 1073741824 + generate_request_id: true + http_filters: + - config: + default_destination_service: istio-telemetry.{{ .Release.Namespace }}.svc.{{ .Values.global.proxy.clusterDomain }} + service_configs: + istio-telemetry.{{ .Release.Namespace }}.svc.{{ .Values.global.proxy.clusterDomain }}: + disable_check_calls: true + {{"{{"}}- if .DisableReportCalls {{"}}"}} + disable_report_calls: true + {{"{{"}}- end {{"}}"}} + mixer_attributes: + attributes: + destination.service.host: + string_value: istio-telemetry.{{ .Release.Namespace }}.svc.{{ .Values.global.proxy.clusterDomain }} + destination.service.uid: + string_value: istio://{{ .Release.Namespace }}/services/istio-telemetry + destination.service.name: + string_value: istio-telemetry + destination.service.namespace: + string_value: {{ .Release.Namespace }} + destination.uid: + string_value: kubernetes://{{"{{"}} .PodName {{"}}"}}.{{ .Release.Namespace }} + destination.namespace: + string_value: {{.Release.Namespace }} + destination.ip: + bytes_value: {{"{{"}} .PodIP {{"}}"}} + destination.port: + int64_value: 9091 + context.reporter.kind: + string_value: inbound + context.reporter.uid: + string_value: kubernetes://{{"{{"}} .PodName {{"}}"}}.{{ .Release.Namespace }} + transport: + check_cluster: mixer_check_server + report_cluster: inbound_9092 + name: mixer + - name: envoy.router + route_config: + name: "9091" + virtual_hosts: + - domains: + - '*' + name: istio-telemetry.{{ .Release.Namespace }}.svc.{{ .Values.global.proxy.clusterDomain }} + routes: + - decorator: + operation: Report + match: + prefix: / + route: + cluster: inbound_9092 + timeout: 0.000s + stat_prefix: "9091" + name: envoy.http_connection_manager + + - name: "local.15019" + address: + socket_address: + address: 127.0.0.1 + port_value: 15019 + filter_chains: + - filters: + - name: envoy.http_connection_manager + config: + codec_type: HTTP2 + stat_prefix: "15019" + stream_idle_timeout: 0s + http2_protocol_options: + max_concurrent_streams: 1073741824 + + access_log: + - name: envoy.file_access_log + config: + path: /dev/stdout + + http_filters: + - name: envoy.router + + route_config: + name: "15019" + + virtual_hosts: + - name: istio-galley + + domains: + - '*' + + routes: + - match: + prefix: / + route: + cluster: out.galley.15019 + timeout: 0.000s +--- diff --git a/istio-1.5.0/install/kubernetes/operator/charts/istio-telemetry/mixer-telemetry/templates/deployment.yaml b/istio-1.5.0/install/kubernetes/operator/charts/istio-telemetry/mixer-telemetry/templates/deployment.yaml new file mode 100644 index 0000000..94b919e --- /dev/null +++ b/istio-1.5.0/install/kubernetes/operator/charts/istio-telemetry/mixer-telemetry/templates/deployment.yaml @@ -0,0 +1,216 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: istio-telemetry + namespace: {{ .Release.Namespace }} + labels: + app: istio-mixer + istio: mixer + release: {{ .Release.Name }} +spec: + replicas: {{ .Values.mixer.telemetry.replicaCount }} + strategy: + rollingUpdate: + maxSurge: {{ .Values.mixer.telemetry.rollingMaxSurge }} + maxUnavailable: {{ .Values.mixer.telemetry.rollingMaxUnavailable }} + selector: + matchLabels: + istio: mixer + istio-mixer-type: telemetry + template: + metadata: + labels: + app: telemetry + istio: mixer + istio-mixer-type: telemetry + annotations: + sidecar.istio.io/inject: "false" +{{- with .Values.mixer.telemetry.podAnnotations }} +{{ toYaml . | indent 8 }} +{{- end }} + spec: + serviceAccountName: istio-mixer-service-account +{{- if .Values.global.priorityClassName }} + priorityClassName: "{{ .Values.global.priorityClassName }}" +{{- end }} + securityContext: + fsGroup: 1337 + volumes: + - name: istio-certs + secret: + secretName: istio.istio-mixer-service-account + optional: true + - name: uds-socket + emptyDir: {} + - name: telemetry-adapter-secret + secret: + secretName: telemetry-adapter-secret + optional: true + - name: telemetry-envoy-config + configMap: + name: telemetry-envoy-config + affinity: + {{- include "nodeaffinity" . | indent 6 }} + {{- include "podAntiAffinity" . | indent 6 }} +{{- if .Values.mixer.telemetry.tolerations }} + tolerations: +{{ toYaml .Values.mixer.telemetry.tolerations | indent 6 }} +{{- else if .Values.global.defaultTolerations }} + tolerations: +{{ toYaml .Values.global.defaultTolerations | indent 6 }} +{{- end }} + containers: + - name: mixer +{{- if contains "/" .Values.mixer.telemetry.image }} + image: "{{ .Values.mixer.telemetry.image }}" +{{- else }} + image: "{{ .Values.mixer.telemetry.hub | default .Values.global.hub }}/{{ .Values.mixer.telemetry.image }}:{{ .Values.mixer.telemetry.tag | default .Values.global.tag }}" +{{- end }} + imagePullPolicy: {{ .Values.global.imagePullPolicy | default "Always" }} + ports: + - containerPort: 9091 + - containerPort: 15014 + - containerPort: 42422 + args: + - --monitoringPort=15014 + - --address +{{- if .Values.global.controlPlaneSecurityEnabled }} + - unix:///sock/mixer.socket +{{- else }} + - tcp://0.0.0.0:9091 +{{- end }} +{{- if .Values.global.logging.level }} + - --log_output_level={{ .Values.global.logging.level }} +{{- end}} +{{- if .Values.global.logAsJson }} + - --log_as_json +{{- end }} +{{- if .Values.global.useMCP }} + {{- if .Values.global.controlPlaneSecurityEnabled}} + - --configStoreURL=mcp://localhost:15019 + {{- else }} + - --configStoreURL=mcp://istio-galley.{{ .Values.global.configNamespace }}.svc:9901 + {{- end }} +{{- else }} + - --configStoreURL=k8s:// +{{- end }} + - --configDefaultNamespace={{ .Values.global.telemetryNamespace }} + {{- if .Values.mixer.adapters.useAdapterCRDs }} + - --useAdapterCRDs=true + {{- else }} + - --useAdapterCRDs=false + {{- end }} + - --useTemplateCRDs=false + {{- if .Values.global.tracer.zipkin.address }} + - --trace_zipkin_url=http://{{- .Values.global.tracer.zipkin.address }}/api/v1/spans + {{- else }} + - --trace_zipkin_url=http://zipkin.{{ .Values.global.telemetryNamespace }}:9411/api/v1/spans + {{- end }} + env: + - name: POD_NAMESPACE + valueFrom: + fieldRef: + apiVersion: v1 + fieldPath: metadata.namespace + {{- if .Values.mixer.telemetry.env }} + {{- range $key, $val := .Values.mixer.telemetry.env }} + - name: {{ $key }} + value: "{{ $val }}" + {{- end }} + {{- end }} + resources: +{{- if .Values.mixer.telemetry.resources }} +{{ toYaml .Values.mixer.telemetry.resources | indent 10 }} +{{- else }} +{{ toYaml .Values.global.defaultResources | indent 10 }} +{{- end }} + securityContext: + runAsUser: 1337 + runAsGroup: 1337 + runAsNonRoot: true + capabilities: + drop: + - ALL + volumeMounts: +{{- if .Values.global.useMCP }} + - name: istio-certs + mountPath: /etc/certs + readOnly: true +{{- end }} + - name: uds-socket + mountPath: /sock + - name: telemetry-adapter-secret + mountPath: /var/run/secrets/istio.io/telemetry/adapter + readOnly: true + livenessProbe: + httpGet: + path: /version + port: 15014 + initialDelaySeconds: 5 + periodSeconds: 5 +{{- if .Values.global.controlPlaneSecurityEnabled }} + - name: istio-proxy +{{- if contains "/" .Values.global.proxy.image }} + image: "{{ .Values.global.proxy.image }}" +{{- else }} + image: "{{ .Values.global.hub }}/{{ .Values.global.proxy.image }}:{{ .Values.global.tag }}" +{{- end }} + imagePullPolicy: {{ .Values.global.imagePullPolicy | default "Always" }} + ports: + - containerPort: 15004 + - containerPort: 15090 + protocol: TCP + name: http-envoy-prom + args: + - proxy + - --domain + - $(POD_NAMESPACE).svc.{{ .Values.global.proxy.clusterDomain }} + - --serviceCluster + - istio-telemetry + - --templateFile + - /var/lib/envoy/envoy.yaml.tmpl + {{- if .Values.global.controlPlaneSecurityEnabled }} + - --controlPlaneAuthPolicy + - MUTUAL_TLS + {{- else }} + - --controlPlaneAuthPolicy + - NONE + {{- end }} + {{- if .Values.global.trustDomain }} + - --trust-domain={{ .Values.global.trustDomain }} + {{- end }} + {{- if .Values.global.logAsJson }} + - --log_as_json + {{- end }} + env: + - name: POD_NAME + valueFrom: + fieldRef: + apiVersion: v1 + fieldPath: metadata.name + - name: POD_NAMESPACE + valueFrom: + fieldRef: + apiVersion: v1 + fieldPath: metadata.namespace + - name: INSTANCE_IP + valueFrom: + fieldRef: + apiVersion: v1 + fieldPath: status.podIP + resources: +{{- if .Values.global.proxy.resources }} +{{ toYaml .Values.global.proxy.resources | indent 10 }} +{{- else }} +{{ toYaml .Values.global.defaultResources | indent 10 }} +{{- end }} + volumeMounts: + - name: telemetry-envoy-config + mountPath: /var/lib/envoy + - name: istio-certs + mountPath: /etc/certs + readOnly: true + - name: uds-socket + mountPath: /sock +{{- end }} +--- diff --git a/istio-1.5.0/install/kubernetes/operator/charts/istio-telemetry/mixer-telemetry/templates/poddisruptionbudget.yaml b/istio-1.5.0/install/kubernetes/operator/charts/istio-telemetry/mixer-telemetry/templates/poddisruptionbudget.yaml new file mode 100644 index 0000000..75d71b6 --- /dev/null +++ b/istio-1.5.0/install/kubernetes/operator/charts/istio-telemetry/mixer-telemetry/templates/poddisruptionbudget.yaml @@ -0,0 +1,21 @@ +{{- if .Values.global.defaultPodDisruptionBudget.enabled }} +apiVersion: policy/v1beta1 +kind: PodDisruptionBudget +metadata: + name: istio-telemetry + namespace: {{ .Release.Namespace }} + labels: + app: telemetry + release: {{ .Release.Name }} + istio: mixer + istio-mixer-type: telemetry +spec: + minAvailable: 1 + selector: + matchLabels: + app: telemetry + istio: mixer + istio-mixer-type: telemetry +--- + +{{- end }} diff --git a/istio-1.5.0/install/kubernetes/operator/charts/istio-telemetry/mixer-telemetry/templates/service.yaml b/istio-1.5.0/install/kubernetes/operator/charts/istio-telemetry/mixer-telemetry/templates/service.yaml new file mode 100644 index 0000000..3e21351 --- /dev/null +++ b/istio-1.5.0/install/kubernetes/operator/charts/istio-telemetry/mixer-telemetry/templates/service.yaml @@ -0,0 +1,26 @@ +apiVersion: v1 +kind: Service +metadata: + name: istio-telemetry + namespace: {{ .Release.Namespace }} + labels: + app: mixer + istio: mixer + release: {{ .Release.Name }} +spec: + ports: + - name: grpc-mixer + port: 9091 + - name: grpc-mixer-mtls + port: 15004 + - name: http-monitoring + port: 15014 + - name: prometheus + port: 42422 + selector: + istio: mixer + istio-mixer-type: telemetry +{{- if .Values.mixer.telemetry.sessionAffinityEnabled }} + sessionAffinity: ClientIP +{{- end }} +--- diff --git a/istio-1.5.0/install/kubernetes/operator/charts/istio-telemetry/mixer-telemetry/templates/serviceaccount.yaml b/istio-1.5.0/install/kubernetes/operator/charts/istio-telemetry/mixer-telemetry/templates/serviceaccount.yaml new file mode 100644 index 0000000..0e026ff --- /dev/null +++ b/istio-1.5.0/install/kubernetes/operator/charts/istio-telemetry/mixer-telemetry/templates/serviceaccount.yaml @@ -0,0 +1,15 @@ +apiVersion: v1 +kind: ServiceAccount +{{- if .Values.global.imagePullSecrets }} +imagePullSecrets: +{{- range .Values.global.imagePullSecrets }} + - name: {{ . }} +{{- end }} +{{- end }} +metadata: + name: istio-mixer-service-account + namespace: {{ .Release.Namespace }} + labels: + app: istio-telemetry + release: {{ .Release.Name }} +--- diff --git a/istio-1.5.0/install/kubernetes/operator/charts/istio-telemetry/mixer-telemetry/templates/stackdriver.yaml b/istio-1.5.0/install/kubernetes/operator/charts/istio-telemetry/mixer-telemetry/templates/stackdriver.yaml new file mode 100644 index 0000000..e51d316 --- /dev/null +++ b/istio-1.5.0/install/kubernetes/operator/charts/istio-telemetry/mixer-telemetry/templates/stackdriver.yaml @@ -0,0 +1,955 @@ +{{- if .Values.mixer.adapters.stackdriver.enabled }} +apiVersion: "config.istio.io/v1alpha2" +kind: handler +metadata: + name: stackdriver + namespace: {{ .Release.Namespace }} + labels: + app: istio-telemetry + release: {{ .Release.Name }} +spec: + compiledAdapter: stackdriver + params: + {{- if .Values.mixer.adapters.stackdriver.tracer.enabled }} + trace: + sampleProbability: {{ .Values.mixer.adapters.stackdriver.tracer.sampleProbability | default 1 }} + {{- end }} + pushInterval: 10s + {{- if ne .Values.mixer.adapters.stackdriver.auth.serviceAccountPath "" }} + serviceAccountPath: {{ .Values.mixer.adapters.stackdriver.auth.serviceAccountPath }} + {{- end }} + {{- if ne .Values.mixer.adapters.stackdriver.auth.apiKey "" }} + apiKey: {{ .Values.mixer.adapters.stackdriver.auth.apiKey }} + {{- end }} + {{- if .Values.mixer.adapters.stackdriver.auth.appCredentials }} + appCredentials: {{ .Values.mixer.adapters.stackdriver.auth.appCredentials }} + {{- end }} + {{- if .Values.mixer.adapters.stackdriver.metrics.enabled }} + metricInfo: + server-request-count.instance.{{ .Release.Namespace }}: + # Due to a bug in gogoproto deserialization, Enums in maps must be + # specified by their integer value, not variant name. See + # https://github.com/googleapis/googleapis/blob/master/google/api/metric.proto + # MetricKind and ValueType for the values to provide. + kind: 3 # CUMULATIVE + value: 2 # INT64 + metric_type: "istio.io/service/server/request_count" + server-request-bytes.instance.{{ .Release.Namespace }}: + kind: 3 # CUMULATIVE + value: 5 # DISTRIBUTION + buckets: + exponentialBuckets: + numFiniteBuckets: 20 + scale: 1 + growthFactor: 2 + metric_type: "istio.io/service/server/request_bytes" + server-response-bytes.instance.{{ .Release.Namespace }}: + kind: 3 # CUMULATIVE + value: 5 # DISTRIBUTION + buckets: + exponentialBuckets: + numFiniteBuckets: 20 + scale: 1 + growthFactor: 2 + metric_type: "istio.io/service/server/response_bytes" + server-response-latencies.instance.{{ .Release.Namespace }}: + kind: 3 # CUMULATIVE + value: 5 # DISTRIBUTION + buckets: + exponentialBuckets: + numFiniteBuckets: 20 + scale: 1 + growthFactor: 2 + metric_type: "istio.io/service/server/response_latencies" + server-received-bytes-count.instance.{{ .Release.Namespace }}: + kind: 3 # CUMULATIVE + value: 2 # INT64 + metric_type: "istio.io/service/server/received_bytes_count" + server-sent-bytes-count.instance.{{ .Release.Namespace }}: + kind: 3 # CUMULATIVE + value: 2 # INT64 + metric_type: "istio.io/service/server/sent_bytes_count" + client-request-count.instance.{{ .Release.Namespace }}: + kind: 3 # CUMULATIVE + value: 2 # INT64 + metric_type: "istio.io/service/client/request_count" + client-request-bytes.instance.{{ .Release.Namespace }}: + kind: 3 # CUMULATIVE + value: 5 # DISTRIBUTION + buckets: + exponentialBuckets: + numFiniteBuckets: 20 + scale: 1 + growthFactor: 2 + metric_type: "istio.io/service/client/request_bytes" + client-response-bytes.instance.{{ .Release.Namespace }}: + kind: 3 # CUMULATIVE + value: 5 # DISTRIBUTION + buckets: + exponentialBuckets: + numFiniteBuckets: 20 + scale: 1 + growthFactor: 2 + metric_type: "istio.io/service/client/response_bytes" + client-roundtrip-latencies.instance.{{ .Release.Namespace }}: + kind: 3 # CUMULATIVE + value: 5 # DISTRIBUTION + buckets: + exponentialBuckets: + numFiniteBuckets: 20 + scale: 1 + growthFactor: 2 + metric_type: "istio.io/service/client/roundtrip_latencies" + client-received-bytes-count.instance.{{ .Release.Namespace }}: + kind: 3 # CUMULATIVE + value: 2 # INT64 + metric_type: "istio.io/service/client/received_bytes_count" + client-sent-bytes-count.instance.{{ .Release.Namespace }}: + kind: 3 # CUMULATIVE + value: 2 # INT64 + metric_type: "istio.io/service/client/sent_bytes_count" + {{- end }} + {{- if .Values.mixer.adapters.stackdriver.logging.enabled }} + logInfo: + server-accesslog-stackdriver.instance.{{ .Release.Namespace }}: + labelNames: + - mesh_uid + - source_uid + - source_ip + - source_app + - source_principal + - source_name + - source_workload + - source_namespace + - source_owner + - destination_uid + - destination_app + - destination_ip + - destination_service_host + - destination_workload + - destination_name + - destination_namespace + - destination_owner + - destination_principal + - api_name + - api_version + - api_claims + - api_key + - request_operation + - protocol + - method + - url + - response_code + - response_size + - request_size + - request_id + - latency + - service_authentication_policy + - user_agent + - response_timestamp + - received_bytes + - sent_bytes + - referer + server-tcp-accesslog-stackdriver.instance.{{ .Release.Namespace }}: + labelNames: + - mesh_uid + - connection_id + - connection_event + - source_uid + - source_ip + - source_app + - source_principal + - source_name + - source_workload + - source_namespace + - source_owner + - destination_uid + - destination_app + - destination_ip + - destination_service_host + - destination_workload + - destination_name + - destination_namespace + - destination_owner + - destination_principal + - protocol + - connction_duration + - service_authentication_policy + - received_bytes + - sent_bytes + - total_received_bytes + - total_sent_bytes + {{- end }} +--- +{{- if .Values.mixer.adapters.stackdriver.metrics.enabled }} +################################################# +############## Metric Config #################### +################################################# +apiVersion: "config.istio.io/v1alpha2" +kind: rule +metadata: + name: stackdriver-server + namespace: {{ .Release.Namespace }} + labels: + app: istio-telemetry + release: {{ .Release.Name }} +spec: + match: (context.protocol == "http" || context.protocol == "grpc") && (context.reporter.kind | "inbound" == "inbound") + actions: + - handler: stackdriver + instances: + - server-request-count + - server-request-bytes + - server-response-bytes + - server-response-latencies +--- +apiVersion: "config.istio.io/v1alpha2" +kind: rule +metadata: + name: stackdriver-client + namespace: {{ .Release.Namespace }} + labels: + app: istio-telemetry + release: {{ .Release.Name }} +spec: + match: (context.protocol == "http" || context.protocol == "grpc") && (context.reporter.kind | "inbound" == "outbound") + actions: + - handler: stackdriver + instances: + - client-request-count + - client-request-bytes + - client-response-bytes + - client-roundtrip-latencies +--- +apiVersion: "config.istio.io/v1alpha2" +kind: rule +metadata: + name: stackdriver-tcp-server + namespace: {{ .Release.Namespace }} + labels: + app: istio-telemetry + release: {{ .Release.Name }} +spec: + match: context.protocol == "tcp" && (context.reporter.kind | "inbound" == "inbound") + actions: + - handler: stackdriver + instances: + - server-received-bytes-count + - server-sent-bytes-count +--- +apiVersion: "config.istio.io/v1alpha2" +kind: rule +metadata: + name: stackdriver-tcp-client + namespace: {{ .Release.Namespace }} + labels: + app: istio-telemetry + release: {{ .Release.Name }} +spec: + match: context.protocol == "tcp" && (context.reporter.kind | "inbound" == "outbound") + actions: + - handler: stackdriver + instances: + - client-received-bytes-count + - client-sent-bytes-count +--- +apiVersion: "config.istio.io/v1alpha2" +kind: instance +metadata: + name: server-request-count + namespace: {{ .Release.Namespace }} + labels: + app: istio-telemetry + release: {{ .Release.Name }} +spec: + compiledTemplate: metric + params: + value: "1" + dimensions: + mesh_uid: '"{{ .Values.global.meshID }}"' + destination_service_name: destination.service.name | "unknown" + destination_service_namespace: destination.service.namespace | "unknown" + destination_port: destination.port | 0 + request_operation: conditional((context.protocol | "unknown") == "grpc", request.path | "unknown", request.method | "unknown") + request_protocol: context.protocol | "unknown" + api_version: api.version | "unknown" + api_name: api.service | "unknown" + response_code: response.code | 0 + service_authentication_policy: conditional((context.reporter.kind | "inbound") == "outbound", "unknown", conditional(connection.mtls | false, "mutual_tls", "none")) + source_workload_namespace: source.workload.namespace | "unknown" + source_workload_name: source.workload.name | "unknown" + source_owner: source.owner | "unknown" + destination_workload_namespace: destination.workload.namespace | "unknown" + destination_workload_name: destination.workload.name | "unknown" + destination_owner: destination.owner | "unknown" + destination_principal: destination.principal | "unknown" + source_principal: source.principal | "unknown" + monitoredResourceType: '"k8s_container"' + monitoredResourceDimensions: + project_id: '""' + cluster_name: '""' + namespace_name: destination.workload.namespace | "unknown" + location: '""' + container_name: conditional((destination.name | "unknown").startsWith("istio-telemetry") || (destination.name | "unknown").startsWith("istio-policy"), "mixer", destination.container.name | "unknown") + pod_name: destination.name | "unknown" +--- +apiVersion: "config.istio.io/v1alpha2" +kind: instance +metadata: + name: client-request-count + namespace: {{ .Release.Namespace }} + labels: + app: istio-telemetry + release: {{ .Release.Name }} +spec: + compiledTemplate: metric + params: + value: "1" + dimensions: + mesh_uid: '"{{ .Values.global.meshID }}"' + destination_service_name: destination.service.name | "unknown" + destination_service_namespace: destination.service.namespace | "unknown" + destination_port: destination.port | 0 + request_operation: conditional((context.protocol | "unknown") == "grpc", request.path | "unknown", request.method | "unknown") + request_protocol: context.protocol | "unknown" + api_version: api.version | "unknown" + api_name: api.service | "unknown" + response_code: response.code | 0 + service_authentication_policy: conditional((context.reporter.kind | "inbound") == "outbound", "unknown", conditional(connection.mtls | false, "mutual_tls", "none")) + source_workload_namespace: source.workload.namespace | "unknown" + source_workload_name: source.workload.name | "unknown" + source_owner: source.owner | "unknown" + destination_workload_namespace: destination.workload.namespace | "unknown" + destination_workload_name: destination.workload.name | "unknown" + destination_owner: destination.owner | "unknown" + destination_principal: destination.principal | "unknown" + source_principal: source.principal | "unknown" + monitoredResourceType: '"k8s_pod"' + monitoredResourceDimensions: + project_id: '""' + cluster_name: '""' + namespace_name: source.workload.namespace | "unknown" + location: '""' + pod_name: source.name | "unknown" +--- +apiVersion: "config.istio.io/v1alpha2" +kind: instance +metadata: + name: server-request-bytes + namespace: {{ .Release.Namespace }} + labels: + app: istio-telemetry + release: {{ .Release.Name }} +spec: + compiledTemplate: metric + params: + value: request.total_size + dimensions: + mesh_uid: '"{{ .Values.global.meshID }}"' + destination_service_name: destination.service.name | "unknown" + destination_service_namespace: destination.service.namespace | "unknown" + destination_port: destination.port | 0 + request_operation: conditional((context.protocol | "unknown") == "grpc", request.path | "unknown", request.method | "unknown") + request_protocol: context.protocol | "unknown" + api_version: api.version | "unknown" + api_name: api.service | "unknown" + response_code: response.code | 0 + service_authentication_policy: conditional((context.reporter.kind | "inbound") == "outbound", "unknown", conditional(connection.mtls | false, "mutual_tls", "none")) + source_workload_namespace: source.workload.namespace | "unknown" + source_workload_name: source.workload.name | "unknown" + source_owner: source.owner | "unknown" + destination_workload_namespace: destination.workload.namespace | "unknown" + destination_workload_name: destination.workload.name | "unknown" + destination_owner: destination.owner | "unknown" + destination_principal: destination.principal | "unknown" + source_principal: source.principal | "unknown" + monitoredResourceType: '"k8s_container"' + monitoredResourceDimensions: + project_id: '""' + cluster_name: '""' + namespace_name: destination.workload.namespace | "unknown" + location: '""' + container_name: conditional((destination.name | "unknown").startsWith("istio-telemetry") || (destination.name | "unknown").startsWith("istio-policy"), "mixer", destination.container.name | "unknown") + pod_name: destination.name | "unknown" +--- +apiVersion: "config.istio.io/v1alpha2" +kind: instance +metadata: + name: client-request-bytes + namespace: {{ .Release.Namespace }} + labels: + app: istio-telemetry + release: {{ .Release.Name }} +spec: + compiledTemplate: metric + params: + value: request.total_size + dimensions: + mesh_uid: '"{{ .Values.global.meshID }}"' + destination_service_name: destination.service.name | "unknown" + destination_service_namespace: destination.service.namespace | "unknown" + destination_port: destination.port | 0 + request_operation: conditional((context.protocol | "unknown") == "grpc", request.path | "unknown", request.method | "unknown") + request_protocol: context.protocol | "unknown" + api_version: api.version | "unknown" + api_name: api.service | "unknown" + response_code: response.code | 0 + service_authentication_policy: conditional((context.reporter.kind | "inbound") == "outbound", "unknown", conditional(connection.mtls | false, "mutual_tls", "none")) + source_workload_namespace: source.workload.namespace | "unknown" + source_workload_name: source.workload.name | "unknown" + source_owner: source.owner | "unknown" + destination_workload_namespace: destination.workload.namespace | "unknown" + destination_workload_name: destination.workload.name | "unknown" + destination_owner: destination.owner | "unknown" + destination_principal: destination.principal | "unknown" + source_principal: source.principal | "unknown" + monitoredResourceType: '"k8s_pod"' + monitoredResourceDimensions: + project_id: '""' + cluster_name: '""' + namespace_name: source.workload.namespace | "unknown" + location: '""' + pod_name: source.name | "unknown" +--- +apiVersion: "config.istio.io/v1alpha2" +kind: instance +metadata: + name: server-response-bytes + namespace: {{ .Release.Namespace }} + labels: + app: istio-telemetry + release: {{ .Release.Name }} +spec: + compiledTemplate: metric + params: + value: response.total_size + dimensions: + mesh_uid: '"{{ .Values.global.meshID }}"' + destination_service_name: destination.service.name | "unknown" + destination_service_namespace: destination.service.namespace | "unknown" + destination_port: destination.port | 0 + request_operation: conditional((context.protocol | "unknown") == "grpc", request.path | "unknown", request.method | "unknown") + request_protocol: context.protocol | "unknown" + api_version: api.version | "unknown" + api_name: api.service | "unknown" + response_code: response.code | 0 + service_authentication_policy: conditional((context.reporter.kind | "inbound") == "outbound", "unknown", conditional(connection.mtls | false, "mutual_tls", "none")) + source_workload_namespace: source.workload.namespace | "unknown" + source_workload_name: source.workload.name | "unknown" + source_owner: source.owner | "unknown" + destination_workload_namespace: destination.workload.namespace | "unknown" + destination_workload_name: destination.workload.name | "unknown" + destination_owner: destination.owner | "unknown" + destination_principal: destination.principal | "unknown" + source_principal: source.principal | "unknown" + monitoredResourceType: '"k8s_container"' + monitoredResourceDimensions: + project_id: '""' + cluster_name: '""' + namespace_name: destination.workload.namespace | "unknown" + location: '""' + container_name: conditional((destination.name | "unknown").startsWith("istio-telemetry") || (destination.name | "unknown").startsWith("istio-policy"), "mixer", destination.container.name | "unknown") + pod_name: destination.name | "unknown" +--- +apiVersion: "config.istio.io/v1alpha2" +kind: instance +metadata: + name: client-response-bytes + namespace: {{ .Release.Namespace }} + labels: + app: istio-telemetry + release: {{ .Release.Name }} +spec: + compiledTemplate: metric + params: + value: response.total_size + dimensions: + mesh_uid: '"{{ .Values.global.meshID }}"' + destination_service_name: destination.service.name | "unknown" + destination_service_namespace: destination.service.namespace | "unknown" + destination_port: destination.port | 0 + request_operation: conditional((context.protocol | "unknown") == "grpc", request.path | "unknown", request.method | "unknown") + request_protocol: context.protocol | "unknown" + api_version: api.version | "unknown" + api_name: api.service | "unknown" + response_code: response.code | 0 + service_authentication_policy: conditional((context.reporter.kind | "inbound") == "outbound", "unknown", conditional(connection.mtls | false, "mutual_tls", "none")) + source_workload_namespace: source.workload.namespace | "unknown" + source_workload_name: source.workload.name | "unknown" + source_owner: source.owner | "unknown" + destination_workload_namespace: destination.workload.namespace | "unknown" + destination_workload_name: destination.workload.name | "unknown" + destination_owner: destination.owner | "unknown" + destination_principal: destination.principal | "unknown" + source_principal: source.principal | "unknown" + monitoredResourceType: '"k8s_pod"' + monitoredResourceDimensions: + project_id: '""' + cluster_name: '""' + namespace_name: source.workload.namespace | "unknown" + location: '""' + pod_name: source.name | "unknown" +--- +apiVersion: "config.istio.io/v1alpha2" +kind: instance +metadata: + name: server-response-latencies + namespace: {{ .Release.Namespace }} + labels: + app: istio-telemetry + release: {{ .Release.Name }} +spec: + compiledTemplate: metric + params: + value: response.duration + dimensions: + mesh_uid: '"{{ .Values.global.meshID }}"' + destination_service_name: destination.service.name | "unknown" + destination_service_namespace: destination.service.namespace | "unknown" + destination_port: destination.port | 0 + request_operation: conditional((context.protocol | "unknown") == "grpc", request.path | "unknown", request.method | "unknown") + request_protocol: context.protocol | "unknown" + api_version: api.version | "unknown" + api_name: api.service | "unknown" + response_code: response.code | 0 + service_authentication_policy: conditional((context.reporter.kind | "inbound") == "outbound", "unknown", conditional(connection.mtls | false, "mutual_tls", "none")) + source_workload_namespace: source.workload.namespace | "unknown" + source_workload_name: source.workload.name | "unknown" + source_owner: source.owner | "unknown" + destination_workload_namespace: destination.workload.namespace | "unknown" + destination_workload_name: destination.workload.name | "unknown" + destination_owner: destination.owner | "unknown" + destination_principal: destination.principal | "unknown" + source_principal: source.principal | "unknown" + monitoredResourceType: '"k8s_container"' + monitoredResourceDimensions: + project_id: '""' + cluster_name: '""' + namespace_name: destination.workload.namespace | "unknown" + location: '""' + container_name: conditional((destination.name | "unknown").startsWith("istio-telemetry") || (destination.name | "unknown").startsWith("istio-policy"), "mixer", destination.container.name | "unknown") + pod_name: destination.name | "unknown" +--- +apiVersion: "config.istio.io/v1alpha2" +kind: instance +metadata: + name: client-roundtrip-latencies + namespace: {{ .Release.Namespace }} + labels: + app: istio-telemetry + release: {{ .Release.Name }} +spec: + compiledTemplate: metric + params: + value: response.duration + dimensions: + mesh_uid: '"{{ .Values.global.meshID }}"' + destination_service_name: destination.service.name | "unknown" + destination_service_namespace: destination.service.namespace | "unknown" + destination_port: destination.port | 0 + request_operation: conditional((context.protocol | "unknown") == "grpc", request.path | "unknown", request.method | "unknown") + request_protocol: context.protocol | "unknown" + api_version: api.version | "unknown" + api_name: api.service | "unknown" + response_code: response.code | 0 + service_authentication_policy: conditional((context.reporter.kind | "inbound") == "outbound", "unknown", conditional(connection.mtls | false, "mutual_tls", "none")) + source_workload_namespace: source.workload.namespace | "unknown" + source_workload_name: source.workload.name | "unknown" + source_owner: source.owner | "unknown" + destination_workload_namespace: destination.workload.namespace | "unknown" + destination_workload_name: destination.workload.name | "unknown" + destination_owner: destination.owner | "unknown" + destination_principal: destination.principal | "unknown" + source_principal: source.principal | "unknown" + monitoredResourceType: '"k8s_pod"' + monitoredResourceDimensions: + project_id: '""' + cluster_name: '""' + namespace_name: source.workload.namespace | "unknown" + location: '""' + pod_name: source.name | "unknown" +--- +apiVersion: "config.istio.io/v1alpha2" +kind: instance +metadata: + name: server-received-bytes-count + namespace: {{ .Release.Namespace }} + labels: + app: istio-telemetry + release: {{ .Release.Name }} +spec: + compiledTemplate: metric + params: + value: connection.received.bytes | 0 + dimensions: + mesh_uid: '"{{ .Values.global.meshID }}"' + destination_service_name: destination.service.name | "unknown" + destination_service_namespace: destination.service.namespace | "unknown" + destination_port: destination.port | 0 + request_protocol: context.protocol | "unknown" + service_authentication_policy: conditional((context.reporter.kind | "inbound") == "outbound", "unknown", conditional(connection.mtls | false, "mutual_tls", "none")) + source_workload_namespace: source.workload.namespace | "unknown" + source_workload_name: source.workload.name | "unknown" + source_owner: source.owner | "unknown" + destination_workload_namespace: destination.workload.namespace | "unknown" + destination_workload_name: destination.workload.name | "unknown" + destination_owner: destination.owner | "unknown" + destination_principal: destination.principal | "unknown" + source_principal: source.principal | "unknown" + monitoredResourceType: '"k8s_container"' + monitoredResourceDimensions: + project_id: '""' + cluster_name: '""' + namespace_name: destination.workload.namespace | "unknown" + location: '""' + container_name: conditional((destination.name | "unknown").startsWith("istio-telemetry") || (destination.name | "unknown").startsWith("istio-policy"), "mixer", destination.container.name | "unknown") + pod_name: destination.name | "unknown" +--- +apiVersion: "config.istio.io/v1alpha2" +kind: instance +metadata: + name: client-received-bytes-count + namespace: {{ .Release.Namespace }} + labels: + app: istio-telemetry + release: {{ .Release.Name }} +spec: + compiledTemplate: metric + params: + value: connection.received.bytes | 0 + dimensions: + mesh_uid: '"{{ .Values.global.meshID }}"' + destination_service_name: destination.service.name | "unknown" + destination_service_namespace: destination.service.namespace | "unknown" + destination_port: destination.port | 0 + request_protocol: context.protocol | "unknown" + service_authentication_policy: conditional((context.reporter.kind | "inbound") == "outbound", "unknown", conditional(connection.mtls | false, "mutual_tls", "none")) + source_workload_namespace: source.workload.namespace | "unknown" + source_workload_name: source.workload.name | "unknown" + source_owner: source.owner | "unknown" + destination_workload_namespace: destination.workload.namespace | "unknown" + destination_workload_name: destination.workload.name | "unknown" + destination_owner: destination.owner | "unknown" + destination_principal: destination.principal | "unknown" + source_principal: source.principal | "unknown" + monitoredResourceType: '"k8s_pod"' + monitoredResourceDimensions: + project_id: '""' + cluster_name: '""' + namespace_name: source.workload.namespace | "unknown" + location: '""' + pod_name: source.name | "unknown" +--- +apiVersion: "config.istio.io/v1alpha2" +kind: instance +metadata: + name: server-sent-bytes-count + namespace: {{ .Release.Namespace }} + labels: + app: istio-telemetry + release: {{ .Release.Name }} +spec: + compiledTemplate: metric + params: + value: connection.sent.bytes | 0 + dimensions: + mesh_uid: '"{{ .Values.global.meshID }}"' + destination_service_name: destination.service.name | "unknown" + destination_service_namespace: destination.service.namespace | "unknown" + destination_port: destination.port | 0 + request_protocol: context.protocol | "unknown" + service_authentication_policy: conditional((context.reporter.kind | "inbound") == "outbound", "unknown", conditional(connection.mtls | false, "mutual_tls", "none")) + source_workload_namespace: source.workload.namespace | "unknown" + source_workload_name: source.workload.name | "unknown" + source_owner: source.owner | "unknown" + destination_workload_namespace: destination.workload.namespace | "unknown" + destination_workload_name: destination.workload.name | "unknown" + destination_owner: destination.owner | "unknown" + destination_principal: destination.principal | "unknown" + source_principal: source.principal | "unknown" + monitoredResourceType: '"k8s_container"' + monitoredResourceDimensions: + project_id: '""' + cluster_name: '""' + namespace_name: destination.workload.namespace | "unknown" + location: '""' + container_name: conditional((destination.name | "unknown").startsWith("istio-telemetry") || (destination.name | "unknown").startsWith("istio-policy"), "mixer", destination.container.name | "unknown") + pod_name: destination.name | "unknown" +--- +apiVersion: "config.istio.io/v1alpha2" +kind: instance +metadata: + name: client-sent-bytes-count + namespace: {{ .Release.Namespace }} + labels: + app: istio-telemetry + release: {{ .Release.Name }} +spec: + compiledTemplate: metric + params: + value: connection.sent.bytes | 0 + dimensions: + mesh_uid: '"{{ .Values.global.meshID }}"' + destination_service_name: destination.service.name | "unknown" + destination_service_namespace: destination.service.namespace | "unknown" + destination_port: destination.port | 0 + request_protocol: context.protocol | "unknown" + service_authentication_policy: conditional((context.reporter.kind | "inbound") == "outbound", "unknown", conditional(connection.mtls | false, "mutual_tls", "none")) + source_workload_namespace: source.workload.namespace | "unknown" + source_workload_name: source.workload.name | "unknown" + source_owner: source.owner | "unknown" + destination_workload_namespace: destination.workload.namespace | "unknown" + destination_workload_name: destination.workload.name | "unknown" + destination_owner: destination.owner | "unknown" + destination_principal: destination.principal | "unknown" + source_principal: source.principal | "unknown" + monitoredResourceType: '"k8s_pod"' + monitoredResourceDimensions: + project_id: '""' + cluster_name: '""' + namespace_name: source.workload.namespace | "unknown" + location: '""' + pod_name: source.name | "unknown" +{{- end }} +--- +{{- if .Values.mixer.adapters.stackdriver.logging.enabled }} +apiVersion: "config.istio.io/v1alpha2" +kind: instance +metadata: + name: server-accesslog-stackdriver + namespace: {{ .Release.Namespace }} + labels: + app: istio-telemetry + release: {{ .Release.Name }} +spec: + compiledTemplate: logentry + params: + severity: '"Info"' + timestamp: request.time + variables: + mesh_uid: '"{{ .Values.global.meshID }}"' + source_uid: source.uid | "" + source_ip: source.ip | ip("0.0.0.0") + source_app: source.labels["app"] | "" + source_principal: source.principal | "" + source_name: source.name | "" + source_workload: source.workload.name | "" + source_namespace: source.namespace | "" + source_owner: source.owner | "" + destination_uid: destination.uid | "" + destination_app: destination.labels["app"] | "" + destination_ip: destination.ip | ip("0.0.0.0") + destination_service_host: destination.service.host | "" + destination_workload: destination.workload.name | "" + destination_name: destination.name | "" + destination_namespace: destination.namespace | "" + destination_owner: destination.owner | "" + destination_principal: destination.principal | "" + api_name: api.service | "" + api_version: api.version | "" + api_claims: request.auth.raw_claims | "" + api_key: request.api_key | request.headers["x-api-key"] | "" + request_operation: conditional((context.protocol | "unknown") == "grpc", request.path | "unknown", request.method | "unknown") + protocol: request.scheme | context.protocol | "http" + method: request.method | "" + url: request.path | "" + response_code: response.code | 0 + response_size: response.size | 0 + request_size: request.size | 0 + request_id: request.headers["x-request-id"] | "" + latency: response.duration | "0ms" + service_authentication_policy: conditional((context.reporter.kind | "inbound") == "outbound", "unknown", conditional(connection.mtls | false, "mutual_tls", "none")) + user_agent: request.useragent | "" + response_timestamp: response.time + received_bytes: request.total_size | 0 + sent_bytes: response.total_size | 0 + referer: request.referer | "" + monitored_resource_type: '"k8s_container"' + monitoredResourceDimensions: + project_id: '""' + cluster_name: '""' + namespace_name: destination.namespace | "unknown" + location: '""' + container_name: conditional((destination.name | "unknown").startsWith("istio-telemetry") || (destination.name | "unknown").startsWith("istio-policy"), "mixer", destination.container.name | "unknown") + pod_name: destination.name | "unknown" +--- +apiVersion: "config.istio.io/v1alpha2" +kind: instance +metadata: + name: server-tcp-accesslog-stackdriver + namespace: {{ .Release.Namespace }} + labels: + app: istio-telemetry + release: {{ .Release.Name }} +spec: + compiledTemplate: logentry + params: + severity: '"Info"' + timestamp: context.time | timestamp("2017-01-01T00:00:00Z") + variables: + mesh_uid: '"{{ .Values.global.meshID }}"' + source_uid: source.uid | "" + connection_id: connection.id | "" + connection_event: connection.event | "" + source_ip: source.ip | ip("0.0.0.0") + source_app: source.labels["app"] | "" + source_principal: source.principal | "" + source_name: source.name | "" + source_workload: source.workload.name | "" + source_namespace: source.namespace | "" + source_owner: source.owner | "" + destination_uid: destination.uid | "" + destination_app: destination.labels["app"] | "" + destination_ip: destination.ip | ip("0.0.0.0") + destination_service_host: destination.service.host | "" + destination_workload: destination.workload.name | "" + destination_name: destination.name | "" + destination_namespace: destination.namespace | "" + destination_owner: destination.owner | "" + destination_principal: destination.principal | "" + protocol: context.protocol | "tcp" + connction_duration: connection.duration | "0ms" + service_authentication_policy: conditional((context.reporter.kind | "inbound") == "outbound", "unknown", conditional(connection.mtls | false, "mutual_tls", "none")) + received_bytes: connection.received.bytes | 0 + sent_bytes: connection.sent.bytes | 0 + total_received_bytes: connection.received.bytes_total | 0 + total_sent_bytes: connection.sent.bytes_total | 0 + monitored_resource_type: '"k8s_container"' + monitoredResourceDimensions: + project_id: '""' + cluster_name: '""' + namespace_name: destination.namespace | "unknown" + location: '""' + container_name: conditional((destination.name | "unknown").startsWith("istio-telemetry") || (destination.name | "unknown").startsWith("istio-policy"), "mixer", destination.container.name | "unknown") + pod_name: destination.name | "unknown" +--- +apiVersion: "config.istio.io/v1alpha2" +kind: rule +metadata: + name: stackdriver-log + namespace: {{ .Release.Namespace }} + labels: + app: istio-telemetry + release: {{ .Release.Name }} +spec: + match: (context.protocol == "http" || context.protocol == "grpc") && (context.reporter.kind | "inbound" == "inbound") + actions: + - handler: stackdriver + instances: + - server-accesslog-stackdriver +--- +apiVersion: "config.istio.io/v1alpha2" +kind: rule +metadata: + name: stackdriver-log-tcp + namespace: {{ .Release.Namespace }} + labels: + app: istio-telemetry + release: {{ .Release.Name }} +spec: + match: (context.protocol == "tcp") && (context.reporter.kind | "inbound" == "inbound") + actions: + - handler: stackdriver + instances: + - server-tcp-accesslog-stackdriver +{{- end }} +--- +{{- if .Values.mixer.adapters.stackdriver.tracer.enabled }} +apiVersion: "config.istio.io/v1alpha2" +kind: instance +metadata: + name: stackdriver-span + namespace: {{ .Release.Namespace }} + labels: + app: istio-telemetry + release: {{ .Release.Name }} +spec: + compiledTemplate: tracespan + params: + traceId: request.headers["x-b3-traceid"] + spanId: request.headers["x-b3-spanid"] | "" + parentSpanId: request.headers["x-b3-parentspanid"] | "" + spanName: destination.service.host | destination.service.name | destination.workload.name | "unknown" + startTime: request.time + endTime: response.time + clientSpan: (context.reporter.kind | "inbound") == "outbound" + rewriteClientSpanId: "true" + spanTags: + destination_service_name: destination.service.name | "unknown" + destination_service_namespace: destination.service.namespace | "unknown" + destination_port: destination.port | 0 + request_operation: conditional((context.protocol | "unknown") == "grpc", request.path | "unknown", request.method | "unknown") + request_protocol: context.protocol | "unknown" + api_version: api.version | "unknown" + api_name: api.service | "unknown" + response_code: response.code | 0 + service_authentication_policy: conditional((context.reporter.kind | "inbound") == "outbound", "unknown", conditional(connection.mtls | false, "mutual_tls", "none")) + source_workload_namespace: source.workload.namespace | "unknown" + source_workload_name: source.workload.name | "unknown" + source_owner: source.owner | "unknown" + destination_workload_namespace: destination.workload.namespace | "unknown" + destination_workload_name: destination.workload.name | "unknown" + destination_owner: destination.owner | "unknown" + http_url: request.path | "" + request_size: request.size | 0 + response_size: response.size | 0 + source_ip: source.ip | ip("0.0.0.0") +--- +apiVersion: "config.istio.io/v1alpha2" +kind: rule +metadata: + name: stackdriver-tracing-rule + namespace: {{ .Release.Namespace }} + labels: + app: istio-telemetry + release: {{ .Release.Name }} +spec: + match: (context.protocol == "http" || context.protocol == "grpc") && request.headers["x-b3-sampled"] == "1" && destination.workload.name != "istio-telemetry" && destination.workload.name != "istio-pilot" + actions: + - handler: stackdriver + instances: + - stackdriver-span +{{- end }} +--- +{{- if .Values.mixer.adapters.stackdriver.contextGraph.enabled }} +apiVersion: "config.istio.io/v1alpha2" +kind: instance +metadata: + name: stackdriver-edge + namespace: {{ .Release.Namespace }} + labels: + app: istio-telemetry + release: {{ .Release.Name }} +spec: + compiledTemplate: edge + params: + timestamp: request.time | context.time | timestamp("2017-01-01T00:00:00Z") + sourceUid: source.uid | "Unknown" + sourceOwner: source.owner | "Unknown" + sourceWorkloadName: source.workload.name | "Unknown" + sourceWorkloadNamespace: source.workload.namespace | "Unknown" + destinationUid: destination.uid | "Unknown" + destinationOwner: destination.owner | "Unknown" + destinationWorkloadName: destination.workload.name | "Unknown" + destinationWorkloadNamespace: destination.workload.namespace | "Unknown" + contextProtocol: context.protocol | "Unknown" + apiProtocol: api.protocol | "Unknown" + destinationServiceName: destination.service.name | "Unknown" + destinationServiceNamespace: destination.service.namespace | "Unknown" +--- +apiVersion: "config.istio.io/v1alpha2" +kind: rule +metadata: + name: stackdriver-edge + namespace: {{ .Release.Namespace }} + labels: + app: istio-telemetry + release: {{ .Release.Name }} +spec: + match: (context.reporter.kind | "inbound" == "inbound") && (context.protocol | "unknown" != "unknown") + actions: + - handler: stackdriver + instances: + - stackdriver-edge +{{- end }} +{{- end }} diff --git a/istio-1.5.0/install/kubernetes/operator/charts/istio-telemetry/mixer-telemetry/values.yaml b/istio-1.5.0/install/kubernetes/operator/charts/istio-telemetry/mixer-telemetry/values.yaml new file mode 100644 index 0000000..febc0ee --- /dev/null +++ b/istio-1.5.0/install/kubernetes/operator/charts/istio-telemetry/mixer-telemetry/values.yaml @@ -0,0 +1,111 @@ +mixer: + + adapters: + # stdio is a debug adapter in istio-telemetry, it is not recommended for production use. + stdio: + # If set to true, will add 'rule' and 'stdio' handler for access logs. + # If false, user will need to configure their own rules outside of installer. + enabled: false + outputAsJson: false + + prometheus: + enabled: true + metricsExpiryDuration: 10m + + kubernetesenv: + enabled: true + + stackdriver: + enabled: false + + auth: + appCredentials: false + apiKey: "" + serviceAccountPath: "" + + tracer: + enabled: false + sampleProbability: 1 + + contextGraph: + enabled: false + + logging: + enabled: true + + metrics: + enabled: true + + # Setting this to false sets the useAdapterCRDs mixer startup argument to false + useAdapterCRDs: false + + telemetry: + hub: "" + tag: "" + image: mixer + enabled: true + replicaCount: 1 + rollingMaxSurge: 100% + rollingMaxUnavailable: 25% + autoscaleEnabled: true + autoscaleMin: 1 + autoscaleMax: 5 + cpu: + targetAverageUtilization: 80 + sessionAffinityEnabled: false + + env: + # max procs should be ceil(cpu limit + 1) + GOMAXPROCS: "6" + + # mixer load shedding configuration. + # When mixer detects that it is overloaded, it starts rejecting grpc requests. + loadshedding: + # disabled, logonly or enforce + mode: enforce + # based on measurements 100ms p50 translates to p99 of under 1s. This is ok for telemetry which is inherently async. + latencyThreshold: 100ms + resources: + requests: + cpu: 1000m + memory: 1G + limits: + # It is best to do horizontal scaling of mixer using moderate cpu allocation. + # We have experimentally found that these values work well. + cpu: 4800m + memory: 4G + + # Set reportBatchMaxEntries to 0 to use the default batching behavior (i.e., every 100 requests). + # A positive value indicates the number of requests that are batched before telemetry data + # is sent to the mixer server + reportBatchMaxEntries: 100 + + # Set reportBatchMaxTime to 0 to use the default batching behavior (i.e., every 1 second). + # A positive time value indicates the maximum wait time since the last request will telemetry data + # be batched before being sent to the mixer server + reportBatchMaxTime: 1s + + nodeSelector: {} + tolerations: [] + podAnnotations: {} + + # Specify the pod anti-affinity that allows you to constrain which nodes + # your pod is eligible to be scheduled based on labels on pods that are + # already running on the node rather than based on labels on nodes. + # There are currently two types of anti-affinity: + # "requiredDuringSchedulingIgnoredDuringExecution" + # "preferredDuringSchedulingIgnoredDuringExecution" + # which denote "hard" vs. "soft" requirements, you can define your values + # in "podAntiAffinityLabelSelector" and "podAntiAffinityTermLabelSelector" + # correspondingly. + # For example: + # podAntiAffinityLabelSelector: + # - key: security + # operator: In + # values: S1,S2 + # topologyKey: "kubernetes.io/hostname" + # This pod anti-affinity rule says that the pod requires not to be scheduled + # onto a node if that node is already running a pod with label having key + # "security" and value "S1". + podAntiAffinityLabelSelector: [] + podAntiAffinityTermLabelSelector: [] diff --git a/istio-1.5.0/install/kubernetes/operator/charts/istio-telemetry/prometheus-operator/Chart.yaml b/istio-1.5.0/install/kubernetes/operator/charts/istio-telemetry/prometheus-operator/Chart.yaml new file mode 100644 index 0000000..2d1b8b1 --- /dev/null +++ b/istio-1.5.0/install/kubernetes/operator/charts/istio-telemetry/prometheus-operator/Chart.yaml @@ -0,0 +1,6 @@ +apiVersion: v1 +description: A Helm chart for Kubernetes +name: prometheus-operator +version: 1.1.0 +appVersion: 2.3.1 +tillerVersion: ">=2.7.2" diff --git a/istio-1.5.0/install/kubernetes/operator/charts/istio-telemetry/prometheus-operator/templates/_affinity.tpl b/istio-1.5.0/install/kubernetes/operator/charts/istio-telemetry/prometheus-operator/templates/_affinity.tpl new file mode 100644 index 0000000..ac4dc9c --- /dev/null +++ b/istio-1.5.0/install/kubernetes/operator/charts/istio-telemetry/prometheus-operator/templates/_affinity.tpl @@ -0,0 +1,93 @@ +{{/* affinity - https://kubernetes.io/docs/concepts/configuration/assign-pod-node/ */}} + +{{- define "nodeaffinity" }} + nodeAffinity: + requiredDuringSchedulingIgnoredDuringExecution: + {{- include "nodeAffinityRequiredDuringScheduling" . }} + preferredDuringSchedulingIgnoredDuringExecution: + {{- include "nodeAffinityPreferredDuringScheduling" . }} +{{- end }} + +{{- define "nodeAffinityRequiredDuringScheduling" }} + nodeSelectorTerms: + - matchExpressions: + - key: beta.kubernetes.io/arch + operator: In + values: + {{- range $key, $val := .Values.global.arch }} + {{- if gt ($val | int) 0 }} + - {{ $key | quote }} + {{- end }} + {{- end }} + {{- $nodeSelector := default .Values.global.defaultNodeSelector .Values.prometheus.nodeSelector -}} + {{- range $key, $val := $nodeSelector }} + - key: {{ $key }} + operator: In + values: + - {{ $val | quote }} + {{- end }} +{{- end }} + +{{- define "nodeAffinityPreferredDuringScheduling" }} + {{- range $key, $val := .Values.global.arch }} + {{- if gt ($val | int) 0 }} + - weight: {{ $val | int }} + preference: + matchExpressions: + - key: beta.kubernetes.io/arch + operator: In + values: + - {{ $key | quote }} + {{- end }} + {{- end }} +{{- end }} + +{{- define "podAntiAffinity" }} +{{- if or .Values.prometheus.podAntiAffinityLabelSelector .Values.prometheus.podAntiAffinityTermLabelSelector}} + podAntiAffinity: + {{- if .Values.prometheus.podAntiAffinityLabelSelector }} + requiredDuringSchedulingIgnoredDuringExecution: + {{- include "podAntiAffinityRequiredDuringScheduling" . }} + {{- end }} + {{- if .Values.prometheus.podAntiAffinityTermLabelSelector }} + preferredDuringSchedulingIgnoredDuringExecution: + {{- include "podAntiAffinityPreferredDuringScheduling" . }} + {{- end }} +{{- end }} +{{- end }} + +{{- define "podAntiAffinityRequiredDuringScheduling" }} + {{- range $index, $item := .Values.prometheus.podAntiAffinityLabelSelector }} + - labelSelector: + matchExpressions: + - key: {{ $item.key }} + operator: {{ $item.operator }} + {{- if $item.values }} + values: + {{- $vals := split "," $item.values }} + {{- range $i, $v := $vals }} + - {{ $v | quote }} + {{- end }} + {{- end }} + topologyKey: {{ $item.topologyKey }} + {{- end }} +{{- end }} + +{{- define "podAntiAffinityPreferredDuringScheduling" }} + {{- range $index, $item := .Values.prometheus.podAntiAffinityTermLabelSelector }} + - podAffinityTerm: + labelSelector: + matchExpressions: + - key: {{ $item.key }} + operator: {{ $item.operator }} + {{- if $item.values }} + values: + {{- $vals := split "," $item.values }} + {{- range $i, $v := $vals }} + - {{ $v | quote }} + {{- end }} + {{- end }} + topologyKey: {{ $item.topologyKey }} + weight: 100 + {{- end }} +{{- end }} diff --git a/istio-1.5.0/install/kubernetes/operator/charts/istio-telemetry/prometheus-operator/templates/prometheus.yaml b/istio-1.5.0/install/kubernetes/operator/charts/istio-telemetry/prometheus-operator/templates/prometheus.yaml new file mode 100644 index 0000000..27b2ad9 --- /dev/null +++ b/istio-1.5.0/install/kubernetes/operator/charts/istio-telemetry/prometheus-operator/templates/prometheus.yaml @@ -0,0 +1,137 @@ +{{- if .Values.prometheusOperator.createPrometheusResource }} +apiVersion: monitoring.coreos.com/v1 +kind: Prometheus +metadata: + name: prometheus + namespace: {{ .Release.Namespace }} + labels: + release: {{ .Release.Name }} +spec: + image: "{{ .Values.prometheusOperator.hub }}/{{ .Values.prometheusOperator.image | default "prometheus" }}:{{ .Values.prometheusOperator.tag }}" + version: {{ .Values.prometheusOperator.tag }} + retention: {{ .Values.prometheusOperator.retention }} + scrapeInterval: {{ .Values.prometheusOperator.scrapeInterval }} + serviceAccountName: prometheus + serviceMonitorSelector: + any: true + serviceMonitorNamespaceSelector: + any: true + secrets: [ istio.prometheus ] + enableAdminAPI: false +{{- if .Values.global.priorityClassName }} + priorityClassName: "{{ .Values.global.priorityClassName }}" +{{- end }} + affinity: + {{- include "nodeaffinity" . | indent 2 }} + {{- include "podAntiAffinity" . | indent 2 }} +{{- if .Values.prometheusOperator.tolerations }} + tolerations: +{{ toYaml .Values.prometheusOperator.tolerations | indent 2 }} +{{- end }} + podMetadata: + labels: + app: prometheus + release: {{ .Release.Name }} + annotations: + sidecar.istio.io/inject: "false" + resources: + requests: + memory: 400Mi +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: prometheus-{{ .Release.Namespace }} + labels: + app: prometheus + release: {{ .Release.Name }} +rules: +- apiGroups: [""] + resources: + - nodes + - services + - endpoints + - pods + - nodes/proxy + verbs: ["get", "list", "watch"] +- apiGroups: [""] + resources: + - configmaps + verbs: ["get"] +- nonResourceURLs: ["/metrics"] + verbs: ["get"] +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: prometheus-{{ .Release.Namespace }} + labels: + app: prometheus + release: {{ .Release.Name }} +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: prometheus-{{ .Release.Namespace }} +subjects: +- kind: ServiceAccount + name: prometheus + namespace: {{ .Release.Namespace }} +--- +{{- if not .Values.prometheusOperator.service.nodePort.enabled }} +apiVersion: v1 +kind: Service +metadata: + name: prometheus + namespace: {{ .Release.Namespace }} + annotations: + prometheus.io/scrape: 'true' + {{- if .Values.service }} + {{- range $key, $val := .Values.prometheusOperator.service.annotations }} + {{ $key }}: {{ $val | quote }} + {{- end }} + {{- end }} + labels: + app: prometheus + release: {{ .Release.Name }} +spec: + selector: + app: prometheus + ports: + - name: http-prometheus + protocol: TCP + port: 9090 +{{- else }} +# Using separate ingress for nodeport, to avoid conflict with pilot e2e test configs. +apiVersion: v1 +kind: Service +metadata: + name: prometheus-nodeport + namespace: {{ .Release.Namespace }} + labels: + app: prometheus + release: {{ .Release.Name }} +spec: + type: NodePort + ports: + - port: 9090 + nodePort: {{ .Values.prometheusOperator.service.nodePort.port }} + name: http-prometheus + selector: + app: prometheus +{{- end }} +--- +apiVersion: v1 +kind: ServiceAccount +{{- if .Values.global.imagePullSecrets }} +imagePullSecrets: +{{- range .Values.global.imagePullSecrets }} + - name: {{ . }} +{{- end }} +{{- end }} +metadata: + name: prometheus + namespace: {{ .Release.Namespace }} + labels: + app: prometheus + release: {{ .Release.Name }} +{{- end }} diff --git a/istio-1.5.0/install/kubernetes/operator/charts/istio-telemetry/prometheus-operator/templates/servicemonitors.yaml b/istio-1.5.0/install/kubernetes/operator/charts/istio-telemetry/prometheus-operator/templates/servicemonitors.yaml new file mode 100644 index 0000000..abcd197 --- /dev/null +++ b/istio-1.5.0/install/kubernetes/operator/charts/istio-telemetry/prometheus-operator/templates/servicemonitors.yaml @@ -0,0 +1,320 @@ +apiVersion: monitoring.coreos.com/v1 +kind: ServiceMonitor +metadata: + name: istio-mesh-monitor + namespace: {{ .Release.Namespace }} + labels: + monitoring: istio-mesh + release: {{ .Release.Name }} +spec: + selector: + matchExpressions: + - {key: istio, operator: In, values: [mixer]} + namespaceSelector: + matchNames: + - {{ .Values.global.telemetryNamespace }} + endpoints: + - port: prometheus + interval: {{ .Values.prometheusOperator.scrapeInterval }} +--- +apiVersion: monitoring.coreos.com/v1 +kind: ServiceMonitor +metadata: + name: istio-component-monitor + namespace: {{ .Release.Namespace }} + labels: + monitoring: istio-components + release: {{ .Release.Name }} +spec: + jobLabel: istio + selector: + matchExpressions: + - {key: istio, operator: In, values: [mixer,pilot,galley,citadel,sidecar-injector]} + namespaceSelector: + any: true + endpoints: + - port: http-monitoring + interval: {{ .Values.prometheusOperator.scrapeInterval }} + - port: http-policy-monitoring + interval: {{ .Values.prometheusOperator.scrapeInterval }} +--- +apiVersion: monitoring.coreos.com/v1 +kind: ServiceMonitor +metadata: + name: envoy-stats-monitor + namespace: {{ .Release.Namespace }} + labels: + monitoring: istio-proxies + release: {{ .Release.Name }} +spec: + selector: + matchExpressions: + - {key: istio-prometheus-ignore, operator: DoesNotExist} + namespaceSelector: + any: true + jobLabel: envoy-stats + endpoints: + - path: /stats/prometheus + targetPort: 15090 + interval: {{ .Values.prometheusOperator.scrapeInterval }} + relabelings: + - sourceLabels: [__meta_kubernetes_pod_container_port_name] + action: keep + regex: '.*-envoy-prom' + - action: labeldrop + regex: "__meta_kubernetes_pod_label_(.+)" + - sourceLabels: [__meta_kubernetes_namespace] + action: replace + targetLabel: namespace + - sourceLabels: [__meta_kubernetes_pod_name] + action: replace + targetLabel: pod_name +--- +apiVersion: monitoring.coreos.com/v1 +kind: ServiceMonitor +metadata: + name: kubernetes-pods-monitor + namespace: {{ .Release.Namespace }} + labels: + monitoring: kube-pods + release: {{ .Release.Name }} +spec: + selector: + matchExpressions: + - {key: istio-prometheus-ignore, operator: DoesNotExist} + namespaceSelector: + any: true + jobLabel: kubernetes-pods + endpoints: + - interval: {{ .Values.prometheusOperator.scrapeInterval }} + relabelings: + - sourceLabels: [__meta_kubernetes_pod_annotation_prometheus_io_scrape] + action: keep + regex: 'true' + - sourceLabels: [__meta_kubernetes_pod_annotation_sidecar_istio_io_status, __meta_kubernetes_pod_annotation_prometheus_io_scheme] + action: keep + regex: '((;.*)|(.*;http)|(.??))' + - sourceLabels: [__meta_kubernetes_pod_annotation_istio_mtls] + action: drop + regex: 'true' + - sourceLabels: [__meta_kubernetes_pod_annotation_prometheus_io_path] + action: replace + targetLabel: __metrics_path__ + regex: '(.+)' + - sourceLabels: [__address__, __meta_kubernetes_pod_annotation_prometheus_io_port] + action: replace + regex: '([^:]+)(?::\d+)?;(\d+)' + replacement: $1:$2 + targetLabel: __address__ + - action: labelmap + regex: '__meta_kubernetes_pod_label_(.+)' + - sourceLabels: [__meta_kubernetes_namespace] + action: replace + targetLabel: namespace + - sourceLabels: [__meta_kubernetes_pod_name] + action: replace + targetLabel: pod_name +--- +{{- if .Values.security.enabled }} +apiVersion: monitoring.coreos.com/v1 +kind: ServiceMonitor +metadata: + name: kubernetes-pods-secure-monitor + namespace: {{ .Release.Namespace }} + labels: + monitoring: kube-pods-secure + release: {{ .Release.Name }} +spec: + selector: + matchExpressions: + - {key: istio-prometheus-ignore, operator: DoesNotExist} + namespaceSelector: + any: true + jobLabel: kubernetes-pods-secure + endpoints: + - interval: {{ .Values.prometheusOperator.scrapeInterval }} + scheme: https + tlsConfig: + caFile: /etc/prometheus/secrets/istio.prometheus/root-cert.pem + certFile: /etc/prometheus/secrets/istio.prometheus/cert-chain.pem + keyFile: /etc/prometheus/secrets/istio.prometheus/key.pem + insecureSkipVerify: true # prometheus does not support secure naming. + relabelings: + - sourceLabels: [__meta_kubernetes_pod_annotation_prometheus_io_scrape] + action: keep + regex: 'true' + # sidecar status annotation is added by sidecar injector and + # istio_workload_mtls_ability can be specifically placed on a pod to indicate its ability to receive mtls traffic. + - sourceLabels: [__meta_kubernetes_pod_annotation_sidecar_istio_io_status, __meta_kubernetes_pod_annotation_istio_mtls] + action: keep + regex: '(([^;]+);([^;]*))|(([^;]*);(true))' + - sourceLabels: [__meta_kubernetes_pod_annotation_prometheus_io_scheme] + action: drop + regex: '(http)' + - sourceLabels: [__meta_kubernetes_pod_annotation_prometheus_io_path] + action: replace + targetLabel: __metrics_path__ + regex: '(.+)' + - sourceLabels: [__address__] # Only keep address that is host:port + action: keep # otherwise an extra target with ':443' is added for https scheme + regex: '([^:]+):(\d+)' + - sourceLabels: [__address__, __meta_kubernetes_pod_annotation_prometheus_io_port] + action: replace + regex: '([^:]+)(?::\d+)?;(\d+)' + replacement: $1:$2 + targetLabel: __address__ + - action: labelmap + regex: '__meta_kubernetes_pod_label_(.+)' + - sourceLabels: [__meta_kubernetes_namespace] + action: replace + targetLabel: namespace + - sourceLabels: [__meta_kubernetes_pod_name] + action: replace + targetLabel: pod_name +{{- end }} +--- +apiVersion: monitoring.coreos.com/v1 +kind: ServiceMonitor +metadata: + name: kubernetes-services-monitor + namespace: {{ .Release.Namespace }} + labels: + monitoring: kube-services + release: {{ .Release.Name }} +spec: + selector: + matchExpressions: + - {key: istio-prometheus-ignore, operator: DoesNotExist} + namespaceSelector: + any: true + jobLabel: kubernetes-services + endpoints: + - interval: {{ .Values.prometheusOperator.scrapeInterval }} + relabelings: + - sourceLabels: [__meta_kubernetes_service_annotation_prometheus_io_scrape] + action: keep + regex: 'true' + - sourceLabels: [__meta_kubernetes_pod_annotation_sidecar_istio_io_status, __meta_kubernetes_service_annotation_prometheus_io_scheme] + action: keep + regex: '((;.*)|(.*;http)|(.??))' + - sourceLabels: [__meta_kubernetes_pod_annotation_istio_mtls] + action: drop + regex: 'true' + - sourceLabels: [__meta_kubernetes_service_annotation_prometheus_io_path] + action: replace + targetLabel: __metrics_path__ + regex: '(.+)' + - sourceLabels: [__address__, __meta_kubernetes_service_annotation_prometheus_io_port] + action: replace + regex: '([^:]+)(?::\d+)?;(\d+)' + replacement: $1:$2 + targetLabel: __address__ + - action: labelmap + regex: '__meta_kubernetes_pod_label_(.+)' + - sourceLabels: [__meta_kubernetes_namespace] + action: replace + targetLabel: namespace + - sourceLabels: [__meta_kubernetes_pod_name] + action: replace + targetLabel: pod_name +--- +{{- if .Values.security.enabled }} +apiVersion: monitoring.coreos.com/v1 +kind: ServiceMonitor +metadata: + name: kubernetes-services-secure-monitor + namespace: {{ .Release.Namespace }} + labels: + monitoring: kube-services-secure + release: {{ .Release.Name }} +spec: + selector: + matchExpressions: + - {key: istio-prometheus-ignore, operator: DoesNotExist} + namespaceSelector: + any: true + jobLabel: kubernetes-services-secure + endpoints: + - interval: {{ .Values.prometheusOperator.scrapeInterval }} + scheme: https + tlsConfig: + caFile: /etc/prometheus/secrets/istio.prometheus/root-cert.pem + certFile: /etc/prometheus/secrets/istio.prometheus/cert-chain.pem + keyFile: /etc/prometheus/secrets/istio.prometheus/key.pem + insecureSkipVerify: true # prometheus does not support secure naming. + relabelings: + - sourceLabels: [__meta_kubernetes_service_annotation_prometheus_io_scrape] + action: keep + regex: 'true' + # sidecar status annotation is added by sidecar injector and + # istio_workload_mtls_ability can be specifically placed on a pod to indicate its ability to receive mtls traffic. + - sourceLabels: [__meta_kubernetes_pod_annotation_sidecar_istio_io_status, __meta_kubernetes_pod_annotation_istio_mtls] + action: keep + regex: '(([^;]+);([^;]*))|(([^;]*);(true))' + - sourceLabels: [__meta_kubernetes_service_annotation_prometheus_io_scheme] + action: drop + regex: '(http)' + - sourceLabels: [__meta_kubernetes_service_annotation_prometheus_io_path] + action: replace + targetLabel: __metrics_path__ + regex: '(.+)' + - sourceLabels: [__address__] # Only keep address that is host:port + action: keep # otherwise an extra target with ':443' is added for https scheme + regex: '([^:]+):(\d+)' + - sourceLabels: [__address__, __meta_kubernetes_service_annotation_prometheus_io_port] + action: replace + regex: '([^:]+)(?::\d+)?;(\d+)' + replacement: $1:$2 + targetLabel: __address__ + - action: labelmap + regex: '__meta_kubernetes_pod_label_(.+)' + - sourceLabels: [__meta_kubernetes_namespace] + action: replace + targetLabel: namespace + - sourceLabels: [__meta_kubernetes_pod_name] + action: replace + targetLabel: pod_name +{{- end }} +--- +apiVersion: monitoring.coreos.com/v1 +kind: ServiceMonitor +metadata: + name: kubelet + namespace: {{ .Release.Namespace }} + labels: + monitoring: kubelet-monitor + release: {{ .Release.Name }} +spec: + endpoints: + - bearerTokenFile: /var/run/secrets/kubernetes.io/serviceaccount/token + honorLabels: true + interval: {{ .Values.prometheusOperator.scrapeInterval }} + port: http-metrics + scheme: http + tlsConfig: + insecureSkipVerify: true + - bearerTokenFile: /var/run/secrets/kubernetes.io/serviceaccount/token + honorLabels: true + interval: {{ .Values.prometheusOperator.scrapeInterval }} + relabelings: + - sourceLabels: [job] + action: replace + replacement: kubernetes-cadvisor + targetLabel: job + metricRelabelings: + - action: drop + regex: container_(network_tcp_usage_total|network_udp_usage_total|tasks_state|cpu_load_average_10s) + sourceLabels: + - __name__ + path: /metrics/cadvisor + port: http-metrics + scheme: http + tlsConfig: + insecureSkipVerify: true + jobLabel: k8s-app + namespaceSelector: + matchNames: + - kube-system + selector: + matchLabels: + k8s-app: kubelet diff --git a/istio-1.5.0/install/kubernetes/operator/charts/istio-telemetry/prometheus-operator/values.yaml b/istio-1.5.0/install/kubernetes/operator/charts/istio-telemetry/prometheus-operator/values.yaml new file mode 100644 index 0000000..c93fe0b --- /dev/null +++ b/istio-1.5.0/install/kubernetes/operator/charts/istio-telemetry/prometheus-operator/values.yaml @@ -0,0 +1,47 @@ +prometheusOperator: + # Controls the default scrape interval used in the ServiceMonitors + scrapeInterval: 15s + + # Enabling this option will generate a Prometheus resource, causing the operator + # to create a prometheus deployment according to the generated spec. It will also + # create a service definition, destination rules, cluster roles and bindings, and + # a service account. Only use this option if you have not already created and configured + # a prometheus resource and/or you desire a distinct prometheus resource for Istio. + createPrometheusResource: false + hub: docker.io/prom + tag: v2.15.1 + retention: 6h + + service: + annotations: {} + nodePort: + enabled: false + port: 32090 + + nodeSelector: {} + tolerations: [] + + # Specify the pod anti-affinity that allows you to constrain which nodes + # your pod is eligible to be scheduled based on labels on pods that are + # already running on the node rather than based on labels on nodes. + # There are currently two types of anti-affinity: + # "requiredDuringSchedulingIgnoredDuringExecution" + # "preferredDuringSchedulingIgnoredDuringExecution" + # which denote "hard" vs. "soft" requirements, you can define your values + # in "podAntiAffinityLabelSelector" and "podAntiAffinityTermLabelSelector" + # correspondingly. + # For example: + # podAntiAffinityLabelSelector: + # - key: security + # operator: In + # values: S1,S2 + # topologyKey: "kubernetes.io/hostname" + # This pod anti-affinity rule says that the pod requires not to be scheduled + # onto a node if that node is already running a pod with label having key + # "security" and value "S1". + podAntiAffinityLabelSelector: [] + podAntiAffinityTermLabelSelector: [] + +# Indicate if Citadel is enabled, i.e., whether its generated certificates are available +security: + enabled: true \ No newline at end of file diff --git a/istio-1.5.0/install/kubernetes/operator/charts/istio-telemetry/prometheus/Chart.yaml b/istio-1.5.0/install/kubernetes/operator/charts/istio-telemetry/prometheus/Chart.yaml new file mode 100644 index 0000000..6431a43 --- /dev/null +++ b/istio-1.5.0/install/kubernetes/operator/charts/istio-telemetry/prometheus/Chart.yaml @@ -0,0 +1,6 @@ +apiVersion: v1 +description: A Helm chart for Kubernetes +name: prometheus +version: 1.1.0 +appVersion: 2.8.0 +tillerVersion: ">=2.7.2" diff --git a/istio-1.5.0/install/kubernetes/operator/charts/istio-telemetry/prometheus/templates/_affinity.tpl b/istio-1.5.0/install/kubernetes/operator/charts/istio-telemetry/prometheus/templates/_affinity.tpl new file mode 100644 index 0000000..ac4dc9c --- /dev/null +++ b/istio-1.5.0/install/kubernetes/operator/charts/istio-telemetry/prometheus/templates/_affinity.tpl @@ -0,0 +1,93 @@ +{{/* affinity - https://kubernetes.io/docs/concepts/configuration/assign-pod-node/ */}} + +{{- define "nodeaffinity" }} + nodeAffinity: + requiredDuringSchedulingIgnoredDuringExecution: + {{- include "nodeAffinityRequiredDuringScheduling" . }} + preferredDuringSchedulingIgnoredDuringExecution: + {{- include "nodeAffinityPreferredDuringScheduling" . }} +{{- end }} + +{{- define "nodeAffinityRequiredDuringScheduling" }} + nodeSelectorTerms: + - matchExpressions: + - key: beta.kubernetes.io/arch + operator: In + values: + {{- range $key, $val := .Values.global.arch }} + {{- if gt ($val | int) 0 }} + - {{ $key | quote }} + {{- end }} + {{- end }} + {{- $nodeSelector := default .Values.global.defaultNodeSelector .Values.prometheus.nodeSelector -}} + {{- range $key, $val := $nodeSelector }} + - key: {{ $key }} + operator: In + values: + - {{ $val | quote }} + {{- end }} +{{- end }} + +{{- define "nodeAffinityPreferredDuringScheduling" }} + {{- range $key, $val := .Values.global.arch }} + {{- if gt ($val | int) 0 }} + - weight: {{ $val | int }} + preference: + matchExpressions: + - key: beta.kubernetes.io/arch + operator: In + values: + - {{ $key | quote }} + {{- end }} + {{- end }} +{{- end }} + +{{- define "podAntiAffinity" }} +{{- if or .Values.prometheus.podAntiAffinityLabelSelector .Values.prometheus.podAntiAffinityTermLabelSelector}} + podAntiAffinity: + {{- if .Values.prometheus.podAntiAffinityLabelSelector }} + requiredDuringSchedulingIgnoredDuringExecution: + {{- include "podAntiAffinityRequiredDuringScheduling" . }} + {{- end }} + {{- if .Values.prometheus.podAntiAffinityTermLabelSelector }} + preferredDuringSchedulingIgnoredDuringExecution: + {{- include "podAntiAffinityPreferredDuringScheduling" . }} + {{- end }} +{{- end }} +{{- end }} + +{{- define "podAntiAffinityRequiredDuringScheduling" }} + {{- range $index, $item := .Values.prometheus.podAntiAffinityLabelSelector }} + - labelSelector: + matchExpressions: + - key: {{ $item.key }} + operator: {{ $item.operator }} + {{- if $item.values }} + values: + {{- $vals := split "," $item.values }} + {{- range $i, $v := $vals }} + - {{ $v | quote }} + {{- end }} + {{- end }} + topologyKey: {{ $item.topologyKey }} + {{- end }} +{{- end }} + +{{- define "podAntiAffinityPreferredDuringScheduling" }} + {{- range $index, $item := .Values.prometheus.podAntiAffinityTermLabelSelector }} + - podAffinityTerm: + labelSelector: + matchExpressions: + - key: {{ $item.key }} + operator: {{ $item.operator }} + {{- if $item.values }} + values: + {{- $vals := split "," $item.values }} + {{- range $i, $v := $vals }} + - {{ $v | quote }} + {{- end }} + {{- end }} + topologyKey: {{ $item.topologyKey }} + weight: 100 + {{- end }} +{{- end }} diff --git a/istio-1.5.0/install/kubernetes/operator/charts/istio-telemetry/prometheus/templates/clusterrole.yaml b/istio-1.5.0/install/kubernetes/operator/charts/istio-telemetry/prometheus/templates/clusterrole.yaml new file mode 100644 index 0000000..ddf0c0d --- /dev/null +++ b/istio-1.5.0/install/kubernetes/operator/charts/istio-telemetry/prometheus/templates/clusterrole.yaml @@ -0,0 +1,22 @@ +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: prometheus-{{ .Release.Namespace }} + labels: + app: prometheus + release: {{ .Release.Name }} +rules: +- apiGroups: [""] + resources: + - nodes + - services + - endpoints + - pods + - nodes/proxy + verbs: ["get", "list", "watch"] +- apiGroups: [""] + resources: + - configmaps + verbs: ["get"] +- nonResourceURLs: ["/metrics"] + verbs: ["get"] diff --git a/istio-1.5.0/install/kubernetes/operator/charts/istio-telemetry/prometheus/templates/clusterrolebindings.yaml b/istio-1.5.0/install/kubernetes/operator/charts/istio-telemetry/prometheus/templates/clusterrolebindings.yaml new file mode 100644 index 0000000..5619efe --- /dev/null +++ b/istio-1.5.0/install/kubernetes/operator/charts/istio-telemetry/prometheus/templates/clusterrolebindings.yaml @@ -0,0 +1,15 @@ +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: prometheus-{{ .Release.Namespace }} + labels: + app: prometheus + release: {{ .Release.Name }} +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: prometheus-{{ .Release.Namespace }} +subjects: +- kind: ServiceAccount + name: prometheus + namespace: {{ .Release.Namespace }} diff --git a/istio-1.5.0/install/kubernetes/operator/charts/istio-telemetry/prometheus/templates/configmap.yaml b/istio-1.5.0/install/kubernetes/operator/charts/istio-telemetry/prometheus/templates/configmap.yaml new file mode 100644 index 0000000..849d70b --- /dev/null +++ b/istio-1.5.0/install/kubernetes/operator/charts/istio-telemetry/prometheus/templates/configmap.yaml @@ -0,0 +1,291 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: prometheus + namespace: {{ .Release.Namespace }} + labels: + app: prometheus + release: {{ .Release.Name }} +data: + prometheus.yml: |- + global: + scrape_interval: {{ .Values.prometheus.scrapeInterval }} + scrape_configs: + + # Mixer scrapping. Defaults to Prometheus and mixer on same namespace. + # + - job_name: 'istio-mesh' + kubernetes_sd_configs: + - role: endpoints + namespaces: + names: + - {{ .Release.Namespace }} + relabel_configs: + - source_labels: [__meta_kubernetes_service_name, __meta_kubernetes_endpoint_port_name] + action: keep + regex: istio-telemetry;prometheus + + # Scrape config for envoy stats + - job_name: 'envoy-stats' + metrics_path: /stats/prometheus + kubernetes_sd_configs: + - role: pod + + relabel_configs: + - source_labels: [__meta_kubernetes_pod_container_port_name] + action: keep + regex: '.*-envoy-prom' + - source_labels: [__address__, __meta_kubernetes_pod_annotation_prometheus_io_port] + action: replace + regex: ([^:]+)(?::\d+)?;(\d+) + replacement: $1:15090 + target_label: __address__ + - action: labeldrop + regex: __meta_kubernetes_pod_label_(.+) + - source_labels: [__meta_kubernetes_namespace] + action: replace + target_label: namespace + - source_labels: [__meta_kubernetes_pod_name] + action: replace + target_label: pod_name + + - job_name: 'istio-policy' + kubernetes_sd_configs: + - role: endpoints + namespaces: + names: + - {{ .Values.global.policyNamespace }} + + + relabel_configs: + - source_labels: [__meta_kubernetes_service_name, __meta_kubernetes_endpoint_port_name] + action: keep + regex: istio-policy;http-policy-monitoring + + - job_name: 'istio-telemetry' + kubernetes_sd_configs: + - role: endpoints + namespaces: + names: + - {{ .Values.global.telemetryNamespace }} + + relabel_configs: + - source_labels: [__meta_kubernetes_service_name, __meta_kubernetes_endpoint_port_name] + action: keep + regex: istio-telemetry;http-monitoring + + - job_name: 'pilot' + kubernetes_sd_configs: + - role: endpoints + namespaces: + names: + - {{ .Values.global.configNamespace }} + + relabel_configs: + - source_labels: [__meta_kubernetes_service_name, __meta_kubernetes_endpoint_port_name] + action: keep + regex: istio-pilot;http-monitoring + + - job_name: 'galley' + kubernetes_sd_configs: + - role: endpoints + namespaces: + names: + - {{ .Values.global.configNamespace }} + + relabel_configs: + - source_labels: [__meta_kubernetes_service_name, __meta_kubernetes_endpoint_port_name] + action: keep + regex: istio-galley;http-monitoring + + - job_name: 'citadel' + kubernetes_sd_configs: + - role: endpoints + namespaces: + names: + - {{ .Values.global.istioNamespace }} + + relabel_configs: + - source_labels: [__meta_kubernetes_service_name, __meta_kubernetes_endpoint_port_name] + action: keep + regex: istio-citadel;http-monitoring + + - job_name: 'sidecar-injector' + + kubernetes_sd_configs: + - role: endpoints + namespaces: + names: + - {{ .Release.Namespace }} + + relabel_configs: + - source_labels: [__meta_kubernetes_service_name, __meta_kubernetes_endpoint_port_name] + action: keep + regex: istio-sidecar-injector;http-monitoring + + # scrape config for API servers + - job_name: 'kubernetes-apiservers' + kubernetes_sd_configs: + - role: endpoints + namespaces: + names: + - default + scheme: https + tls_config: + ca_file: /var/run/secrets/kubernetes.io/serviceaccount/ca.crt + bearer_token_file: /var/run/secrets/kubernetes.io/serviceaccount/token + relabel_configs: + - source_labels: [__meta_kubernetes_service_name, __meta_kubernetes_endpoint_port_name] + action: keep + regex: kubernetes;https + + # scrape config for nodes (kubelet) + - job_name: 'kubernetes-nodes' + scheme: https + tls_config: + ca_file: /var/run/secrets/kubernetes.io/serviceaccount/ca.crt + bearer_token_file: /var/run/secrets/kubernetes.io/serviceaccount/token + kubernetes_sd_configs: + - role: node + relabel_configs: + - action: labelmap + regex: __meta_kubernetes_node_label_(.+) + - target_label: __address__ + replacement: kubernetes.default.svc:443 + - source_labels: [__meta_kubernetes_node_name] + regex: (.+) + target_label: __metrics_path__ + replacement: /api/v1/nodes/${1}/proxy/metrics + + # Scrape config for Kubelet cAdvisor. + # + # This is required for Kubernetes 1.7.3 and later, where cAdvisor metrics + # (those whose names begin with 'container_') have been removed from the + # Kubelet metrics endpoint. This job scrapes the cAdvisor endpoint to + # retrieve those metrics. + # + # In Kubernetes 1.7.0-1.7.2, these metrics are only exposed on the cAdvisor + # HTTP endpoint; use "replacement: /api/v1/nodes/${1}:4194/proxy/metrics" + # in that case (and ensure cAdvisor's HTTP server hasn't been disabled with + # the --cadvisor-port=0 Kubelet flag). + # + # This job is not necessary and should be removed in Kubernetes 1.6 and + # earlier versions, or it will cause the metrics to be scraped twice. + - job_name: 'kubernetes-cadvisor' + scheme: https + tls_config: + ca_file: /var/run/secrets/kubernetes.io/serviceaccount/ca.crt + bearer_token_file: /var/run/secrets/kubernetes.io/serviceaccount/token + kubernetes_sd_configs: + - role: node + relabel_configs: + - action: labelmap + regex: __meta_kubernetes_node_label_(.+) + - target_label: __address__ + replacement: kubernetes.default.svc:443 + - source_labels: [__meta_kubernetes_node_name] + regex: (.+) + target_label: __metrics_path__ + replacement: /api/v1/nodes/${1}/proxy/metrics/cadvisor + + # scrape config for service endpoints. + - job_name: 'kubernetes-service-endpoints' + kubernetes_sd_configs: + - role: endpoints + relabel_configs: + - source_labels: [__meta_kubernetes_service_annotation_prometheus_io_scrape] + action: keep + regex: true + - source_labels: [__meta_kubernetes_service_annotation_prometheus_io_scheme] + action: replace + target_label: __scheme__ + regex: (https?) + - source_labels: [__meta_kubernetes_service_annotation_prometheus_io_path] + action: replace + target_label: __metrics_path__ + regex: (.+) + - source_labels: [__address__, __meta_kubernetes_service_annotation_prometheus_io_port] + action: replace + target_label: __address__ + regex: ([^:]+)(?::\d+)?;(\d+) + replacement: $1:$2 + - action: labelmap + regex: __meta_kubernetes_service_label_(.+) + - source_labels: [__meta_kubernetes_namespace] + action: replace + target_label: kubernetes_namespace + - source_labels: [__meta_kubernetes_service_name] + action: replace + target_label: kubernetes_name + + - job_name: 'kubernetes-pods' + kubernetes_sd_configs: + - role: pod + relabel_configs: # If first two labels are present, pod should be scraped by the istio-secure job. + - source_labels: [__meta_kubernetes_pod_annotation_prometheus_io_scrape] + action: keep + regex: true + - source_labels: [__meta_kubernetes_pod_annotation_sidecar_istio_io_status] + action: drop + regex: (.+) + - source_labels: [__meta_kubernetes_pod_annotation_istio_mtls] + action: drop + regex: (true) + - source_labels: [__meta_kubernetes_pod_annotation_prometheus_io_path] + action: replace + target_label: __metrics_path__ + regex: (.+) + - source_labels: [__address__, __meta_kubernetes_pod_annotation_prometheus_io_port] + action: replace + regex: ([^:]+)(?::\d+)?;(\d+) + replacement: $1:$2 + target_label: __address__ + - action: labelmap + regex: __meta_kubernetes_pod_label_(.+) + - source_labels: [__meta_kubernetes_namespace] + action: replace + target_label: namespace + - source_labels: [__meta_kubernetes_pod_name] + action: replace + target_label: pod_name + +{{- if .Values.security.enabled }} + - job_name: 'kubernetes-pods-istio-secure' + scheme: https + tls_config: + ca_file: /etc/istio-certs/root-cert.pem + cert_file: /etc/istio-certs/cert-chain.pem + key_file: /etc/istio-certs/key.pem + insecure_skip_verify: true # prometheus does not support secure naming. + kubernetes_sd_configs: + - role: pod + relabel_configs: + - source_labels: [__meta_kubernetes_pod_annotation_prometheus_io_scrape] + action: keep + regex: true + # sidecar status annotation is added by sidecar injector and + # istio_workload_mtls_ability can be specifically placed on a pod to indicate its ability to receive mtls traffic. + - source_labels: [__meta_kubernetes_pod_annotation_sidecar_istio_io_status, __meta_kubernetes_pod_annotation_istio_mtls] + action: keep + regex: (([^;]+);([^;]*))|(([^;]*);(true)) + - source_labels: [__meta_kubernetes_pod_annotation_prometheus_io_path] + action: replace + target_label: __metrics_path__ + regex: (.+) + - source_labels: [__address__] # Only keep address that is host:port + action: keep # otherwise an extra target with ':443' is added for https scheme + regex: ([^:]+):(\d+) + - source_labels: [__address__, __meta_kubernetes_pod_annotation_prometheus_io_port] + action: replace + regex: ([^:]+)(?::\d+)?;(\d+) + replacement: $1:$2 + target_label: __address__ + - action: labelmap + regex: __meta_kubernetes_pod_label_(.+) + - source_labels: [__meta_kubernetes_namespace] + action: replace + target_label: namespace + - source_labels: [__meta_kubernetes_pod_name] + action: replace + target_label: pod_name +{{- end }} diff --git a/istio-1.5.0/install/kubernetes/operator/charts/istio-telemetry/prometheus/templates/deployment.yaml b/istio-1.5.0/install/kubernetes/operator/charts/istio-telemetry/prometheus/templates/deployment.yaml new file mode 100644 index 0000000..23454df --- /dev/null +++ b/istio-1.5.0/install/kubernetes/operator/charts/istio-telemetry/prometheus/templates/deployment.yaml @@ -0,0 +1,269 @@ +# TODO: the original template has service account, roles, etc +apiVersion: apps/v1 +kind: Deployment +metadata: + name: prometheus + namespace: {{ .Release.Namespace }} + labels: + app: prometheus + release: {{ .Release.Name }} +spec: + replicas: {{ .Values.prometheus.replicaCount }} + selector: + matchLabels: + app: prometheus + template: + metadata: + labels: + app: prometheus + release: {{ .Release.Name }} + annotations: + sidecar.istio.io/inject: "false" + {{- if .Values.prometheus.podAnnotations }} +{{ toYaml .Values.prometheus.podAnnotations | indent 8 }} + {{- end }} + spec: + serviceAccountName: prometheus +{{- if .Values.global.priorityClassName }} + priorityClassName: "{{ .Values.global.priorityClassName }}" +{{- end }} + containers: + - name: prometheus + image: "{{ .Values.prometheus.hub }}/{{ .Values.prometheus.image }}:{{ .Values.prometheus.tag }}" + imagePullPolicy: {{ .Values.global.imagePullPolicy | default "Always" }} + args: + - '--storage.tsdb.retention={{ .Values.prometheus.retention }}' + - '--config.file=/etc/prometheus/prometheus.yml' + ports: + - containerPort: 9090 + name: http + livenessProbe: + httpGet: + path: /-/healthy + port: 9090 + readinessProbe: + httpGet: + path: /-/ready + port: 9090 + resources: +{{- if .Values.prometheus.resources }} +{{ toYaml .Values.prometheus.resources | indent 12 }} +{{- else }} +{{ toYaml .Values.global.defaultResources | indent 12 }} +{{- end }} + volumeMounts: + - name: config-volume + mountPath: /etc/prometheus + - mountPath: /etc/istio-certs + name: istio-certs +{{- if and .Values.prometheus.provisionPrometheusCert .Values.global.istiod.enabled }} + - name: istio-proxy + image: "{{ .Values.global.hub }}/{{ .Values.global.proxy.image }}:{{ .Values.global.tag }}" + ports: + - containerPort: 15090 + protocol: TCP + name: http-envoy-prom + args: + - proxy + - sidecar + - --domain + - $(POD_NAMESPACE).svc.{{ .Values.global.proxy.clusterDomain }} + - --configPath + - "/etc/istio/proxy" + - --binaryPath + - "/usr/local/bin/envoy" + - --serviceCluster + - "istio-proxy-prometheus" + - --drainDuration + - "45s" + - --parentShutdownDuration + - "1m0s" + - --discoveryAddress + {{- if .Values.global.configNamespace }} + - istio-pilot.{{ .Values.global.configNamespace }}.svc:15012 + {{- else }} + - istio-pilot.istio-system.svc:15012 + {{- end }} + {{- if .Values.global.proxy.logLevel }} + - --proxyLogLevel={{ .Values.global.proxy.logLevel }} + {{- end}} + {{- if .Values.global.proxy.componentLogLevel }} + - --proxyComponentLogLevel={{ .Values.global.proxy.componentLogLevel }} + {{- end}} + - --connectTimeout + - "10s" + {{- if .Values.global.proxy.envoyStatsd.enabled }} + - --statsdUdpAddress + - "{{ .ProxyConfig.StatsdUdpAddress }}" + {{- end }} + {{- if $.Values.global.proxy.envoyMetricsService.enabled }} + - --envoyMetricsService + {{- with $.Values.global.proxy.envoyMetricsService }} + - '{"address":"{{ .host }}:{{.port }}"{{ if .tlsSettings }},"tlsSettings":{{ .tlsSettings | toJson }}{{- end }}{{ if .tcpKeepalive }},"tcpKeepalive":{{ .tcpKeepalive | toJson }}{{- end }}}' + {{- end }} + {{- end}} + {{- if $.Values.global.proxy.envoyAccessLogService.enabled }} + - --envoyAccessLogService + {{- with $.Values.global.proxy.envoyAccessLogService }} + - '{"address":"{{ .host }}:{{.port }}"{{ if .tlsSettings }},"tlsSettings":{{ .tlsSettings | toJson }}{{- end }}{{ if .tcpKeepalive }},"tcpKeepalive":{{ .tcpKeepalive | toJson }}{{- end }}}' + {{- end }} + {{- end }} + - --proxyAdminPort + - "15000" + {{- if .Values.global.istiod.enabled }} + - --controlPlaneAuthPolicy + - NONE + {{- else if .Values.global.controlPlaneSecurityEnabled }} + - --controlPlaneAuthPolicy + - MUTUAL_TLS + {{- else }} + - --controlPlaneAuthPolicy + - NONE + {{- end }} + - --dnsRefreshRate + - "300s" + - --statusPort + - "15020" + {{- if .Values.global.trustDomain }} + - --trust-domain={{ .Values.global.trustDomain }} + {{- end }} + {{- if .Values.global.logAsJson }} + - --log_as_json + {{- end }} + - --controlPlaneBootstrap=false + env: + - name: OUTPUT_KEY_CERT_TO_DIRECTORY + value: "/etc/istio-certs" + - name: JWT_POLICY + value: {{ .Values.global.jwtPolicy }} + - name: PILOT_CERT_PROVIDER + value: {{ .Values.global.pilotCertProvider }} + # Temp, pending PR to make it default or based on the istiodAddr env + - name: CA_ADDR + {{- if .Values.global.configNamespace }} + value: istio-pilot.{{ .Values.global.configNamespace }}.svc:15012 + {{- else }} + value: istio-pilot.istio-system.svc:15012 + {{- end }} + - name: POD_NAME + valueFrom: + fieldRef: + fieldPath: metadata.name + - name: POD_NAMESPACE + valueFrom: + fieldRef: + fieldPath: metadata.namespace + - name: INSTANCE_IP + valueFrom: + fieldRef: + fieldPath: status.podIP + - name: SERVICE_ACCOUNT + valueFrom: + fieldRef: + fieldPath: spec.serviceAccountName + - name: HOST_IP + valueFrom: + fieldRef: + fieldPath: status.hostIP + - name: ISTIO_META_POD_NAME + valueFrom: + fieldRef: + fieldPath: metadata.name + - name: ISTIO_META_CONFIG_NAMESPACE + valueFrom: + fieldRef: + fieldPath: metadata.namespace + {{- if .Values.global.network }} + - name: ISTIO_META_NETWORK + value: "{{ .Values.global.network }}" + {{- end }} + {{- if .Values.global.meshID }} + - name: ISTIO_META_MESH_ID + value: "{{ .Values.global.meshID }}" + {{- else if .Values.global.trustDomain }} + - name: ISTIO_META_MESH_ID + value: "{{ .Values.global.trustDomain }}" + {{- end }} + imagePullPolicy: {{ .Values.global.imagePullPolicy | default "Always" }} + readinessProbe: + failureThreshold: 30 + httpGet: + path: /healthz/ready + port: 15020 + scheme: HTTP + initialDelaySeconds: 1 + periodSeconds: 2 + successThreshold: 1 + timeoutSeconds: 1 + volumeMounts: + {{- if eq .Values.global.pilotCertProvider "istiod" }} + - mountPath: /var/run/secrets/istio + name: istiod-ca-cert + {{- end }} + - mountPath: /etc/istio/proxy + name: istio-envoy + {{- if eq .Values.global.jwtPolicy "third-party-jwt" }} + - mountPath: /var/run/secrets/tokens + name: istio-token + {{- end }} + - mountPath: /etc/istio-certs/ + name: istio-certs +{{- end }} + + volumes: + - name: config-volume + configMap: + name: prometheus + +{{- if .Values.prometheus.provisionPrometheusCert }} + - name: istio-certs + emptyDir: + medium: Memory +{{- else }} + - name: istio-certs + secret: + defaultMode: 420 +{{- if not .Values.security.enabled }} + optional: true +{{- end }} + secretName: istio.default +{{- end }} + +{{- if .Values.prometheus.provisionPrometheusCert }} + - emptyDir: + medium: Memory + name: istio-envoy + {{- if eq .Values.global.jwtPolicy "third-party-jwt" }} + - name: istio-token + projected: + defaultMode: 420 + sources: + - serviceAccountToken: + path: istio-token + expirationSeconds: 43200 + audience: {{ .Values.global.sds.token.aud }} + {{- end }} + {{- if eq .Values.global.pilotCertProvider "istiod" }} + - name: istiod-ca-cert + configMap: + defaultMode: 420 + name: istio-ca-root-cert + {{- end }} + {{- if and (eq .Values.global.proxy.tracer "lightstep") .Values.global.tracer.lightstep.cacertPath }} + - name: lightstep-certs + secret: + optional: true + secretName: lightstep.cacert + {{- end }} +{{- end }} + + affinity: + {{- include "nodeaffinity" . | indent 6 }} + {{- include "podAntiAffinity" . | indent 6 }} +{{- if .Values.prometheus.tolerations }} + tolerations: +{{ toYaml .Values.prometheus.tolerations | indent 6 }} +{{- else if .Values.global.defaultTolerations }} + tolerations: +{{ toYaml .Values.global.defaultTolerations | indent 6 }} +{{- end }} diff --git a/istio-1.5.0/install/kubernetes/operator/charts/istio-telemetry/prometheus/templates/ingress.yaml b/istio-1.5.0/install/kubernetes/operator/charts/istio-telemetry/prometheus/templates/ingress.yaml new file mode 100644 index 0000000..7850066 --- /dev/null +++ b/istio-1.5.0/install/kubernetes/operator/charts/istio-telemetry/prometheus/templates/ingress.yaml @@ -0,0 +1,38 @@ +{{- if .Values.prometheus.ingress.enabled -}} +apiVersion: extensions/v1beta1 +kind: Ingress +metadata: + name: prometheus + namespace: {{ .Release.Namespace }} + labels: + app: prometheus + release: {{ .Release.Name }} + annotations: + {{- range $key, $value := .Values.prometheus.ingress.annotations }} + {{ $key }}: {{ $value | quote }} + {{- end }} +spec: + rules: +{{- if .Values.prometheus.ingress.hosts }} + {{- range $host := .Values.prometheus.ingress.hosts }} + - host: {{ $host }} + http: + paths: + - path: {{ if $.Values.prometheus.contextPath }} {{ $.Values.prometheus.contextPath }} {{ else }} / {{ end }} + backend: + serviceName: prometheus + servicePort: 9090 + {{- end -}} +{{- else }} + - http: + paths: + - path: {{ if .Values.prometheus.contextPath }} {{ .Values.prometheus.contextPath }} {{ else }} / {{ end }} + backend: + serviceName: prometheus + servicePort: 9090 +{{- end }} + {{- if .Values.prometheus.ingress.tls }} + tls: +{{ toYaml .Values.prometheus.ingress.tls | indent 4 }} + {{- end -}} +{{- end -}} diff --git a/istio-1.5.0/install/kubernetes/operator/charts/istio-telemetry/prometheus/templates/service.yaml b/istio-1.5.0/install/kubernetes/operator/charts/istio-telemetry/prometheus/templates/service.yaml new file mode 100644 index 0000000..321c4ff --- /dev/null +++ b/istio-1.5.0/install/kubernetes/operator/charts/istio-telemetry/prometheus/templates/service.yaml @@ -0,0 +1,43 @@ +apiVersion: v1 +kind: Service +metadata: + name: prometheus + namespace: {{ .Release.Namespace }} + annotations: + prometheus.io/scrape: 'true' + {{- if .Values.prometheus.service }} + {{- range $key, $val := .Values.prometheus.service.annotations }} + {{ $key }}: {{ $val | quote }} + {{- end }} + {{- end }} + labels: + app: prometheus + release: {{ .Release.Name }} +spec: + selector: + app: prometheus + ports: + - name: http-prometheus + protocol: TCP + port: 9090 + +{{- if .Values.prometheus.service }} +# Using separate ingress for nodeport, to avoid conflict with pilot e2e test configs. +--- +apiVersion: v1 +kind: Service +metadata: + name: prometheus-nodeport + namespace: {{ .Release.Namespace }} + labels: + app: prometheus + release: {{ .Release.Name }} +spec: + type: NodePort + ports: + - port: 9090 + nodePort: {{ .Values.prometheus.service.nodePort.port }} + name: http-prometheus + selector: + app: prometheus +{{- end }} diff --git a/istio-1.5.0/install/kubernetes/operator/charts/istio-telemetry/prometheus/templates/serviceaccount.yaml b/istio-1.5.0/install/kubernetes/operator/charts/istio-telemetry/prometheus/templates/serviceaccount.yaml new file mode 100644 index 0000000..095d1c7 --- /dev/null +++ b/istio-1.5.0/install/kubernetes/operator/charts/istio-telemetry/prometheus/templates/serviceaccount.yaml @@ -0,0 +1,14 @@ +apiVersion: v1 +kind: ServiceAccount +{{- if .Values.global.imagePullSecrets }} +imagePullSecrets: +{{- range .Values.global.imagePullSecrets }} + - name: {{ . }} +{{- end }} +{{- end }} +metadata: + name: prometheus + namespace: {{ .Release.Namespace }} + labels: + app: prometheus + release: {{ .Release.Name }} diff --git a/istio-1.5.0/install/kubernetes/operator/charts/istio-telemetry/prometheus/templates/tests/test-prometheus-connection.yaml b/istio-1.5.0/install/kubernetes/operator/charts/istio-telemetry/prometheus/templates/tests/test-prometheus-connection.yaml new file mode 100644 index 0000000..d41dc14 --- /dev/null +++ b/istio-1.5.0/install/kubernetes/operator/charts/istio-telemetry/prometheus/templates/tests/test-prometheus-connection.yaml @@ -0,0 +1,27 @@ +{{- if .Values.global.enableHelmTest }} +apiVersion: v1 +kind: Pod +metadata: + name: prometheus-test + namespace: {{ .Release.Namespace }} + labels: + app: prometheus-test + release: {{ .Release.Name }} + istio: prometheus + annotations: + sidecar.istio.io/inject: "false" + helm.sh/hook: test-success +spec: +{{- if .Values.global.priorityClassName }} + priorityClassName: "{{ .Values.global.priorityClassName }}" +{{- end }} + containers: + - name: "prometheus-test" + image: {{ .Values.global.hub }}/{{ .Values.global.proxy.image }}:{{ .Values.global.tag }} + imagePullPolicy: "{{ .Values.global.imagePullPolicy }}" + command: ['sh', '-c', 'for i in 1 2 3; do curl http://prometheus:9090/-/ready && exit 0 || sleep 15; done; exit 1'] + restartPolicy: Never + affinity: + {{- include "nodeaffinity" . | indent 4 }} + {{- include "podAntiAffinity" . | indent 4 }} +{{- end }} diff --git a/istio-1.5.0/install/kubernetes/operator/charts/istio-telemetry/prometheus/values.yaml b/istio-1.5.0/install/kubernetes/operator/charts/istio-telemetry/prometheus/values.yaml new file mode 100644 index 0000000..e035443 --- /dev/null +++ b/istio-1.5.0/install/kubernetes/operator/charts/istio-telemetry/prometheus/values.yaml @@ -0,0 +1,72 @@ +prometheus: + enabled: true + replicaCount: 1 + hub: docker.io/prom + image: prometheus + tag: v2.15.1 + retention: 6h + + # Controls the frequency of prometheus scraping + scrapeInterval: 15s + + contextPath: /prometheus + + ingress: + enabled: false + ## Used to create an Ingress record. + hosts: + - prometheus.local + annotations: + # kubernetes.io/ingress.class: nginx + # kubernetes.io/tls-acme: "true" + tls: + # Secrets must be manually created in the namespace. + # - secretName: prometheus-tls + # hosts: + # - prometheus.local + + # 1.2 it is disabled by default - it can be enabled for special cases, but would create port + # conflicts. In general it is not recommended to use node ports for services, but use gateways instead. +# service: +# annotations: {} +# nodePort: +# enabled: false +# port: 32090 + + nodeSelector: {} + tolerations: [] + podAnnotations: {} + service: {} + resources: {} + datasources: [] + # Specify the pod anti-affinity that allows you to constrain which nodes + # your pod is eligible to be scheduled based on labels on pods that are + # already running on the node rather than based on labels on nodes. + # There are currently two types of anti-affinity: + # "requiredDuringSchedulingIgnoredDuringExecution" + # "preferredDuringSchedulingIgnoredDuringExecution" + # which denote "hard" vs. "soft" requirements, you can define your values + # in "podAntiAffinityLabelSelector" and "podAntiAffinityTermLabelSelector" + # correspondingly. + # For example: + # podAntiAffinityLabelSelector: + # - key: security + # operator: In + # values: S1,S2 + # topologyKey: "kubernetes.io/hostname" + # This pod anti-affinity rule says that the pod requires not to be scheduled + # onto a node if that node is already running a pod with label having key + # "security" and value "S1". + podAntiAffinityLabelSelector: [] + podAntiAffinityTermLabelSelector: [] + + # Configure whether provisions a certificate to Prometheus through Istio Agent. + # When this option is set as true, a sidecar is deployed along Prometheus to + # provision a certificate through Istio Agent to Prometheus. The provisioned certificate + # is shared with Prometheus through mounted files. + # When this option is set as false, this certificate provisioning mechanism is disabled. + provisionPrometheusCert: true + +# Indicate if Citadel is enabled, i.e., whether its generated certificates are available +security: + enabled: true \ No newline at end of file diff --git a/istio-1.5.0/install/kubernetes/operator/charts/istio-telemetry/tracing/Chart.yaml b/istio-1.5.0/install/kubernetes/operator/charts/istio-telemetry/tracing/Chart.yaml new file mode 100644 index 0000000..e030ced --- /dev/null +++ b/istio-1.5.0/install/kubernetes/operator/charts/istio-telemetry/tracing/Chart.yaml @@ -0,0 +1,6 @@ +apiVersion: v1 +description: A Helm chart for tracing +name: tracing +version: 1.1.0 +appVersion: 1.5.1 +tillerVersion: ">=2.7.2" diff --git a/istio-1.5.0/install/kubernetes/operator/charts/istio-telemetry/tracing/templates/_affinity.tpl b/istio-1.5.0/install/kubernetes/operator/charts/istio-telemetry/tracing/templates/_affinity.tpl new file mode 100644 index 0000000..d91f409 --- /dev/null +++ b/istio-1.5.0/install/kubernetes/operator/charts/istio-telemetry/tracing/templates/_affinity.tpl @@ -0,0 +1,93 @@ +{{/* affinity - https://kubernetes.io/docs/concepts/configuration/assign-pod-node/ */}} + +{{- define "nodeaffinity" }} + nodeAffinity: + requiredDuringSchedulingIgnoredDuringExecution: + {{- include "nodeAffinityRequiredDuringScheduling" . }} + preferredDuringSchedulingIgnoredDuringExecution: + {{- include "nodeAffinityPreferredDuringScheduling" . }} +{{- end }} + +{{- define "nodeAffinityRequiredDuringScheduling" }} + nodeSelectorTerms: + - matchExpressions: + - key: beta.kubernetes.io/arch + operator: In + values: + {{- range $key, $val := .Values.global.arch }} + {{- if gt ($val | int) 0 }} + - {{ $key | quote }} + {{- end }} + {{- end }} + {{- $nodeSelector := default .Values.global.defaultNodeSelector .Values.tracing.nodeSelector -}} + {{- range $key, $val := $nodeSelector }} + - key: {{ $key }} + operator: In + values: + - {{ $val | quote }} + {{- end }} +{{- end }} + +{{- define "nodeAffinityPreferredDuringScheduling" }} + {{- range $key, $val := .Values.global.arch }} + {{- if gt ($val | int) 0 }} + - weight: {{ $val | int }} + preference: + matchExpressions: + - key: beta.kubernetes.io/arch + operator: In + values: + - {{ $key | quote }} + {{- end }} + {{- end }} +{{- end }} + +{{- define "podAntiAffinity" }} +{{- if or .Values.tracing.podAntiAffinityLabelSelector .Values.tracing.podAntiAffinityTermLabelSelector}} + podAntiAffinity: + {{- if .Values.tracing.podAntiAffinityLabelSelector }} + requiredDuringSchedulingIgnoredDuringExecution: + {{- include "podAntiAffinityRequiredDuringScheduling" . }} + {{- end }} + {{- if or .Values.tracing.podAntiAffinityTermLabelSelector}} + preferredDuringSchedulingIgnoredDuringExecution: + {{- include "podAntiAffinityPreferredDuringScheduling" . }} + {{- end }} +{{- end }} +{{- end }} + +{{- define "podAntiAffinityRequiredDuringScheduling" }} + {{- range $index, $item := .Values.tracing.podAntiAffinityLabelSelector }} + - labelSelector: + matchExpressions: + - key: {{ $item.key }} + operator: {{ $item.operator }} + {{- if $item.values }} + values: + {{- $vals := split "," $item.values }} + {{- range $i, $v := $vals }} + - {{ $v | quote }} + {{- end }} + {{- end }} + topologyKey: {{ $item.topologyKey }} + {{- end }} +{{- end }} + +{{- define "podAntiAffinityPreferredDuringScheduling" }} + {{- range $index, $item := .Values.tracing.podAntiAffinityTermLabelSelector }} + - podAffinityTerm: + labelSelector: + matchExpressions: + - key: {{ $item.key }} + operator: {{ $item.operator }} + {{- if $item.values }} + values: + {{- $vals := split "," $item.values }} + {{- range $i, $v := $vals }} + - {{ $v | quote }} + {{- end }} + {{- end }} + topologyKey: {{ $item.topologyKey }} + weight: 100 + {{- end }} +{{- end }} \ No newline at end of file diff --git a/istio-1.5.0/install/kubernetes/operator/charts/istio-telemetry/tracing/templates/deployment-jaeger.yaml b/istio-1.5.0/install/kubernetes/operator/charts/istio-telemetry/tracing/templates/deployment-jaeger.yaml new file mode 100644 index 0000000..20595e4 --- /dev/null +++ b/istio-1.5.0/install/kubernetes/operator/charts/istio-telemetry/tracing/templates/deployment-jaeger.yaml @@ -0,0 +1,115 @@ +{{ if eq .Values.tracing.provider "jaeger" }} + +apiVersion: apps/v1 +kind: Deployment +metadata: + name: istio-tracing + namespace: {{ .Release.Namespace }} + labels: + app: jaeger + release: {{ .Release.Name }} +spec: + selector: + matchLabels: + app: jaeger + template: + metadata: + labels: + app: jaeger + release: {{ .Release.Name }} + annotations: + sidecar.istio.io/inject: "false" + prometheus.io/scrape: "true" + prometheus.io/port: "14269" + {{- if .Values.tracing.jaeger.podAnnotations }} +{{ toYaml .Values.tracing.jaeger.podAnnotations | indent 8 }} + {{- end }} + spec: +{{- if .Values.global.priorityClassName }} + priorityClassName: "{{ .Values.global.priorityClassName }}" +{{- end }} +{{- if .Values.global.imagePullSecrets }} + imagePullSecrets: +{{- range .Values.global.imagePullSecrets }} + - name: {{ . }} +{{- end }} +{{- end }} + containers: + - name: jaeger + image: "{{ .Values.tracing.jaeger.hub }}/{{ .Values.tracing.jaeger.image }}:{{ .Values.tracing.jaeger.tag }}" + imagePullPolicy: {{ .Values.global.imagePullPolicy | default "Always" }} + ports: + - containerPort: 9411 + - containerPort: 16686 + - containerPort: 14250 + - containerPort: 14267 + - containerPort: 14268 + - containerPort: 14269 + - containerPort: 5775 + protocol: UDP + - containerPort: 6831 + protocol: UDP + - containerPort: 6832 + protocol: UDP + env: + - name: POD_NAMESPACE + valueFrom: + fieldRef: + apiVersion: v1 + fieldPath: metadata.namespace + {{- if eq .Values.tracing.jaeger.spanStorageType "badger" }} + - name: BADGER_EPHEMERAL + value: "false" + - name: SPAN_STORAGE_TYPE + value: "badger" + - name: BADGER_DIRECTORY_VALUE + value: "/badger/data" + - name: BADGER_DIRECTORY_KEY + value: "/badger/key" + {{- end }} + - name: COLLECTOR_ZIPKIN_HTTP_PORT + value: "9411" + - name: MEMORY_MAX_TRACES + value: "{{ .Values.tracing.jaeger.memory.max_traces }}" + - name: QUERY_BASE_PATH + value: {{ if .Values.tracing.contextPath }} {{ .Values.tracing.contextPath }} {{ else }} /{{ .Values.tracing.provider }} {{ end }} + livenessProbe: + httpGet: + path: / + port: 14269 + readinessProbe: + httpGet: + path: / + port: 14269 +{{- if eq .Values.tracing.jaeger.spanStorageType "badger" }} + volumeMounts: + - name: data + mountPath: /badger +{{- end }} + resources: +{{- if .Values.tracing.jaeger.resources }} +{{ toYaml .Values.tracing.jaeger.resources | indent 12 }} +{{- else }} +{{ toYaml .Values.global.defaultResources | indent 12 }} +{{- end }} + affinity: + {{- include "nodeaffinity" . | indent 6 }} + {{- include "podAntiAffinity" . | indent 6 }} +{{- if .Values.tracing.tolerations }} + tolerations: +{{ toYaml .Values.tracing.tolerations | indent 6 }} +{{- else if .Values.global.defaultTolerations }} + tolerations: +{{ toYaml .Values.global.defaultTolerations | indent 6 }} +{{- end }} +{{- if eq .Values.tracing.jaeger.spanStorageType "badger" }} + volumes: + - name: data +{{- if .Values.tracing.jaeger.persist }} + persistentVolumeClaim: + claimName: istio-jaeger-pvc +{{- else }} + emptyDir: {} +{{- end }} +{{- end }} +{{ end }} diff --git a/istio-1.5.0/install/kubernetes/operator/charts/istio-telemetry/tracing/templates/deployment-opencensus.yaml b/istio-1.5.0/install/kubernetes/operator/charts/istio-telemetry/tracing/templates/deployment-opencensus.yaml new file mode 100644 index 0000000..64de6cd --- /dev/null +++ b/istio-1.5.0/install/kubernetes/operator/charts/istio-telemetry/tracing/templates/deployment-opencensus.yaml @@ -0,0 +1,104 @@ +{{ if eq .Values.tracing.provider "opencensus" }} +apiVersion: v1 +kind: ConfigMap +metadata: + name: oc-collector-config + labels: + app: opencensus + component: oc-collector-config +data: + oc-collector-config: | + receivers: + zipkin: + address: "127.0.0.1:9411" + exporters: +{{- if .Values.tracing.opencensus.exporters }} +{{ toYaml .Values.tracing.opencensus.exporters | indent 6 }} +{{- end }} +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: istio-tracing + namespace: {{ .Release.Namespace }} + labels: + app: opencensus + component: oc-collector + release: {{ .Release.Name }} +spec: + selector: + matchLabels: + app: opencensus + minReadySeconds: 5 + progressDeadlineSeconds: 120 + replicas: 1 + template: + metadata: + annotations: + sidecar.istio.io/inject: "false" + prometheus.io/path: "/metrics" + prometheus.io/port: "8888" + prometheus.io/scrape: "true" + {{- if .Values.tracing.opencensus.podAnnotations }} +{{ toYaml .Values.tracing.opencensus.podAnnotations | indent 8 }} + {{- end }} + labels: + app: opencensus + component: oc-collector + spec: +{{- if .Values.global.priorityClassName }} + priorityClassName: "{{ .Values.global.priorityClassName }}" +{{- end }} +{{- if .Values.global.imagePullSecrets }} + imagePullSecrets: +{{- range .Values.global.imagePullSecrets }} + - name: {{ . }} +{{- end }} +{{- end }} + containers: + - name: oc-collector + image: "{{ .Values.tracing.opencensus.hub }}/opencensus-collector:{{ .Values.tracing.opencensus.tag }}" + imagePullPolicy: {{ .Values.global.imagePullPolicy | default "Always" }} + command: + - "/occollector_linux" + - "--config=/conf/oc-collector-config.yaml" + ports: + - containerPort: 9411 + resources: +{{- if .Values.tracing.opencensus.resources }} +{{ toYaml .Values.tracing.opencensus.resources | indent 12 }} +{{- else }} +{{ toYaml .Values.global.defaultResources | indent 12 }} +{{- end }} + volumeMounts: + - name: oc-collector-config-vol + mountPath: /conf + livenessProbe: + httpGet: + path: / + port: 13133 + readinessProbe: + httpGet: + path: / + port: 13133 + env: + - name: GOGC + value: "80" + volumes: + - configMap: + name: oc-collector-config + items: + - key: oc-collector-config + path: oc-collector-config.yaml + name: oc-collector-config-vol + affinity: + {{- include "nodeaffinity" . | indent 6 }} + {{- include "podAntiAffinity" . | indent 6 }} +{{- if .Values.tracing.tolerations }} + tolerations: +{{ toYaml .Values.tracing.tolerations | indent 6 }} +{{- else if .Values.global.defaultTolerations }} + tolerations: +{{ toYaml .Values.global.defaultTolerations | indent 6 }} +{{- end }} +{{ end }} diff --git a/istio-1.5.0/install/kubernetes/operator/charts/istio-telemetry/tracing/templates/deployment-zipkin.yaml b/istio-1.5.0/install/kubernetes/operator/charts/istio-telemetry/tracing/templates/deployment-zipkin.yaml new file mode 100644 index 0000000..3c07412 --- /dev/null +++ b/istio-1.5.0/install/kubernetes/operator/charts/istio-telemetry/tracing/templates/deployment-zipkin.yaml @@ -0,0 +1,81 @@ +{{ if eq .Values.tracing.provider "zipkin" }} + +apiVersion: apps/v1 +kind: Deployment +metadata: + name: istio-tracing + namespace: {{ .Release.Namespace }} + labels: + app: zipkin + release: {{ .Release.Name }} +spec: + selector: + matchLabels: + app: zipkin + template: + metadata: + labels: + app: zipkin + release: {{ .Release.Name }} + annotations: + sidecar.istio.io/inject: "false" + scheduler.alpha.kubernetes.io/critical-pod: "" + {{- if .Values.tracing.zipkin.podAnnotations }} +{{ toYaml .Values.tracing.zipkin.podAnnotations | indent 8 }} + {{- end }} + spec: +{{- if .Values.global.priorityClassName }} + priorityClassName: "{{ .Values.global.priorityClassName }}" +{{- end }} +{{- if .Values.global.imagePullSecrets }} + imagePullSecrets: +{{- range .Values.global.imagePullSecrets }} + - name: {{ . }} +{{- end }} +{{- end }} + containers: + - name: zipkin + image: "{{ .Values.tracing.zipkin.hub }}/{{ .Values.tracing.zipkin.image }}:{{ .Values.tracing.zipkin.tag }}" + imagePullPolicy: {{ .Values.global.imagePullPolicy | default "Always" }} + ports: + - containerPort: {{ .Values.tracing.zipkin.queryPort }} + livenessProbe: + initialDelaySeconds: {{ .Values.tracing.zipkin.probeStartupDelay }} + tcpSocket: + port: {{ .Values.tracing.zipkin.queryPort }} + readinessProbe: + initialDelaySeconds: {{ .Values.tracing.zipkin.probeStartupDelay }} + httpGet: + path: /health + port: {{ .Values.tracing.zipkin.queryPort }} + resources: +{{- if .Values.tracing.zipkin.resources }} +{{ toYaml .Values.tracing.zipkin.resources | indent 12 }} +{{- else }} +{{ toYaml .Values.global.defaultResources | indent 12 }} +{{- end }} + env: + - name: POD_NAMESPACE + valueFrom: + fieldRef: + apiVersion: v1 + fieldPath: metadata.namespace + - name: QUERY_PORT + value: "{{ .Values.tracing.zipkin.queryPort }}" + - name: JAVA_OPTS + value: "-XX:ConcGCThreads={{ .Values.tracing.zipkin.node.cpus }} -XX:ParallelGCThreads={{ .Values.tracing.zipkin.node.cpus }} -Djava.util.concurrent.ForkJoinPool.common.parallelism={{ .Values.tracing.zipkin.node.cpus }} -Xms{{ .Values.tracing.zipkin.javaOptsHeap }}M -Xmx{{ .Values.tracing.zipkin.javaOptsHeap }}M -XX:+UseG1GC -server" + - name: STORAGE_METHOD + value: "mem" + - name: ZIPKIN_STORAGE_MEM_MAXSPANS + value: "{{ .Values.tracing.zipkin.maxSpans }}" + affinity: + {{- include "nodeaffinity" . | indent 6 }} + {{- include "podAntiAffinity" . | indent 6 }} +{{- if .Values.tracing.tolerations }} + tolerations: +{{ toYaml .Values.tracing.tolerations | indent 6 }} +{{- else if .Values.global.defaultTolerations }} + tolerations: +{{ toYaml .Values.global.defaultTolerations | indent 6 }} +{{- end }} +{{ end }} diff --git a/istio-1.5.0/install/kubernetes/operator/charts/istio-telemetry/tracing/templates/pvc.yaml b/istio-1.5.0/install/kubernetes/operator/charts/istio-telemetry/tracing/templates/pvc.yaml new file mode 100644 index 0000000..0c1ea9f --- /dev/null +++ b/istio-1.5.0/install/kubernetes/operator/charts/istio-telemetry/tracing/templates/pvc.yaml @@ -0,0 +1,19 @@ +{{- if eq .Values.tracing.provider "jaeger" }} +{{- if .Values.tracing.jaeger.persist }} +kind: PersistentVolumeClaim +apiVersion: v1 +metadata: + name: istio-jaeger-pvc + namespace: {{ .Release.Namespace }} + labels: + app: {{ .Values.tracing.provider }} + release: {{ .Release.Name }} +spec: + storageClassName: {{ .Values.tracing.jaeger.storageClassName }} + accessModes: + - {{ .Values.tracing.jaeger.accessMode }} + resources: + requests: + storage: 5Gi +{{- end }} +{{- end }} diff --git a/istio-1.5.0/install/kubernetes/operator/charts/istio-telemetry/tracing/templates/service-jaeger.yaml b/istio-1.5.0/install/kubernetes/operator/charts/istio-telemetry/tracing/templates/service-jaeger.yaml new file mode 100644 index 0000000..b5d9bd1 --- /dev/null +++ b/istio-1.5.0/install/kubernetes/operator/charts/istio-telemetry/tracing/templates/service-jaeger.yaml @@ -0,0 +1,96 @@ +{{ if eq .Values.tracing.provider "jaeger" }} +apiVersion: v1 +kind: Service +metadata: + name: jaeger-query + namespace: {{ .Release.Namespace }} + annotations: + {{- range $key, $val := .Values.tracing.service.annotations }} + {{ $key }}: {{ $val | quote }} + {{- end }} + labels: + app: jaeger + jaeger-infra: jaeger-service + release: {{ .Release.Name }} +spec: + ports: + - name: query-http + port: 16686 + protocol: TCP + targetPort: 16686 + selector: + app: jaeger +--- +apiVersion: v1 +kind: Service +metadata: + name: jaeger-collector + namespace: {{ .Release.Namespace }} + labels: + app: jaeger + jaeger-infra: collector-service + release: {{ .Release.Name }} +spec: + ports: + - name: jaeger-collector-tchannel + port: 14267 + protocol: TCP + targetPort: 14267 + - name: jaeger-collector-http + port: 14268 + targetPort: 14268 + protocol: TCP + - name: jaeger-collector-grpc + port: 14250 + targetPort: 14250 + protocol: TCP + selector: + app: jaeger + type: ClusterIP +--- +apiVersion: v1 +kind: Service +metadata: + name: jaeger-collector-headless + namespace: {{ .Release.Namespace }} + labels: + app: jaeger + jaeger-infra: collector-service + release: {{ .Release.Name }} +spec: + ports: + - name: jaeger-collector-grpc + port: 14250 + targetPort: 14250 + protocol: TCP + selector: + app: jaeger + clusterIP: None +--- +apiVersion: v1 +kind: Service +metadata: + name: jaeger-agent + namespace: {{ .Release.Namespace }} + labels: + app: jaeger + jaeger-infra: agent-service + release: {{ .Release.Name }} +spec: + ports: + - name: agent-zipkin-thrift + port: 5775 + protocol: UDP + targetPort: 5775 + - name: agent-compact + port: 6831 + protocol: UDP + targetPort: 6831 + - name: agent-binary + port: 6832 + protocol: UDP + targetPort: 6832 + clusterIP: None + selector: + app: jaeger +{{ end }} diff --git a/istio-1.5.0/install/kubernetes/operator/charts/istio-telemetry/tracing/templates/service.yaml b/istio-1.5.0/install/kubernetes/operator/charts/istio-telemetry/tracing/templates/service.yaml new file mode 100644 index 0000000..1ebfb16 --- /dev/null +++ b/istio-1.5.0/install/kubernetes/operator/charts/istio-telemetry/tracing/templates/service.yaml @@ -0,0 +1,44 @@ +apiVersion: v1 +kind: Service +metadata: + name: zipkin + namespace: {{ .Release.Namespace }} + labels: + app: {{ .Values.tracing.provider }} + release: {{ .Release.Name }} +spec: + ports: + - port: {{ .Values.tracing.zipkin.queryPort }} + targetPort: {{ .Values.tracing.zipkin.queryPort }} + protocol: TCP + name: {{ .Values.tracing.service.name }} + selector: + app: {{ .Values.tracing.provider }} +--- +{{- if ne .Values.tracing.provider "opencensus"}} +apiVersion: v1 +kind: Service +metadata: + name: tracing + namespace: {{ .Release.Namespace }} + annotations: + {{- range $key, $val := .Values.tracing.service.annotations }} + {{ $key }}: {{ $val | quote }} + {{- end }} + labels: + app: {{ .Values.tracing.provider }} + release: {{ .Release.Name }} +spec: + type: {{ .Values.tracing.service.type }} + ports: + - name: {{ .Values.tracing.service.name }} + port: 80 + protocol: TCP +{{ if eq .Values.tracing.provider "jaeger" }} + targetPort: 16686 +{{ else }} + targetPort: {{ .Values.tracing.zipkin.queryPort }} +{{ end}} + selector: + app: {{ .Values.tracing.provider }} +{{- end }} diff --git a/istio-1.5.0/install/kubernetes/operator/charts/istio-telemetry/tracing/values.yaml b/istio-1.5.0/install/kubernetes/operator/charts/istio-telemetry/tracing/values.yaml new file mode 100644 index 0000000..d0c9b75 --- /dev/null +++ b/istio-1.5.0/install/kubernetes/operator/charts/istio-telemetry/tracing/values.yaml @@ -0,0 +1,106 @@ +# +# addon tracing configuration +# +tracing: + enabled: false + + provider: jaeger + nodeSelector: {} + tolerations: [] + + # Specify the pod anti-affinity that allows you to constrain which nodes + # your pod is eligible to be scheduled based on labels on pods that are + # already running on the node rather than based on labels on nodes. + # There are currently two types of anti-affinity: + # "requiredDuringSchedulingIgnoredDuringExecution" + # "preferredDuringSchedulingIgnoredDuringExecution" + # which denote "hard" vs. "soft" requirements, you can define your values + # in "podAntiAffinityLabelSelector" and "podAntiAffinityTermLabelSelector" + # correspondingly. + # For example: + # podAntiAffinityLabelSelector: + # - key: security + # operator: In + # values: S1,S2 + # topologyKey: "kubernetes.io/hostname" + # This pod anti-affinity rule says that the pod requires not to be scheduled + # onto a node if that node is already running a pod with label having key + # "security" and value "S1". + podAntiAffinityLabelSelector: [] + podAntiAffinityTermLabelSelector: [] + + contextPath: "" + + + jaeger: + hub: docker.io/jaegertracing + image: all-in-one + tag: 1.16 + memory: + max_traces: 50000 + resources: {} + # spanStorageType value can be "memory" and "badger" for all-in-one image + spanStorageType: badger + persist: false + storageClassName: "" + accessMode: ReadWriteMany + podAnnotations: {} + + zipkin: + hub: docker.io/openzipkin + image: zipkin + tag: 2.14.2 + probeStartupDelay: 200 + queryPort: 9411 + resources: + limits: + cpu: 300m + memory: 900Mi + requests: + cpu: 150m + memory: 900Mi + javaOptsHeap: 700 + # From: https://github.com/openzipkin/zipkin/blob/master/zipkin-server/src/main/resources/zipkin-server-shared.yml#L51 + # Maximum number of spans to keep in memory. When exceeded, oldest traces (and their spans) will be purged. + # A safe estimate is 1K of memory per span (each span with 2 annotations + 1 binary annotation), plus + # 100 MB for a safety buffer. You'll need to verify in your own environment. + maxSpans: 500000 + node: + cpus: 2 + podAnnotations: {} + + opencensus: + hub: docker.io/omnition + tag: 0.1.9 + resources: + limits: + cpu: 1 + memory: 2Gi + requests: + cpu: 200m + memory: 400Mi + exporters: + stackdriver: + enable_tracing: true + podAnnotations: {} + + service: + annotations: {} + name: http-query + type: ClusterIP + externalPort: 80 + + ingress: + enabled: false + # Used to create an Ingress record. + hosts: + # - tracing.local + annotations: + # kubernetes.io/ingress.class: nginx + # kubernetes.io/tls-acme: "true" + tls: + # Secrets must be manually created in the namespace. + # - secretName: tracing-tls + # hosts: + # - tracing.local + diff --git a/istio-1.5.0/install/kubernetes/operator/charts/istiocoredns/Chart.yaml b/istio-1.5.0/install/kubernetes/operator/charts/istiocoredns/Chart.yaml new file mode 100644 index 0000000..fa04814 --- /dev/null +++ b/istio-1.5.0/install/kubernetes/operator/charts/istiocoredns/Chart.yaml @@ -0,0 +1,6 @@ +apiVersion: v1 +description: Istio CoreDNS provides DNS resolution for services in multicluster setups. +name: istiocoredns +version: 1.1.0 +appVersion: 0.1 +tillerVersion: ">=2.7.2" diff --git a/istio-1.5.0/install/kubernetes/operator/charts/istiocoredns/templates/_affinity.tpl b/istio-1.5.0/install/kubernetes/operator/charts/istiocoredns/templates/_affinity.tpl new file mode 100644 index 0000000..6d9416d --- /dev/null +++ b/istio-1.5.0/install/kubernetes/operator/charts/istiocoredns/templates/_affinity.tpl @@ -0,0 +1,93 @@ +{{/* affinity - https://kubernetes.io/docs/concepts/configuration/assign-pod-node/ */}} + +{{- define "nodeaffinity" }} + nodeAffinity: + requiredDuringSchedulingIgnoredDuringExecution: + {{- include "nodeAffinityRequiredDuringScheduling" . }} + preferredDuringSchedulingIgnoredDuringExecution: + {{- include "nodeAffinityPreferredDuringScheduling" . }} +{{- end }} + +{{- define "nodeAffinityRequiredDuringScheduling" }} + nodeSelectorTerms: + - matchExpressions: + - key: beta.kubernetes.io/arch + operator: In + values: + {{- range $key, $val := .Values.global.arch }} + {{- if gt ($val | int) 0 }} + - {{ $key | quote }} + {{- end }} + {{- end }} + {{- $nodeSelector := default .Values.global.defaultNodeSelector .Values.istiocoredns.nodeSelector -}} + {{- range $key, $val := $nodeSelector }} + - key: {{ $key }} + operator: In + values: + - {{ $val | quote }} + {{- end }} +{{- end }} + +{{- define "nodeAffinityPreferredDuringScheduling" }} + {{- range $key, $val := .Values.global.arch }} + {{- if gt ($val | int) 0 }} + - weight: {{ $val | int }} + preference: + matchExpressions: + - key: beta.kubernetes.io/arch + operator: In + values: + - {{ $key | quote }} + {{- end }} + {{- end }} +{{- end }} + +{{- define "podAntiAffinity" }} +{{- if or .Values.istiocoredns.podAntiAffinityLabelSelector .Values.istiocoredns.podAntiAffinityTermLabelSelector}} + podAntiAffinity: + {{- if .Values.istiocoredns.podAntiAffinityLabelSelector }} + requiredDuringSchedulingIgnoredDuringExecution: + {{- include "podAntiAffinityRequiredDuringScheduling" . }} + {{- end }} + {{- if .Values.istiocoredns.podAntiAffinityTermLabelSelector }} + preferredDuringSchedulingIgnoredDuringExecution: + {{- include "podAntiAffinityPreferredDuringScheduling" . }} + {{- end }} +{{- end }} +{{- end }} + +{{- define "podAntiAffinityRequiredDuringScheduling" }} + {{- range $index, $item := .Values.istiocoredns.podAntiAffinityLabelSelector }} + - labelSelector: + matchExpressions: + - key: {{ $item.key }} + operator: {{ $item.operator }} + {{- if $item.values }} + values: + {{- $vals := split "," $item.values }} + {{- range $i, $v := $vals }} + - {{ $v | quote }} + {{- end }} + {{- end }} + topologyKey: {{ $item.topologyKey }} + {{- end }} +{{- end }} + +{{- define "podAntiAffinityPreferredDuringScheduling" }} + {{- range $index, $item := .Values.istiocoredns.podAntiAffinityTermLabelSelector }} + - podAffinityTerm: + labelSelector: + matchExpressions: + - key: {{ $item.key }} + operator: {{ $item.operator }} + {{- if $item.values }} + values: + {{- $vals := split "," $item.values }} + {{- range $i, $v := $vals }} + - {{ $v | quote }} + {{- end }} + {{- end }} + topologyKey: {{ $item.topologyKey }} + weight: 100 + {{- end }} +{{- end }} diff --git a/istio-1.5.0/install/kubernetes/operator/charts/istiocoredns/templates/clusterrole.yaml b/istio-1.5.0/install/kubernetes/operator/charts/istiocoredns/templates/clusterrole.yaml new file mode 100644 index 0000000..160f564 --- /dev/null +++ b/istio-1.5.0/install/kubernetes/operator/charts/istiocoredns/templates/clusterrole.yaml @@ -0,0 +1,11 @@ +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: istiocoredns + labels: + app: istiocoredns + release: {{ .Release.Name }} +rules: +- apiGroups: ["networking.istio.io"] + resources: ["*"] + verbs: ["get", "watch", "list"] diff --git a/istio-1.5.0/install/kubernetes/operator/charts/istiocoredns/templates/clusterrolebinding.yaml b/istio-1.5.0/install/kubernetes/operator/charts/istiocoredns/templates/clusterrolebinding.yaml new file mode 100644 index 0000000..ccb594b --- /dev/null +++ b/istio-1.5.0/install/kubernetes/operator/charts/istiocoredns/templates/clusterrolebinding.yaml @@ -0,0 +1,15 @@ +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: istio-istiocoredns-role-binding-{{ .Release.Namespace }} + labels: + app: istiocoredns + release: {{ .Release.Name }} +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: istiocoredns +subjects: +- kind: ServiceAccount + name: istiocoredns-service-account + namespace: {{ .Release.Namespace }} diff --git a/istio-1.5.0/install/kubernetes/operator/charts/istiocoredns/templates/configmap.yaml b/istio-1.5.0/install/kubernetes/operator/charts/istiocoredns/templates/configmap.yaml new file mode 100644 index 0000000..ab95b99 --- /dev/null +++ b/istio-1.5.0/install/kubernetes/operator/charts/istiocoredns/templates/configmap.yaml @@ -0,0 +1,30 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: coredns + namespace: {{ .Release.Namespace }} + labels: + app: istiocoredns + release: {{ .Release.Name }} +data: + Corefile: | + .:53 { + errors + health + {{ if eq -1 (semver .Values.istiocoredns.coreDNSTag | (semver "1.4.0").Compare) }} + # Removed support for the proxy plugin: https://coredns.io/2019/03/03/coredns-1.4.0-release/ + grpc global 127.0.0.1:8053 + forward . /etc/resolv.conf { + except global + } + {{ else }} + proxy global 127.0.0.1:8053 { + protocol grpc insecure + } + proxy . /etc/resolv.conf + {{ end }} + prometheus :9153 + cache 30 + reload + } +--- diff --git a/istio-1.5.0/install/kubernetes/operator/charts/istiocoredns/templates/deployment.yaml b/istio-1.5.0/install/kubernetes/operator/charts/istiocoredns/templates/deployment.yaml new file mode 100644 index 0000000..2cf2742 --- /dev/null +++ b/istio-1.5.0/install/kubernetes/operator/charts/istiocoredns/templates/deployment.yaml @@ -0,0 +1,99 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: istiocoredns + namespace: {{ .Release.Namespace }} + labels: + app: istiocoredns + release: {{ .Release.Name }} +spec: + replicas: {{ .Values.istiocoredns.replicaCount }} + selector: + matchLabels: + app: istiocoredns + strategy: + rollingUpdate: + maxSurge: {{ .Values.istiocoredns.rollingMaxSurge }} + maxUnavailable: {{ .Values.istiocoredns.rollingMaxUnavailable }} + template: + metadata: + name: istiocoredns + labels: + app: istiocoredns + release: {{ .Release.Name }} + annotations: + sidecar.istio.io/inject: "false" + {{- if .Values.istiocoredns.podAnnotations }} +{{ toYaml .Values.istiocoredns.podAnnotations | indent 8 }} + {{- end }} + spec: + serviceAccountName: istiocoredns-service-account +{{- if .Values.global.priorityClassName }} + priorityClassName: "{{ .Values.global.priorityClassName }}" +{{- end }} + containers: + - name: coredns + image: {{ .Values.istiocoredns.coreDNSImage }}:{{ .Values.istiocoredns.coreDNSTag }} + imagePullPolicy: {{ .Values.global.imagePullPolicy | default "Always" }} + args: [ "-conf", "/etc/coredns/Corefile" ] + volumeMounts: + - name: config-volume + mountPath: /etc/coredns + ports: + - containerPort: 53 + name: dns + protocol: UDP + - containerPort: 53 + name: dns-tcp + protocol: TCP + - containerPort: 9153 + name: metrics + protocol: TCP + livenessProbe: + httpGet: + path: /health + port: 8080 + scheme: HTTP + initialDelaySeconds: 60 + timeoutSeconds: 5 + successThreshold: 1 + failureThreshold: 5 + resources: +{{- if .Values.istiocoredns.resources }} +{{ toYaml .Values.istiocoredns.resources | indent 10 }} +{{- else }} +{{ toYaml .Values.global.defaultResources | indent 10 }} +{{- end }} + - name: istio-coredns-plugin + command: + - /usr/local/bin/plugin + image: {{ .Values.istiocoredns.coreDNSPluginImage }} + imagePullPolicy: {{ .Values.global.imagePullPolicy | default "Always" }} + ports: + - containerPort: 8053 + name: dns-grpc + protocol: TCP + resources: +{{- if .Values.istiocoredns.resources }} +{{ toYaml .Values.istiocorednsresources | indent 10 }} +{{- else }} +{{ toYaml .Values.global.defaultResources | indent 10 }} +{{- end }} + dnsPolicy: Default + volumes: + - name: config-volume + configMap: + name: coredns + items: + - key: Corefile + path: Corefile + affinity: + {{- include "nodeaffinity" . | indent 6 }} + {{- include "podAntiAffinity" . | indent 6 }} +{{- if .Values.istiocoredns.tolerations }} + tolerations: +{{ toYaml .Values.istiocoredns.tolerations | indent 6 }} +{{- else if .Values.global.defaultTolerations }} + tolerations: +{{ toYaml .Values.global.defaultTolerations | indent 6 }} +{{- end }} diff --git a/istio-1.5.0/install/kubernetes/operator/charts/istiocoredns/templates/service.yaml b/istio-1.5.0/install/kubernetes/operator/charts/istiocoredns/templates/service.yaml new file mode 100644 index 0000000..30251b5 --- /dev/null +++ b/istio-1.5.0/install/kubernetes/operator/charts/istiocoredns/templates/service.yaml @@ -0,0 +1,18 @@ +apiVersion: v1 +kind: Service +metadata: + name: istiocoredns + namespace: {{ .Release.Namespace }} + labels: + app: istiocoredns + release: {{ .Release.Name }} +spec: + selector: + app: istiocoredns + ports: + - name: dns + port: 53 + protocol: UDP + - name: dns-tcp + port: 53 + protocol: TCP diff --git a/istio-1.5.0/install/kubernetes/operator/charts/istiocoredns/templates/serviceaccount.yaml b/istio-1.5.0/install/kubernetes/operator/charts/istiocoredns/templates/serviceaccount.yaml new file mode 100644 index 0000000..3cec94a --- /dev/null +++ b/istio-1.5.0/install/kubernetes/operator/charts/istiocoredns/templates/serviceaccount.yaml @@ -0,0 +1,14 @@ +apiVersion: v1 +kind: ServiceAccount +{{- if .Values.global.imagePullSecrets }} +imagePullSecrets: +{{- range .Values.global.imagePullSecrets }} + - name: {{ . }} +{{- end }} +{{- end }} +metadata: + name: istiocoredns-service-account + namespace: {{ .Release.Namespace }} + labels: + app: istiocoredns + release: {{ .Release.Name }} diff --git a/istio-1.5.0/install/kubernetes/operator/charts/istiocoredns/values.yaml b/istio-1.5.0/install/kubernetes/operator/charts/istiocoredns/values.yaml new file mode 100644 index 0000000..b54b82e --- /dev/null +++ b/istio-1.5.0/install/kubernetes/operator/charts/istiocoredns/values.yaml @@ -0,0 +1,38 @@ +# +# addon istiocoredns tracing configuration +# +istiocoredns: + enabled: false + replicaCount: 1 + rollingMaxSurge: 100% + rollingMaxUnavailable: 25% + coreDNSImage: coredns/coredns + coreDNSTag: 1.6.2 + # Source code for the plugin can be found at + # https://github.com/istio-ecosystem/istio-coredns-plugin + # The plugin listens for DNS requests from coredns server at 127.0.0.1:8053 + coreDNSPluginImage: istio/coredns-plugin:0.2-istio-1.1 + nodeSelector: {} + tolerations: [] + podAnnotations: {} + resources: {} + # Specify the pod anti-affinity that allows you to constrain which nodes + # your pod is eligible to be scheduled based on labels on pods that are + # already running on the node rather than based on labels on nodes. + # There are currently two types of anti-affinity: + # "requiredDuringSchedulingIgnoredDuringExecution" + # "preferredDuringSchedulingIgnoredDuringExecution" + # which denote "hard" vs. "soft" requirements, you can define your values + # in "podAntiAffinityLabelSelector" and "podAntiAffinityTermLabelSelector" + # correspondingly. + # For example: + # podAntiAffinityLabelSelector: + # - key: security + # operator: In + # values: S1,S2 + # topologyKey: "kubernetes.io/hostname" + # This pod anti-affinity rule says that the pod requires not to be scheduled + # onto a node if that node is already running a pod with label having key + # "security" and value "S1". + podAntiAffinityLabelSelector: [] + podAntiAffinityTermLabelSelector: [] diff --git a/istio-1.5.0/install/kubernetes/operator/charts/security/citadel/Chart.yaml b/istio-1.5.0/install/kubernetes/operator/charts/security/citadel/Chart.yaml new file mode 100644 index 0000000..58d547f --- /dev/null +++ b/istio-1.5.0/install/kubernetes/operator/charts/security/citadel/Chart.yaml @@ -0,0 +1,13 @@ +apiVersion: v1 +name: citadel +version: 1.1.0 +appVersion: 1.1.0 +tillerVersion: ">=2.7.2" +description: Helm chart for istio authentication +keywords: + - istio + - security +sources: + - http://github.com/istio/istio +engine: gotpl +icon: https://istio.io/favicons/android-192x192.png diff --git a/istio-1.5.0/install/kubernetes/operator/charts/security/citadel/templates/NOTES.txt b/istio-1.5.0/install/kubernetes/operator/charts/security/citadel/templates/NOTES.txt new file mode 100644 index 0000000..816d340 --- /dev/null +++ b/istio-1.5.0/install/kubernetes/operator/charts/security/citadel/templates/NOTES.txt @@ -0,0 +1,7 @@ +This template contains the 'singleton' part of Istio. + +All other components support multiple instances (profiles) running in parallel. + +For upgrade purpose, this component should run in istio-system - where the existing mesh certificates are stored. +Will install a new deployment of Citadel, using 1.1 - it can run in parallel with the old-style install of either 1.0 +or 1.1. diff --git a/istio-1.5.0/install/kubernetes/operator/charts/security/citadel/templates/_affinity.tpl b/istio-1.5.0/install/kubernetes/operator/charts/security/citadel/templates/_affinity.tpl new file mode 100644 index 0000000..91ab62f --- /dev/null +++ b/istio-1.5.0/install/kubernetes/operator/charts/security/citadel/templates/_affinity.tpl @@ -0,0 +1,93 @@ +{{/* affinity - https://kubernetes.io/docs/concepts/configuration/assign-pod-node/ */}} + +{{- define "nodeaffinity" }} + nodeAffinity: + requiredDuringSchedulingIgnoredDuringExecution: + {{- include "nodeAffinityRequiredDuringScheduling" . }} + preferredDuringSchedulingIgnoredDuringExecution: + {{- include "nodeAffinityPreferredDuringScheduling" . }} +{{- end }} + +{{- define "nodeAffinityRequiredDuringScheduling" }} + nodeSelectorTerms: + - matchExpressions: + - key: beta.kubernetes.io/arch + operator: In + values: + {{- range $key, $val := .Values.global.arch }} + {{- if gt ($val | int) 0 }} + - {{ $key | quote }} + {{- end }} + {{- end }} + {{- $nodeSelector := default .Values.global.defaultNodeSelector .Values.security.nodeSelector -}} + {{- range $key, $val := $nodeSelector }} + - key: {{ $key }} + operator: In + values: + - {{ $val | quote }} + {{- end }} +{{- end }} + +{{- define "nodeAffinityPreferredDuringScheduling" }} + {{- range $key, $val := .Values.global.arch }} + {{- if gt ($val | int) 0 }} + - weight: {{ $val | int }} + preference: + matchExpressions: + - key: beta.kubernetes.io/arch + operator: In + values: + - {{ $key | quote }} + {{- end }} + {{- end }} +{{- end }} + +{{- define "podAntiAffinity" }} +{{- if or .Values.security.podAntiAffinityLabelSelector .Values.security.podAntiAffinityTermLabelSelector}} + podAntiAffinity: + {{- if .Values.security.podAntiAffinityLabelSelector }} + requiredDuringSchedulingIgnoredDuringExecution: + {{- include "podAntiAffinityRequiredDuringScheduling" . }} + {{- end }} + {{- if .Values.security.podAntiAffinityTermLabelSelector }} + preferredDuringSchedulingIgnoredDuringExecution: + {{- include "podAntiAffinityPreferredDuringScheduling" . }} + {{- end }} +{{- end }} +{{- end }} + +{{- define "podAntiAffinityRequiredDuringScheduling" }} + {{- range $index, $item := .Values.security.podAntiAffinityLabelSelector }} + - labelSelector: + matchExpressions: + - key: {{ $item.key }} + operator: {{ $item.operator }} + {{- if $item.values }} + values: + {{- $vals := split "," $item.values }} + {{- range $i, $v := $vals }} + - {{ $v | quote }} + {{- end }} + {{- end }} + topologyKey: {{ $item.topologyKey }} + {{- end }} +{{- end }} + +{{- define "podAntiAffinityPreferredDuringScheduling" }} + {{- range $index, $item := .Values.security.podAntiAffinityTermLabelSelector }} + - podAffinityTerm: + labelSelector: + matchExpressions: + - key: {{ $item.key }} + operator: {{ $item.operator }} + {{- if $item.values }} + values: + {{- $vals := split "," $item.values }} + {{- range $i, $v := $vals }} + - {{ $v | quote }} + {{- end }} + {{- end }} + topologyKey: {{ $item.topologyKey }} + weight: 100 + {{- end }} +{{- end }} diff --git a/istio-1.5.0/install/kubernetes/operator/charts/security/citadel/templates/_helpers.tpl b/istio-1.5.0/install/kubernetes/operator/charts/security/citadel/templates/_helpers.tpl new file mode 100644 index 0000000..addbba1 --- /dev/null +++ b/istio-1.5.0/install/kubernetes/operator/charts/security/citadel/templates/_helpers.tpl @@ -0,0 +1,77 @@ +{{/* vim: set filetype=mustache: */}} +{{/* +Expand the name of the chart. +*/}} +{{- define "istio.name" -}} +{{- default .Chart.Name .Values.security.nameOverride | trunc 63 | trimSuffix "-" -}} +{{- end -}} + +{{/* +Create a default fully qualified app name. +We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). +If release name contains chart name it will be used as a full name. +*/}} +{{- define "istio.fullname" -}} +{{- if .Values.security.fullnameOverride -}} +{{- .Values.security.fullnameOverride | trunc 63 | trimSuffix "-" -}} +{{- else -}} +{{- $name := default .Chart.Name .Values.security.nameOverride -}} +{{- if contains $name .Release.Name -}} +{{- .Release.Name | trunc 63 | trimSuffix "-" -}} +{{- else -}} +{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" -}} +{{- end -}} +{{- end -}} +{{- end -}} + +{{/* +Create chart name and version as used by the chart label. +*/}} +{{- define "istio.chart" -}} +{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" -}} +{{- end -}} + +{{/* +Create a fully qualified configmap name. +*/}} +{{- define "istio.configmap.fullname" -}} +{{- printf "%s-%s" .Release.Name "istio-mesh-config" | trunc 63 | trimSuffix "-" -}} +{{- end -}} + +{{/* +Configmap checksum. +*/}} +{{- define "istio.configmap.checksum" -}} +{{- print $.Template.BasePath "/configmap.yaml" | sha256sum -}} +{{- end -}} +{{/* +Expand the name of the chart. +*/}} +{{- define "security.name" -}} +{{- default .Chart.Name .Values.security.nameOverride | trunc 63 | trimSuffix "-" -}} +{{- end -}} + +{{/* +Create a default fully qualified app name. +We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). +If release name contains chart name it will be used as a full name. +*/}} +{{- define "security.fullname" -}} +{{- if .Values.security.fullnameOverride -}} +{{- .Values.security.fullnameOverride | trunc 63 | trimSuffix "-" -}} +{{- else -}} +{{- $name := default .Chart.Name .Values.security.nameOverride -}} +{{- if contains $name .Release.Name -}} +{{- .Release.Name | trunc 63 | trimSuffix "-" -}} +{{- else -}} +{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" -}} +{{- end -}} +{{- end -}} +{{- end -}} + +{{/* +Create chart name and version as used by the chart label. +*/}} +{{- define "security.chart" -}} +{{- .Chart.Name | trunc 63 | trimSuffix "-" -}} +{{- end -}} diff --git a/istio-1.5.0/install/kubernetes/operator/charts/security/citadel/templates/clusterrole.yaml b/istio-1.5.0/install/kubernetes/operator/charts/security/citadel/templates/clusterrole.yaml new file mode 100644 index 0000000..910d36f --- /dev/null +++ b/istio-1.5.0/install/kubernetes/operator/charts/security/citadel/templates/clusterrole.yaml @@ -0,0 +1,24 @@ +{{ if .Values.clusterResources }} +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: istio-citadel-{{ .Release.Namespace }} + labels: + app: citadel + release: {{ .Release.Name }} +rules: +- apiGroups: [""] + resources: ["configmaps"] + verbs: ["create", "get", "update"] +- apiGroups: [""] + resources: ["secrets"] + verbs: ["create", "get", "watch", "list", "update", "delete"] +- apiGroups: [""] + resources: ["serviceaccounts", "services", "namespaces"] + verbs: ["get", "watch", "list"] +- apiGroups: ["authentication.k8s.io"] + resources: ["tokenreviews"] + verbs: ["create"] + +--- +{{ end }} diff --git a/istio-1.5.0/install/kubernetes/operator/charts/security/citadel/templates/clusterrolebinding.yaml b/istio-1.5.0/install/kubernetes/operator/charts/security/citadel/templates/clusterrolebinding.yaml new file mode 100644 index 0000000..c32e1d4 --- /dev/null +++ b/istio-1.5.0/install/kubernetes/operator/charts/security/citadel/templates/clusterrolebinding.yaml @@ -0,0 +1,17 @@ +{{ if .Values.clusterResources }} +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: istio-citadel-{{ .Release.Namespace }} + labels: + release: {{ .Release.Name }} +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: istio-citadel-{{ .Release.Namespace }} +subjects: + - kind: ServiceAccount + name: istio-citadel-service-account + namespace: {{ .Release.Namespace }} +--- +{{- end}} diff --git a/istio-1.5.0/install/kubernetes/operator/charts/security/citadel/templates/deployment.yaml b/istio-1.5.0/install/kubernetes/operator/charts/security/citadel/templates/deployment.yaml new file mode 100644 index 0000000..1f1b641 --- /dev/null +++ b/istio-1.5.0/install/kubernetes/operator/charts/security/citadel/templates/deployment.yaml @@ -0,0 +1,136 @@ +# istio CA watching all namespaces +apiVersion: apps/v1 +kind: Deployment +metadata: + name: istio-citadel + namespace: {{ .Release.Namespace }} + labels: + app: security + istio: citadel + release: {{ .Release.Name }} + +spec: + selector: + matchLabels: + istio: citadel + replicas: {{ .Values.security.replicaCount }} + strategy: + rollingUpdate: + maxSurge: {{ .Values.security.rollingMaxSurge }} + maxUnavailable: {{ .Values.security.rollingMaxUnavailable }} + template: + metadata: + labels: + app: citadel + istio: citadel + annotations: + sidecar.istio.io/inject: "false" + {{- if .Values.security.podAnnotations }} +{{ toYaml .Values.security.podAnnotations | indent 8 }} + {{- end }} + spec: + serviceAccountName: istio-citadel-service-account +{{- if .Values.global.priorityClassName }} + priorityClassName: "{{ .Values.global.priorityClassName }}" +{{- end }} + containers: + - name: citadel + image: "{{ .Values.global.hub }}/{{ .Values.security.image }}:{{ .Values.global.tag }}" + imagePullPolicy: {{ .Values.global.imagePullPolicy | default "Always" }} + args: + {{- if .Values.global.sds.enabled }} + - --sds-enabled=true + {{- end }} + - --append-dns-names=true + - --grpc-port=8060 + - --citadel-storage-namespace={{ .Release.Namespace }} + {{- if .Values.kustomize }} + - --custom-dns-names=$(CITADEL_DNS) + {{- else }} + - --custom-dns-names={{ range $k,$v := .Values.security.dnsCerts }}{{ $k }}:{{ $v }},{{ end }} + {{- end }} + {{- if .Values.security.selfSigned }} + - --self-signed-ca=true + {{- else }} + - --self-signed-ca=false + - --signing-cert=/etc/cacerts/ca-cert.pem + - --signing-key=/etc/cacerts/ca-key.pem + - --root-cert=/etc/cacerts/root-cert.pem + - --cert-chain=/etc/cacerts/cert-chain.pem + {{- end }} + {{- if .Values.global.trustDomain }} + - --trust-domain={{ .Values.global.trustDomain }} + {{- end }} + {{- if .Values.security.workloadCertTtl }} + - --workload-cert-ttl={{ .Values.security.workloadCertTtl }} + {{- end }} + {{- if .Values.security.citadelHealthCheck }} + - --liveness-probe-path=/tmp/ca.liveness # path to the liveness health check status file + - --liveness-probe-interval=60s # interval for health check file update + - --probe-check-interval=15s # interval for health status check + {{- end }} + {{- if .Values.global.logAsJson }} + - --log_as_json + {{- end }} + env: + - name: CITADEL_ENABLE_NAMESPACES_BY_DEFAULT + value: "{{ .Values.security.enableNamespacesByDefault }}" + {{- if .Values.security.env }} + {{- range $key, $val := .Values.security.env }} + - name: {{ $key }} + value: {{ $val | quote }} + {{- end }} + {{- end }} + livenessProbe: + {{- if .Values.security.citadelHealthCheck }} + exec: + command: + - /usr/local/bin/istio_ca + - probe + - --probe-path=/tmp/ca.liveness # path to the liveness health check status file + - --interval=125s # the maximum time gap allowed between the file mtime and the current sys clock + initialDelaySeconds: 60 + periodSeconds: 60 + {{- else }} + httpGet: + path: /version + port: 15014 + initialDelaySeconds: 5 + periodSeconds: 5 + {{- end }} + resources: +{{- if .Values.security.resources }} +{{ toYaml .Values.security.resources | indent 12 }} +{{- else }} +{{ toYaml .Values.global.defaultResources | indent 12 }} +{{- end }} + securityContext: + runAsUser: 1337 + runAsGroup: 1337 + runAsNonRoot: true + capabilities: + drop: + - ALL +{{- if not .Values.security.selfSigned }} + volumeMounts: + - name: cacerts + mountPath: /etc/cacerts + readOnly: true + securityContext: + fsGroup: 1337 + volumes: + - name: cacerts + secret: + secretName: cacerts + optional: true +{{- end }} + affinity: + {{- include "nodeaffinity" . | indent 6 }} + {{- include "podAntiAffinity" . | indent 6 }} +{{- if .Values.security.tolerations }} + tolerations: +{{ toYaml .Values.security.tolerations | indent 6 }} +{{- else if .Values.global.defaultTolerations }} + tolerations: +{{ toYaml .Values.global.defaultTolerations | indent 6 }} +{{- end }} diff --git a/istio-1.5.0/install/kubernetes/operator/charts/security/citadel/templates/poddisruptionbudget.yaml b/istio-1.5.0/install/kubernetes/operator/charts/security/citadel/templates/poddisruptionbudget.yaml new file mode 100644 index 0000000..77a594a --- /dev/null +++ b/istio-1.5.0/install/kubernetes/operator/charts/security/citadel/templates/poddisruptionbudget.yaml @@ -0,0 +1,17 @@ +{{- if .Values.global.defaultPodDisruptionBudget.enabled }} +apiVersion: policy/v1beta1 +kind: PodDisruptionBudget +metadata: + name: istio-citadel + namespace: {{ .Release.Namespace }} + labels: + app: security + istio: citadel + release: {{ .Release.Name }} +spec: + minAvailable: 1 + selector: + matchLabels: + app: citadel + istio: citadel +{{- end }} diff --git a/istio-1.5.0/install/kubernetes/operator/charts/security/citadel/templates/service.yaml b/istio-1.5.0/install/kubernetes/operator/charts/security/citadel/templates/service.yaml new file mode 100644 index 0000000..a0511b3 --- /dev/null +++ b/istio-1.5.0/install/kubernetes/operator/charts/security/citadel/templates/service.yaml @@ -0,0 +1,21 @@ +apiVersion: v1 +kind: Service +metadata: + # Must match the certificate, this is used in the node agent in same namespace. + name: istio-citadel + namespace: {{ .Release.Namespace }} + labels: + app: security + istio: citadel + release: {{ .Release.Name }} + +spec: + ports: + - name: grpc-citadel + port: 8060 + targetPort: 8060 + protocol: TCP + - name: http-monitoring + port: 15014 + selector: + app: citadel diff --git a/istio-1.5.0/install/kubernetes/operator/charts/security/citadel/templates/serviceaccount.yaml b/istio-1.5.0/install/kubernetes/operator/charts/security/citadel/templates/serviceaccount.yaml new file mode 100644 index 0000000..7bd5af4 --- /dev/null +++ b/istio-1.5.0/install/kubernetes/operator/charts/security/citadel/templates/serviceaccount.yaml @@ -0,0 +1,15 @@ +apiVersion: v1 +kind: ServiceAccount +metadata: + name: istio-citadel-service-account + namespace: {{ .Release.Namespace }} + labels: + app: security + release: {{ .Release.Name }} + {{- if .Values.global.imagePullSecrets }} +spec: + imagePullSecrets: + {{- range .Values.global.imagePullSecrets }} + - name: {{ . }} + {{- end }} + {{- end }} diff --git a/istio-1.5.0/install/kubernetes/operator/charts/security/citadel/values.yaml b/istio-1.5.0/install/kubernetes/operator/charts/security/citadel/values.yaml new file mode 100644 index 0000000..2117b9c --- /dev/null +++ b/istio-1.5.0/install/kubernetes/operator/charts/security/citadel/values.yaml @@ -0,0 +1,74 @@ +# +# security (citadel) configuration +# +security: + enabled: true + replicaCount: 1 + rollingMaxSurge: 100% + rollingMaxUnavailable: 25% + image: citadel + selfSigned: true # indicate if self-signed CA is used. + citadelHealthCheck: false + + # 90*24hour = 2160h + workloadCertTtl: 2160h + + # Environment variables that configure Citadel. + env: {} + + # Determines Citadel default behavior if the ca.istio.io/env or ca.istio.io/override + # labels are not found on a given namespace. + # + # For example: consider a namespace called "target", which has neither the "ca.istio.io/env" + # nor the "ca.istio.io/override" namespace labels. To decide whether or not to generate secrets + # for service accounts created in this "target" namespace, Citadel will defer to this option. If the value + # of this option is "true" in this case, secrets will be generated for the "target" namespace. + # If the value of this option is "false" Citadel will not generate secrets upon service account creation. + enableNamespacesByDefault: true + + # Galley, pilot in each 'profile' must have a DNS cert. + dnsCerts: + istio-pilot-service-account.istio-control: istio-pilot.istio-control + istio-pilot-service-account.istio-pilot11: istio-pilot.istio-system + + istio-sidecar-injector-service-account.istio-remote: istio-sidecar-injector.istio-remote.svc + istio-sidecar-injector-service-account.istio-pilot11: istio-sidecar-injector.istio-pilot11.svc + istio-sidecar-injector-service-account.istio-control: istio-sidecar-injector.istio-control.svc + istio-sidecar-injector-service-account.istio-master: istio-sidecar-injector.istio-master.svc + istio-sidecar-injector-service-account.istio-control-master: istio-sidecar-injector.istio-control-master.svc + + istio-galley-service-account.istio-pilot11: istio-galley.istio-pilot11.svc + istio-galley-service-account.istio-control: istio-galley.istio-control.svc + + istio-galley-service-account.istio-master: istio-galley.istio-master.svc + istio-galley-service-account.istio-control-master: istio-galley.istio-control-master.svc + + istio-galley-service-account.istio-config: istio-galley.istio-config.svc + + nodeSelector: {} + tolerations: [] + podAnnotations: {} + + # Specify the pod anti-affinity that allows you to constrain which nodes + # your pod is eligible to be scheduled based on labels on pods that are + # already running on the node rather than based on labels on nodes. + # There are currently two types of anti-affinity: + # "requiredDuringSchedulingIgnoredDuringExecution" + # "preferredDuringSchedulingIgnoredDuringExecution" + # which denote "hard" vs. "soft" requirements, you can define your values + # in "podAntiAffinityLabelSelector" and "podAntiAffinityTermLabelSelector" + # correspondingly. + # For example: + # podAntiAffinityLabelSelector: + # - key: security + # operator: In + # values: S1,S2 + # topologyKey: "kubernetes.io/hostname" + # This pod anti-affinity rule says that the pod requires not to be scheduled + # onto a node if that node is already running a pod with label having key + # "security" and value "S1". + podAntiAffinityLabelSelector: [] + podAntiAffinityTermLabelSelector: [] + + resources: {} +kustomize: false diff --git a/istio-1.5.0/install/kubernetes/operator/charts/security/nodeagent/Chart.yaml b/istio-1.5.0/install/kubernetes/operator/charts/security/nodeagent/Chart.yaml new file mode 100644 index 0000000..9ba4eeb --- /dev/null +++ b/istio-1.5.0/install/kubernetes/operator/charts/security/nodeagent/Chart.yaml @@ -0,0 +1,13 @@ +apiVersion: v1 +name: nodeagent +version: 1.1.0 +appVersion: 1.1.0 +tillerVersion: ">=2.7.2" +description: Helm chart for nodeagent deployment +keywords: + - istio + - nodeagent +sources: + - http://github.com/istio/istio +engine: gotpl +icon: https://istio.io/favicons/android-192x192.png diff --git a/istio-1.5.0/install/kubernetes/operator/charts/security/nodeagent/templates/_affinity.tpl b/istio-1.5.0/install/kubernetes/operator/charts/security/nodeagent/templates/_affinity.tpl new file mode 100644 index 0000000..db1cb23 --- /dev/null +++ b/istio-1.5.0/install/kubernetes/operator/charts/security/nodeagent/templates/_affinity.tpl @@ -0,0 +1,93 @@ +{{/* affinity - https://kubernetes.io/docs/concepts/configuration/assign-pod-node/ */}} + +{{- define "nodeaffinity" }} + nodeAffinity: + requiredDuringSchedulingIgnoredDuringExecution: + {{- include "nodeAffinityRequiredDuringScheduling" . }} + preferredDuringSchedulingIgnoredDuringExecution: + {{- include "nodeAffinityPreferredDuringScheduling" . }} +{{- end }} + +{{- define "nodeAffinityRequiredDuringScheduling" }} + nodeSelectorTerms: + - matchExpressions: + - key: beta.kubernetes.io/arch + operator: In + values: + {{- range $key, $val := .Values.global.arch }} + {{- if gt ($val | int) 0 }} + - {{ $key | quote }} + {{- end }} + {{- end }} + {{- $nodeSelector := default .Values.global.defaultNodeSelector .Values.nodeagent.nodeSelector -}} + {{- range $key, $val := $nodeSelector }} + - key: {{ $key }} + operator: In + values: + - {{ $val | quote }} + {{- end }} +{{- end }} + +{{- define "nodeAffinityPreferredDuringScheduling" }} + {{- range $key, $val := .Values.global.arch }} + {{- if gt ($val | int) 0 }} + - weight: {{ $val | int }} + preference: + matchExpressions: + - key: beta.kubernetes.io/arch + operator: In + values: + - {{ $key | quote }} + {{- end }} + {{- end }} +{{- end }} + +{{- define "podAntiAffinity" }} +{{- if or .Values.nodeagent.podAntiAffinityLabelSelector .Values.nodeagent.podAntiAffinityTermLabelSelector}} + podAntiAffinity: + {{- if .Values.nodeagent.podAntiAffinityLabelSelector }} + requiredDuringSchedulingIgnoredDuringExecution: + {{- include "podAntiAffinityRequiredDuringScheduling" . }} + {{- end }} + {{- if .Values.nodeagent.podAntiAffinityTermLabelSelector }} + preferredDuringSchedulingIgnoredDuringExecution: + {{- include "podAntiAffinityPreferredDuringScheduling" . }} + {{- end }} +{{- end }} +{{- end }} + +{{- define "podAntiAffinityRequiredDuringScheduling" }} + {{- range $index, $item := .Values.nodeagent.podAntiAffinityLabelSelector }} + - labelSelector: + matchExpressions: + - key: {{ $item.key }} + operator: {{ $item.operator }} + {{- if $item.values }} + values: + {{- $vals := split "," $item.values }} + {{- range $i, $v := $vals }} + - {{ $v | quote }} + {{- end }} + {{- end }} + topologyKey: {{ $item.topologyKey }} + {{- end }} +{{- end }} + +{{- define "podAntiAffinityPreferredDuringScheduling" }} + {{- range $index, $item := .Values.nodeagent.podAntiAffinityTermLabelSelector }} + - podAffinityTerm: + labelSelector: + matchExpressions: + - key: {{ $item.key }} + operator: {{ $item.operator }} + {{- if $item.values }} + values: + {{- $vals := split "," $item.values }} + {{- range $i, $v := $vals }} + - {{ $v | quote }} + {{- end }} + {{- end }} + topologyKey: {{ $item.topologyKey }} + weight: 100 + {{- end }} +{{- end }} diff --git a/istio-1.5.0/install/kubernetes/operator/charts/security/nodeagent/templates/clusterrole.yaml b/istio-1.5.0/install/kubernetes/operator/charts/security/nodeagent/templates/clusterrole.yaml new file mode 100644 index 0000000..ac51632 --- /dev/null +++ b/istio-1.5.0/install/kubernetes/operator/charts/security/nodeagent/templates/clusterrole.yaml @@ -0,0 +1,11 @@ +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: istio-nodeagent-{{ .Release.Namespace }} + labels: + app: istio-nodeagent + release: {{ .Release.Name }} +rules: +- apiGroups: [""] + resources: ["configmaps"] + verbs: ["get"] diff --git a/istio-1.5.0/install/kubernetes/operator/charts/security/nodeagent/templates/clusterrolebinding.yaml b/istio-1.5.0/install/kubernetes/operator/charts/security/nodeagent/templates/clusterrolebinding.yaml new file mode 100644 index 0000000..33e923e --- /dev/null +++ b/istio-1.5.0/install/kubernetes/operator/charts/security/nodeagent/templates/clusterrolebinding.yaml @@ -0,0 +1,15 @@ +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: istio-nodeagent-{{ .Release.Namespace }} + labels: + app: istio-nodeagent + release: {{ .Release.Name }} +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: istio-nodeagent-{{ .Release.Namespace }} +subjects: + - kind: ServiceAccount + name: istio-nodeagent-service-account + namespace: {{ .Release.Namespace }} diff --git a/istio-1.5.0/install/kubernetes/operator/charts/security/nodeagent/templates/daemonset.yaml b/istio-1.5.0/install/kubernetes/operator/charts/security/nodeagent/templates/daemonset.yaml new file mode 100644 index 0000000..024d633 --- /dev/null +++ b/istio-1.5.0/install/kubernetes/operator/charts/security/nodeagent/templates/daemonset.yaml @@ -0,0 +1,73 @@ +apiVersion: apps/v1 +kind: DaemonSet +metadata: + name: istio-nodeagent + namespace: {{ .Release.Namespace }} + labels: + app: istio-nodeagent + istio: nodeagent + release: {{ .Release.Name }} +spec: + selector: + matchLabels: + istio: nodeagent + template: + metadata: + labels: + app: istio-nodeagent + istio: nodeagent + release: {{ .Release.Name }} + annotations: + sidecar.istio.io/inject: "false" + {{- if .Values.nodeagent.podAnnotations }} +{{ toYaml .Values.nodeagent.podAnnotations | indent 8 }} + {{- end }} + spec: + serviceAccountName: istio-nodeagent-service-account +{{- if .Values.global.priorityClassName }} + priorityClassName: "{{ .Values.global.priorityClassName }}" +{{- end }} + containers: + - name: nodeagent +{{- if contains "/" .Values.nodeagent.image }} + image: "{{ .Values.nodeagent.image }}" +{{- else }} + image: "{{ .Values.nodeagent.hub | default .Values.global.hub }}/{{ .Values.nodeagent.image }}:{{ .Values.nodeagent.tag | default .Values.global.tag }}" +{{- end }} + imagePullPolicy: {{ .Values.global.imagePullPolicy | default "Always" }} + args: + {{- if .Values.global.logAsJson }} + - --log_as_json + {{- end }} + volumeMounts: + - mountPath: /var/run/sds + name: sdsudspath + env: + {{- if .Values.nodeagent.env }} + {{- range $key, $val := .Values.nodeagent.env }} + - name: {{ $key }} + value: "{{ $val }}" + {{- end }} + {{- end }} + - name: "TRUST_DOMAIN" + value: "{{ .Values.global.trustDomain }}" + - name: NAMESPACE + valueFrom: + fieldRef: + fieldPath: metadata.namespace + volumes: + - name: sdsudspath + hostPath: + path: /var/run/sds + affinity: + {{- include "nodeaffinity" . | indent 6 }} + {{- include "podAntiAffinity" . | indent 6 }} +{{- if .Values.nodeagent.tolerations }} + tolerations: +{{ toYaml .Values.nodeagent.tolerations | indent 6 }} +{{- else if .Values.global.defaultTolerations }} + tolerations: +{{ toYaml .Values.global.defaultTolerations | indent 6 }} +{{- end }} + updateStrategy: + type: RollingUpdate diff --git a/istio-1.5.0/install/kubernetes/operator/charts/security/nodeagent/templates/serviceaccount.yaml b/istio-1.5.0/install/kubernetes/operator/charts/security/nodeagent/templates/serviceaccount.yaml new file mode 100644 index 0000000..6f1f946 --- /dev/null +++ b/istio-1.5.0/install/kubernetes/operator/charts/security/nodeagent/templates/serviceaccount.yaml @@ -0,0 +1,14 @@ +apiVersion: v1 +kind: ServiceAccount +{{- if .Values.global.imagePullSecrets }} +imagePullSecrets: +{{- range .Values.global.imagePullSecrets }} + - name: {{ . }} +{{- end }} +{{- end }} +metadata: + name: istio-nodeagent-service-account + namespace: {{ .Release.Namespace }} + labels: + app: istio-nodeagent + release: {{ .Release.Name }} diff --git a/istio-1.5.0/install/kubernetes/operator/charts/security/nodeagent/values.yaml b/istio-1.5.0/install/kubernetes/operator/charts/security/nodeagent/values.yaml new file mode 100644 index 0000000..2136011 --- /dev/null +++ b/istio-1.5.0/install/kubernetes/operator/charts/security/nodeagent/values.yaml @@ -0,0 +1,40 @@ +# +# nodeagent configuration +# +nodeagent: + enabled: false + hub: "" + tag: "" + image: node-agent-k8s + env: + # name of authentication provider. + CA_PROVIDER: "" + # CA endpoint. + CA_ADDR: "" + # names of authentication provider's plugins. + PLUGINS: "" + + nodeSelector: {} + tolerations: [] + podAnnotations: {} + + # Specify the pod anti-affinity that allows you to constrain which nodes + # your pod is eligible to be scheduled based on labels on pods that are + # already running on the node rather than based on labels on nodes. + # There are currently two types of anti-affinity: + # "requiredDuringSchedulingIgnoredDuringExecution" + # "preferredDuringSchedulingIgnoredDuringExecution" + # which denote "hard" vs. "soft" requirements, you can define your values + # in "podAntiAffinityLabelSelector" and "podAntiAffinityTermLabelSelector" + # correspondingly. + # For example: + # podAntiAffinityLabelSelector: + # - key: security + # operator: In + # values: S1,S2 + # topologyKey: "kubernetes.io/hostname" + # This pod anti-affinity rule says that the pod requires not to be scheduled + # onto a node if that node is already running a pod with label having key + # "security" and value "S1". + podAntiAffinityLabelSelector: [] + podAntiAffinityTermLabelSelector: [] diff --git a/istio-1.5.0/install/kubernetes/operator/deploy/clusterrole.yaml b/istio-1.5.0/install/kubernetes/operator/deploy/clusterrole.yaml new file mode 100644 index 0000000..6374301 --- /dev/null +++ b/istio-1.5.0/install/kubernetes/operator/deploy/clusterrole.yaml @@ -0,0 +1,114 @@ +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + creationTimestamp: null + name: istio-operator +rules: +# istio groups +- apiGroups: + - authentication.istio.io + resources: + - '*' + verbs: + - '*' +- apiGroups: + - config.istio.io + resources: + - '*' + verbs: + - '*' +- apiGroups: + - install.istio.io + resources: + - '*' + verbs: + - '*' +- apiGroups: + - networking.istio.io + resources: + - '*' + verbs: + - '*' +- apiGroups: + - rbac.istio.io + resources: + - '*' + verbs: + - '*' +- apiGroups: + - security.istio.io + resources: + - '*' + verbs: + - '*' +# k8s groups +- apiGroups: + - admissionregistration.k8s.io + resources: + - mutatingwebhookconfigurations + - validatingwebhookconfigurations + verbs: + - '*' +- apiGroups: + - apiextensions.k8s.io + resources: + - customresourcedefinitions.apiextensions.k8s.io + - customresourcedefinitions + verbs: + - '*' +- apiGroups: + - apps + - extensions + resources: + - daemonsets + - deployments + - deployments/finalizers + - ingresses + - replicasets + - statefulsets + verbs: + - '*' +- apiGroups: + - autoscaling + resources: + - horizontalpodautoscalers + verbs: + - '*' +- apiGroups: + - monitoring.coreos.com + resources: + - servicemonitors + verbs: + - get + - create +- apiGroups: + - policy + resources: + - poddisruptionbudgets + verbs: + - '*' +- apiGroups: + - rbac.authorization.k8s.io + resources: + - clusterrolebindings + - clusterroles + - roles + - rolebindings + verbs: + - '*' +- apiGroups: + - "" + resources: + - configmaps + - endpoints + - events + - namespaces + - pods + - persistentvolumeclaims + - secrets + - services + - serviceaccounts + verbs: + - '*' +... diff --git a/istio-1.5.0/install/kubernetes/operator/deploy/clusterrole_binding.yaml b/istio-1.5.0/install/kubernetes/operator/deploy/clusterrole_binding.yaml new file mode 100644 index 0000000..0d66e93 --- /dev/null +++ b/istio-1.5.0/install/kubernetes/operator/deploy/clusterrole_binding.yaml @@ -0,0 +1,14 @@ +--- +kind: ClusterRoleBinding +apiVersion: rbac.authorization.k8s.io/v1 +metadata: + name: istio-operator +subjects: +- kind: ServiceAccount + name: istio-operator + namespace: istio-operator +roleRef: + kind: ClusterRole + name: istio-operator + apiGroup: rbac.authorization.k8s.io +... diff --git a/istio-1.5.0/install/kubernetes/operator/deploy/crds/istio_v1alpha1_istiooperator_cr.yaml b/istio-1.5.0/install/kubernetes/operator/deploy/crds/istio_v1alpha1_istiooperator_cr.yaml new file mode 100644 index 0000000..4830397 --- /dev/null +++ b/istio-1.5.0/install/kubernetes/operator/deploy/crds/istio_v1alpha1_istiooperator_cr.yaml @@ -0,0 +1,9 @@ +--- +apiVersion: install.istio.io/v1alpha1 +kind: IstioOperator +metadata: + namespace: istio-system + name: example-istiocontrolplane +spec: + profile: demo +... diff --git a/istio-1.5.0/install/kubernetes/operator/deploy/crds/istio_v1alpha1_istiooperator_crd.yaml b/istio-1.5.0/install/kubernetes/operator/deploy/crds/istio_v1alpha1_istiooperator_crd.yaml new file mode 100644 index 0000000..d4dc192 --- /dev/null +++ b/istio-1.5.0/install/kubernetes/operator/deploy/crds/istio_v1alpha1_istiooperator_crd.yaml @@ -0,0 +1,22 @@ +--- +apiVersion: apiextensions.k8s.io/v1beta1 +kind: CustomResourceDefinition +metadata: + name: istiooperators.install.istio.io +spec: + group: install.istio.io + versions: + - name: v1alpha1 + served: true + storage: true + scope: Namespaced + subresources: + status: {} + names: + kind: IstioOperator + listKind: IstioOperatorList + plural: istiooperators + singular: istiooperator + shortNames: + - iop +... diff --git a/istio-1.5.0/install/kubernetes/operator/deploy/kustomization.yaml b/istio-1.5.0/install/kubernetes/operator/deploy/kustomization.yaml new file mode 100644 index 0000000..c9f0a60 --- /dev/null +++ b/istio-1.5.0/install/kubernetes/operator/deploy/kustomization.yaml @@ -0,0 +1,13 @@ +--- +apiVersion: kustomize.config.k8s.io/v1beta1 +kind: Kustomization +namespace: istio-operator +resources: +- crds/istio_v1alpha1_istiooperator_crd.yaml +- namespace.yaml +- clusterrole.yaml +- clusterrole_binding.yaml +- service_account.yaml +- operator.yaml +- service.yaml +... diff --git a/istio-1.5.0/install/kubernetes/operator/deploy/namespace.yaml b/istio-1.5.0/install/kubernetes/operator/deploy/namespace.yaml new file mode 100644 index 0000000..e9a5bd7 --- /dev/null +++ b/istio-1.5.0/install/kubernetes/operator/deploy/namespace.yaml @@ -0,0 +1,6 @@ +--- +apiVersion: v1 +kind: Namespace +metadata: + name: istio-operator +... diff --git a/istio-1.5.0/install/kubernetes/operator/deploy/operator.yaml b/istio-1.5.0/install/kubernetes/operator/deploy/operator.yaml new file mode 100644 index 0000000..c05ba93 --- /dev/null +++ b/istio-1.5.0/install/kubernetes/operator/deploy/operator.yaml @@ -0,0 +1,45 @@ +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + namespace: istio-operator + name: istio-operator +spec: + replicas: 1 + selector: + matchLabels: + name: istio-operator + template: + metadata: + labels: + name: istio-operator + spec: + serviceAccountName: istio-operator + containers: + - name: istio-operator + image: docker.io/istio/operator:1.5.0 + command: + - operator + - server + imagePullPolicy: IfNotPresent + resources: + limits: + cpu: 200m + memory: 256Mi + requests: + cpu: 50m + memory: 128Mi + env: + - name: WATCH_NAMESPACE + value: "istio-system" + - name: LEADER_ELECTION_NAMESPACE + valueFrom: + fieldRef: + fieldPath: metadata.namespace + - name: POD_NAME + valueFrom: + fieldRef: + fieldPath: metadata.name + - name: OPERATOR_NAME + value: "istio-operator" +... diff --git a/istio-1.5.0/install/kubernetes/operator/deploy/service.yaml b/istio-1.5.0/install/kubernetes/operator/deploy/service.yaml new file mode 100644 index 0000000..b5b47d1 --- /dev/null +++ b/istio-1.5.0/install/kubernetes/operator/deploy/service.yaml @@ -0,0 +1,16 @@ +--- +apiVersion: v1 +kind: Service +metadata: + namespace: istio-operator + labels: + name: istio-operator + name: istio-operator-metrics +spec: + ports: + - name: http-metrics + port: 8383 + targetPort: 8383 + selector: + name: istio-operator +... diff --git a/istio-1.5.0/install/kubernetes/operator/deploy/service_account.yaml b/istio-1.5.0/install/kubernetes/operator/deploy/service_account.yaml new file mode 100644 index 0000000..ca49f29 --- /dev/null +++ b/istio-1.5.0/install/kubernetes/operator/deploy/service_account.yaml @@ -0,0 +1,7 @@ +--- +apiVersion: v1 +kind: ServiceAccount +metadata: + namespace: istio-operator + name: istio-operator +... diff --git a/istio-1.5.0/install/kubernetes/operator/examples/customresource/istio_v1alpha1_istiooperator_cr.yaml b/istio-1.5.0/install/kubernetes/operator/examples/customresource/istio_v1alpha1_istiooperator_cr.yaml new file mode 100644 index 0000000..4830397 --- /dev/null +++ b/istio-1.5.0/install/kubernetes/operator/examples/customresource/istio_v1alpha1_istiooperator_cr.yaml @@ -0,0 +1,9 @@ +--- +apiVersion: install.istio.io/v1alpha1 +kind: IstioOperator +metadata: + namespace: istio-system + name: example-istiocontrolplane +spec: + profile: demo +... diff --git a/istio-1.5.0/install/kubernetes/operator/examples/googleca/values-istio-google-ca.yaml b/istio-1.5.0/install/kubernetes/operator/examples/googleca/values-istio-google-ca.yaml new file mode 100644 index 0000000..902e2d6 --- /dev/null +++ b/istio-1.5.0/install/kubernetes/operator/examples/googleca/values-istio-google-ca.yaml @@ -0,0 +1,25 @@ +apiVersion: install.istio.io/v1alpha1 +kind: IstioOperator +spec: + security: + components: + nodeAgent: + enabled: true + values: + global: + controlPlaneSecurityEnabled: true + mtls: + enabled: true + sds: + enabled: true + udsPath: "unix:/var/run/sds/uds_path" + token: + aud: "istio-ca" + useMCP: true + nodeagent: + image: node-agent-k8s + env: + CA_PROVIDER: "GoogleCA" + CA_ADDR: "meshca.googleapis.com:443" + PLUGINS: "GoogleTokenExchange" + GKE_CLUSTER_URL: "" diff --git a/istio-1.5.0/install/kubernetes/operator/examples/multicluster/values-istio-multicluster-gateways.yaml b/istio-1.5.0/install/kubernetes/operator/examples/multicluster/values-istio-multicluster-gateways.yaml new file mode 100644 index 0000000..b46f467 --- /dev/null +++ b/istio-1.5.0/install/kubernetes/operator/examples/multicluster/values-istio-multicluster-gateways.yaml @@ -0,0 +1,34 @@ +apiVersion: install.istio.io/v1alpha1 +kind: IstioOperator +spec: + addonComponents: + istiocoredns: + enabled: true + + components: + egressGateways: + - name: istio-egressgateway + enabled: true + + values: + global: + # Provides dns resolution for global services + podDNSSearchNamespaces: + - global + - "{{ valueOrDefault .DeploymentMeta.Namespace \"default\" }}.global" + + multiCluster: + enabled: true + + controlPlaneSecurityEnabled: true + + # Multicluster with gateways requires a root CA + # Cluster local CAs are bootstrapped with the root CA. + security: + selfSigned: false + + gateways: + istio-egressgateway: + env: + # Needed to route traffic via egress gateway if desired. + ISTIO_META_REQUESTED_NETWORK_VIEW: "external" diff --git a/istio-1.5.0/install/kubernetes/operator/examples/multicluster/values-istio-multicluster-primary.yaml b/istio-1.5.0/install/kubernetes/operator/examples/multicluster/values-istio-multicluster-primary.yaml new file mode 100644 index 0000000..d892591 --- /dev/null +++ b/istio-1.5.0/install/kubernetes/operator/examples/multicluster/values-istio-multicluster-primary.yaml @@ -0,0 +1,34 @@ +apiVersion: install.istio.io/v1alpha1 +kind: IstioOperator +spec: + values: + security: + selfSigned: false + gateways: + istio-ingressgateway: + env: + ISTIO_META_NETWORK: "network1" + global: + mtls: + enabled: true + controlPlaneSecurityEnabled: true + proxy: + accessLogFile: "/dev/stdout" + network: network1 + meshExpansion: + enabled: true + pilot: + meshNetworks: + networks: + network1: + endpoints: + - fromRegistry: Kubernetes + gateways: + - address: 0.0.0.0 + port: 443 + network2: + endpoints: + - fromRegistry: n2-k8s-config + gateways: + - address: 0.0.0.0 + port: 443 diff --git a/istio-1.5.0/install/kubernetes/operator/examples/user-gateway/ingress-gateway-only.yaml b/istio-1.5.0/install/kubernetes/operator/examples/user-gateway/ingress-gateway-only.yaml new file mode 100644 index 0000000..8ee1c6d --- /dev/null +++ b/istio-1.5.0/install/kubernetes/operator/examples/user-gateway/ingress-gateway-only.yaml @@ -0,0 +1,10 @@ +apiVersion: install.istio.io/v1alpha1 +kind: IstioOperator +spec: + profile: empty + gateways: + enabled: true + components: + namespace: my-namespace + ingressGateway: + enabled: true diff --git a/istio-1.5.0/install/kubernetes/operator/examples/vm/values-istio-meshexpansion-gateways.yaml b/istio-1.5.0/install/kubernetes/operator/examples/vm/values-istio-meshexpansion-gateways.yaml new file mode 100644 index 0000000..0118ce4 --- /dev/null +++ b/istio-1.5.0/install/kubernetes/operator/examples/vm/values-istio-meshexpansion-gateways.yaml @@ -0,0 +1,22 @@ +apiVersion: install.istio.io/v1alpha1 +kind: IstioOperator +spec: + values: + global: + multiCluster: + enabled: true + + meshExpansion: + enabled: true + + controlPlaneSecurityEnabled: true + + # Multicluster with gateways requires a root CA + # Cluster local CAs are bootstrapped with the root CA. + security: + selfSigned: false + + # Provides dns resolution for service entries of form + # name.namespace.global + istiocoredns: + enabled: true diff --git a/istio-1.5.0/install/kubernetes/operator/examples/vm/values-istio-meshexpansion.yaml b/istio-1.5.0/install/kubernetes/operator/examples/vm/values-istio-meshexpansion.yaml new file mode 100644 index 0000000..465fb20 --- /dev/null +++ b/istio-1.5.0/install/kubernetes/operator/examples/vm/values-istio-meshexpansion.yaml @@ -0,0 +1,14 @@ +apiVersion: install.istio.io/v1alpha1 +kind: IstioOperator +spec: + values: + global: + meshExpansion: + enabled: true + + controlPlaneSecurityEnabled: true + + # Multicluster with gateways requires a root CA + # Cluster local CAs are bootstrapped with the root CA. + security: + selfSigned: false diff --git a/istio-1.5.0/install/kubernetes/operator/profiles/default.yaml b/istio-1.5.0/install/kubernetes/operator/profiles/default.yaml new file mode 100644 index 0000000..bb14cff --- /dev/null +++ b/istio-1.5.0/install/kubernetes/operator/profiles/default.yaml @@ -0,0 +1,719 @@ +apiVersion: install.istio.io/v1alpha1 +kind: IstioOperator +metadata: + namespace: istio-system +spec: + hub: docker.io/istio + tag: 1.5.0 + + # Traffic management feature + components: + base: + enabled: true + pilot: + enabled: true + k8s: + env: + - name: POD_NAME + valueFrom: + fieldRef: + apiVersion: v1 + fieldPath: metadata.name + - name: POD_NAMESPACE + valueFrom: + fieldRef: + apiVersion: v1 + fieldPath: metadata.namespace + readinessProbe: + httpGet: + path: /ready + port: 8080 + initialDelaySeconds: 5 + periodSeconds: 5 + timeoutSeconds: 5 + resources: + requests: + cpu: 500m + memory: 2048Mi + strategy: + rollingUpdate: + maxSurge: "100%" + maxUnavailable: "25%" + + # Policy feature + policy: + enabled: false + k8s: + hpaSpec: + maxReplicas: 5 + minReplicas: 1 + scaleTargetRef: + apiVersion: apps/v1 + kind: Deployment + name: istio-policy + metrics: + - type: Resource + resource: + name: cpu + targetAverageUtilization: 80 + env: + - name: POD_NAMESPACE + valueFrom: + fieldRef: + apiVersion: v1 + fieldPath: metadata.namespace + strategy: + rollingUpdate: + maxSurge: "100%" + maxUnavailable: "25%" + + # Telemetry feature + telemetry: + enabled: false + k8s: + env: + - name: POD_NAMESPACE + valueFrom: + fieldRef: + apiVersion: v1 + fieldPath: metadata.namespace + - name: GOMAXPROCS + value: "6" + hpaSpec: + maxReplicas: 5 + minReplicas: 1 + scaleTargetRef: + apiVersion: apps/v1 + kind: Deployment + name: istio-telemetry + metrics: + - type: Resource + resource: + name: cpu + targetAverageUtilization: 80 + replicaCount: 1 + resources: + requests: + cpu: 1000m + memory: 1G + limits: + cpu: 4800m + memory: 4G + strategy: + rollingUpdate: + maxSurge: "100%" + maxUnavailable: "25%" + + # Security feature + citadel: + enabled: false + k8s: + strategy: + rollingUpdate: + maxSurge: "100%" + maxUnavailable: "25%" + + nodeAgent: + enabled: false + + # Config management feature + galley: + enabled: false + k8s: + replicaCount: 1 + resources: + requests: + cpu: 100m + strategy: + rollingUpdate: + maxSurge: "100%" + maxUnavailable: "25%" + + # Auto injection feature + sidecarInjector: + enabled: false + k8s: + replicaCount: 1 + strategy: + rollingUpdate: + maxSurge: "100%" + maxUnavailable: "25%" + + # Istio Gateway feature + ingressGateways: + - name: istio-ingressgateway + enabled: true + k8s: + hpaSpec: + maxReplicas: 5 + minReplicas: 1 + scaleTargetRef: + apiVersion: apps/v1 + kind: Deployment + name: istio-ingressgateway + metrics: + - type: Resource + resource: + name: cpu + targetAverageUtilization: 80 + resources: + requests: + cpu: 100m + memory: 128Mi + limits: + cpu: 2000m + memory: 1024Mi + strategy: + rollingUpdate: + maxSurge: "100%" + maxUnavailable: "25%" + + egressGateways: + - name: istio-egressgateway + enabled: false + k8s: + hpaSpec: + maxReplicas: 5 + minReplicas: 1 + scaleTargetRef: + apiVersion: apps/v1 + kind: Deployment + name: istio-ingressgateway + metrics: + - type: Resource + resource: + name: cpu + targetAverageUtilization: 80 + resources: + requests: + cpu: 100m + memory: 128Mi + limits: + cpu: 2000m + memory: 1024Mi + strategy: + rollingUpdate: + maxSurge: "100%" + maxUnavailable: "25%" + # Istio CNI feature + cni: + enabled: false + + addonComponents: + prometheus: + enabled: true + k8s: + replicaCount: 1 + kiali: + enabled: false + k8s: + replicaCount: 1 + grafana: + enabled: false + k8s: + replicaCount: 1 + tracing: + enabled: false + istiocoredns: + enabled: false + + # Global values passed through to helm global.yaml. + values: + global: + istioNamespace: istio-system + istiod: + enabled: true + logging: + level: "default:info" + logAsJson: false + k8sIngress: + enabled: false + gatewayName: ingressgateway + enableHttps: false + pilotCertProvider: istiod + jwtPolicy: third-party-jwt + proxy: + image: proxyv2 + clusterDomain: "cluster.local" + resources: + requests: + cpu: 100m + memory: 128Mi + limits: + cpu: 2000m + memory: 1024Mi + concurrency: 2 + accessLogFile: "" + accessLogFormat: "" + accessLogEncoding: TEXT + envoyAccessLogService: + enabled: false + host: # example: accesslog-service.istio-system + port: # example: 15000 + logLevel: warning + componentLogLevel: "misc:error" + dnsRefreshRate: 300s + protocolDetectionTimeout: 100ms + privileged: false + enableCoreDump: false + statusPort: 15020 + readinessInitialDelaySeconds: 1 + readinessPeriodSeconds: 2 + readinessFailureThreshold: 30 + includeIPRanges: "*" + excludeIPRanges: "" + excludeOutboundPorts: "" + kubevirtInterfaces: "" + includeInboundPorts: "*" + excludeInboundPorts: "" + autoInject: enabled + envoyStatsd: + enabled: false + host: # example: statsd-svc.istio-system + port: # example: 9125 + envoyMetricsService: + enabled: false + host: # example: metrics-service.istio-system + port: # example: 15000 + tlsSettings: + mode: DISABLE # DISABLE, SIMPLE, MUTUAL, ISTIO_MUTUAL + clientCertificate: # example: /etc/istio/ms/cert-chain.pem + privateKey: # example: /etc/istio/ms/key.pem + caCertificates: # example: /etc/istio/ms/root-cert.pem + sni: # example: ms.somedomain + subjectAltNames: [] + tcpKeepalive: + probes: 3 + time: 10s + interval: 10s + tracer: "zipkin" + proxy_init: + image: proxyv2 + resources: + limits: + cpu: 100m + memory: 50Mi + requests: + cpu: 10m + memory: 10Mi + imagePullPolicy: IfNotPresent + certificates: [] + operatorManageWebhooks: false + controlPlaneSecurityEnabled: true + disablePolicyChecks: true + policyCheckFailOpen: false + enableTracing: true + tracer: + lightstep: + address: "" # example: lightstep-satellite:443 + accessToken: "" # example: abcdefg1234567 + secure: true # example: true|false + cacertPath: "" # example: /etc/lightstep/cacert.pem + zipkin: + address: "" + datadog: + address: "$(HOST_IP):8126" + stackdriver: + debug: false + maxNumberOfAttributes: 200 + maxNumberOfAnnotations: 200 + maxNumberOfMessageEvents: 200 + mtls: + enabled: false + auto: true + imagePullSecrets: [] + arch: + amd64: 2 + s390x: 2 + ppc64le: 2 + oneNamespace: false + defaultNodeSelector: {} + configValidation: true + meshExpansion: + enabled: false + useILB: false + multiCluster: + enabled: false + clusterName: "" + omitSidecarInjectorConfigMap: false + network: "" + defaultResources: + requests: + cpu: 10m + defaultPodDisruptionBudget: + enabled: true + priorityClassName: "" + useMCP: false + trustDomain: "cluster.local" + outboundTrafficPolicy: + mode: ALLOW_ANY + sds: + enabled: false + udsPath: "" + token: + aud: istio-ca + sts: + servicePort: 0 + meshNetworks: {} + localityLbSetting: + enabled: true + enableHelmTest: false + mountMtlsCerts: false + pilot: + autoscaleEnabled: true + autoscaleMin: 1 + autoscaleMax: 5 + replicaCount: 1 + image: pilot + traceSampling: 1.0 + configNamespace: istio-config + appNamespaces: [] + env: {} + cpu: + targetAverageUtilization: 80 + nodeSelector: {} + tolerations: [] + podAntiAffinityLabelSelector: [] + podAntiAffinityTermLabelSelector: [] + keepaliveMaxServerConnectionAge: 30m + enableProtocolSniffingForOutbound: true + enableProtocolSniffingForInbound: false + deploymentLabels: + meshNetworks: + networks: {} + configMap: true + ingress: + ingressService: istio-ingressgateway + ingressControllerMode: "STRICT" + ingressClass: istio + policy: + enabled: false + + telemetry: + enabled: true + v1: + enabled: false + v2: + enabled: true + prometheus: + enabled: true + stackdriver: + enabled: false + logging: false + monitoring: false + topology: false + configOverride: {} + mixer: + adapters: + stdio: + enabled: false + outputAsJson: false + prometheus: + enabled: true + metricsExpiryDuration: 10m + kubernetesenv: + enabled: true + stackdriver: + enabled: false + auth: + appCredentials: false + apiKey: "" + serviceAccountPath: "" + tracer: + enabled: false + sampleProbability: 1 + useAdapterCRDs: false + + telemetry: + image: mixer + replicaCount: 1 + autoscaleEnabled: true + sessionAffinityEnabled: false + loadshedding: + mode: enforce + latencyThreshold: 100ms + reportBatchMaxEntries: 100 + reportBatchMaxTime: 1s + env: + GOMAXPROCS: "6" + nodeSelector: {} + tolerations: [] + podAntiAffinityLabelSelector: [] + podAntiAffinityTermLabelSelector: [] + + policy: + autoscaleEnabled: true + image: mixer + sessionAffinityEnabled: false + adapters: + kubernetesenv: + enabled: true + useAdapterCRDs: false + + galley: + image: galley + enableAnalysis: false + + security: + image: citadel + selfSigned: true # indicate if self-signed CA is used. + enableNamespacesByDefault: true + dnsCerts: + istio-pilot-service-account.istio-control: istio-pilot.istio-control + + nodeagent: + image: node-agent-k8s + + gateways: + istio-egressgateway: + autoscaleEnabled: true + type: ClusterIP + env: + ISTIO_META_ROUTER_MODE: "sni-dnat" + ports: + - port: 80 + name: http2 + - port: 443 + name: https + - port: 15443 + targetPort: 15443 + name: tls + secretVolumes: + - name: egressgateway-certs + secretName: istio-egressgateway-certs + mountPath: /etc/istio/egressgateway-certs + - name: egressgateway-ca-certs + secretName: istio-egressgateway-ca-certs + mountPath: /etc/istio/egressgateway-ca-certs + + istio-ingressgateway: + autoscaleEnabled: true + applicationPorts: "" + debug: info + domain: "" + type: LoadBalancer + zvpn: + enabled: false + suffix: global + sds: + enabled: false + image: node-agent-k8s + resources: + requests: + cpu: 100m + memory: 128Mi + limits: + cpu: 2000m + memory: 1024Mi + env: + ISTIO_META_ROUTER_MODE: "sni-dnat" + ports: + - port: 15020 + targetPort: 15020 + name: status-port + - port: 80 + targetPort: 80 + name: http2 + - port: 443 + name: https + - port: 15029 + targetPort: 15029 + name: kiali + - port: 15030 + targetPort: 15030 + name: prometheus + - port: 15031 + targetPort: 15031 + name: grafana + - port: 15032 + targetPort: 15032 + name: tracing + - port: 15443 + targetPort: 15443 + name: tls + meshExpansionPorts: + - port: 15011 + targetPort: 15011 + name: tcp-pilot-grpc-tls + - port: 8060 + targetPort: 8060 + name: tcp-citadel-grpc-tls + - port: 853 + targetPort: 853 + name: tcp-dns-tls + secretVolumes: + - name: ingressgateway-certs + secretName: istio-ingressgateway-certs + mountPath: /etc/istio/ingressgateway-certs + - name: ingressgateway-ca-certs + secretName: istio-ingressgateway-ca-certs + mountPath: /etc/istio/ingressgateway-ca-certs + + sidecarInjectorWebhook: + image: sidecar_injector + enableNamespacesByDefault: false + rewriteAppHTTPProbe: false + selfSigned: false + injectLabel: istio-injection + objectSelector: + enabled: false + autoInject: true + + prometheus: + hub: docker.io/prom + tag: v2.15.1 + retention: 6h + scrapeInterval: 15s + contextPath: /prometheus + ingress: + enabled: false + hosts: + - prometheus.local + annotations: + tls: + security: + enabled: true + nodeSelector: {} + tolerations: [] + podAntiAffinityLabelSelector: [] + podAntiAffinityTermLabelSelector: [] + provisionPrometheusCert: true + + grafana: + image: + repository: grafana/grafana + tag: 6.5.2 + persist: false + storageClassName: "" + accessMode: ReadWriteMany + security: + enabled: false + secretName: grafana + usernameKey: username + passphraseKey: passphrase + contextPath: /grafana + service: + annotations: {} + name: http + type: ClusterIP + externalPort: 3000 + loadBalancerIP: + loadBalancerSourceRanges: + ingress: + enabled: false + hosts: + - grafana.local + annotations: + tls: + datasources: + datasources.yaml: + apiVersion: 1 + datasources: + dashboardProviders: + dashboardproviders.yaml: + apiVersion: 1 + providers: + - name: 'istio' + orgId: 1 + folder: 'istio' + type: file + disableDeletion: false + options: + path: /var/lib/grafana/dashboards/istio + nodeSelector: {} + tolerations: [] + podAntiAffinityLabelSelector: [] + podAntiAffinityTermLabelSelector: [] + env: {} + envSecrets: {} + + tracing: + provider: jaeger + nodeSelector: {} + podAntiAffinityLabelSelector: [] + podAntiAffinityTermLabelSelector: [] + jaeger: + hub: docker.io/jaegertracing + tag: "1.16" + memory: + max_traces: 50000 + spanStorageType: badger + persist: false + storageClassName: "" + accessMode: ReadWriteMany + zipkin: + hub: docker.io/openzipkin + tag: 2.14.2 + probeStartupDelay: 200 + queryPort: 9411 + resources: + limits: + cpu: 300m + memory: 900Mi + requests: + cpu: 150m + memory: 900Mi + javaOptsHeap: 700 + maxSpans: 500000 + node: + cpus: 2 + opencensus: + hub: docker.io/omnition + tag: 0.1.9 + resources: + limits: + cpu: "1" + memory: 2Gi + requests: + cpu: 200m + memory: 400Mi + exporters: + stackdriver: + enable_tracing: true + service: + annotations: {} + name: http-query + type: ClusterIP + externalPort: 9411 + ingress: + enabled: false + hosts: + annotations: + tls: + istiocoredns: + coreDNSImage: coredns/coredns + coreDNSTag: 1.6.2 + coreDNSPluginImage: istio/coredns-plugin:0.2-istio-1.1 + + kiali: + hub: quay.io/kiali + tag: v1.14 + contextPath: /kiali + nodeSelector: {} + podAntiAffinityLabelSelector: [] + podAntiAffinityTermLabelSelector: [] + ingress: + enabled: false + hosts: + - kiali.local + annotations: + tls: + dashboard: + secretName: kiali + usernameKey: username + passphraseKey: passphrase + viewOnlyMode: false + grafanaURL: + grafanaInClusterURL: http://grafana:3000 + jaegerURL: + jaegerInClusterURL: http://tracing/jaeger + prometheusNamespace: + createDemoSecret: false + security: + enabled: false + cert_file: /kiali-cert/cert-chain.pem + private_key_file: /kiali-cert/key.pem + + # TODO: derive from operator API + version: "" + clusterResources: true diff --git a/istio-1.5.0/install/kubernetes/operator/profiles/demo.yaml b/istio-1.5.0/install/kubernetes/operator/profiles/demo.yaml new file mode 100644 index 0000000..2be2171 --- /dev/null +++ b/istio-1.5.0/install/kubernetes/operator/profiles/demo.yaml @@ -0,0 +1,138 @@ +apiVersion: install.istio.io/v1alpha1 +kind: IstioOperator +spec: + components: + egressGateways: + - name: istio-egressgateway + enabled: true + k8s: + resources: + requests: + cpu: 10m + memory: 40Mi + + ingressGateways: + - name: istio-ingressgateway + enabled: true + k8s: + resources: + requests: + cpu: 10m + memory: 40Mi + + policy: + enabled: false + k8s: + resources: + requests: + cpu: 10m + memory: 100Mi + + telemetry: + k8s: + resources: + requests: + cpu: 50m + memory: 100Mi + + pilot: + k8s: + env: + - name: POD_NAME + valueFrom: + fieldRef: + apiVersion: v1 + fieldPath: metadata.name + - name: POD_NAMESPACE + valueFrom: + fieldRef: + apiVersion: v1 + fieldPath: metadata.namespace + - name: GODEBUG + value: gctrace=1 + - name: PILOT_TRACE_SAMPLING + value: "100" + - name: CONFIG_NAMESPACE + value: istio-config + resources: + requests: + cpu: 10m + memory: 100Mi + + addonComponents: + kiali: + enabled: true + grafana: + enabled: true + tracing: + enabled: true + + values: + global: + disablePolicyChecks: false + proxy: + accessLogFile: /dev/stdout + resources: + requests: + cpu: 10m + memory: 40Mi + + pilot: + autoscaleEnabled: false + + mixer: + adapters: + useAdapterCRDs: false + kubernetesenv: + enabled: true + prometheus: + enabled: true + metricsExpiryDuration: 10m + stackdriver: + enabled: false + stdio: + enabled: true + outputAsJson: false + policy: + autoscaleEnabled: false + telemetry: + autoscaleEnabled: false + + gateways: + istio-egressgateway: + autoscaleEnabled: false + istio-ingressgateway: + autoscaleEnabled: false + ports: + ## You can add custom gateway ports in user values overrides, but it must include those ports since helm replaces. + # Note that AWS ELB will by default perform health checks on the first port + # on this list. Setting this to the health check port will ensure that health + # checks always work. https://github.com/istio/istio/issues/12503 + - port: 15020 + targetPort: 15020 + name: status-port + - port: 80 + targetPort: 80 + name: http2 + - port: 443 + name: https + - port: 15029 + targetPort: 15029 + name: kiali + - port: 15030 + targetPort: 15030 + name: prometheus + - port: 15031 + targetPort: 15031 + name: grafana + - port: 15032 + targetPort: 15032 + name: tracing + - port: 31400 + targetPort: 31400 + name: tcp + - port: 15443 + targetPort: 15443 + name: tls + kiali: + createDemoSecret: true diff --git a/istio-1.5.0/install/kubernetes/operator/profiles/empty.yaml b/istio-1.5.0/install/kubernetes/operator/profiles/empty.yaml new file mode 100644 index 0000000..18419af --- /dev/null +++ b/istio-1.5.0/install/kubernetes/operator/profiles/empty.yaml @@ -0,0 +1,52 @@ +# The empty profile has everything disabled +# This is useful as a base for custom user configuration +apiVersion: install.istio.io/v1alpha1 +kind: IstioOperator +spec: + hub: gcr.io/istio-testing + tag: latest + meshConfig: + rootNamespace: istio-system + components: + base: + enabled: false + pilot: + enabled: false + policy: + enabled: false + telemetry: + enabled: false + proxy: + enabled: false + sidecarInjector: + enabled: false + citadel: + enabled: false + nodeAgent: + enabled: false + galley: + enabled: false + cni: + enabled: false + ingressGateways: + egressGateways: + + addonComponents: + prometheus: + enabled: false + + values: + global: + useMCP: false + controlPlaneSecurityEnabled: false + proxy: + envoyStatsd: + enabled: false + host: + port: + mtls: + auto: false + + pilot: + sidecar: false + useMCP: false diff --git a/istio-1.5.0/install/kubernetes/operator/profiles/minimal.yaml b/istio-1.5.0/install/kubernetes/operator/profiles/minimal.yaml new file mode 100644 index 0000000..082eb61 --- /dev/null +++ b/istio-1.5.0/install/kubernetes/operator/profiles/minimal.yaml @@ -0,0 +1,49 @@ +# The minimal profile will install just the core control plane +apiVersion: install.istio.io/v1alpha1 +kind: IstioOperator +spec: + components: + pilot: + enabled: true + policy: + enabled: false + telemetry: + enabled: false + proxy: + enabled: false + sidecarInjector: + enabled: false + citadel: + enabled: false + nodeAgent: + enabled: false + galley: + enabled: false + cni: + enabled: false + ingressGateways: + - name: istio-ingressgateway + enabled: false + egressGateways: + - name: istio-egressgateway + enabled: false + + addonComponents: + prometheus: + enabled: false + + values: + global: + useMCP: false + controlPlaneSecurityEnabled: false + proxy: + envoyStatsd: + enabled: false + host: + port: + mtls: + auto: false + + pilot: + sidecar: false + useMCP: false diff --git a/istio-1.5.0/install/kubernetes/operator/profiles/remote.yaml b/istio-1.5.0/install/kubernetes/operator/profiles/remote.yaml new file mode 100644 index 0000000..0f0107a --- /dev/null +++ b/istio-1.5.0/install/kubernetes/operator/profiles/remote.yaml @@ -0,0 +1,35 @@ +apiVersion: install.istio.io/v1alpha1 +kind: IstioOperator +spec: + components: + pilot: + enabled: true + policy: + enabled: false + telemetry: + enabled: false + proxy: + enabled: false + sidecarInjector: + enabled: false + citadel: + enabled: false + nodeAgent: + enabled: false + galley: + enabled: false + cni: + enabled: false + + addonComponents: + prometheus: + enabled: false + + values: + security: + createMeshPolicy: false + + global: + istioRemote: true + enableTracing: false + network: "" diff --git a/istio-1.5.0/install/kubernetes/operator/profiles/separate.yaml b/istio-1.5.0/install/kubernetes/operator/profiles/separate.yaml new file mode 100644 index 0000000..c406711 --- /dev/null +++ b/istio-1.5.0/install/kubernetes/operator/profiles/separate.yaml @@ -0,0 +1,25 @@ +# The separate profile will disable istiod and bring back the old microservices model +# This will be removed in future (1.6) releases +apiVersion: install.istio.io/v1alpha1 +kind: IstioOperator +spec: + components: + sidecarInjector: + enabled: true + citadel: + enabled: true + galley: + enabled: true + telemetry: + enabled: true + values: + telemetry: + v1: + enabled: true + v2: + enabled: false + global: + pilotCertProvider: kubernetes + mountMtlsCerts: true + istiod: + enabled: false \ No newline at end of file diff --git a/istio-1.5.0/install/kubernetes/operator/versions.yaml b/istio-1.5.0/install/kubernetes/operator/versions.yaml new file mode 100644 index 0000000..5f724e3 --- /dev/null +++ b/istio-1.5.0/install/kubernetes/operator/versions.yaml @@ -0,0 +1,54 @@ +- operatorVersion: 1.3.0 + supportedIstioVersions: 1.3.0 + recommendedIstioVersions: 1.3.0 +- operatorVersion: 1.3.1 + supportedIstioVersions: ">=1.3.0,<=1.3.1" + recommendedIstioVersions: 1.3.1 +- operatorVersion: 1.3.2 + supportedIstioVersions: ">=1.3.0,<=1.3.2" + recommendedIstioVersions: 1.3.2 +- operatorVersion: 1.3.3 + supportedIstioVersions: ">=1.3.0,<=1.3.3" + recommendedIstioVersions: 1.3.3 +- operatorVersion: 1.3.4 + supportedIstioVersions: ">=1.3.0,<=1.3.4" + recommendedIstioVersions: 1.3.4 +- operatorVersion: 1.3.5 + supportedIstioVersions: ">=1.3.0,<=1.3.5" + recommendedIstioVersions: 1.3.5 +- operatorVersion: 1.3.6 + supportedIstioVersions: ">=1.3.0,<=1.3.6" + recommendedIstioVersions: 1.3.6 +- operatorVersion: 1.3.7 + operatorVersionRange: ">=1.3.7,<1.4.0" + supportedIstioVersions: ">=1.3.0,<1.4.0" + recommendedIstioVersions: 1.3.7 +- operatorVersion: 1.4.0 + supportedIstioVersions: ">=1.3.3, <1.6" + recommendedIstioVersions: 1.4.0 +- operatorVersion: 1.4.1 + supportedIstioVersions: ">=1.3.3, <1.6" + recommendedIstioVersions: 1.4.1 +- operatorVersion: 1.4.2 + supportedIstioVersions: ">=1.3.3, <1.6" + recommendedIstioVersions: 1.4.2 +- operatorVersion: 1.4.3 + operatorVersionRange: ">=1.4.3,<1.5.0" + supportedIstioVersions: ">=1.3.3, <1.6" + recommendedIstioVersions: 1.4.3 +- operatorVersion: 1.4.4 + operatorVersionRange: ">=1.4.4,<1.5.0" + supportedIstioVersions: ">=1.3.3, <1.6" + recommendedIstioVersions: 1.4.4 +- operatorVersion: 1.5.0 + operatorVersionRange: ">=1.5.0,<1.6.0" + supportedIstioVersions: ">=1.4.0, <1.6" + recommendedIstioVersions: 1.5.0 + k8sClientVersionRange: ">=1.14" + k8sServerVersionRange: ">=1.14" +- operatorVersion: 1.6.0 + operatorVersionRange: ">=1.6.0,<1.7.0" + supportedIstioVersions: ">=1.5.0, <1.7" + recommendedIstioVersions: 1.6.0 + k8sClientVersionRange: ">=1.14" + k8sServerVersionRange: ">=1.14" diff --git a/istio-1.5.0/manifest.yaml b/istio-1.5.0/manifest.yaml new file mode 100644 index 0000000..d009eb5 --- /dev/null +++ b/istio-1.5.0/manifest.yaml @@ -0,0 +1,21 @@ +dependencies: + api: + sha: 891bf31f3c325bbf2de0e7d0ed6406bbbc93deba + client-go: + sha: 23b87b42e49bd613c2fca9fe5f3a8ab62450bebb + cni: + sha: 0d3c739609d715bd2c09cc00fbc688b0f2ab96a8 + gogo-genproto: + sha: a0338448499a99db79cf32c3b34b44670b9fb5b5 + istio: + sha: c3c353285578eb68b334fc8766746b754b6b3789 + pkg: + sha: 47b6d38ec7841906f8d539e0823cd9b63d971ae4 + proxy: + sha: 73f240a29bece92a8882a36893ccce07b4a54664 + test-infra: + sha: 14319a3f515ff9aa579ae35e1cfd436374a10d60 + tools: + sha: b26535a152f3f6f56dfcaf6d80e1d2f4858f216e +docker: docker.io/istio +version: 1.5.0 diff --git a/istio-1.5.0/path.txt b/istio-1.5.0/path.txt new file mode 100644 index 0000000..4560a92 --- /dev/null +++ b/istio-1.5.0/path.txt @@ -0,0 +1 @@ +/usr/local/opt/helm@2/bin:/Users/tonyh/.fastlane/bin:/usr/local/sbin:/usr/local/opt/icu4c/sbin:/usr/local/opt/icu4c/bin:/usr/local/opt/gettext/bin:/Users/tonyh/git/microservices-demo/istio-1.3.5/bin:/Users/tonyh/.fastlane/bin:/usr/local/sbin:/usr/local/opt/icu4c/sbin:/usr/local/opt/icu4c/bin:/usr/local/opt/gettext/bin:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin:/opt/X11/bin:/Users/tonyh/.fastlane/bin:/usr/local/sbin:/usr/local/opt/icu4c/sbin:/usr/local/opt/icu4c/bin:/usr/local/opt/gettext/bin:/Applications/Visual Studio Code.app/Contents/Resources/app/bin:/usr/local/go/bin:/Users/tonyh/go/bin:/usr/local/bin/flutter/bin:/usr/local/opt/fzf/bin:/Applications/Visual Studio Code.app/Contents/Resources/app/bin:/usr/local/go/bin:/Users/tonyh/go/bin:/usr/local/bin/flutter/bin:/Applications/Visual Studio Code.app/Contents/Resources/app/bin:/usr/local/go/bin:/Users/tonyh/go/bin:/usr/local/bin/flutter/bin diff --git a/istio-1.5.0/samples/README.md b/istio-1.5.0/samples/README.md new file mode 100644 index 0000000..a1a140f --- /dev/null +++ b/istio-1.5.0/samples/README.md @@ -0,0 +1,3 @@ +# Istio Samples + +This directory contains sample applications highlighting various Istio features. diff --git a/istio-1.5.0/samples/bookinfo/README.md b/istio-1.5.0/samples/bookinfo/README.md new file mode 100644 index 0000000..993beae --- /dev/null +++ b/istio-1.5.0/samples/bookinfo/README.md @@ -0,0 +1,31 @@ +# Bookinfo Sample + +See + +## Build docker images without pushing + +```bash +src/build-services.sh +``` + +The bookinfo versions are different from Istio versions since the sample should work with any version of Istio. + +## Update docker images in the yaml files + +```bash +sed -i "s/\(istio\/examples-bookinfo-.*\):[[:digit:]]\.[[:digit:]]\.[[:digit:]]//g" */bookinfo*.yaml +``` + +## Push docker images to docker hub + +One script to build the docker images, push them to docker hub and to update the yaml files + +```bash +build_push_update_images.sh +``` + +## Tests + +Bookinfo is tested by e2e smoke test on every PR. The Bookinfo e2e test is in [tests/e2e/tests/bookinfo](https://github.com/istio/istio/tree/master/tests/e2e/tests/bookinfo), make target `e2e_bookinfo`. + +The reference productpage HTML files are in [tests/apps/bookinfo/output](https://github.com/istio/istio/tree/master/tests/apps/bookinfo/output). If the productpage HTML produced by the app is changed, remember to regenerate the reference HTML files and commit them with the same PR. diff --git a/istio-1.5.0/samples/bookinfo/networking/bookinfo-gateway.yaml b/istio-1.5.0/samples/bookinfo/networking/bookinfo-gateway.yaml new file mode 100644 index 0000000..951f069 --- /dev/null +++ b/istio-1.5.0/samples/bookinfo/networking/bookinfo-gateway.yaml @@ -0,0 +1,41 @@ +apiVersion: networking.istio.io/v1alpha3 +kind: Gateway +metadata: + name: bookinfo-gateway +spec: + selector: + istio: ingressgateway # use istio default controller + servers: + - port: + number: 80 + name: http + protocol: HTTP + hosts: + - "*" +--- +apiVersion: networking.istio.io/v1alpha3 +kind: VirtualService +metadata: + name: bookinfo +spec: + hosts: + - "*" + gateways: + - bookinfo-gateway + http: + - match: + - uri: + exact: /productpage + - uri: + prefix: /static + - uri: + exact: /login + - uri: + exact: /logout + - uri: + prefix: /api/v1/products + route: + - destination: + host: productpage + port: + number: 9080 diff --git a/istio-1.5.0/samples/bookinfo/networking/certmanager-gateway.yaml b/istio-1.5.0/samples/bookinfo/networking/certmanager-gateway.yaml new file mode 100644 index 0000000..3fa6537 --- /dev/null +++ b/istio-1.5.0/samples/bookinfo/networking/certmanager-gateway.yaml @@ -0,0 +1,35 @@ +apiVersion: networking.istio.io/v1alpha3 +kind: Gateway +metadata: + name: cert-manager-gateway + namespace: istio-system +spec: + selector: + istio: ingressgateway + servers: + - port: + number: 80 + name: http + protocol: HTTP + hosts: + - "*" +--- +apiVersion: networking.istio.io/v1alpha3 +kind: VirtualService +metadata: + name: cert-manager + namespace: istio-system +spec: + hosts: + - "*" + gateways: + - cert-manager-gateway + http: + - match: + - uri: + prefix: /.well-known/acme-challenge/ + route: + - destination: + host: cert-manager-resolver + port: + number: 8089 diff --git a/istio-1.5.0/samples/bookinfo/networking/destination-rule-all-mtls.yaml b/istio-1.5.0/samples/bookinfo/networking/destination-rule-all-mtls.yaml new file mode 100644 index 0000000..2a19c3f --- /dev/null +++ b/istio-1.5.0/samples/bookinfo/networking/destination-rule-all-mtls.yaml @@ -0,0 +1,74 @@ +apiVersion: networking.istio.io/v1alpha3 +kind: DestinationRule +metadata: + name: productpage +spec: + host: productpage + trafficPolicy: + tls: + mode: ISTIO_MUTUAL + subsets: + - name: v1 + labels: + version: v1 +--- +apiVersion: networking.istio.io/v1alpha3 +kind: DestinationRule +metadata: + name: reviews +spec: + host: reviews + trafficPolicy: + tls: + mode: ISTIO_MUTUAL + subsets: + - name: v1 + labels: + version: v1 + - name: v2 + labels: + version: v2 + - name: v3 + labels: + version: v3 +--- +apiVersion: networking.istio.io/v1alpha3 +kind: DestinationRule +metadata: + name: ratings +spec: + host: ratings + trafficPolicy: + tls: + mode: ISTIO_MUTUAL + subsets: + - name: v1 + labels: + version: v1 + - name: v2 + labels: + version: v2 + - name: v2-mysql + labels: + version: v2-mysql + - name: v2-mysql-vm + labels: + version: v2-mysql-vm +--- +apiVersion: networking.istio.io/v1alpha3 +kind: DestinationRule +metadata: + name: details +spec: + host: details + trafficPolicy: + tls: + mode: ISTIO_MUTUAL + subsets: + - name: v1 + labels: + version: v1 + - name: v2 + labels: + version: v2 +--- diff --git a/istio-1.5.0/samples/bookinfo/networking/destination-rule-all.yaml b/istio-1.5.0/samples/bookinfo/networking/destination-rule-all.yaml new file mode 100644 index 0000000..96be699 --- /dev/null +++ b/istio-1.5.0/samples/bookinfo/networking/destination-rule-all.yaml @@ -0,0 +1,62 @@ +apiVersion: networking.istio.io/v1alpha3 +kind: DestinationRule +metadata: + name: productpage +spec: + host: productpage + subsets: + - name: v1 + labels: + version: v1 +--- +apiVersion: networking.istio.io/v1alpha3 +kind: DestinationRule +metadata: + name: reviews +spec: + host: reviews + subsets: + - name: v1 + labels: + version: v1 + - name: v2 + labels: + version: v2 + - name: v3 + labels: + version: v3 +--- +apiVersion: networking.istio.io/v1alpha3 +kind: DestinationRule +metadata: + name: ratings +spec: + host: ratings + subsets: + - name: v1 + labels: + version: v1 + - name: v2 + labels: + version: v2 + - name: v2-mysql + labels: + version: v2-mysql + - name: v2-mysql-vm + labels: + version: v2-mysql-vm +--- +apiVersion: networking.istio.io/v1alpha3 +kind: DestinationRule +metadata: + name: details +spec: + host: details + subsets: + - name: v1 + labels: + version: v1 + - name: v2 + labels: + version: v2 +--- diff --git a/istio-1.5.0/samples/bookinfo/networking/destination-rule-reviews.yaml b/istio-1.5.0/samples/bookinfo/networking/destination-rule-reviews.yaml new file mode 100644 index 0000000..69f30f1 --- /dev/null +++ b/istio-1.5.0/samples/bookinfo/networking/destination-rule-reviews.yaml @@ -0,0 +1,19 @@ +apiVersion: networking.istio.io/v1alpha3 +kind: DestinationRule +metadata: + name: reviews +spec: + host: reviews + trafficPolicy: + loadBalancer: + simple: RANDOM + subsets: + - name: v1 + labels: + version: v1 + - name: v2 + labels: + version: v2 + - name: v3 + labels: + version: v3 diff --git a/istio-1.5.0/samples/bookinfo/networking/egress-rule-google-apis.yaml b/istio-1.5.0/samples/bookinfo/networking/egress-rule-google-apis.yaml new file mode 100644 index 0000000..d35e3ac --- /dev/null +++ b/istio-1.5.0/samples/bookinfo/networking/egress-rule-google-apis.yaml @@ -0,0 +1,46 @@ +apiVersion: networking.istio.io/v1alpha3 +kind: ServiceEntry +metadata: + name: googleapis +spec: + hosts: + - www.googleapis.com + ports: + - number: 80 + name: http + protocol: HTTP + - number: 443 + name: https + protocol: HTTPS + resolution: DNS +--- +apiVersion: networking.istio.io/v1alpha3 +kind: VirtualService +metadata: + name: rewrite-port-for-googleapis +spec: + hosts: + - www.googleapis.com + http: + - match: + - port: 80 + route: + - destination: + host: www.googleapis.com + port: + number: 443 +--- +apiVersion: networking.istio.io/v1alpha3 +kind: DestinationRule +metadata: + name: originate-tls-for-googleapis +spec: + host: www.googleapis.com + trafficPolicy: + loadBalancer: + simple: ROUND_ROBIN + portLevelSettings: + - port: + number: 443 + tls: + mode: SIMPLE # initiates HTTPS when accessing www.googleapis.com diff --git a/istio-1.5.0/samples/bookinfo/networking/fault-injection-details-v1.yaml b/istio-1.5.0/samples/bookinfo/networking/fault-injection-details-v1.yaml new file mode 100644 index 0000000..c455092 --- /dev/null +++ b/istio-1.5.0/samples/bookinfo/networking/fault-injection-details-v1.yaml @@ -0,0 +1,32 @@ +apiVersion: networking.istio.io/v1alpha3 +kind: VirtualService +metadata: + name: details +spec: + hosts: + - details + http: + - fault: + abort: + httpStatus: 555 + percentage: + value: 100 + route: + - destination: + host: details + subset: v1 + - route: + - destination: + host: details + subset: v1 +--- +apiVersion: networking.istio.io/v1alpha3 +kind: DestinationRule +metadata: + name: details +spec: + host: details + subsets: + - name: v1 + labels: + version: v1 \ No newline at end of file diff --git a/istio-1.5.0/samples/bookinfo/networking/virtual-service-all-v1.yaml b/istio-1.5.0/samples/bookinfo/networking/virtual-service-all-v1.yaml new file mode 100644 index 0000000..6811e31 --- /dev/null +++ b/istio-1.5.0/samples/bookinfo/networking/virtual-service-all-v1.yaml @@ -0,0 +1,52 @@ +apiVersion: networking.istio.io/v1alpha3 +kind: VirtualService +metadata: + name: productpage +spec: + hosts: + - productpage + http: + - route: + - destination: + host: productpage + subset: v1 +--- +apiVersion: networking.istio.io/v1alpha3 +kind: VirtualService +metadata: + name: reviews +spec: + hosts: + - reviews + http: + - route: + - destination: + host: reviews + subset: v1 +--- +apiVersion: networking.istio.io/v1alpha3 +kind: VirtualService +metadata: + name: ratings +spec: + hosts: + - ratings + http: + - route: + - destination: + host: ratings + subset: v1 +--- +apiVersion: networking.istio.io/v1alpha3 +kind: VirtualService +metadata: + name: details +spec: + hosts: + - details + http: + - route: + - destination: + host: details + subset: v1 +--- diff --git a/istio-1.5.0/samples/bookinfo/networking/virtual-service-details-v2.yaml b/istio-1.5.0/samples/bookinfo/networking/virtual-service-details-v2.yaml new file mode 100644 index 0000000..5f21fa5 --- /dev/null +++ b/istio-1.5.0/samples/bookinfo/networking/virtual-service-details-v2.yaml @@ -0,0 +1,12 @@ +apiVersion: networking.istio.io/v1alpha3 +kind: VirtualService +metadata: + name: details +spec: + hosts: + - details + http: + - route: + - destination: + host: details + subset: v2 diff --git a/istio-1.5.0/samples/bookinfo/networking/virtual-service-ratings-db.yaml b/istio-1.5.0/samples/bookinfo/networking/virtual-service-ratings-db.yaml new file mode 100644 index 0000000..1698ec2 --- /dev/null +++ b/istio-1.5.0/samples/bookinfo/networking/virtual-service-ratings-db.yaml @@ -0,0 +1,26 @@ +apiVersion: networking.istio.io/v1alpha3 +kind: VirtualService +metadata: + name: reviews +spec: + hosts: + - reviews + http: + - route: + - destination: + host: reviews + subset: v3 +--- +apiVersion: networking.istio.io/v1alpha3 +kind: VirtualService +metadata: + name: ratings +spec: + hosts: + - ratings + http: + - route: + - destination: + host: ratings + subset: v2 +--- diff --git a/istio-1.5.0/samples/bookinfo/networking/virtual-service-ratings-mysql-vm.yaml b/istio-1.5.0/samples/bookinfo/networking/virtual-service-ratings-mysql-vm.yaml new file mode 100644 index 0000000..fdf8827 --- /dev/null +++ b/istio-1.5.0/samples/bookinfo/networking/virtual-service-ratings-mysql-vm.yaml @@ -0,0 +1,26 @@ +apiVersion: networking.istio.io/v1alpha3 +kind: VirtualService +metadata: + name: reviews +spec: + hosts: + - reviews + http: + - route: + - destination: + host: reviews + subset: v3 +--- +apiVersion: networking.istio.io/v1alpha3 +kind: VirtualService +metadata: + name: ratings +spec: + hosts: + - ratings + http: + - route: + - destination: + host: ratings + subset: v2-mysql-vm +--- diff --git a/istio-1.5.0/samples/bookinfo/networking/virtual-service-ratings-mysql.yaml b/istio-1.5.0/samples/bookinfo/networking/virtual-service-ratings-mysql.yaml new file mode 100644 index 0000000..03a700e --- /dev/null +++ b/istio-1.5.0/samples/bookinfo/networking/virtual-service-ratings-mysql.yaml @@ -0,0 +1,26 @@ +apiVersion: networking.istio.io/v1alpha3 +kind: VirtualService +metadata: + name: reviews +spec: + hosts: + - reviews + http: + - route: + - destination: + host: reviews + subset: v3 +--- +apiVersion: networking.istio.io/v1alpha3 +kind: VirtualService +metadata: + name: ratings +spec: + hosts: + - ratings + http: + - route: + - destination: + host: ratings + subset: v2-mysql +--- diff --git a/istio-1.5.0/samples/bookinfo/networking/virtual-service-ratings-test-abort.yaml b/istio-1.5.0/samples/bookinfo/networking/virtual-service-ratings-test-abort.yaml new file mode 100644 index 0000000..51c6fe9 --- /dev/null +++ b/istio-1.5.0/samples/bookinfo/networking/virtual-service-ratings-test-abort.yaml @@ -0,0 +1,25 @@ +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 diff --git a/istio-1.5.0/samples/bookinfo/networking/virtual-service-ratings-test-delay.yaml b/istio-1.5.0/samples/bookinfo/networking/virtual-service-ratings-test-delay.yaml new file mode 100644 index 0000000..6c4e19d --- /dev/null +++ b/istio-1.5.0/samples/bookinfo/networking/virtual-service-ratings-test-delay.yaml @@ -0,0 +1,25 @@ +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 diff --git a/istio-1.5.0/samples/bookinfo/networking/virtual-service-reviews-50-v3.yaml b/istio-1.5.0/samples/bookinfo/networking/virtual-service-reviews-50-v3.yaml new file mode 100644 index 0000000..aad8c31 --- /dev/null +++ b/istio-1.5.0/samples/bookinfo/networking/virtual-service-reviews-50-v3.yaml @@ -0,0 +1,17 @@ +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 diff --git a/istio-1.5.0/samples/bookinfo/networking/virtual-service-reviews-80-20.yaml b/istio-1.5.0/samples/bookinfo/networking/virtual-service-reviews-80-20.yaml new file mode 100644 index 0000000..7304d86 --- /dev/null +++ b/istio-1.5.0/samples/bookinfo/networking/virtual-service-reviews-80-20.yaml @@ -0,0 +1,17 @@ +apiVersion: networking.istio.io/v1alpha3 +kind: VirtualService +metadata: + name: reviews +spec: + hosts: + - reviews + http: + - route: + - destination: + host: reviews + subset: v1 + weight: 80 + - destination: + host: reviews + subset: v2 + weight: 20 diff --git a/istio-1.5.0/samples/bookinfo/networking/virtual-service-reviews-90-10.yaml b/istio-1.5.0/samples/bookinfo/networking/virtual-service-reviews-90-10.yaml new file mode 100644 index 0000000..d211dd1 --- /dev/null +++ b/istio-1.5.0/samples/bookinfo/networking/virtual-service-reviews-90-10.yaml @@ -0,0 +1,17 @@ +apiVersion: networking.istio.io/v1alpha3 +kind: VirtualService +metadata: + name: reviews +spec: + hosts: + - reviews + http: + - route: + - destination: + host: reviews + subset: v1 + weight: 90 + - destination: + host: reviews + subset: v2 + weight: 10 diff --git a/istio-1.5.0/samples/bookinfo/networking/virtual-service-reviews-jason-v2-v3.yaml b/istio-1.5.0/samples/bookinfo/networking/virtual-service-reviews-jason-v2-v3.yaml new file mode 100644 index 0000000..fb35713 --- /dev/null +++ b/istio-1.5.0/samples/bookinfo/networking/virtual-service-reviews-jason-v2-v3.yaml @@ -0,0 +1,20 @@ +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: v3 diff --git a/istio-1.5.0/samples/bookinfo/networking/virtual-service-reviews-test-v2.yaml b/istio-1.5.0/samples/bookinfo/networking/virtual-service-reviews-test-v2.yaml new file mode 100644 index 0000000..ea07efb --- /dev/null +++ b/istio-1.5.0/samples/bookinfo/networking/virtual-service-reviews-test-v2.yaml @@ -0,0 +1,20 @@ +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 diff --git a/istio-1.5.0/samples/bookinfo/networking/virtual-service-reviews-v2-v3.yaml b/istio-1.5.0/samples/bookinfo/networking/virtual-service-reviews-v2-v3.yaml new file mode 100644 index 0000000..7ae7b80 --- /dev/null +++ b/istio-1.5.0/samples/bookinfo/networking/virtual-service-reviews-v2-v3.yaml @@ -0,0 +1,17 @@ +apiVersion: networking.istio.io/v1alpha3 +kind: VirtualService +metadata: + name: reviews +spec: + hosts: + - reviews + http: + - route: + - destination: + host: reviews + subset: v2 + weight: 50 + - destination: + host: reviews + subset: v3 + weight: 50 diff --git a/istio-1.5.0/samples/bookinfo/networking/virtual-service-reviews-v3.yaml b/istio-1.5.0/samples/bookinfo/networking/virtual-service-reviews-v3.yaml new file mode 100644 index 0000000..5da999d --- /dev/null +++ b/istio-1.5.0/samples/bookinfo/networking/virtual-service-reviews-v3.yaml @@ -0,0 +1,12 @@ +apiVersion: networking.istio.io/v1alpha3 +kind: VirtualService +metadata: + name: reviews +spec: + hosts: + - reviews + http: + - route: + - destination: + host: reviews + subset: v3 diff --git a/istio-1.5.0/samples/bookinfo/platform/consul/README.md b/istio-1.5.0/samples/bookinfo/platform/consul/README.md new file mode 100644 index 0000000..a4405e1 --- /dev/null +++ b/istio-1.5.0/samples/bookinfo/platform/consul/README.md @@ -0,0 +1,71 @@ +# Consul Adapter for Istio on Docker + +Make Istio run in docker environment by integrating Consul as a service registry. + +## Disclaimer + +This example is not included in Istio's release verification testing, so it may not function exactly as documented. + +## Design Principle + +The key issue is how to implement the ServiceDiscovery interface functions in Istio. +This platform adapter uses Consul Server to help Istio monitor service instances running in the underlying platform. +When a service instance is brought up in docker, the [Registrator](http://gliderlabs.github.io/registrator/latest/) +automatically registers the service in Consul. + +Note that Istio pilot is running inside each app container so as to coordinate Envoy and the service mesh. + +## Prerequisites + +* Clone Istio Pilot [repo](https://github.com/istio/pilot) (required only if building images locally) + +* Download istioctl from Istio's [releases page](https://github.com/istio/istio/releases) or build from +source in Istio Pilot repository + +## Bookinfo Demo + +The ingress controller is still under construction, routing functionalities can be tested by curling a service container directly. + +To build all images for the bookinfo sample for the consul adapter, run: + +```bash +samples/bookinfo/src/build-services.sh +``` + +For Linux users, configure the `DOCKER_GATEWAY` environment variable + +```bash +export DOCKER_GATEWAY=172.28.0.1: +``` + +To bring up the control plane containers directly, from the root repository directory run + +```bash +docker-compose -f install/consul/istio.yaml up -d +``` + +This will pull images from docker hub to your local computing space. + +Now you can see all the containers in the mesh by running `docker ps -a`. + +If the webpage is not displaying properly, you may need to run the previous command once more to resolve a timing issue during start up. + +To bring up the app containers, from the `samples/bookinfo/consul` directory run + +```bash +docker-compose -f bookinfo.yaml up -d +``` + +To view the productpage webpage, open a web browser and enter `localhost:9081/productpage`. + +If you refresh the page several times, you should see different versions of reviews shown in productpage presented in a round robin style (red stars, black stars, no stars). + +Configure `kubectl` to use the locally mapped port for the Istio api server + +```bash +kubectl config set-context istio --cluster=istio +kubectl config set-cluster istio --server=http://localhost:8080 +kubectl config use-context istio +``` + +If you are an advanced consul and docker network user, you may choose to configure your own envoymesh network dns and consul port mapping and istio-apiserver ipv4_address in the `istio.yaml` file. diff --git a/istio-1.5.0/samples/bookinfo/platform/consul/bookinfo.yaml b/istio-1.5.0/samples/bookinfo/platform/consul/bookinfo.yaml new file mode 100644 index 0000000..c78ae3d --- /dev/null +++ b/istio-1.5.0/samples/bookinfo/platform/consul/bookinfo.yaml @@ -0,0 +1,128 @@ +# Copyright 2017 Istio Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +############################################################################ +version: '2' +services: + details-v1: + image: istio/examples-bookinfo-details-v1:1.15.0 + networks: + istiomesh: + dns: + - 172.28.0.1 + - 8.8.8.8 + dns_search: + - service.consul + environment: + - SERVICE_NAME=details + - SERVICE_TAGS=version|v1 + - SERVICE_PROTOCOL=http + - SERVICE_VERSION=v1 + expose: + - "9080" + + ratings-v1: + image: istio/examples-bookinfo-ratings-v1:1.15.0 + networks: + istiomesh: + dns: + - 172.28.0.1 + - 8.8.8.8 + dns_search: + - service.consul + environment: + - SERVICE_NAME=ratings + - SERVICE_TAGS=version|v1 + - SERVICE_PROTOCOL=http + - SERVICE_VERSION=v1 + expose: + - "9080" + + reviews-v1: + image: istio/examples-bookinfo-reviews-v1:1.15.0 + networks: + istiomesh: + dns: + - 172.28.0.1 + - 8.8.8.8 + dns_search: + - service.consul + environment: + - SERVICE_9080_NAME=reviews + - SERVICE_TAGS=version|v1 + - SERVICE_PROTOCOL=http + - SERVICE_9443_IGNORE=1 + - SERVICE_VERSION=v1 + expose: + - "9080" + + reviews-v2: + image: istio/examples-bookinfo-reviews-v2:1.15.0 + networks: + istiomesh: + dns: + - 172.28.0.1 + - 8.8.8.8 + dns_search: + - service.consul + environment: + - SERVICE_9080_NAME=reviews + - SERVICE_TAGS=version|v2 + - SERVICE_PROTOCOL=http + - SERVICE_9443_IGNORE=1 + - SERVICE_VERSION=v2 + expose: + - "9080" + + reviews-v3: + image: istio/examples-bookinfo-reviews-v3:1.15.0 + networks: + istiomesh: + dns: + - 172.28.0.1 + - 8.8.8.8 + dns_search: + - service.consul + environment: + - SERVICE_9080_NAME=reviews + - SERVICE_TAGS=version|v3 + - SERVICE_PROTOCOL=http + - SERVICE_9443_IGNORE=1 + - SERVICE_VERSION=v3 + expose: + - "9080" + + productpage-v1: + image: istio/examples-bookinfo-productpage-v1:1.15.0 + networks: + istiomesh: + ipv4_address: 172.28.0.14 + dns: + - 172.28.0.1 + - 8.8.8.8 + dns_search: + - service.consul + environment: + - SERVICE_NAME=productpage + - SERVICE_TAGS=version|v1 + - SERVICE_PROTOCOL=http + - SERVICE_VERSION=v1 + ports: + - "9081:9080" + expose: + - "9080" +networks: + istiomesh: + external: + name: consul_istiomesh diff --git a/istio-1.5.0/samples/bookinfo/platform/consul/cleanup.sh b/istio-1.5.0/samples/bookinfo/platform/consul/cleanup.sh new file mode 100755 index 0000000..2120b94 --- /dev/null +++ b/istio-1.5.0/samples/bookinfo/platform/consul/cleanup.sh @@ -0,0 +1,61 @@ +#!/bin/bash +# +# Copyright 2017 Istio Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +SCRIPTDIR=$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd ) + +# only ask if in interactive mode +if [[ -t 0 ]];then + echo -n "namespace ? [default] " + read -r NAMESPACE +fi + +if [[ -z ${NAMESPACE} ]];then + NAMESPACE=default +fi + +echo "using NAMESPACE=${NAMESPACE}" + +protos=( destinationrules virtualservices gateways ) +for proto in "${protos[@]}"; do + for resource in $(kubectl get -n ${NAMESPACE} "$proto" -o name); do + kubectl delete -n ${NAMESPACE} "$resource"; + done +done + +OUTPUT=$(mktemp) +export OUTPUT +echo "Application cleanup may take up to one minute" +docker-compose -f "$SCRIPTDIR/bookinfo.sidecars.yaml" down > "${OUTPUT}" 2>&1 +docker-compose -f "$SCRIPTDIR/bookinfo.yaml" down > "${OUTPUT}" 2>&1 +ret=$? +function cleanup() { + rm -f "${OUTPUT}" +} + +trap cleanup EXIT + +if [[ ${ret} -eq 0 ]];then + cat "${OUTPUT}" +else + # ignore NotFound errors + OUT2=$(grep -v NotFound "${OUTPUT}") + if [[ -n ${OUT2} ]];then + cat "${OUTPUT}" + exit ${ret} + fi +fi + +echo "Application cleanup successful" diff --git a/istio-1.5.0/samples/bookinfo/platform/consul/destination-rule-all.yaml b/istio-1.5.0/samples/bookinfo/platform/consul/destination-rule-all.yaml new file mode 100644 index 0000000..e28055a --- /dev/null +++ b/istio-1.5.0/samples/bookinfo/platform/consul/destination-rule-all.yaml @@ -0,0 +1,53 @@ +apiVersion: networking.istio.io/v1alpha3 +kind: DestinationRule +metadata: + name: productpage +spec: + host: productpage.service.consul + subsets: + - name: v1 + labels: + version: v1 +--- +apiVersion: networking.istio.io/v1alpha3 +kind: DestinationRule +metadata: + name: reviews +spec: + host: reviews.service.consul + subsets: + - name: v1 + labels: + version: v1 + - name: v2 + labels: + version: v2 + - name: v3 + labels: + version: v3 +--- +apiVersion: networking.istio.io/v1alpha3 +kind: DestinationRule +metadata: + name: ratings +spec: + host: ratings.service.consul + subsets: + - name: v1 + labels: + version: v1 +--- +apiVersion: networking.istio.io/v1alpha3 +kind: DestinationRule +metadata: + name: details +spec: + host: details.service.consul + subsets: + - name: v1 + labels: + version: v1 + - name: v2 + labels: + version: v2 +--- diff --git a/istio-1.5.0/samples/bookinfo/platform/consul/virtual-service-all-v1.yaml b/istio-1.5.0/samples/bookinfo/platform/consul/virtual-service-all-v1.yaml new file mode 100644 index 0000000..19b4772 --- /dev/null +++ b/istio-1.5.0/samples/bookinfo/platform/consul/virtual-service-all-v1.yaml @@ -0,0 +1,52 @@ +apiVersion: networking.istio.io/v1alpha3 +kind: VirtualService +metadata: + name: productpage +spec: + hosts: + - productpage.service.consul + http: + - route: + - destination: + host: productpage.service.consul + subset: v1 +--- +apiVersion: networking.istio.io/v1alpha3 +kind: VirtualService +metadata: + name: reviews +spec: + hosts: + - reviews.service.consul + http: + - route: + - destination: + host: reviews.service.consul + subset: v1 +--- +apiVersion: networking.istio.io/v1alpha3 +kind: VirtualService +metadata: + name: ratings +spec: + hosts: + - ratings.service.consul + http: + - route: + - destination: + host: ratings.service.consul + subset: v1 +--- +apiVersion: networking.istio.io/v1alpha3 +kind: VirtualService +metadata: + name: details +spec: + hosts: + - details.service.consul + http: + - route: + - destination: + host: details.service.consul + subset: v1 +--- diff --git a/istio-1.5.0/samples/bookinfo/platform/consul/virtual-service-ratings-test-abort.yaml b/istio-1.5.0/samples/bookinfo/platform/consul/virtual-service-ratings-test-abort.yaml new file mode 100644 index 0000000..f0c8f6d --- /dev/null +++ b/istio-1.5.0/samples/bookinfo/platform/consul/virtual-service-ratings-test-abort.yaml @@ -0,0 +1,25 @@ +apiVersion: networking.istio.io/v1alpha3 +kind: VirtualService +metadata: + name: ratings +spec: + hosts: + - ratings.service.consul + http: + - match: + - headers: + end-user: + exact: jason + fault: + abort: + percentage: + value: 100.0 + httpStatus: 500 + route: + - destination: + host: ratings.service.consul + subset: v1 + - route: + - destination: + host: ratings.service.consul + subset: v1 diff --git a/istio-1.5.0/samples/bookinfo/platform/consul/virtual-service-ratings-test-delay.yaml b/istio-1.5.0/samples/bookinfo/platform/consul/virtual-service-ratings-test-delay.yaml new file mode 100644 index 0000000..1978632 --- /dev/null +++ b/istio-1.5.0/samples/bookinfo/platform/consul/virtual-service-ratings-test-delay.yaml @@ -0,0 +1,25 @@ +apiVersion: networking.istio.io/v1alpha3 +kind: VirtualService +metadata: + name: ratings +spec: + hosts: + - ratings.service.consul + http: + - match: + - headers: + end-user: + exact: jason + fault: + delay: + percentage: + value: 100.0 + fixedDelay: 7s + route: + - destination: + host: ratings.service.consul + subset: v1 + - route: + - destination: + host: ratings.service.consul + subset: v1 diff --git a/istio-1.5.0/samples/bookinfo/platform/consul/virtual-service-reviews-50-v3.yaml b/istio-1.5.0/samples/bookinfo/platform/consul/virtual-service-reviews-50-v3.yaml new file mode 100644 index 0000000..7e91c8c --- /dev/null +++ b/istio-1.5.0/samples/bookinfo/platform/consul/virtual-service-reviews-50-v3.yaml @@ -0,0 +1,17 @@ +apiVersion: networking.istio.io/v1alpha3 +kind: VirtualService +metadata: + name: reviews +spec: + hosts: + - reviews.service.consul + http: + - route: + - destination: + host: reviews.service.consul + subset: v1 + weight: 50 + - destination: + host: reviews.service.consul + subset: v3 + weight: 50 diff --git a/istio-1.5.0/samples/bookinfo/platform/consul/virtual-service-reviews-test-v2.yaml b/istio-1.5.0/samples/bookinfo/platform/consul/virtual-service-reviews-test-v2.yaml new file mode 100644 index 0000000..92fa461 --- /dev/null +++ b/istio-1.5.0/samples/bookinfo/platform/consul/virtual-service-reviews-test-v2.yaml @@ -0,0 +1,20 @@ +apiVersion: networking.istio.io/v1alpha3 +kind: VirtualService +metadata: + name: reviews +spec: + hosts: + - reviews.service.consul + http: + - match: + - headers: + end-user: + exact: jason + route: + - destination: + host: reviews.service.consul + subset: v2 + - route: + - destination: + host: reviews.service.consul + subset: v1 diff --git a/istio-1.5.0/samples/bookinfo/platform/consul/virtual-service-reviews-v2-v3.yaml b/istio-1.5.0/samples/bookinfo/platform/consul/virtual-service-reviews-v2-v3.yaml new file mode 100644 index 0000000..60271c0 --- /dev/null +++ b/istio-1.5.0/samples/bookinfo/platform/consul/virtual-service-reviews-v2-v3.yaml @@ -0,0 +1,17 @@ +apiVersion: networking.istio.io/v1alpha3 +kind: VirtualService +metadata: + name: reviews +spec: + hosts: + - reviews.service.consul + http: + - route: + - destination: + host: reviews.service.consul + subset: v2 + weight: 50 + - destination: + host: reviews.service.consul + subset: v3 + weight: 50 diff --git a/istio-1.5.0/samples/bookinfo/platform/consul/virtual-service-reviews-v3.yaml b/istio-1.5.0/samples/bookinfo/platform/consul/virtual-service-reviews-v3.yaml new file mode 100644 index 0000000..da9440c --- /dev/null +++ b/istio-1.5.0/samples/bookinfo/platform/consul/virtual-service-reviews-v3.yaml @@ -0,0 +1,12 @@ +apiVersion: networking.istio.io/v1alpha3 +kind: VirtualService +metadata: + name: reviews +spec: + hosts: + - reviews.service.consul + http: + - route: + - destination: + host: reviews.service.consul + subset: v3 diff --git a/istio-1.5.0/samples/bookinfo/platform/kube/README.md b/istio-1.5.0/samples/bookinfo/platform/kube/README.md new file mode 100644 index 0000000..d1189be --- /dev/null +++ b/istio-1.5.0/samples/bookinfo/platform/kube/README.md @@ -0,0 +1,2 @@ +See the [Bookinfo guide](https://istio.io/docs/guides/bookinfo.html) in Istio +docs for instructions on how to run this demo application. diff --git a/istio-1.5.0/samples/bookinfo/platform/kube/bookinfo-certificate.yaml b/istio-1.5.0/samples/bookinfo/platform/kube/bookinfo-certificate.yaml new file mode 100644 index 0000000..bce874d --- /dev/null +++ b/istio-1.5.0/samples/bookinfo/platform/kube/bookinfo-certificate.yaml @@ -0,0 +1,37 @@ +--- +apiVersion: certmanager.k8s.io/v1alpha1 +kind: ClusterIssuer +metadata: + name: letsencrypt-staging + namespace: istio-system +spec: + acme: + # The ACME server URL + server: https://acme-staging-v02.api.letsencrypt.org/directory + # Email address used for ACME registration + email: stage@istio.io + # Name of a secret used to store the ACME account private key + privateKeySecretRef: + name: letsencrypt-staging + # Enable the HTTP-01 challenge provider + http01: {} +--- +apiVersion: certmanager.k8s.io/v1alpha1 +kind: Certificate +metadata: + name: istio-ingressgateway-certs + namespace: istio-system +spec: + secretName: istio-ingressgateway-certs + issuerRef: + name: letsencrypt-staging + kind: ClusterIssuer + commonName: bookinfo.example.com + dnsNames: + - bookinfo.example.com + acme: + config: + - http01: + ingressClass: none + domains: + - bookinfo.example.com diff --git a/istio-1.5.0/samples/bookinfo/platform/kube/bookinfo-db.yaml b/istio-1.5.0/samples/bookinfo/platform/kube/bookinfo-db.yaml new file mode 100644 index 0000000..e6ab9c1 --- /dev/null +++ b/istio-1.5.0/samples/bookinfo/platform/kube/bookinfo-db.yaml @@ -0,0 +1,53 @@ +# Copyright 2017 Istio Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +apiVersion: v1 +kind: Service +metadata: + name: mongodb + labels: + app: mongodb +spec: + ports: + - port: 27017 + name: mongo + selector: + app: mongodb +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: mongodb-v1 + labels: + app: mongodb + version: v1 +spec: + replicas: 1 + selector: + matchLabels: + app: mongodb + version: v1 + template: + metadata: + labels: + app: mongodb + version: v1 + spec: + containers: + - name: mongodb + image: istio/examples-bookinfo-mongodb:1.15.0 + imagePullPolicy: IfNotPresent + ports: + - containerPort: 27017 +--- diff --git a/istio-1.5.0/samples/bookinfo/platform/kube/bookinfo-details-v2.yaml b/istio-1.5.0/samples/bookinfo/platform/kube/bookinfo-details-v2.yaml new file mode 100644 index 0000000..e6fb123 --- /dev/null +++ b/istio-1.5.0/samples/bookinfo/platform/kube/bookinfo-details-v2.yaml @@ -0,0 +1,46 @@ +# Copyright 2017 Istio Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +################################################################################################## +# Details service v2 +################################################################################################## +apiVersion: apps/v1 +kind: Deployment +metadata: + name: details-v2 + labels: + app: details + version: v2 +spec: + replicas: 1 + selector: + matchLabels: + app: details + version: v2 + template: + metadata: + labels: + app: details + version: v2 + spec: + containers: + - name: details + image: docker.io/istio/examples-bookinfo-details-v2:1.15.0 + imagePullPolicy: IfNotPresent + ports: + - containerPort: 9080 + env: + - name: DO_NOT_ENCRYPT + value: "true" +--- diff --git a/istio-1.5.0/samples/bookinfo/platform/kube/bookinfo-details.yaml b/istio-1.5.0/samples/bookinfo/platform/kube/bookinfo-details.yaml new file mode 100644 index 0000000..bffaae2 --- /dev/null +++ b/istio-1.5.0/samples/bookinfo/platform/kube/bookinfo-details.yaml @@ -0,0 +1,56 @@ +# Copyright 2017 Istio Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +################################################################################################## +# Details service +################################################################################################## +apiVersion: v1 +kind: Service +metadata: + name: details + labels: + app: details +spec: + ports: + - port: 9080 + name: http + selector: + app: details +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: details-v1 + labels: + app: details + version: v1 +spec: + replicas: 1 + selector: + matchLabels: + app: details + version: v1 + template: + metadata: + labels: + app: details + version: v1 + spec: + containers: + - name: details + image: docker.io/istio/examples-bookinfo-details-v1:1.15.0 + imagePullPolicy: IfNotPresent + ports: + - containerPort: 9080 +--- diff --git a/istio-1.5.0/samples/bookinfo/platform/kube/bookinfo-ingress.yaml b/istio-1.5.0/samples/bookinfo/platform/kube/bookinfo-ingress.yaml new file mode 100644 index 0000000..0dd6561 --- /dev/null +++ b/istio-1.5.0/samples/bookinfo/platform/kube/bookinfo-ingress.yaml @@ -0,0 +1,44 @@ +# Copyright 2017 Istio Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +########################################################################### +# Ingress resource (gateway) +########################################################################## +apiVersion: extensions/v1beta1 +kind: Ingress +metadata: + name: gateway + annotations: + kubernetes.io/ingress.class: "istio" +spec: + rules: + - http: + paths: + - path: /productpage + backend: + serviceName: productpage + servicePort: 9080 + - path: /login + backend: + serviceName: productpage + servicePort: 9080 + - path: /logout + backend: + serviceName: productpage + servicePort: 9080 + - path: /api/v1/products.* + backend: + serviceName: productpage + servicePort: 9080 +--- diff --git a/istio-1.5.0/samples/bookinfo/platform/kube/bookinfo-mysql.yaml b/istio-1.5.0/samples/bookinfo/platform/kube/bookinfo-mysql.yaml new file mode 100644 index 0000000..9a8edd7 --- /dev/null +++ b/istio-1.5.0/samples/bookinfo/platform/kube/bookinfo-mysql.yaml @@ -0,0 +1,72 @@ +# Copyright 2017 Istio Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +################################################################################################## +# Mysql db services +# credentials: root/password +################################################################################################## +apiVersion: v1 +kind: Secret +metadata: + name: mysql-credentials +type: Opaque +data: + rootpasswd: cGFzc3dvcmQ= +--- +apiVersion: v1 +kind: Service +metadata: + name: mysqldb + labels: + app: mysqldb +spec: + ports: + - port: 3306 + name: tcp + selector: + app: mysqldb +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: mysqldb-v1 + labels: + app: mysqldb + version: v1 +spec: + replicas: 1 + selector: + matchLabels: + app: mysqldb + version: v1 + template: + metadata: + labels: + app: mysqldb + version: v1 + spec: + containers: + - name: mysqldb + image: docker.io/istio/examples-bookinfo-mysqldb:1.15.0 + imagePullPolicy: IfNotPresent + ports: + - containerPort: 3306 + env: + - name: MYSQL_ROOT_PASSWORD + valueFrom: + secretKeyRef: + name: mysql-credentials + key: rootpasswd + args: ["--default-authentication-plugin","mysql_native_password"] +--- diff --git a/istio-1.5.0/samples/bookinfo/platform/kube/bookinfo-ratings-discovery.yaml b/istio-1.5.0/samples/bookinfo/platform/kube/bookinfo-ratings-discovery.yaml new file mode 100644 index 0000000..fa63eb2 --- /dev/null +++ b/istio-1.5.0/samples/bookinfo/platform/kube/bookinfo-ratings-discovery.yaml @@ -0,0 +1,30 @@ +# Copyright 2017 Istio Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +################################################################################################## +# Ratings service +################################################################################################## +apiVersion: v1 +kind: Service +metadata: + name: ratings + labels: + app: ratings +spec: + ports: + - port: 9080 + name: http + selector: + app: ratings +--- diff --git a/istio-1.5.0/samples/bookinfo/platform/kube/bookinfo-ratings-v2-mysql-vm.yaml b/istio-1.5.0/samples/bookinfo/platform/kube/bookinfo-ratings-v2-mysql-vm.yaml new file mode 100644 index 0000000..364e7af --- /dev/null +++ b/istio-1.5.0/samples/bookinfo/platform/kube/bookinfo-ratings-v2-mysql-vm.yaml @@ -0,0 +1,53 @@ +# Copyright 2017 Istio Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +apiVersion: apps/v1 +kind: Deployment +metadata: + name: ratings-v2-mysql-vm + labels: + app: ratings + version: v2-mysql-vm +spec: + replicas: 1 + selector: + matchLabels: + app: ratings + version: v2-mysql-vm + template: + metadata: + labels: + app: ratings + version: v2-mysql-vm + spec: + containers: + - name: ratings + image: docker.io/istio/examples-bookinfo-ratings-v2:1.15.0 + imagePullPolicy: IfNotPresent + env: + # This assumes you registered your mysql vm as + # istioctl register -n vm mysqldb 1.2.3.4 3306 + - name: DB_TYPE + value: "mysql" + - name: MYSQL_DB_HOST + value: mysqldb.vm.svc.cluster.local + - name: MYSQL_DB_PORT + value: "3306" + - name: MYSQL_DB_USER + value: root + - name: MYSQL_DB_PASSWORD + value: password + ports: + - containerPort: 9080 +--- diff --git a/istio-1.5.0/samples/bookinfo/platform/kube/bookinfo-ratings-v2-mysql.yaml b/istio-1.5.0/samples/bookinfo/platform/kube/bookinfo-ratings-v2-mysql.yaml new file mode 100644 index 0000000..0a7745c --- /dev/null +++ b/istio-1.5.0/samples/bookinfo/platform/kube/bookinfo-ratings-v2-mysql.yaml @@ -0,0 +1,56 @@ +# Copyright 2017 Istio Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +apiVersion: apps/v1 +kind: Deployment +metadata: + name: ratings-v2-mysql + labels: + app: ratings + version: v2-mysql +spec: + replicas: 1 + selector: + matchLabels: + app: ratings + version: v2-mysql + template: + metadata: + labels: + app: ratings + version: v2-mysql + spec: + containers: + - name: ratings + image: docker.io/istio/examples-bookinfo-ratings-v2:1.15.0 + imagePullPolicy: IfNotPresent + env: + # ratings-v2 will use mongodb as the default db backend. + # if you would like to use mysqldb then you can use this file + # which sets DB_TYPE = 'mysql' and the rest of the parameters shown + # here and also create the # mysqldb service using bookinfo-mysql.yaml + # NOTE: This file is mutually exclusive to bookinfo-ratings-v2.yaml + - name: DB_TYPE + value: "mysql" + - name: MYSQL_DB_HOST + value: mysqldb + - name: MYSQL_DB_PORT + value: "3306" + - name: MYSQL_DB_USER + value: root + - name: MYSQL_DB_PASSWORD + value: password + ports: + - containerPort: 9080 +--- diff --git a/istio-1.5.0/samples/bookinfo/platform/kube/bookinfo-ratings-v2.yaml b/istio-1.5.0/samples/bookinfo/platform/kube/bookinfo-ratings-v2.yaml new file mode 100644 index 0000000..569bb1f --- /dev/null +++ b/istio-1.5.0/samples/bookinfo/platform/kube/bookinfo-ratings-v2.yaml @@ -0,0 +1,63 @@ +# Copyright 2017 Istio Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +apiVersion: v1 +kind: ServiceAccount +metadata: + name: bookinfo-ratings-v2 +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: ratings-v2 + labels: + app: ratings + version: v2 +spec: + replicas: 1 + selector: + matchLabels: + app: ratings + version: v2 + template: + metadata: + labels: + app: ratings + version: v2 + spec: + serviceAccountName: bookinfo-ratings-v2 + containers: + - name: ratings + image: docker.io/istio/examples-bookinfo-ratings-v2:1.15.0 + imagePullPolicy: IfNotPresent + env: + # ratings-v2 will use mongodb as the default db backend. + # if you would like to use mysqldb then set DB_TYPE = 'mysql', set + # the rest of the parameters shown here and also create the + # mysqldb service using bookinfo-mysql.yaml + # - name: DB_TYPE #default to + # value: "mysql" + # - name: MYSQL_DB_HOST + # value: mysqldb + # - name: MYSQL_DB_PORT + # value: "3306" + # - name: MYSQL_DB_USER + # value: root + # - name: MYSQL_DB_PASSWORD + # value: password + - name: MONGO_DB_URL + value: mongodb://mongodb:27017/test + ports: + - containerPort: 9080 +--- diff --git a/istio-1.5.0/samples/bookinfo/platform/kube/bookinfo-ratings.yaml b/istio-1.5.0/samples/bookinfo/platform/kube/bookinfo-ratings.yaml new file mode 100644 index 0000000..dab1c1f --- /dev/null +++ b/istio-1.5.0/samples/bookinfo/platform/kube/bookinfo-ratings.yaml @@ -0,0 +1,56 @@ +# Copyright 2017 Istio Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +################################################################################################## +# Ratings service +################################################################################################## +apiVersion: v1 +kind: Service +metadata: + name: ratings + labels: + app: ratings +spec: + ports: + - port: 9080 + name: http + selector: + app: ratings +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: ratings-v1 + labels: + app: ratings + version: v1 +spec: + replicas: 1 + selector: + matchLabels: + app: ratings + version: v1 + template: + metadata: + labels: + app: ratings + version: v1 + spec: + containers: + - name: ratings + image: docker.io/istio/examples-bookinfo-ratings-v1:1.15.0 + imagePullPolicy: IfNotPresent + ports: + - containerPort: 9080 +--- diff --git a/istio-1.5.0/samples/bookinfo/platform/kube/bookinfo-reviews-v2.yaml b/istio-1.5.0/samples/bookinfo/platform/kube/bookinfo-reviews-v2.yaml new file mode 100644 index 0000000..c4de438 --- /dev/null +++ b/istio-1.5.0/samples/bookinfo/platform/kube/bookinfo-reviews-v2.yaml @@ -0,0 +1,56 @@ +# Copyright 2017 Istio Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +################################################################################################## +# Reviews service v2 +################################################################################################## +apiVersion: apps/v1 +kind: Deployment +metadata: + name: reviews-v2 + labels: + app: reviews + version: v2 +spec: + replicas: 1 + selector: + matchLabels: + app: reviews + version: v2 + template: + metadata: + labels: + app: reviews + version: v2 + spec: + containers: + - name: reviews + image: docker.io/istio/examples-bookinfo-reviews-v2:1.15.0 + imagePullPolicy: IfNotPresent + env: + - name: LOG_DIR + value: "/tmp/logs" + ports: + - containerPort: 9080 + volumeMounts: + - name: tmp + mountPath: /tmp + - name: wlp-output + mountPath: /opt/ibm/wlp/output + volumes: + - name: wlp-output + emptyDir: {} + - name: tmp + emptyDir: {} +--- diff --git a/istio-1.5.0/samples/bookinfo/platform/kube/bookinfo.yaml b/istio-1.5.0/samples/bookinfo/platform/kube/bookinfo.yaml new file mode 100644 index 0000000..9883983 --- /dev/null +++ b/istio-1.5.0/samples/bookinfo/platform/kube/bookinfo.yaml @@ -0,0 +1,331 @@ +# Copyright 2017 Istio Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +################################################################################################## +# This file defines the services, service accounts, and deployments for the Bookinfo sample. +# +# To apply all 4 Bookinfo services, their corresponding service accounts, and deployments: +# +# kubectl apply -f samples/bookinfo/platform/kube/bookinfo.yaml +# +# Alternatively, you can deploy any resource separately: +# +# kubectl apply -f samples/bookinfo/platform/kube/bookinfo.yaml -l service=reviews # reviews Service +# kubectl apply -f samples/bookinfo/platform/kube/bookinfo.yaml -l account=reviews # reviews ServiceAccount +# kubectl apply -f samples/bookinfo/platform/kube/bookinfo.yaml -l app=reviews,version=v3 # reviews-v3 Deployment +################################################################################################## + +################################################################################################## +# Details service +################################################################################################## +apiVersion: v1 +kind: Service +metadata: + name: details + labels: + app: details + service: details +spec: + ports: + - port: 9080 + name: http + selector: + app: details +--- +apiVersion: v1 +kind: ServiceAccount +metadata: + name: bookinfo-details + labels: + account: details +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: details-v1 + labels: + app: details + version: v1 +spec: + replicas: 1 + selector: + matchLabels: + app: details + version: v1 + template: + metadata: + labels: + app: details + version: v1 + spec: + serviceAccountName: bookinfo-details + containers: + - name: details + image: docker.io/istio/examples-bookinfo-details-v1:1.15.0 + imagePullPolicy: IfNotPresent + ports: + - containerPort: 9080 +--- +################################################################################################## +# Ratings service +################################################################################################## +apiVersion: v1 +kind: Service +metadata: + name: ratings + labels: + app: ratings + service: ratings +spec: + ports: + - port: 9080 + name: http + selector: + app: ratings +--- +apiVersion: v1 +kind: ServiceAccount +metadata: + name: bookinfo-ratings + labels: + account: ratings +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: ratings-v1 + labels: + app: ratings + version: v1 +spec: + replicas: 1 + selector: + matchLabels: + app: ratings + version: v1 + template: + metadata: + labels: + app: ratings + version: v1 + spec: + serviceAccountName: bookinfo-ratings + containers: + - name: ratings + image: docker.io/istio/examples-bookinfo-ratings-v1:1.15.0 + imagePullPolicy: IfNotPresent + ports: + - containerPort: 9080 +--- +################################################################################################## +# Reviews service +################################################################################################## +apiVersion: v1 +kind: Service +metadata: + name: reviews + labels: + app: reviews + service: reviews +spec: + ports: + - port: 9080 + name: http + selector: + app: reviews +--- +apiVersion: v1 +kind: ServiceAccount +metadata: + name: bookinfo-reviews + labels: + account: reviews +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: reviews-v1 + labels: + app: reviews + version: v1 +spec: + replicas: 1 + selector: + matchLabels: + app: reviews + version: v1 + template: + metadata: + labels: + app: reviews + version: v1 + spec: + serviceAccountName: bookinfo-reviews + containers: + - name: reviews + image: docker.io/istio/examples-bookinfo-reviews-v1:1.15.0 + imagePullPolicy: IfNotPresent + env: + - name: LOG_DIR + value: "/tmp/logs" + ports: + - containerPort: 9080 + volumeMounts: + - name: tmp + mountPath: /tmp + - name: wlp-output + mountPath: /opt/ibm/wlp/output + volumes: + - name: wlp-output + emptyDir: {} + - name: tmp + emptyDir: {} +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: reviews-v2 + labels: + app: reviews + version: v2 +spec: + replicas: 1 + selector: + matchLabels: + app: reviews + version: v2 + template: + metadata: + labels: + app: reviews + version: v2 + spec: + serviceAccountName: bookinfo-reviews + containers: + - name: reviews + image: docker.io/istio/examples-bookinfo-reviews-v2:1.15.0 + imagePullPolicy: IfNotPresent + env: + - name: LOG_DIR + value: "/tmp/logs" + ports: + - containerPort: 9080 + volumeMounts: + - name: tmp + mountPath: /tmp + - name: wlp-output + mountPath: /opt/ibm/wlp/output + volumes: + - name: wlp-output + emptyDir: {} + - name: tmp + emptyDir: {} +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: reviews-v3 + labels: + app: reviews + version: v3 +spec: + replicas: 1 + selector: + matchLabels: + app: reviews + version: v3 + template: + metadata: + labels: + app: reviews + version: v3 + spec: + serviceAccountName: bookinfo-reviews + containers: + - name: reviews + image: docker.io/istio/examples-bookinfo-reviews-v3:1.15.0 + imagePullPolicy: IfNotPresent + env: + - name: LOG_DIR + value: "/tmp/logs" + ports: + - containerPort: 9080 + volumeMounts: + - name: tmp + mountPath: /tmp + - name: wlp-output + mountPath: /opt/ibm/wlp/output + volumes: + - name: wlp-output + emptyDir: {} + - name: tmp + emptyDir: {} +--- +################################################################################################## +# Productpage services +################################################################################################## +apiVersion: v1 +kind: Service +metadata: + name: productpage + labels: + app: productpage + service: productpage +spec: + ports: + - port: 9080 + name: http + selector: + app: productpage +--- +apiVersion: v1 +kind: ServiceAccount +metadata: + name: bookinfo-productpage + labels: + account: productpage +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: productpage-v1 + labels: + app: productpage + version: v1 +spec: + replicas: 1 + selector: + matchLabels: + app: productpage + version: v1 + template: + metadata: + labels: + app: productpage + version: v1 + spec: + serviceAccountName: bookinfo-productpage + containers: + - name: productpage + image: docker.io/istio/examples-bookinfo-productpage-v1:1.15.0 + imagePullPolicy: IfNotPresent + ports: + - containerPort: 9080 + volumeMounts: + - name: tmp + mountPath: /tmp + volumes: + - name: tmp + emptyDir: {} +--- diff --git a/istio-1.5.0/samples/bookinfo/platform/kube/cleanup.sh b/istio-1.5.0/samples/bookinfo/platform/kube/cleanup.sh new file mode 100755 index 0000000..1930237 --- /dev/null +++ b/istio-1.5.0/samples/bookinfo/platform/kube/cleanup.sh @@ -0,0 +1,60 @@ +#!/bin/bash +# +# Copyright 2017 Istio Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +SCRIPTDIR=$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd ) + +# only ask if in interactive mode +if [[ -t 0 && -z ${NAMESPACE} ]];then + echo -n "namespace ? [default] " + read -r NAMESPACE +fi + +if [[ -z ${NAMESPACE} ]];then + NAMESPACE=default +fi + +echo "using NAMESPACE=${NAMESPACE}" + +protos=( destinationrules virtualservices gateways ) +for proto in "${protos[@]}"; do + for resource in $(kubectl get -n ${NAMESPACE} "$proto" -o name); do + kubectl delete -n ${NAMESPACE} "$resource"; + done +done + +OUTPUT=$(mktemp) +export OUTPUT +echo "Application cleanup may take up to one minute" +kubectl delete -n ${NAMESPACE} -f "$SCRIPTDIR/bookinfo.yaml" > "${OUTPUT}" 2>&1 +ret=$? +function cleanup() { + rm -f "${OUTPUT}" +} + +trap cleanup EXIT + +if [[ ${ret} -eq 0 ]];then + cat "${OUTPUT}" +else + # ignore NotFound errors + OUT2=$(grep -v NotFound "${OUTPUT}") + if [[ -n ${OUT2} ]];then + cat "${OUTPUT}" + exit ${ret} + fi +fi + +echo "Application cleanup successful" diff --git a/istio-1.5.0/samples/bookinfo/platform/kube/productpage-nodeport.yaml b/istio-1.5.0/samples/bookinfo/platform/kube/productpage-nodeport.yaml new file mode 100644 index 0000000..00aa249 --- /dev/null +++ b/istio-1.5.0/samples/bookinfo/platform/kube/productpage-nodeport.yaml @@ -0,0 +1,32 @@ +# Copyright 2017 Istio Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +################################################################################################## +# Productpage services +################################################################################################## +apiVersion: v1 +kind: Service +metadata: + name: productpage + labels: + app: productpage + service: productpage +spec: + type: NodePort + ports: + - port: 9080 + name: http + selector: + app: productpage +--- diff --git a/istio-1.5.0/samples/bookinfo/platform/kube/rbac/details-reviews-policy-permissive.yaml b/istio-1.5.0/samples/bookinfo/platform/kube/rbac/details-reviews-policy-permissive.yaml new file mode 100644 index 0000000..24a7de4 --- /dev/null +++ b/istio-1.5.0/samples/bookinfo/platform/kube/rbac/details-reviews-policy-permissive.yaml @@ -0,0 +1,22 @@ +apiVersion: "rbac.istio.io/v1alpha1" +kind: ServiceRole +metadata: + name: details-reviews-viewer + namespace: default +spec: + rules: + - services: ["details.default.svc.cluster.local", "reviews.default.svc.cluster.local"] + methods: ["GET"] +--- +apiVersion: "rbac.istio.io/v1alpha1" +kind: ServiceRoleBinding +metadata: + name: bind-details-reviews + namespace: default +spec: + subjects: + - user: "cluster.local/ns/default/sa/bookinfo-productpage" + roleRef: + kind: ServiceRole + name: "details-reviews-viewer" + mode: PERMISSIVE diff --git a/istio-1.5.0/samples/bookinfo/platform/kube/rbac/details-reviews-policy.yaml b/istio-1.5.0/samples/bookinfo/platform/kube/rbac/details-reviews-policy.yaml new file mode 100644 index 0000000..7957714 --- /dev/null +++ b/istio-1.5.0/samples/bookinfo/platform/kube/rbac/details-reviews-policy.yaml @@ -0,0 +1,21 @@ +apiVersion: "rbac.istio.io/v1alpha1" +kind: ServiceRole +metadata: + name: details-reviews-viewer + namespace: default +spec: + rules: + - services: ["details.default.svc.cluster.local", "reviews.default.svc.cluster.local"] + methods: ["GET"] +--- +apiVersion: "rbac.istio.io/v1alpha1" +kind: ServiceRoleBinding +metadata: + name: bind-details-reviews + namespace: default +spec: + subjects: + - user: "cluster.local/ns/default/sa/bookinfo-productpage" + roleRef: + kind: ServiceRole + name: "details-reviews-viewer" diff --git a/istio-1.5.0/samples/bookinfo/platform/kube/rbac/mongodb-policy.yaml b/istio-1.5.0/samples/bookinfo/platform/kube/rbac/mongodb-policy.yaml new file mode 100644 index 0000000..03ff0a8 --- /dev/null +++ b/istio-1.5.0/samples/bookinfo/platform/kube/rbac/mongodb-policy.yaml @@ -0,0 +1,24 @@ +apiVersion: "rbac.istio.io/v1alpha1" +kind: ServiceRole +metadata: + name: mongodb-viewer + namespace: default +spec: + rules: + - services: ["mongodb.default.svc.cluster.local"] + constraints: + - key: "destination.port" + values: ["27017"] +--- +apiVersion: "rbac.istio.io/v1alpha1" +kind: ServiceRoleBinding +metadata: + name: bind-mongodb-viewer + namespace: default +spec: + subjects: + - user: "cluster.local/ns/default/sa/bookinfo-ratings-v2" + roleRef: + kind: ServiceRole + name: "mongodb-viewer" +--- diff --git a/istio-1.5.0/samples/bookinfo/platform/kube/rbac/namespace-policy.yaml b/istio-1.5.0/samples/bookinfo/platform/kube/rbac/namespace-policy.yaml new file mode 100644 index 0000000..ac6e4a7 --- /dev/null +++ b/istio-1.5.0/samples/bookinfo/platform/kube/rbac/namespace-policy.yaml @@ -0,0 +1,27 @@ +apiVersion: "rbac.istio.io/v1alpha1" +kind: ServiceRole +metadata: + name: service-viewer + namespace: default +spec: + rules: + - services: ["*"] + methods: ["GET"] + constraints: + - key: "destination.labels[app]" + values: ["productpage", "details", "reviews", "ratings"] +--- +apiVersion: "rbac.istio.io/v1alpha1" +kind: ServiceRoleBinding +metadata: + name: bind-service-viewer + namespace: default +spec: + subjects: + - properties: + source.namespace: "istio-system" + - properties: + source.namespace: "default" + roleRef: + kind: ServiceRole + name: "service-viewer" diff --git a/istio-1.5.0/samples/bookinfo/platform/kube/rbac/productpage-policy.yaml b/istio-1.5.0/samples/bookinfo/platform/kube/rbac/productpage-policy.yaml new file mode 100644 index 0000000..6758ef2 --- /dev/null +++ b/istio-1.5.0/samples/bookinfo/platform/kube/rbac/productpage-policy.yaml @@ -0,0 +1,21 @@ +apiVersion: "rbac.istio.io/v1alpha1" +kind: ServiceRole +metadata: + name: productpage-viewer + namespace: default +spec: + rules: + - services: ["productpage.default.svc.cluster.local"] + methods: ["GET"] +--- +apiVersion: "rbac.istio.io/v1alpha1" +kind: ServiceRoleBinding +metadata: + name: bind-productpage-viewer + namespace: default +spec: + subjects: + - user: "*" + roleRef: + kind: ServiceRole + name: "productpage-viewer" diff --git a/istio-1.5.0/samples/bookinfo/platform/kube/rbac/ratings-policy.yaml b/istio-1.5.0/samples/bookinfo/platform/kube/rbac/ratings-policy.yaml new file mode 100644 index 0000000..d0e4f2b --- /dev/null +++ b/istio-1.5.0/samples/bookinfo/platform/kube/rbac/ratings-policy.yaml @@ -0,0 +1,21 @@ +apiVersion: "rbac.istio.io/v1alpha1" +kind: ServiceRole +metadata: + name: ratings-viewer + namespace: default +spec: + rules: + - services: ["ratings.default.svc.cluster.local"] + methods: ["GET"] +--- +apiVersion: "rbac.istio.io/v1alpha1" +kind: ServiceRoleBinding +metadata: + name: bind-ratings + namespace: default +spec: + subjects: + - user: "cluster.local/ns/default/sa/bookinfo-reviews" + roleRef: + kind: ServiceRole + name: "ratings-viewer" diff --git a/istio-1.5.0/samples/bookinfo/platform/kube/rbac/rbac-config-ON.yaml b/istio-1.5.0/samples/bookinfo/platform/kube/rbac/rbac-config-ON.yaml new file mode 100644 index 0000000..534a500 --- /dev/null +++ b/istio-1.5.0/samples/bookinfo/platform/kube/rbac/rbac-config-ON.yaml @@ -0,0 +1,8 @@ +apiVersion: "rbac.istio.io/v1alpha1" +kind: ClusterRbacConfig +metadata: + name: default +spec: + mode: 'ON_WITH_INCLUSION' + inclusion: + namespaces: ["default"] diff --git a/istio-1.5.0/samples/bookinfo/platform/kube/rbac/rbac-config-on-mongodb.yaml b/istio-1.5.0/samples/bookinfo/platform/kube/rbac/rbac-config-on-mongodb.yaml new file mode 100644 index 0000000..9c22675 --- /dev/null +++ b/istio-1.5.0/samples/bookinfo/platform/kube/rbac/rbac-config-on-mongodb.yaml @@ -0,0 +1,9 @@ +apiVersion: "rbac.istio.io/v1alpha1" +kind: ClusterRbacConfig +metadata: + name: default +spec: + mode: 'ON_WITH_INCLUSION' + inclusion: + services: ["mongodb.default.svc.cluster.local"] +--- diff --git a/istio-1.5.0/samples/bookinfo/platform/kube/rbac/rbac-config-on-permissive.yaml b/istio-1.5.0/samples/bookinfo/platform/kube/rbac/rbac-config-on-permissive.yaml new file mode 100644 index 0000000..3b52651 --- /dev/null +++ b/istio-1.5.0/samples/bookinfo/platform/kube/rbac/rbac-config-on-permissive.yaml @@ -0,0 +1,9 @@ +apiVersion: "rbac.istio.io/v1alpha1" +kind: ClusterRbacConfig +metadata: + name: default +spec: + mode: 'ON_WITH_INCLUSION' + inclusion: + namespaces: ["default"] + enforcement_mode: PERMISSIVE diff --git a/istio-1.5.0/samples/bookinfo/platform/kube/rbac/rbac-permissive-telemetry.yaml b/istio-1.5.0/samples/bookinfo/platform/kube/rbac/rbac-permissive-telemetry.yaml new file mode 100644 index 0000000..1da9508 --- /dev/null +++ b/istio-1.5.0/samples/bookinfo/platform/kube/rbac/rbac-permissive-telemetry.yaml @@ -0,0 +1,47 @@ +# Configuration for logentry instances +apiVersion: "config.istio.io/v1alpha2" +kind: instance +metadata: + name: rbacsamplelog + namespace: istio-system +spec: + compiledTemplate: logentry + params: + severity: '"warning"' + timestamp: request.time + variables: + source: source.labels["app"] | source.workload.name | "unknown" + user: source.user | "unknown" + destination: destination.labels["app"] | destination.workload.name | "unknown" + responseCode: response.code | 0 + responseSize: response.size | 0 + latency: response.duration | "0ms" + permissiveResponseCode: rbac.permissive.response_code | "" + permissiveResponsePolicyID: rbac.permissive.effective_policy_id | "" + monitored_resource_type: '"UNSPECIFIED"' +--- +# Configuration for a stdio handler +apiVersion: "config.istio.io/v1alpha2" +kind: handler +metadata: + name: rbacsamplehandler + namespace: istio-system +spec: + compiledAdapter: stdio + params: + severity_levels: + warning: 1 # Params.Level.WARNING + outputAsJson: true +--- +# Rule to send logentry instances to a stdio handler +apiVersion: "config.istio.io/v1alpha2" +kind: rule +metadata: + name: rabcsamplestdio + namespace: istio-system +spec: + actions: + - handler: rbacsamplehandler + instances: [ rbacsamplelog ] +--- + diff --git a/istio-1.5.0/samples/bookinfo/policy/mixer-rule-deny-ip-crd.yaml b/istio-1.5.0/samples/bookinfo/policy/mixer-rule-deny-ip-crd.yaml new file mode 100644 index 0000000..63fc5e6 --- /dev/null +++ b/istio-1.5.0/samples/bookinfo/policy/mixer-rule-deny-ip-crd.yaml @@ -0,0 +1,29 @@ +apiVersion: config.istio.io/v1alpha2 +kind: listchecker +metadata: + name: whitelistip +spec: + # providerUrl: ordinarily black and white lists are maintained + # externally and fetched asynchronously using the providerUrl. + overrides: ["10.57.0.0/16"] # overrides provide a static list + blacklist: false + entryType: IP_ADDRESSES +--- +apiVersion: config.istio.io/v1alpha2 +kind: listentry +metadata: + name: sourceip +spec: + value: source.ip | ip("0.0.0.0") +--- +apiVersion: config.istio.io/v1alpha2 +kind: rule +metadata: + name: checkip +spec: + match: source.labels["istio"] == "ingressgateway" + actions: + - handler: whitelistip.listchecker + instances: + - sourceip.listentry +--- diff --git a/istio-1.5.0/samples/bookinfo/policy/mixer-rule-deny-ip.yaml b/istio-1.5.0/samples/bookinfo/policy/mixer-rule-deny-ip.yaml new file mode 100644 index 0000000..b771fd6 --- /dev/null +++ b/istio-1.5.0/samples/bookinfo/policy/mixer-rule-deny-ip.yaml @@ -0,0 +1,32 @@ +apiVersion: config.istio.io/v1alpha2 +kind: handler +metadata: + name: whitelistip +spec: + compiledAdapter: listchecker + params: + # providerUrl: ordinarily black and white lists are maintained + # externally and fetched asynchronously using the providerUrl. + overrides: ["10.57.0.0/16"] # overrides provide a static list + blacklist: false + entryType: IP_ADDRESSES +--- +apiVersion: config.istio.io/v1alpha2 +kind: instance +metadata: + name: sourceip +spec: + compiledTemplate: listentry + params: + value: source.ip | ip("0.0.0.0") +--- +apiVersion: config.istio.io/v1alpha2 +kind: rule +metadata: + name: checkip +spec: + match: source.labels["istio"] == "ingressgateway" + actions: + - handler: whitelistip + instances: [ sourceip ] +--- diff --git a/istio-1.5.0/samples/bookinfo/policy/mixer-rule-deny-label-crd.yaml b/istio-1.5.0/samples/bookinfo/policy/mixer-rule-deny-label-crd.yaml new file mode 100644 index 0000000..249d505 --- /dev/null +++ b/istio-1.5.0/samples/bookinfo/policy/mixer-rule-deny-label-crd.yaml @@ -0,0 +1,24 @@ +apiVersion: "config.istio.io/v1alpha2" +kind: denier +metadata: + name: denyreviewsv3handler +spec: + status: + code: 7 + message: Not allowed +--- +apiVersion: "config.istio.io/v1alpha2" +kind: checknothing +metadata: + name: denyreviewsv3request +spec: +--- +apiVersion: "config.istio.io/v1alpha2" +kind: rule +metadata: + name: denyreviewsv3 +spec: + match: destination.labels["app"] == "ratings" && source.labels["app"]=="reviews" && source.labels["version"] == "v3" + actions: + - handler: denyreviewsv3handler.denier + instances: [ denyreviewsv3request.checknothing ] diff --git a/istio-1.5.0/samples/bookinfo/policy/mixer-rule-deny-label.yaml b/istio-1.5.0/samples/bookinfo/policy/mixer-rule-deny-label.yaml new file mode 100644 index 0000000..0d1e85e --- /dev/null +++ b/istio-1.5.0/samples/bookinfo/policy/mixer-rule-deny-label.yaml @@ -0,0 +1,27 @@ +apiVersion: "config.istio.io/v1alpha2" +kind: handler +metadata: + name: denyreviewsv3handler +spec: + compiledAdapter: denier + params: + status: + code: 7 + message: Not allowed +--- +apiVersion: "config.istio.io/v1alpha2" +kind: instance +metadata: + name: denyreviewsv3request +spec: + compiledTemplate: checknothing +--- +apiVersion: "config.istio.io/v1alpha2" +kind: rule +metadata: + name: denyreviewsv3 +spec: + match: destination.labels["app"] == "ratings" && source.labels["app"]=="reviews" && source.labels["version"] == "v3" + actions: + - handler: denyreviewsv3handler + instances: [ denyreviewsv3request ] diff --git a/istio-1.5.0/samples/bookinfo/policy/mixer-rule-deny-serviceaccount.yaml b/istio-1.5.0/samples/bookinfo/policy/mixer-rule-deny-serviceaccount.yaml new file mode 100644 index 0000000..c7b91c1 --- /dev/null +++ b/istio-1.5.0/samples/bookinfo/policy/mixer-rule-deny-serviceaccount.yaml @@ -0,0 +1,27 @@ +apiVersion: "config.istio.io/v1alpha2" +kind: handler +metadata: + name: denyproductpagehandler +spec: + compiledAdapter: denier + params: + status: + code: 7 + message: Not allowed +--- +apiVersion: "config.istio.io/v1alpha2" +kind: instance +metadata: + name: denyproductpagerequest +spec: + compiledTemplate: checknothing +--- +apiVersion: "config.istio.io/v1alpha2" +kind: rule +metadata: + name: denyproductpage +spec: + match: destination.labels["app"] == "details" && source.user == "cluster.local/ns/default/sa/bookinfo-productpage" + actions: + - handler: denyproductpagehandler + instances: [ denyproductpagerequest ] diff --git a/istio-1.5.0/samples/bookinfo/policy/mixer-rule-deny-whitelist-crd.yaml b/istio-1.5.0/samples/bookinfo/policy/mixer-rule-deny-whitelist-crd.yaml new file mode 100644 index 0000000..7486e6e --- /dev/null +++ b/istio-1.5.0/samples/bookinfo/policy/mixer-rule-deny-whitelist-crd.yaml @@ -0,0 +1,28 @@ +apiVersion: config.istio.io/v1alpha2 +kind: listchecker +metadata: + name: whitelist +spec: + # providerUrl: ordinarily black and white lists are maintained + # externally and fetched asynchronously using the providerUrl. + overrides: ["v1", "v2"] # overrides provide a static list + blacklist: false +--- +apiVersion: config.istio.io/v1alpha2 +kind: listentry +metadata: + name: appversion +spec: + value: source.labels["version"] +--- +apiVersion: config.istio.io/v1alpha2 +kind: rule +metadata: + name: checkversion +spec: + match: destination.labels["app"] == "ratings" + actions: + - handler: whitelist.listchecker + instances: + - appversion.listentry +--- diff --git a/istio-1.5.0/samples/bookinfo/policy/mixer-rule-deny-whitelist.yaml b/istio-1.5.0/samples/bookinfo/policy/mixer-rule-deny-whitelist.yaml new file mode 100644 index 0000000..4c51279 --- /dev/null +++ b/istio-1.5.0/samples/bookinfo/policy/mixer-rule-deny-whitelist.yaml @@ -0,0 +1,31 @@ +apiVersion: config.istio.io/v1alpha2 +kind: handler +metadata: + name: whitelist +spec: + compiledAdapter: listchecker + params: + # providerUrl: ordinarily black and white lists are maintained + # externally and fetched asynchronously using the providerUrl. + overrides: ["v1", "v2"] # overrides provide a static list + blacklist: false +--- +apiVersion: config.istio.io/v1alpha2 +kind: instance +metadata: + name: appversion +spec: + compiledTemplate: listentry + params: + value: source.labels["version"] +--- +apiVersion: config.istio.io/v1alpha2 +kind: rule +metadata: + name: checkversion +spec: + match: destination.labels["app"] == "ratings" + actions: + - handler: whitelist + instances: [ appversion ] +--- diff --git a/istio-1.5.0/samples/bookinfo/policy/mixer-rule-ingress-denial.yaml b/istio-1.5.0/samples/bookinfo/policy/mixer-rule-ingress-denial.yaml new file mode 100644 index 0000000..0199373 --- /dev/null +++ b/istio-1.5.0/samples/bookinfo/policy/mixer-rule-ingress-denial.yaml @@ -0,0 +1,30 @@ +apiVersion: "config.istio.io/v1alpha2" +kind: handler +metadata: + name: handler + namespace: istio-system +spec: + compiledAdapter: denier + params: + status: + code: 7 + message: Not allowed +--- +apiVersion: "config.istio.io/v1alpha2" +kind: instance +metadata: + name: denyrequest + namespace: istio-system +spec: + compiledTemplate: checknothing +--- +apiVersion: "config.istio.io/v1alpha2" +kind: rule +metadata: + name: denyingress + namespace: istio-system +spec: + match: (source.labels["istio"] | "") == "ingressgateway" && (request.headers["x-user"] | "") == "john" + actions: + - handler: handler + instances: [ denyrequest ] diff --git a/istio-1.5.0/samples/bookinfo/policy/mixer-rule-kubernetesenv-telemetry.yaml b/istio-1.5.0/samples/bookinfo/policy/mixer-rule-kubernetesenv-telemetry.yaml new file mode 100644 index 0000000..10c2c95 --- /dev/null +++ b/istio-1.5.0/samples/bookinfo/policy/mixer-rule-kubernetesenv-telemetry.yaml @@ -0,0 +1,56 @@ +apiVersion: "config.istio.io/v1alpha2" +kind: handler +metadata: + name: kubeenvhandler + namespace: istio-system +spec: + compiledAdapter: prometheus + params: + metrics: + - name: kube_request_count + instance_name: kubeenvrequestcount.instance.istio-system + kind: COUNTER + label_names: + - response_code + - source_pod + - source_workload_uid + - source_workload + - source_owner + - destination_pod + - destination_workload_uid + - destination_workload + - destination_owner + - destination_container +--- +apiVersion: "config.istio.io/v1alpha2" +kind: instance +metadata: + name: kubeenvrequestcount + namespace: istio-system +spec: + compiledTemplate: metric + params: + value: "1" + dimensions: + response_code: response.code | 200 + source_pod: source.name | "unknown" + source_workload_uid: source.workload.uid | "unknown" + source_workload: source.workload.name | "unknown" + source_owner: source.owner | "unknown" + destination_pod: destination.name | "unknown" + destination_workload: destination.workload.name | "unknown" + destination_workload_uid: destination.workload.uid | "unknown" + destination_owner: destination.owner | "unknown" + destination_container: destination.container.name | "unknown" + monitored_resource_type: '"UNSPECIFIED"' +--- +apiVersion: "config.istio.io/v1alpha2" +kind: rule +metadata: + name: promkubeenv + namespace: istio-system +spec: + match: "true" + actions: + - handler: kubeenvhandler + instances: [ kubeenvrequestcount ] diff --git a/istio-1.5.0/samples/bookinfo/policy/mixer-rule-productpage-ratelimit-crd.yaml b/istio-1.5.0/samples/bookinfo/policy/mixer-rule-productpage-ratelimit-crd.yaml new file mode 100644 index 0000000..2262035 --- /dev/null +++ b/istio-1.5.0/samples/bookinfo/policy/mixer-rule-productpage-ratelimit-crd.yaml @@ -0,0 +1,81 @@ +apiVersion: config.istio.io/v1alpha2 +kind: memquota +metadata: + name: handler + namespace: istio-system +spec: + quotas: + - name: requestcount.quota.istio-system + maxAmount: 500 + validDuration: 1s + # The first matching override is applied. + # A requestcount instance is checked against override dimensions. + overrides: + # The following override applies to 'reviews' regardless + # of the source. + - dimensions: + destination: reviews + maxAmount: 1 + validDuration: 5s + # The following override applies to 'productpage' when + # the source is a specific ip address. + - dimensions: + destination: productpage + source: "10.28.11.20" + maxAmount: 500 + validDuration: 1s + # The following override applies to 'productpage' regardless + # of the source. + - dimensions: + destination: productpage + maxAmount: 2 + validDuration: 5s +--- +apiVersion: config.istio.io/v1alpha2 +kind: quota +metadata: + name: requestcount + namespace: istio-system +spec: + dimensions: + source: request.headers["x-forwarded-for"] | "unknown" + destination: destination.labels["app"] | destination.service.name | "unknown" + destinationVersion: destination.labels["version"] | "unknown" +--- +apiVersion: config.istio.io/v1alpha2 +kind: QuotaSpec +metadata: + name: request-count + namespace: istio-system +spec: + rules: + - quotas: + - charge: 1 + quota: requestcount +--- +apiVersion: config.istio.io/v1alpha2 +kind: QuotaSpecBinding +metadata: + name: request-count + namespace: istio-system +spec: + quotaSpecs: + - name: request-count + namespace: istio-system + services: + - name: productpage + namespace: default + # - service: '*' # Uncomment this to bind *all* services to request-count +--- +apiVersion: config.istio.io/v1alpha2 +kind: rule +metadata: + name: quota + namespace: istio-system +spec: + # quota only applies if you are not logged in. + # match: match(request.headers["cookie"], "user=*") == false + actions: + - handler: handler.memquota + instances: + - requestcount.quota diff --git a/istio-1.5.0/samples/bookinfo/policy/mixer-rule-productpage-ratelimit.yaml b/istio-1.5.0/samples/bookinfo/policy/mixer-rule-productpage-ratelimit.yaml new file mode 100644 index 0000000..5b2233b --- /dev/null +++ b/istio-1.5.0/samples/bookinfo/policy/mixer-rule-productpage-ratelimit.yaml @@ -0,0 +1,85 @@ +apiVersion: config.istio.io/v1alpha2 +kind: handler +metadata: + name: quotahandler + namespace: istio-system +spec: + compiledAdapter: memquota + params: + quotas: + - name: requestcountquota.instance.istio-system + maxAmount: 500 + validDuration: 1s + # The first matching override is applied. + # A requestcount instance is checked against override dimensions. + overrides: + # The following override applies to 'reviews' regardless + # of the source. + - dimensions: + destination: reviews + maxAmount: 1 + validDuration: 5s + # The following override applies to 'productpage' when + # the source is a specific ip address. + - dimensions: + destination: productpage + source: "10.28.11.20" + maxAmount: 500 + validDuration: 1s + # The following override applies to 'productpage' regardless + # of the source. + - dimensions: + destination: productpage + maxAmount: 2 + validDuration: 5s +--- +apiVersion: config.istio.io/v1alpha2 +kind: instance +metadata: + name: requestcountquota + namespace: istio-system +spec: + compiledTemplate: quota + params: + dimensions: + source: request.headers["x-forwarded-for"] | "unknown" + destination: destination.labels["app"] | destination.service.name | "unknown" + destinationVersion: destination.labels["version"] | "unknown" +--- +apiVersion: config.istio.io/v1alpha2 +kind: QuotaSpec +metadata: + name: request-count + namespace: istio-system +spec: + rules: + - quotas: + - charge: 1 + quota: requestcountquota +--- +apiVersion: config.istio.io/v1alpha2 +kind: QuotaSpecBinding +metadata: + name: request-count + namespace: istio-system +spec: + quotaSpecs: + - name: request-count + namespace: istio-system + services: + - name: productpage + namespace: default + # - service: '*' # Uncomment this to bind *all* services to request-count +--- +apiVersion: config.istio.io/v1alpha2 +kind: rule +metadata: + name: quota + namespace: istio-system +spec: + # quota only applies if you are not logged in. + # match: match(request.headers["cookie"], "user=*") == false + actions: + - handler: quotahandler + instances: + - requestcountquota diff --git a/istio-1.5.0/samples/bookinfo/policy/mixer-rule-productpage-redis-quota-fixed-window.yaml b/istio-1.5.0/samples/bookinfo/policy/mixer-rule-productpage-redis-quota-fixed-window.yaml new file mode 100644 index 0000000..85787a2 --- /dev/null +++ b/istio-1.5.0/samples/bookinfo/policy/mixer-rule-productpage-redis-quota-fixed-window.yaml @@ -0,0 +1,83 @@ +apiVersion: config.istio.io/v1alpha2 +kind: handler +metadata: + name: redishandler + namespace: istio-system +spec: + compiledAdapter: redisquota + params: + redisServerUrl: redis-release-master:6379 + connectionPoolSize: 10 + quotas: + - name: requestcountquota.instance.istio-system + maxAmount: 1 + validDuration: 30s + rateLimitAlgorithm: FIXED_WINDOW + # The first matching override is applied. + # A requestquotacount instance is checked against override dimensions. + overrides: + # The following override applies to 'productpage' when + # the source is 'istio-ingressgateway'. + - dimensions: + destination: productpage + source: istio-ingressgateway + maxAmount: 50 +--- +apiVersion: config.istio.io/v1alpha2 +kind: instance +metadata: + name: requestcountquota + namespace: istio-system +spec: + compiledTemplate: quota + params: + dimensions: + source: source.labels["app"] | "unknown" + sourceVersion: source.labels["version"] | "unknown" + destination: destination.labels["app"] | "unknown" + destinationVersion: destination.labels["version"] | "unknown" +--- +apiVersion: config.istio.io/v1alpha2 +kind: QuotaSpec +metadata: + name: request-count + namespace: istio-system +spec: + rules: + - quotas: + - charge: 1 + quota: requestcountquota +--- +# Note: change the default namespace to the namespace of the bookinfo app +apiVersion: config.istio.io/v1alpha2 +kind: QuotaSpecBinding +metadata: + name: request-count + namespace: istio-system +spec: + quotaSpecs: + - name: request-count + namespace: istio-system + services: + - name: ratings + namespace: default + - name: reviews + namespace: default + - name: details + namespace: default + - name: productpage + namespace: default + - name: istio-ingressgateway + namespace: istio-system +--- +apiVersion: config.istio.io/v1alpha2 +kind: rule +metadata: + name: quota + namespace: istio-system +spec: + match: (destination.labels["app"]|"unknown") == "productpage" + actions: + - handler: redishandler + instances: + - requestcountquota diff --git a/istio-1.5.0/samples/bookinfo/policy/mixer-rule-productpage-redis-quota-rolling-window.yaml b/istio-1.5.0/samples/bookinfo/policy/mixer-rule-productpage-redis-quota-rolling-window.yaml new file mode 100644 index 0000000..ec524b9 --- /dev/null +++ b/istio-1.5.0/samples/bookinfo/policy/mixer-rule-productpage-redis-quota-rolling-window.yaml @@ -0,0 +1,87 @@ +apiVersion: config.istio.io/v1alpha2 +kind: handler +metadata: + name: redishandler + namespace: istio-system +spec: + compiledAdapter: redisquota + params: + redisServerUrl: redis-release-master:6379 + connectionPoolSize: 10 + quotas: + - name: requestcountquota.instance.istio-system + maxAmount: 500 + validDuration: 1s + bucketDuration: 500ms + rateLimitAlgorithm: ROLLING_WINDOW + # The first matching override is applied. + # A requestcount instance is checked against override dimensions. + overrides: + # The following override applies to 'reviews' regardless + # of the source. + - dimensions: + destination: reviews + maxAmount: 1 + # The following override applies to 'productpage' when + # the source is a specific ip address. + - dimensions: + destination: productpage + source: "10.28.11.20" + maxAmount: 500 + # The following override applies to 'productpage' regardless + # of the source. + - dimensions: + destination: productpage + maxAmount: 2 +--- +apiVersion: config.istio.io/v1alpha2 +kind: instance +metadata: + name: requestcountquota + namespace: istio-system +spec: + compiledTemplate: quota + params: + dimensions: + source: request.headers["x-forwarded-for"] | "unknown" + destination: destination.labels["app"] | destination.workload.name | "unknown" + destinationVersion: destination.labels["version"] | "unknown" +--- +apiVersion: config.istio.io/v1alpha2 +kind: QuotaSpec +metadata: + name: request-count + namespace: istio-system +spec: + rules: + - quotas: + - charge: 1 + quota: requestcountquota +--- +apiVersion: config.istio.io/v1alpha2 +kind: QuotaSpecBinding +metadata: + name: request-count + namespace: istio-system +spec: + quotaSpecs: + - name: request-count + namespace: istio-system + services: + - name: productpage + namespace: default + # - service: '*' # Uncomment this to bind *all* services to request-count +--- +apiVersion: config.istio.io/v1alpha2 +kind: rule +metadata: + name: quota + namespace: istio-system +spec: + # quota only applies if you are not logged in. + # match: match(request.headers["cookie"], "session=*") == false + actions: + - handler: redishandler + instances: + - requestcountquota +--- diff --git a/istio-1.5.0/samples/bookinfo/policy/mixer-rule-ratings-denial.yaml b/istio-1.5.0/samples/bookinfo/policy/mixer-rule-ratings-denial.yaml new file mode 100644 index 0000000..4239b03 --- /dev/null +++ b/istio-1.5.0/samples/bookinfo/policy/mixer-rule-ratings-denial.yaml @@ -0,0 +1,31 @@ +apiVersion: "config.istio.io/v1alpha2" +kind: handler +metadata: + name: denierhandler + namespace: istio-system +spec: + compiledAdapter: denier + params: + status: + code: 7 + message: Not allowed +--- +apiVersion: "config.istio.io/v1alpha2" +kind: instance +metadata: + name: denyrequest + namespace: istio-system +spec: + compiledTemplate: checknothing +--- +apiVersion: "config.istio.io/v1alpha2" +kind: rule +metadata: + name: denyreviewsv3 + namespace: istio-system +spec: + #FIXME match: destination.labels["app"]=="productpage" && request.headers["x-user"] == "" + match: (request.headers["x-user"] | "") == "john" + actions: + - handler: denierhandler + instances: [ denyrequest ] diff --git a/istio-1.5.0/samples/bookinfo/policy/mixer-rule-ratings-ratelimit.yaml b/istio-1.5.0/samples/bookinfo/policy/mixer-rule-ratings-ratelimit.yaml new file mode 100644 index 0000000..4989262 --- /dev/null +++ b/istio-1.5.0/samples/bookinfo/policy/mixer-rule-ratings-ratelimit.yaml @@ -0,0 +1,81 @@ +apiVersion: "config.istio.io/v1alpha2" +kind: handler +metadata: + name: quotahandler + namespace: istio-system +spec: + compiledAdapter: memquota + params: + quotas: + - name: requestcountquota.instance.istio-system + maxAmount: 5000 + validDuration: 1s + # The first matching override is applied. + # A requestcount instance is checked against override dimensions. + overrides: + # The following override applies to 'ratings' when + # the source is 'reviews'. + - dimensions: + destination: ratings + source: reviews + maxAmount: 1 + validDuration: 1s + # The following override applies to 'ratings' regardless + # of the source. + - dimensions: + destination: ratings + maxAmount: 100 + validDuration: 1s + +--- +apiVersion: "config.istio.io/v1alpha2" +kind: instance +metadata: + name: requestcountquota + namespace: istio-system +spec: + compiledTemplate: quota + params: + dimensions: + source: source.labels["app"] | "unknown" + sourceVersion: source.labels["version"] | "unknown" + destination: destination.labels["app"] | destination.service.name | "unknown" + destinationVersion: destination.labels["version"] | "unknown" +--- +apiVersion: "config.istio.io/v1alpha2" +kind: rule +metadata: + name: quota + namespace: istio-system +spec: + actions: + - handler: quotahandler + instances: + - requestcountquota +--- +apiVersion: config.istio.io/v1alpha2 +kind: QuotaSpec +metadata: + name: request-count + namespace: istio-system +spec: + rules: + - quotas: + - charge: 1 + quota: requestcountquota +--- +apiVersion: config.istio.io/v1alpha2 +kind: QuotaSpecBinding +metadata: + name: request-count + namespace: istio-system +spec: + quotaSpecs: + - name: request-count + namespace: istio-system + services: + - name: ratings + - name: reviews + - name: details + - name: productpage + diff --git a/istio-1.5.0/samples/bookinfo/policy/mixer-rule-ratings-redis-quota-fixed-window.yaml b/istio-1.5.0/samples/bookinfo/policy/mixer-rule-ratings-redis-quota-fixed-window.yaml new file mode 100644 index 0000000..a8bce7c --- /dev/null +++ b/istio-1.5.0/samples/bookinfo/policy/mixer-rule-ratings-redis-quota-fixed-window.yaml @@ -0,0 +1,87 @@ +apiVersion: config.istio.io/v1alpha2 +kind: handler +metadata: + name: redishandler + namespace: istio-system +spec: + compiledAdapter: redisquota + params: + redisServerUrl: redis-release-master:6379 + connectionPoolSize: 10 + quotas: + - name: requestcountquota.instance.istio-system + maxAmount: 5000 + validDuration: 30s + rateLimitAlgorithm: FIXED_WINDOW + # The first matching override is applied. + # A requestcount instance is checked against override dimensions. + overrides: + # The following override applies to 'ratings' when + # the source is 'reviews'. + - dimensions: + destination: ratings + source: reviews + maxAmount: 50 + # The following override applies to 'ratings' regardless + # of the source. + - dimensions: + destination: ratings + maxAmount: 100 +--- +apiVersion: config.istio.io/v1alpha2 +kind: instance +metadata: + name: requestcountquota + namespace: istio-system +spec: + compiledTemplate: quota + params: + dimensions: + source: source.labels["app"] | "unknown" + sourceVersion: source.labels["version"] | "unknown" + destination: destination.labels["app"] | "unknown" + destinationVersion: destination.labels["version"] | "unknown" +--- +apiVersion: config.istio.io/v1alpha2 +kind: QuotaSpec +metadata: + name: request-count + namespace: istio-system +spec: + rules: + - quotas: + - charge: 1 + quota: requestcountquota +--- +# Note: change the default namespace to the namespace of the bookinfo app +apiVersion: config.istio.io/v1alpha2 +kind: QuotaSpecBinding +metadata: + name: request-count + namespace: istio-system +spec: + quotaSpecs: + - name: request-count + namespace: istio-system + services: + - name: ratings + namespace: default + - name: reviews + namespace: default + - name: details + namespace: default + - name: productpage + namespace: default +--- +apiVersion: config.istio.io/v1alpha2 +kind: rule +metadata: + name: quota + namespace: istio-system +spec: + match: (destination.labels["app"]|"unknown") == "ratings" + actions: + - handler: redishandler + instances: + - requestcountquota +--- diff --git a/istio-1.5.0/samples/bookinfo/policy/mixer-rule-ratings-redis-quota-rolling-window.yaml b/istio-1.5.0/samples/bookinfo/policy/mixer-rule-ratings-redis-quota-rolling-window.yaml new file mode 100644 index 0000000..b713637 --- /dev/null +++ b/istio-1.5.0/samples/bookinfo/policy/mixer-rule-ratings-redis-quota-rolling-window.yaml @@ -0,0 +1,88 @@ +apiVersion: config.istio.io/v1alpha2 +kind: handler +metadata: + name: redishandler + namespace: istio-system +spec: + compiledAdapter: redisquota + params: + redisServerUrl: redis-release-master:6379 + connectionPoolSize: 10 + quotas: + - name: requestcountquota.instance.istio-system + maxAmount: 5000 + validDuration: 30s + bucketDuration: 9s + rateLimitAlgorithm: ROLLING_WINDOW + # The first matching override is applied. + # A requestcount instance is checked against override dimensions. + overrides: + # The following override applies to 'ratings' when + # the source is 'reviews'. + - dimensions: + destination: ratings + source: reviews + maxAmount: 50 + # The following override applies to 'ratings' regardless + # of the source. + - dimensions: + destination: ratings + maxAmount: 100 +--- +apiVersion: config.istio.io/v1alpha2 +kind: instance +metadata: + name: requestcountquota + namespace: istio-system +spec: + compiledTemplate: quota + params: + dimensions: + source: source.labels["app"] | "unknown" + sourceVersion: source.labels["version"] | "unknown" + destination: destination.labels["app"] | "unknown" + destinationVersion: destination.labels["version"] | "unknown" +--- +apiVersion: config.istio.io/v1alpha2 +kind: QuotaSpec +metadata: + name: request-count + namespace: istio-system +spec: + rules: + - quotas: + - charge: 1 + quota: requestcountquota +--- +# Note: change the default namespace to the namespace of the bookinfo app +apiVersion: config.istio.io/v1alpha2 +kind: QuotaSpecBinding +metadata: + name: request-count + namespace: istio-system +spec: + quotaSpecs: + - name: request-count + namespace: istio-system + services: + - name: ratings + namespace: default + - name: reviews + namespace: default + - name: details + namespace: default + - name: productpage + namespace: default +--- +apiVersion: config.istio.io/v1alpha2 +kind: rule +metadata: + name: quota + namespace: istio-system +spec: + match: (destination.labels["app"]|"unknown") == "ratings" + actions: + - handler: redishandler + instances: + - requestcountquota +--- diff --git a/istio-1.5.0/samples/bookinfo/policy/prometheus-adapter-deployment.yaml b/istio-1.5.0/samples/bookinfo/policy/prometheus-adapter-deployment.yaml new file mode 100644 index 0000000..f744947 --- /dev/null +++ b/istio-1.5.0/samples/bookinfo/policy/prometheus-adapter-deployment.yaml @@ -0,0 +1,44 @@ +apiVersion: v1 +kind: Service +metadata: + name: prometheusadapter + namespace: istio-system + labels: + app: prometheusadapter +spec: + ports: + - name: http + port: 8080 + - name: prometheus + port: 42422 + selector: + app: prometheusadapter +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: prometheusadapter + namespace: istio-system +spec: + replicas: 1 + selector: + matchLabels: + app: prometheusadapter + version: v1 + template: + metadata: + labels: + app: prometheusadapter + version: v1 + annotations: + prometheus.io/scrape: "true" + prometheus.io/port: "42422" + spec: + containers: + - image: gcr.io/istio-testing/prometheusadapter:release-1.1 + imagePullPolicy: Always + name: prometheusadapter + ports: + - containerPort: 8080 + - containerPort: 42422 +--- diff --git a/istio-1.5.0/samples/bookinfo/policy/prometheus-oop-rule.yaml b/istio-1.5.0/samples/bookinfo/policy/prometheus-oop-rule.yaml new file mode 100644 index 0000000..059d067 --- /dev/null +++ b/istio-1.5.0/samples/bookinfo/policy/prometheus-oop-rule.yaml @@ -0,0 +1,78 @@ +apiVersion: "config.istio.io/v1alpha2" +kind: instance +metadata: + name: requestcount-oop + namespace: istio-system +spec: + template: metric + params: + value: "1" + dimensions: + reporter: conditional((context.reporter.kind | "inbound") == "outbound", "source", "destination") + source_workload: source.workload.name | "unknown" + source_workload_namespace: source.workload.namespace | "unknown" + source_principal: source.principal | "unknown" + source_app: source.labels["app"] | "unknown" + source_version: source.labels["version"] | "unknown" + destination_workload: destination.workload.name | "unknown" + destination_workload_namespace: destination.workload.namespace | "unknown" + destination_principal: destination.principal | "unknown" + destination_app: destination.labels["app"] | "unknown" + destination_version: destination.labels["version"] | "unknown" + destination_service: destination.service.host | "unknown" + destination_service_name: destination.service.name | "unknown" + destination_service_namespace: destination.service.namespace | "unknown" + request_protocol: api.protocol | context.protocol | "unknown" + response_code: response.code | 200 + response_flags: context.proxy_error_code | "-" + permissive_response_code: rbac.permissive.response_code | "none" + permissive_response_policyid: rbac.permissive.effective_policy_id | "none" + connection_security_policy: conditional((context.reporter.kind | "inbound") == "outbound", "unknown", conditional(connection.mtls | false, "mutual_tls", "none")) + monitored_resource_type: '"UNSPECIFIED"' +--- +apiVersion: "config.istio.io/v1alpha2" +kind: handler +metadata: + name: prometheus-handler + namespace: istio-system +spec: + adapter: prometheus-nosession + connection: + address: "prometheusadapter:8080" + params: + metrics: + - name: request_count_oop + instance_name: requestcount-oop.instance.istio-system + kind: COUNTER + label_names: + - reporter + - source_workload + - source_workload_namespace + - source_principal + - source_app + - source_version + - destination_workload + - destination_workload_namespace + - destination_principal + - destination_app + - destination_version + - destination_service + - destination_service_name + - destination_service_namespace + - request_protocol + - response_code + - response_flags + - permissive_response_code + - permissive_response_policyid + - connection_security_policy +--- +apiVersion: "config.istio.io/v1alpha2" +kind: rule +metadata: + name: promhttp-oop + namespace: istio-system +spec: + actions: + - handler: prometheus-handler + instances: [ requestcount-oop ] +--- diff --git a/istio-1.5.0/samples/bookinfo/src/mongodb/ratings_data.json b/istio-1.5.0/samples/bookinfo/src/mongodb/ratings_data.json new file mode 100644 index 0000000..b4563b5 --- /dev/null +++ b/istio-1.5.0/samples/bookinfo/src/mongodb/ratings_data.json @@ -0,0 +1,2 @@ +{rating: 5} +{rating: 4} diff --git a/istio-1.5.0/samples/bookinfo/src/productpage/requirements.txt b/istio-1.5.0/samples/bookinfo/src/productpage/requirements.txt new file mode 100644 index 0000000..c1968c8 --- /dev/null +++ b/istio-1.5.0/samples/bookinfo/src/productpage/requirements.txt @@ -0,0 +1,31 @@ +certifi==2019.3.9 +chardet==3.0.4 +Click==7.0 +contextlib2==0.5.5 +dominate==2.3.5 +Flask==1.0.2 +Flask-Bootstrap==3.3.7.1 +Flask-JSON==0.3.3 +future==0.17.1 +futures==3.1.1 +gevent==1.4.0 +greenlet==0.4.15 +idna==2.8 +itsdangerous==1.1.0 +jaeger-client==3.13.0 +Jinja2==2.10.1 +json2html==1.2.1 +MarkupSafe==0.23 +nose==1.3.7 +opentracing==1.2.2 +opentracing-instrumentation==2.4.3 +requests==2.21.0 +simplejson==3.16.0 +six==1.12.0 +threadloop==1.0.2 +thrift==0.11.0 +tornado==4.5.3 +urllib3==1.24.2 +visitor==0.1.3 +Werkzeug==0.15.5 +wrapt==1.11.1 diff --git a/istio-1.5.0/samples/bookinfo/src/productpage/test-requirements.txt b/istio-1.5.0/samples/bookinfo/src/productpage/test-requirements.txt new file mode 100644 index 0000000..f756640 --- /dev/null +++ b/istio-1.5.0/samples/bookinfo/src/productpage/test-requirements.txt @@ -0,0 +1 @@ +requests-mock==1.5.2 diff --git a/istio-1.5.0/samples/bookinfo/src/ratings/package.json b/istio-1.5.0/samples/bookinfo/src/ratings/package.json new file mode 100644 index 0000000..9093980 --- /dev/null +++ b/istio-1.5.0/samples/bookinfo/src/ratings/package.json @@ -0,0 +1,10 @@ +{ + "scripts": { + "start": "node ratings.js" + }, + "dependencies": { + "httpdispatcher": "1.0.0", + "mongodb": "^2.2.31", + "mysql": "^2.15.0" + } +} diff --git a/istio-1.5.0/samples/bookinfo/swagger.yaml b/istio-1.5.0/samples/bookinfo/swagger.yaml new file mode 100644 index 0000000..6782e73 --- /dev/null +++ b/istio-1.5.0/samples/bookinfo/swagger.yaml @@ -0,0 +1,248 @@ +swagger: "2.0" +info: + description: "This is the API of the Istio BookInfo sample application." + version: "1.0.0" + title: "BookInfo API" + termsOfService: "https://istio.io/" + license: + name: "Apache 2.0" + url: "http://www.apache.org/licenses/LICENSE-2.0.html" +basePath: "/api/v1" +tags: +- name: "product" + description: "Information about a product (in this case a book)" +- name: "review" + description: "Review information for a product" +- name: "rating" + description: "Rating information for a product" +externalDocs: + description: "Learn more about the Istio BookInfo application" + url: "https://istio.io/docs/samples/bookinfo.html" +paths: + /products: + get: + tags: + - "product" + summary: "List all products" + description: "List all products available in the application with a minimum amount of information." + operationId: "getProducts" + consumes: + - "application/json" + produces: + - "application/json" + responses: + 200: + description: "successful operation" + schema: + type: "array" + items: + $ref: "#/definitions/Product" + /products/{id}: + get: + tags: + - "product" + summary: "Get individual product" + description: "Get detailed information about an individual product with the given id." + operationId: "getProduct" + consumes: + - "application/json" + produces: + - "application/json" + parameters: + - name: "id" + in: "path" + description: "Product id" + required: true + type: "integer" + format: "int32" + responses: + 200: + description: "successful operation" + schema: + $ref: "#/definitions/ProductDetails" + 400: + description: "Invalid product id" + /products/{id}/reviews: + get: + tags: + - "review" + summary: "Get reviews for a product" + description: "Get reviews for a product, including review text and possibly ratings information." + operationId: "getProductReviews" + consumes: + - "application/json" + produces: + - "application/json" + parameters: + - name: "id" + in: "path" + description: "Product id" + required: true + type: "integer" + format: "int32" + responses: + 200: + description: "successful operation" + schema: + $ref: "#/definitions/ProductReviews" + 400: + description: "Invalid product id" + /products/{id}/ratings: + get: + tags: + - "rating" + summary: "Get ratings for a product" + description: "Get ratings for a product, including stars and their color." + operationId: "getProductRatings" + consumes: + - "application/json" + produces: + - "application/json" + parameters: + - name: "id" + in: "path" + description: "Product id" + required: true + type: "integer" + format: "int32" + responses: + 200: + description: "successful operation" + schema: + $ref: "#/definitions/ProductRatings" + 400: + description: "Invalid product id" + + +definitions: + Product: + type: "object" + description: "Basic information about a product" + properties: + id: + type: "integer" + format: "int32" + description: "Product id" + title: + type: "string" + description: "Title of the book" + descriptionHtml: + type: "string" + description: "Description of the book - may contain HTML tags" + required: + - "id" + - "title" + - "descriptionHtml" + ProductDetails: + type: "object" + description: "Detailed information about a product" + properties: + id: + type: "integer" + format: "int32" + description: "Product id" + publisher: + type: "string" + description: "Publisher of the book" + language: + type: "string" + description: "Language of the book" + author: + type: "string" + description: "Author of the book" + ISBN-10: + type: "string" + description: "ISBN-10 of the book" + ISBN-13: + type: "string" + description: "ISBN-13 of the book" + year: + type: "integer" + format: "int32" + description: "Year the book was first published in" + type: + type: "string" + enum: + - "paperback" + - "hardcover" + description: "Type of the book" + pages: + type: "integer" + format: "int32" + description: "Number of pages of the book" + required: + - "id" + - "publisher" + - "language" + - "author" + - "ISBN-10" + - "ISBN-13" + - "year" + - "type" + - "pages" + ProductReviews: + type: "object" + description: "Object containing reviews for a product" + properties: + id: + type: "integer" + format: "int32" + description: "Product id" + reviews: + type: "array" + description: "List of reviews" + items: + $ref: "#/definitions/Review" + required: + - "id" + - "reviews" + Review: + type: "object" + description: "Review of a product" + properties: + reviewer: + type: "string" + description: "Name of the reviewer" + text: + type: "string" + description: "Review text" + rating: + $ref: "#/definitions/Rating" + required: + - "reviewer" + - "text" + Rating: + type: "object" + description: "Rating of a product" + properties: + stars: + type: "integer" + format: "int32" + minimum: 1 + maximum: 5 + description: "Number of stars" + color: + type: "string" + enum: + - "red" + - "black" + description: "Color in which stars should be displayed" + required: + - "stars" + - "color" + ProductRatings: + type: "object" + description: "Object containing ratings of a product" + properties: + id: + type: "integer" + format: "int32" + description: "Product id" + ratings: + type: "object" + description: "A hashmap where keys are reviewer names, values are number of stars" + additionalProperties: + type: "string" + required: + - "id" + - "ratings" \ No newline at end of file diff --git a/istio-1.5.0/samples/bookinfo/telemetry/fluentd-istio-crd.yaml b/istio-1.5.0/samples/bookinfo/telemetry/fluentd-istio-crd.yaml new file mode 100644 index 0000000..4df061e --- /dev/null +++ b/istio-1.5.0/samples/bookinfo/telemetry/fluentd-istio-crd.yaml @@ -0,0 +1,40 @@ +# Configuration for logentry instances +apiVersion: "config.istio.io/v1alpha2" +kind: logentry +metadata: + name: newlog + namespace: istio-system +spec: + severity: '"info"' + timestamp: request.time + variables: + source: source.labels["app"] | source.workload.name | "unknown" + user: source.user | "unknown" + destination: destination.labels["app"] | destination.workload.name | "unknown" + responseCode: response.code | 0 + responseSize: response.size | 0 + latency: response.duration | "0ms" + monitored_resource_type: '"UNSPECIFIED"' +--- +# Configuration for a Fluentd handler +apiVersion: "config.istio.io/v1alpha2" +kind: fluentd +metadata: + name: handler + namespace: istio-system +spec: + address: "fluentd-es.logging:24224" +--- +# Rule to send logentry instances to the Fluentd handler +apiVersion: "config.istio.io/v1alpha2" +kind: rule +metadata: + name: newlogtofluentd + namespace: istio-system +spec: + match: "true" # match for all requests + actions: + - handler: handler.fluentd + instances: + - newlog.logentry +--- diff --git a/istio-1.5.0/samples/bookinfo/telemetry/fluentd-istio.yaml b/istio-1.5.0/samples/bookinfo/telemetry/fluentd-istio.yaml new file mode 100644 index 0000000..c416f31 --- /dev/null +++ b/istio-1.5.0/samples/bookinfo/telemetry/fluentd-istio.yaml @@ -0,0 +1,44 @@ +# Configuration for logentry instances +apiVersion: config.istio.io/v1alpha2 +kind: instance +metadata: + name: newlog + namespace: istio-system +spec: + compiledTemplate: logentry + params: + severity: '"info"' + timestamp: request.time + variables: + source: source.labels["app"] | source.workload.name | "unknown" + user: source.user | "unknown" + destination: destination.labels["app"] | destination.workload.name | "unknown" + responseCode: response.code | 0 + responseSize: response.size | 0 + latency: response.duration | "0ms" + monitored_resource_type: '"UNSPECIFIED"' +--- +# Configuration for a Fluentd handler +apiVersion: config.istio.io/v1alpha2 +kind: handler +metadata: + name: handler + namespace: istio-system +spec: + compiledAdapter: fluentd + params: + address: "fluentd-es.logging:24224" +--- +# Rule to send logentry instances to the Fluentd handler +apiVersion: config.istio.io/v1alpha2 +kind: rule +metadata: + name: newlogtofluentd + namespace: istio-system +spec: + match: "true" # match for all requests + actions: + - handler: handler + instances: + - newlog +--- diff --git a/istio-1.5.0/samples/bookinfo/telemetry/log-entry-crd.yaml b/istio-1.5.0/samples/bookinfo/telemetry/log-entry-crd.yaml new file mode 100644 index 0000000..d439676 --- /dev/null +++ b/istio-1.5.0/samples/bookinfo/telemetry/log-entry-crd.yaml @@ -0,0 +1,42 @@ +# Configuration for logentry instances +apiVersion: "config.istio.io/v1alpha2" +kind: logentry +metadata: + name: newlog + namespace: istio-system +spec: + severity: '"warning"' + timestamp: request.time + variables: + source: source.labels["app"] | source.workload.name | "unknown" + user: source.user | "unknown" + destination: destination.labels["app"] | destination.workload.name | "unknown" + responseCode: response.code | 0 + responseSize: response.size | 0 + latency: response.duration | "0ms" + monitored_resource_type: '"UNSPECIFIED"' +--- +# Configuration for a stdio handler +apiVersion: "config.istio.io/v1alpha2" +kind: stdio +metadata: + name: newloghandler + namespace: istio-system +spec: + severity_levels: + warning: 1 # Params.Level.WARNING + outputAsJson: true +--- +# Rule to send logentry instances to a stdio handler +apiVersion: "config.istio.io/v1alpha2" +kind: rule +metadata: + name: newlogstdio + namespace: istio-system +spec: + match: "true" # match for all requests + actions: + - handler: newloghandler.stdio + instances: + - newlog.logentry +--- diff --git a/istio-1.5.0/samples/bookinfo/telemetry/log-entry.yaml b/istio-1.5.0/samples/bookinfo/telemetry/log-entry.yaml new file mode 100644 index 0000000..43f47e7 --- /dev/null +++ b/istio-1.5.0/samples/bookinfo/telemetry/log-entry.yaml @@ -0,0 +1,46 @@ +# Configuration for logentry instances +apiVersion: config.istio.io/v1alpha2 +kind: instance +metadata: + name: newlog + namespace: istio-system +spec: + compiledTemplate: logentry + params: + severity: '"warning"' + timestamp: request.time + variables: + source: source.labels["app"] | source.workload.name | "unknown" + user: source.user | "unknown" + destination: destination.labels["app"] | destination.workload.name | "unknown" + responseCode: response.code | 0 + responseSize: response.size | 0 + latency: response.duration | "0ms" + monitored_resource_type: '"UNSPECIFIED"' +--- +# Configuration for a stdio handler +apiVersion: config.istio.io/v1alpha2 +kind: handler +metadata: + name: newloghandler + namespace: istio-system +spec: + compiledAdapter: stdio + params: + severity_levels: + warning: 1 # Params.Level.WARNING + outputAsJson: true +--- +# Rule to send logentry instances to a stdio handler +apiVersion: config.istio.io/v1alpha2 +kind: rule +metadata: + name: newlogstdio + namespace: istio-system +spec: + match: "true" # match for all requests + actions: + - handler: newloghandler + instances: + - newlog +--- diff --git a/istio-1.5.0/samples/bookinfo/telemetry/metrics-crd.yaml b/istio-1.5.0/samples/bookinfo/telemetry/metrics-crd.yaml new file mode 100644 index 0000000..9ee2f5f --- /dev/null +++ b/istio-1.5.0/samples/bookinfo/telemetry/metrics-crd.yaml @@ -0,0 +1,45 @@ +# Configuration for metric instances +apiVersion: "config.istio.io/v1alpha2" +kind: instance +metadata: + name: doublerequestcount + namespace: istio-system +spec: + compiledTemplate: metric + params: + value: "2" # count each request twice + dimensions: + reporter: conditional((context.reporter.kind | "inbound") == "outbound", "client", "server") + source: source.workload.name | "unknown" + destination: destination.workload.name | "unknown" + message: '"twice the fun!"' + monitored_resource_type: '"UNSPECIFIED"' +--- +# Configuration for a Prometheus handler +apiVersion: "config.istio.io/v1alpha2" +kind: prometheus +metadata: + name: doublehandler + namespace: istio-system +spec: + metrics: + - name: double_request_count # Prometheus metric name + instance_name: doublerequestcount.instance.istio-system # Mixer instance name (fully-qualified) + kind: COUNTER + label_names: + - reporter + - source + - destination + - message +--- +# Rule to send metric instances to a Prometheus handler +apiVersion: "config.istio.io/v1alpha2" +kind: rule +metadata: + name: doubleprom + namespace: istio-system +spec: + actions: + - handler: doublehandler.prometheus + instances: + - doublerequestcount diff --git a/istio-1.5.0/samples/bookinfo/telemetry/metrics.yaml b/istio-1.5.0/samples/bookinfo/telemetry/metrics.yaml new file mode 100644 index 0000000..45d9877 --- /dev/null +++ b/istio-1.5.0/samples/bookinfo/telemetry/metrics.yaml @@ -0,0 +1,46 @@ +# Configuration for metric instances +apiVersion: config.istio.io/v1alpha2 +kind: instance +metadata: + name: doublerequestcount + namespace: istio-system +spec: + compiledTemplate: metric + params: + value: "2" # count each request twice + dimensions: + reporter: conditional((context.reporter.kind | "inbound") == "outbound", "client", "server") + source: source.workload.name | "unknown" + destination: destination.workload.name | "unknown" + message: '"twice the fun!"' + monitored_resource_type: '"UNSPECIFIED"' +--- +# Configuration for a Prometheus handler +apiVersion: config.istio.io/v1alpha2 +kind: handler +metadata: + name: doublehandler + namespace: istio-system +spec: + compiledAdapter: prometheus + params: + metrics: + - name: double_request_count # Prometheus metric name + instance_name: doublerequestcount.instance.istio-system # Mixer instance name (fully-qualified) + kind: COUNTER + label_names: + - reporter + - source + - destination + - message +--- +# Rule to send metric instances to a Prometheus handler +apiVersion: config.istio.io/v1alpha2 +kind: rule +metadata: + name: doubleprom + namespace: istio-system +spec: + actions: + - handler: doublehandler + instances: [ doublerequestcount ] diff --git a/istio-1.5.0/samples/bookinfo/telemetry/tcp-metrics-crd.yaml b/istio-1.5.0/samples/bookinfo/telemetry/tcp-metrics-crd.yaml new file mode 100644 index 0000000..36ba5ec --- /dev/null +++ b/istio-1.5.0/samples/bookinfo/telemetry/tcp-metrics-crd.yaml @@ -0,0 +1,67 @@ +# Configuration for a metric measuring bytes sent from a server +# to a client +apiVersion: "config.istio.io/v1alpha2" +kind: metric +metadata: + name: mongosentbytes + namespace: default +spec: + value: connection.sent.bytes | 0 # uses a TCP-specific attribute + dimensions: + source_service: source.workload.name | "unknown" + source_version: source.labels["version"] | "unknown" + destination_version: destination.labels["version"] | "unknown" + monitoredResourceType: '"UNSPECIFIED"' +--- +# Configuration for a metric measuring bytes sent from a client +# to a server +apiVersion: "config.istio.io/v1alpha2" +kind: metric +metadata: + name: mongoreceivedbytes + namespace: default +spec: + value: connection.received.bytes | 0 # uses a TCP-specific attribute + dimensions: + source_service: source.workload.name | "unknown" + source_version: source.labels["version"] | "unknown" + destination_version: destination.labels["version"] | "unknown" + monitoredResourceType: '"UNSPECIFIED"' +--- +# Configuration for a Prometheus handler +apiVersion: "config.istio.io/v1alpha2" +kind: prometheus +metadata: + name: mongohandler + namespace: default +spec: + metrics: + - name: mongo_sent_bytes # Prometheus metric name + instance_name: mongosentbytes.metric.default # Mixer instance name (fully-qualified) + kind: COUNTER + label_names: + - source_service + - source_version + - destination_version + - name: mongo_received_bytes # Prometheus metric name + instance_name: mongoreceivedbytes.metric.default # Mixer instance name (fully-qualified) + kind: COUNTER + label_names: + - source_service + - source_version + - destination_version +--- +# Rule to send metric instances to a Prometheus handler +apiVersion: "config.istio.io/v1alpha2" +kind: rule +metadata: + name: mongoprom + namespace: default +spec: + match: context.protocol == "tcp" + && destination.service.host == "mongodb.default.svc.cluster.local" + actions: + - handler: mongohandler.prometheus + instances: + - mongoreceivedbytes.metric + - mongosentbytes.metric diff --git a/istio-1.5.0/samples/bookinfo/telemetry/tcp-metrics.yaml b/istio-1.5.0/samples/bookinfo/telemetry/tcp-metrics.yaml new file mode 100644 index 0000000..817507b --- /dev/null +++ b/istio-1.5.0/samples/bookinfo/telemetry/tcp-metrics.yaml @@ -0,0 +1,73 @@ +# Configuration for a metric measuring bytes sent from a server +# to a client +apiVersion: config.istio.io/v1alpha2 +kind: instance +metadata: + name: mongosentbytes + namespace: default +spec: + compiledTemplate: metric + params: + value: connection.sent.bytes | 0 # uses a TCP-specific attribute + dimensions: + source_service: source.workload.name | "unknown" + source_version: source.labels["version"] | "unknown" + destination_version: destination.labels["version"] | "unknown" + monitoredResourceType: '"UNSPECIFIED"' +--- +# Configuration for a metric measuring bytes sent from a client +# to a server +apiVersion: config.istio.io/v1alpha2 +kind: instance +metadata: + name: mongoreceivedbytes + namespace: default +spec: + compiledTemplate: metric + params: + value: connection.received.bytes | 0 # uses a TCP-specific attribute + dimensions: + source_service: source.workload.name | "unknown" + source_version: source.labels["version"] | "unknown" + destination_version: destination.labels["version"] | "unknown" + monitoredResourceType: '"UNSPECIFIED"' +--- +# Configuration for a Prometheus handler +apiVersion: config.istio.io/v1alpha2 +kind: handler +metadata: + name: mongohandler + namespace: default +spec: + compiledAdapter: prometheus + params: + metrics: + - name: mongo_sent_bytes # Prometheus metric name + instance_name: mongosentbytes.instance.default # Mixer instance name (fully-qualified) + kind: COUNTER + label_names: + - source_service + - source_version + - destination_version + - name: mongo_received_bytes # Prometheus metric name + instance_name: mongoreceivedbytes.instance.default # Mixer instance name (fully-qualified) + kind: COUNTER + label_names: + - source_service + - source_version + - destination_version +--- +# Rule to send metric instances to a Prometheus handler +apiVersion: config.istio.io/v1alpha2 +kind: rule +metadata: + name: mongoprom + namespace: default +spec: + match: context.protocol == "tcp" + && destination.service.host == "mongodb.default.svc.cluster.local" + actions: + - handler: mongohandler + instances: + - mongoreceivedbytes + - mongosentbytes diff --git a/istio-1.5.0/samples/certs/README.md b/istio-1.5.0/samples/certs/README.md new file mode 100644 index 0000000..af87ec4 --- /dev/null +++ b/istio-1.5.0/samples/certs/README.md @@ -0,0 +1,37 @@ +# Sample Certificates for Citadel CA + +This directory contains sample pre-generated certificate and keys to demonstrate how an operator could configure Citadel with an existing root certificate, signing certificates and keys. In such +a deployment, Citadel acts as an intermediate certificate authority (CA), under the given root CA. +Instructions are available [here](https://istio.io/docs/tasks/security/plugin-ca-cert/). + +The included sample files are: + +- `root-cert.pem`: root CA certificate. +- `ca-cert.pem` and `ca-cert.key`: Citadel intermediate certificate and corresponding private key. +- `cert-chain.pem`: certificate trust chain. + +## Generating Certificates for Bootstrapping Multicluster Chain of Trust + +Using the sample certificates to establish trust between multiple clusters is not recommended. +Since the directory is missing the root CA's private key, we're unable to create new certificates +for the clusters. Our only workable option is to use the **same** files for all clusters. +A better alternative would be to assign a different intermediate CA to each cluster, all signed by +a shared root CA. This will enable trust between workloads from different clusters as long as +they share a common root CA. + +The directory contains a `Makefile` for generating new root and intermediate certificates. +The following `make` targets are defined: + +- `make root-ca`: this will generate a new root CA key and certificate. +- `make $NAME-certs`: this will generate all needed files to bootstrap a new Citadel for cluster `$NAME` (e.g., `us-east`, `cluster01`, etc.). + +The intermediate CA files used for cluster `$NAME` are created under a directory named +`$NAME`. By creating files under a directory, we can create them using the naming convention +expected by Citadel's command line options. To differentiate between clusters, we include a +`Location` (`L`) designation in the certificates `Subject` field, with the cluster's name. +Similarly, we set the `Subject Alternate Name` field to include the cluster name as part +of the SPIFFE identity. + +Note that the Makefile generates long lived intermediate certificates. While this might be +acceptable for demonstration purposes, a more realistic and secure deployment would use short +lived and automatically renewed certificates for the intermediate Citadels. \ No newline at end of file diff --git a/istio-1.5.0/samples/certs/ca-cert.pem b/istio-1.5.0/samples/certs/ca-cert.pem new file mode 100644 index 0000000..a460e03 --- /dev/null +++ b/istio-1.5.0/samples/certs/ca-cert.pem @@ -0,0 +1,22 @@ +-----BEGIN CERTIFICATE----- +MIIDnzCCAoegAwIBAgIJAON1ifrBZ2/BMA0GCSqGSIb3DQEBCwUAMIGLMQswCQYD +VQQGEwJVUzETMBEGA1UECAwKQ2FsaWZvcm5pYTESMBAGA1UEBwwJU3Vubnl2YWxl +MQ4wDAYDVQQKDAVJc3RpbzENMAsGA1UECwwEVGVzdDEQMA4GA1UEAwwHUm9vdCBD +QTEiMCAGCSqGSIb3DQEJARYTdGVzdHJvb3RjYUBpc3Rpby5pbzAgFw0xODAxMjQx +OTE1NTFaGA8yMTE3MTIzMTE5MTU1MVowWTELMAkGA1UEBhMCVVMxEzARBgNVBAgT +CkNhbGlmb3JuaWExEjAQBgNVBAcTCVN1bm55dmFsZTEOMAwGA1UEChMFSXN0aW8x +ETAPBgNVBAMTCElzdGlvIENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKC +AQEAyzCxr/xu0zy5rVBiso9ffgl00bRKvB/HF4AX9/ytmZ6Hqsy13XIQk8/u/By9 +iCvVwXIMvyT0CbiJq/aPEj5mJUy0lzbrUs13oneXqrPXf7ir3HzdRw+SBhXlsh9z +APZJXcF93DJU3GabPKwBvGJ0IVMJPIFCuDIPwW4kFAI7R/8A5LSdPrFx6EyMXl7K +M8jekC0y9DnTj83/fY72WcWX7YTpgZeBHAeeQOPTZ2KYbFal2gLsar69PgFS0Tom +ESO9M14Yit7mzB1WDK2z9g3r+zLxENdJ5JG/ZskKe+TO4Diqi5OJt/h8yspS1ck8 +LJtCole9919umByg5oruflqIlQIDAQABozUwMzALBgNVHQ8EBAMCAgQwDAYDVR0T +BAUwAwEB/zAWBgNVHREEDzANggtjYS5pc3Rpby5pbzANBgkqhkiG9w0BAQsFAAOC +AQEAltHEhhyAsve4K4bLgBXtHwWzo6SpFzdAfXpLShpOJNtQNERb3qg6iUGQdY+w +A2BpmSkKr3Rw/6ClP5+cCG7fGocPaZh+c+4Nxm9suMuZBZCtNOeYOMIfvCPcCS+8 +PQ/0hC4/0J3WJKzGBssaaMufJxzgFPPtDJ998kY8rlROghdSaVt423/jXIAYnP3Y +05n8TGERBj7TLdtIVbtUIx3JHAo3PWJywA6mEDovFMJhJERp9sDHIr1BbhXK1TFN +Z6HNH6gInkSSMtvC4Ptejb749PTaePRPF7ID//eq/3AH8UK50F3TQcLjEqWUsJUn +aFKltOc+RAjzDklcUPeG4Y6eMA== +-----END CERTIFICATE----- diff --git a/istio-1.5.0/samples/certs/ca-key.pem b/istio-1.5.0/samples/certs/ca-key.pem new file mode 100644 index 0000000..faa77f3 --- /dev/null +++ b/istio-1.5.0/samples/certs/ca-key.pem @@ -0,0 +1,27 @@ +-----BEGIN RSA PRIVATE KEY----- +MIIEpAIBAAKCAQEAyzCxr/xu0zy5rVBiso9ffgl00bRKvB/HF4AX9/ytmZ6Hqsy1 +3XIQk8/u/By9iCvVwXIMvyT0CbiJq/aPEj5mJUy0lzbrUs13oneXqrPXf7ir3Hzd +Rw+SBhXlsh9zAPZJXcF93DJU3GabPKwBvGJ0IVMJPIFCuDIPwW4kFAI7R/8A5LSd +PrFx6EyMXl7KM8jekC0y9DnTj83/fY72WcWX7YTpgZeBHAeeQOPTZ2KYbFal2gLs +ar69PgFS0TomESO9M14Yit7mzB1WDK2z9g3r+zLxENdJ5JG/ZskKe+TO4Diqi5OJ +t/h8yspS1ck8LJtCole9919umByg5oruflqIlQIDAQABAoIBAGZI8fnUinmd5R6B +C941XG3XFs6GAuUm3hNPcUFuGnntmv/5I0gBpqSyFO0nDqYg4u8Jma8TTCIkmnFN +ogIeFU+LiJFinR3GvwWzTE8rTz1FWoaY+M9P4ENd/I4pVLxUPuSKhfA2ChAVOupU +8F7D9Q/dfBXQQCT3VoUaC+FiqjL4HvIhji1zIqaqpK7fChGPraC/4WHwLMNzI0Zg +oDdAanwVygettvm6KD7AeKzhK94gX1PcnsOi3KuzQYvkenQE1M6/K7YtEc5qXCYf +QETj0UCzB55btgdF36BGoZXf0LwHqxys9ubfHuhwKBpY0xg2z4/4RXZNhfIDih3w +J3mihcECgYEA6FtQ0cfh0Zm03OPDpBGc6sdKxTw6aBDtE3KztfI2hl26xHQoeFqp +FmV/TbnExnppw+gWJtwx7IfvowUD8uRR2P0M2wGctWrMpnaEYTiLAPhXsj69HSM/ +CYrh54KM0YWyjwNhtUzwbOTrh1jWtT9HV5e7ay9Atk3UWljuR74CFMUCgYEA392e +DVoDLE0XtbysmdlfSffhiQLP9sT8+bf/zYnr8Eq/4LWQoOtjEARbuCj3Oq7bP8IE +Vz45gT1mEE3IacC9neGwuEa6icBiuQi86NW8ilY/ZbOWrRPLOhk3zLiZ+yqkt+sN +cqWx0JkIh7IMKWI4dVQgk4I0jcFP7vNG/So4AZECgYEA426eSPgxHQwqcBuwn6Nt +yJCRq0UsljgbFfIr3Wfb3uFXsntQMZ3r67QlS1sONIgVhmBhbmARrcfQ0+xQ1SqO +wqnOL4AAd8K11iojoVXLGYP7ssieKysYxKpgPE8Yru0CveE9fkx0+OGJeM2IO5hY +qHAoTt3NpaPAuz5Y3XgqaVECgYA0TONS/TeGjxA9/jFY1Cbl8gp35vdNEKKFeM5D +Z7h+cAg56FE8tyFyqYIAGVoBFL7WO26mLzxiDEUfA/0Rb90c2JBfzO5hpleqIPd5 +cg3VR+cRzI4kK16sWR3nLy2SN1k6OqjuovVS5Z3PjfI3bOIBz0C5FY9Pmt0g1yc7 +mDRzcQKBgQCXWCZStbdjewaLd5u5Hhbw8tIWImMVfcfs3H1FN669LLpbARM8RtAa +8dYwDVHmWmevb/WX03LiSE+GCjCBO79fa1qc5RKAalqH/1OYxTuvYOeTUebSrg8+ +lQFlP2OC4GGolKrN6HVWdxtf+F+SdjwX6qGCfYkXJRLYXIFSFjFeuw== +-----END RSA PRIVATE KEY----- diff --git a/istio-1.5.0/samples/certs/cert-chain.pem b/istio-1.5.0/samples/certs/cert-chain.pem new file mode 100644 index 0000000..a460e03 --- /dev/null +++ b/istio-1.5.0/samples/certs/cert-chain.pem @@ -0,0 +1,22 @@ +-----BEGIN CERTIFICATE----- +MIIDnzCCAoegAwIBAgIJAON1ifrBZ2/BMA0GCSqGSIb3DQEBCwUAMIGLMQswCQYD +VQQGEwJVUzETMBEGA1UECAwKQ2FsaWZvcm5pYTESMBAGA1UEBwwJU3Vubnl2YWxl +MQ4wDAYDVQQKDAVJc3RpbzENMAsGA1UECwwEVGVzdDEQMA4GA1UEAwwHUm9vdCBD +QTEiMCAGCSqGSIb3DQEJARYTdGVzdHJvb3RjYUBpc3Rpby5pbzAgFw0xODAxMjQx +OTE1NTFaGA8yMTE3MTIzMTE5MTU1MVowWTELMAkGA1UEBhMCVVMxEzARBgNVBAgT +CkNhbGlmb3JuaWExEjAQBgNVBAcTCVN1bm55dmFsZTEOMAwGA1UEChMFSXN0aW8x +ETAPBgNVBAMTCElzdGlvIENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKC +AQEAyzCxr/xu0zy5rVBiso9ffgl00bRKvB/HF4AX9/ytmZ6Hqsy13XIQk8/u/By9 +iCvVwXIMvyT0CbiJq/aPEj5mJUy0lzbrUs13oneXqrPXf7ir3HzdRw+SBhXlsh9z +APZJXcF93DJU3GabPKwBvGJ0IVMJPIFCuDIPwW4kFAI7R/8A5LSdPrFx6EyMXl7K +M8jekC0y9DnTj83/fY72WcWX7YTpgZeBHAeeQOPTZ2KYbFal2gLsar69PgFS0Tom +ESO9M14Yit7mzB1WDK2z9g3r+zLxENdJ5JG/ZskKe+TO4Diqi5OJt/h8yspS1ck8 +LJtCole9919umByg5oruflqIlQIDAQABozUwMzALBgNVHQ8EBAMCAgQwDAYDVR0T +BAUwAwEB/zAWBgNVHREEDzANggtjYS5pc3Rpby5pbzANBgkqhkiG9w0BAQsFAAOC +AQEAltHEhhyAsve4K4bLgBXtHwWzo6SpFzdAfXpLShpOJNtQNERb3qg6iUGQdY+w +A2BpmSkKr3Rw/6ClP5+cCG7fGocPaZh+c+4Nxm9suMuZBZCtNOeYOMIfvCPcCS+8 +PQ/0hC4/0J3WJKzGBssaaMufJxzgFPPtDJ998kY8rlROghdSaVt423/jXIAYnP3Y +05n8TGERBj7TLdtIVbtUIx3JHAo3PWJywA6mEDovFMJhJERp9sDHIr1BbhXK1TFN +Z6HNH6gInkSSMtvC4Ptejb749PTaePRPF7ID//eq/3AH8UK50F3TQcLjEqWUsJUn +aFKltOc+RAjzDklcUPeG4Y6eMA== +-----END CERTIFICATE----- diff --git a/istio-1.5.0/samples/certs/root-cert.pem b/istio-1.5.0/samples/certs/root-cert.pem new file mode 100644 index 0000000..64c3fd5 --- /dev/null +++ b/istio-1.5.0/samples/certs/root-cert.pem @@ -0,0 +1,24 @@ +-----BEGIN CERTIFICATE----- +MIID7TCCAtWgAwIBAgIJAOIRDhOcxsx6MA0GCSqGSIb3DQEBCwUAMIGLMQswCQYD +VQQGEwJVUzETMBEGA1UECAwKQ2FsaWZvcm5pYTESMBAGA1UEBwwJU3Vubnl2YWxl +MQ4wDAYDVQQKDAVJc3RpbzENMAsGA1UECwwEVGVzdDEQMA4GA1UEAwwHUm9vdCBD +QTEiMCAGCSqGSIb3DQEJARYTdGVzdHJvb3RjYUBpc3Rpby5pbzAgFw0xODAxMjQx +OTE1NTFaGA8yMTE3MTIzMTE5MTU1MVowgYsxCzAJBgNVBAYTAlVTMRMwEQYDVQQI +DApDYWxpZm9ybmlhMRIwEAYDVQQHDAlTdW5ueXZhbGUxDjAMBgNVBAoMBUlzdGlv +MQ0wCwYDVQQLDARUZXN0MRAwDgYDVQQDDAdSb290IENBMSIwIAYJKoZIhvcNAQkB +FhN0ZXN0cm9vdGNhQGlzdGlvLmlvMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB +CgKCAQEA38uEfAatzQYqbaLou1nxJ348VyNzumYMmDDt5pbLYRrCo2pS3ki1ZVDN +8yxIENJFkpKw9UctTGdbNGuGCiSDP7uqF6BiVn+XKAU/3pnPFBbTd0S33NqbDEQu +IYraHSl/tSk5rARbC1DrQRdZ6nYD2KrapC4g0XbjY6Pu5l4y7KnFwSunnp9uqpZw +uERv/BgumJ5QlSeSeCmhnDhLxooG8w5tC2yVr1yDpsOHGimP/mc8Cds4V0zfIhQv +YzfIHphhE9DKjmnjBYLOdj4aycv44jHnOGc+wvA1Jqsl60t3wgms+zJTiWwABLdw +zgMAa7yxLyoV0+PiVQud6k+8ZoIFcwIDAQABo1AwTjAdBgNVHQ4EFgQUOUYGtUyh +euxO4lGe4Op1y8NVoagwHwYDVR0jBBgwFoAUOUYGtUyheuxO4lGe4Op1y8NVoagw +DAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAQEANXLyfAs7J9rmBamGJvPZ +ltx390WxzzLFQsBRAaH6rgeipBq3dR9qEjAwb6BTF+ROmtQzX+fjstCRrJxCto9W +tC8KvXTdRfIjfCCZjhtIOBKqRxE4KJV/RBfv9xD5lyjtCPCQl3Ia6MSf42N+abAK +WCdU6KCojA8WB9YhSCzza3aQbPTzd26OC/JblJpVgtus5f8ILzCsz+pbMimgTkhy +AuhYRppJaQ24APijsEC9+GIaVKPg5IwWroiPoj+QXNpshuvqVQQXvGaRiq4zoSnx +xAJz+w8tjrDWcf826VN14IL+/Cmqlg/rIfB5CHdwVIfWwpuGB66q/UiPegZMNs8a +3g== +-----END CERTIFICATE----- diff --git a/istio-1.5.0/samples/custom-bootstrap/README.md b/istio-1.5.0/samples/custom-bootstrap/README.md new file mode 100644 index 0000000..eac8127 --- /dev/null +++ b/istio-1.5.0/samples/custom-bootstrap/README.md @@ -0,0 +1,52 @@ +# Custom Envoy Bootstrap Configuration + +This sample creates a simple helloworld service that bootstraps the Envoy proxy with a custom configuration file. + +## Starting the service + +First, we need to create a `ConfigMap` resource with our bootstrap configuration. + +```bash +kubectl apply -f custom-bootstrap.yaml +``` + +Next, we can create a service that uses this bootstrap configuration. + +To do this, we need to add an annotation, `sidecar.istio.io/bootstrapOverride`, with the name of our ConfigMap as the value. + +We can create our helloworld app, using the custom config, with: + +```bash +kubectl apply -f example-app.yaml +``` + +If you don't have [automatic sidecar injection](https://istio.io/docs/setup/additional-setup/sidecar-injection/#automatic-sidecar-injection) +set in your cluster you will need to manually inject it to the services instead: + +```bash +istioctl kube-inject -f example-app.yaml -o example-app-istio.yaml +kubectl apply -f example-app-istio.yaml +``` + +## Checking the Bootstrap Configuration + +To see what bootstrap configuration a pod is using: + +```bash +istioctl proxy-config bootstrap +``` + +## Customizing the Bootstrap + +The configuration provided will be passed to envoy using the [`--config-yaml`](https://www.envoyproxy.io/docs/envoy/v1.7.1/operations/cli#cmdoption-config-yaml) flag. + +This will merge the passed in configuration with the default configuration. Singular values will replace the default values, while repeated values will be appended. + +For reference, [the default bootstrap configuration](/tools/packaging/common/envoy_bootstrap_v2.json) and Envoy's [configuration reference](https://www.envoyproxy.io/docs/envoy/latest/configuration/configuration#config) may be useful + +## Cleanup + +```bash +kubectl delete -f custom-bootstrap.yaml +kubectl delete -f example-app.yaml +``` \ No newline at end of file diff --git a/istio-1.5.0/samples/custom-bootstrap/custom-bootstrap.yaml b/istio-1.5.0/samples/custom-bootstrap/custom-bootstrap.yaml new file mode 100644 index 0000000..7ef8d1d --- /dev/null +++ b/istio-1.5.0/samples/custom-bootstrap/custom-bootstrap.yaml @@ -0,0 +1,19 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: istio-custom-bootstrap-config + namespace: default +data: + custom_bootstrap.json: | + { + "tracing": { + "http": { + "name": "envoy.zipkin", + "config": { + "collector_cluster": "zipkin", + "collector_endpoint": "/api/v1/spans/custom", + "trace_id_128bit": "true" + } + } + } + } diff --git a/istio-1.5.0/samples/custom-bootstrap/example-app.yaml b/istio-1.5.0/samples/custom-bootstrap/example-app.yaml new file mode 100644 index 0000000..24b4fdc --- /dev/null +++ b/istio-1.5.0/samples/custom-bootstrap/example-app.yaml @@ -0,0 +1,27 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: helloworld-v1 +spec: + replicas: 1 + selector: + matchLabels: + app: helloworld + version: v1 + template: + metadata: + annotations: + sidecar.istio.io/bootstrapOverride: "istio-custom-bootstrap-config" + labels: + app: helloworld + version: v1 + spec: + containers: + - name: helloworld + image: docker.io/istio/examples-helloworld-v1 + resources: + requests: + cpu: "100m" + imagePullPolicy: IfNotPresent + ports: + - containerPort: 5000 diff --git a/istio-1.5.0/samples/external/README.md b/istio-1.5.0/samples/external/README.md new file mode 100644 index 0000000..e17198b --- /dev/null +++ b/istio-1.5.0/samples/external/README.md @@ -0,0 +1,34 @@ +# External Services + +By default Istio-enabled services are unable to access services and URLs outside of the cluster. Pods use iptables to transparently redirect all outbound traffic to the sidecar proxy, which only handles intra-cluster destinations. + +See [the Egress Task](https://istio.io/docs/tasks/traffic-management/egress/) for +information on configuring Istio to contact external services. + +This directory contains samples showing how to enable pods to contact a few well +known services. + +If Istio is not configured to allow pods to contact external services, the pods will +see errors such as 404s, HTTPS connection problems, and TCP connection problems. If +ServiceEntries are misconfigured pods may see problems with server names. + +## Try it out + +After an operator runs `kubectl create -f aptget.yaml` pods will be able to +succeed with `apt-get update` and `apt-get install`. + +After an operator runs `kubectl create -f github.yaml` pods will be able to +succeed with `git clone https://github.com/fortio/fortio.git`. + +Running `kubectl create -f pypi.yaml` allows pods to update Python libraries using `pip`. + +It is not a best practice to enable pods to update libraries dynamically. +We are providing these samples +because they have proven to be helpful with interactive troubleshooting. Security minded clusters should only allow traffic to service dependencies such as cloud +services. + +### Enable communication by default + +Note that [this note](https://istio.io/docs/tasks/traffic-management/egress/#install-istio-with-access-to-all-external-services-by-default) shows how to configure Istio to contact services by default. The technique +discussed there does not allow HTTP on port 80 or SSH on port 22. These examples will +allow external communication for ports 80 and 22. diff --git a/istio-1.5.0/samples/external/aptget.yaml b/istio-1.5.0/samples/external/aptget.yaml new file mode 100644 index 0000000..fa24fa4 --- /dev/null +++ b/istio-1.5.0/samples/external/aptget.yaml @@ -0,0 +1,20 @@ +# This ServiceEntry exposes the hosts needed for installing packages with apt-get. +# After applying this file, Istio-enabled pods (configured apt-get) be able to execute +# `apt-get upgrade` and `apt-get install`. If this is not installed you may get +# "404 Not Found" + +apiVersion: networking.istio.io/v1alpha3 +kind: ServiceEntry +metadata: + name: make-aptget-work +spec: + hosts: + - deb.debian.org + - cdn-fastly.deb.debian.org + - security.debian.org + - archive.ubuntu.com + - security.ubuntu.com + ports: + - number: 80 + name: http + protocol: HTTP diff --git a/istio-1.5.0/samples/external/github.yaml b/istio-1.5.0/samples/external/github.yaml new file mode 100644 index 0000000..832cbc3 --- /dev/null +++ b/istio-1.5.0/samples/external/github.yaml @@ -0,0 +1,53 @@ +# This ServiceEntry exposes the hosts needed for github.com. +# After applying this file, Istio-enabled pods will be able to execute +# `git clone https://github.com/istio/api.git` and (with local identification +# config and certificate) `git clone git@github.com:istio/api.git` + +# HTTP and TLS, the host must be specified +# See https://istio.io/docs/tasks/traffic-management/egress/ +apiVersion: networking.istio.io/v1alpha3 +kind: ServiceEntry +metadata: + name: github-https +spec: + hosts: + - github.com + ports: + - number: 443 + name: https + protocol: HTTPS +--- +# For TCP services the IP ranges SHOULD be specified to avoid problems +# if multiple SEs use the same port number. +# See https://istio.io/blog/2018/egress-tcp/#mesh-external-service-entry-for-an-external-mysql-instance +apiVersion: networking.istio.io/v1alpha3 +kind: ServiceEntry +metadata: + name: github-tcp +spec: + hosts: + - dummy.github.com # not used + addresses: # from https://help.github.com/articles/about-github-s-ip-addresses/ + - "13.229.188.59/32" + - "13.250.177.223/32" + - "140.82.112.0/20" + - "18.194.104.89/32" + - "18.195.85.27/32" + - "185.199.108.0/22" + - "185.199.108.153/32" + - "185.199.109.153/32" + - "185.199.110.153/32" + - "185.199.111.153/32" + - "192.30.252.0/22" + - "192.30.252.153/32" + - "192.30.252.154/32" + - "23.20.92.3/32" + - "35.159.8.160/32" + - "52.74.223.119/32" + - "54.166.52.62/32" + - "54.87.5.173/32" + ports: + - name: tcp + number: 22 + protocol: tcp + location: MESH_EXTERNAL diff --git a/istio-1.5.0/samples/external/pypi.yaml b/istio-1.5.0/samples/external/pypi.yaml new file mode 100644 index 0000000..7f457a5 --- /dev/null +++ b/istio-1.5.0/samples/external/pypi.yaml @@ -0,0 +1,44 @@ +# This ServiceEntry exposes the hosts needed for Python `pip`. +# After applying this file, Istio-enabled pods will be able to execute +# `pip search istio`. + +# HTTP and TLS, the host must be specified +# See https://istio.io/docs/tasks/traffic-management/egress/ + +apiVersion: networking.istio.io/v1alpha3 +kind: ServiceEntry +metadata: + name: python-https +spec: + hosts: + - pypi.python.org + ports: + - number: 443 + name: https + protocol: HTTPS +--- +# pypi.python.org may 301 redirect to pypi.org, so we need this too. +apiVersion: networking.istio.io/v1alpha3 +kind: ServiceEntry +metadata: + name: pypi-https +spec: + hosts: + - pypi.org + ports: + - number: 443 + name: https + protocol: HTTPS +--- +# pip install may fetch files from files.pythonhosted.org +apiVersion: networking.istio.io/v1alpha3 +kind: ServiceEntry +metadata: + name: pythonhosted-https +spec: + hosts: + - files.pythonhosted.org + ports: + - number: 443 + name: https + protocol: HTTPS diff --git a/istio-1.5.0/samples/fortio/stackdriver.yaml b/istio-1.5.0/samples/fortio/stackdriver.yaml new file mode 100644 index 0000000..2bc93dc --- /dev/null +++ b/istio-1.5.0/samples/fortio/stackdriver.yaml @@ -0,0 +1,245 @@ +apiVersion: "config.istio.io/v1alpha2" +kind: handler +metadata: + name: stackdriver +spec: + compiledAdapter: stackdriver + params: + appCredentials: y + pushInterval: 5s + metricInfo: + server-request-count.instance.{{.Namespace}}: + kind: 3 # CUMULATIVE + value: 2 # INT64 + metric_type: "istio.io/service/server/request_count" + logInfo: + server-accesslog-stackdriver.instance.{{.Namespace}}: + labelNames: + - source_uid + - source_ip + - source_app + - source_principal + - source_name + - source_workload + - source_namespace + - source_owner + - destination_uid + - destination_app + - destination_ip + - destination_service_host + - destination_workload + - destination_name + - destination_namespace + - destination_owner + - destination_principal + - api_name + - api_version + - api_claims + - api_key + - request_operation + - protocol + - method + - url + - response_code + - response_size + - request_size + - request_id + - client_trace_id + - latency + - service_authentication_policy + - user_agent + - response_timestamp + - received_bytes + - sent_bytes + - referer + trace: + sampleProbability: 1.0 +--- +# For future Context Graph test. +# apiVersion: "config.istio.io/v1alpha2" +# kind: edge +# metadata: +# name: default +# spec: +# timestamp: request.time | context.time +# sourceUid: source.uid | "Unknown" +# sourceOwner: source.owner | "Unknown" +# sourceWorkloadName: source.workload.name | "Unknown" +# sourceWorkloadNamespace: source.workload.namespace | "Unknown" +# destinationUid: destination.uid | "Unknown" +# destinationOwner: destination.owner | "Unknown" +# destinationWorkloadName: destination.workload.name | "Unknown" +# destinationWorkloadNamespace: destination.workload.namespace | "Unknown" +# contextProtocol: context.protocol | "Unknown" +# apiProtocol: api.protocol | "Unknown" +--- +apiVersion: "config.istio.io/v1alpha2" +kind: instance +metadata: + name: server-accesslog-stackdriver +spec: + compiledTemplate: logentry + params: + severity: '"Info"' + timestamp: request.time + variables: + source_uid: source.uid | "" + source_ip: source.ip | ip("0.0.0.0") + source_app: source.labels["app"] | "" + source_principal: source.principal | "" + source_name: source.name | "" + source_workload: source.workload.name | "" + source_namespace: source.namespace | "" + source_owner: source.owner | "" + destination_uid: destination.uid | "" + destination_app: destination.labels["app"] | "" + destination_ip: destination.ip | ip("0.0.0.0") + destination_service_host: destination.service.host | "" + destination_workload: destination.workload.name | "" + destination_name: destination.name | "" + destination_namespace: destination.namespace | "" + destination_owner: destination.owner | "" + destination_principal: destination.principal | "" + api_name: api.service | "" + api_version: api.version | "" + api_claims: request.auth.raw_claims | "" + api_key: request.api_key | request.headers["x-api-key"] | "" + request_operation: conditional((context.protocol | "unknown") == "grpc", request.path | "unknown", request.method | "unknown") + protocol: request.scheme | context.protocol | "http" + method: request.method | "" + url: request.path | "" + response_code: response.code | 0 + response_size: response.size | 0 + request_size: request.size | 0 + request_id: request.headers["x-request-id"] | "" + client_trace_id: request.headers["x-client-trace-id"] | "" + latency: response.duration | "0ms" + service_authentication_policy: conditional((context.reporter.kind | "inbound") == "outbound", "unknown", conditional(connection.mtls | false, "mutual_tls", "none")) + user_agent: request.useragent | "" + response_timestamp: response.time + received_bytes: request.total_size | 0 + sent_bytes: response.total_size | 0 + referer: request.referer | "" + monitored_resource_type: '"k8s_container"' + monitoredResourceDimensions: + project_id: '""' + cluster_name: '""' + namespace_name: destination.namespace | "unknown" + location: '""' + container_name: destination.container.name | "unknown" + pod_name: destination.name | "unknown" +--- +apiVersion: "config.istio.io/v1alpha2" +kind: instance +metadata: + name: server-request-count +spec: + compiledTemplate: metric + params: + value: "1" + dimensions: + destination_service_name: destination.service.name | "unknown" + destination_service_namespace: destination.service.namespace | "unknown" + destination_port: destination.port | 0 + request_operation: conditional((context.protocol | "unknown") == "grpc", request.path | "unknown", request.method | "unknown") + request_protocol: context.protocol | "unknown" + api_version: api.version | "unknown" + api_name: api.service | "unknown" + response_code: response.code | 0 + service_authentication_policy: conditional((context.reporter.kind | "inbound") == "outbound", "unknown", conditional(connection.mtls | false, "mutual_tls", "none")) + source_workload_namespace: source.workload.namespace | "unknown" + source_workload_name: source.workload.name | "unknown" + source_owner: source.owner | "unknown" + destination_workload_namespace: destination.workload.namespace | "unknown" + destination_workload_name: destination.workload.name | "unknown" + destination_owner: destination.owner | "unknown" + monitoredResourceType: '"k8s_container"' + monitoredResourceDimensions: + project_id: '""' + cluster_name: '""' + namespace_name: destination.workload.namespace | "unknown" + location: '""' + container_name: destination.container.name | "unknown" + pod_name: destination.name | "unknown" +--- +apiVersion: "config.istio.io/v1alpha2" +kind: instance +metadata: + name: stackdriver-span +spec: + compiledTemplate: tracespan + params: + traceId: request.headers["x-b3-traceid"] + spanId: request.headers["x-b3-spanid"] | "" + parentSpanId: request.headers["x-b3-parentspanid"] | "" + spanName: destination.service.host | destination.service.name | destination.workload.name | "unknown" + startTime: request.time + endTime: response.time + clientSpan: (context.reporter.kind | "inbound") == "outbound" + rewriteClientSpanId: "true" + spanTags: + destination_service_name: destination.service.name | "unknown" + destination_service_namespace: destination.service.namespace | "unknown" + destination_port: destination.port | 0 + request_operation: conditional((context.protocol | "unknown") == "grpc", request.path | "unknown", request.method | "unknown") + request_protocol: context.protocol | "unknown" + api_version: api.version | "unknown" + api_name: api.service | "unknown" + response_code: response.code | 0 + service_authentication_policy: conditional((context.reporter.kind | "inbound") == "outbound", "unknown", conditional(connection.mtls | false, "mutual_tls", "none")) + source_workload_namespace: source.workload.namespace | "unknown" + source_workload_name: source.workload.name | "unknown" + source_owner: source.owner | "unknown" + destination_workload_namespace: destination.workload.namespace | "unknown" + destination_workload_name: destination.workload.name | "unknown" + destination_owner: destination.owner | "unknown" + http_url: request.path | "" + request_size: request.size | 0 + response_size: response.size | 0 + source_ip: source.ip | ip("0.0.0.0") +--- +apiVersion: "config.istio.io/v1alpha2" +kind: rule +metadata: + name: stackdriver-log +spec: + match: (context.protocol == "http" || context.protocol == "grpc") && (context.reporter.kind | "inbound" == "inbound") + actions: + - handler: stackdriver.handler + instances: + - server-accesslog-stackdriver +--- +apiVersion: "config.istio.io/v1alpha2" +kind: rule +metadata: + name: stackdriver-server +spec: + match: (context.protocol == "http" || context.protocol == "grpc") && (context.reporter.kind | "inbound" == "inbound") + actions: + - handler: stackdriver.handler + instances: + - server-request-count +--- +apiVersion: "config.istio.io/v1alpha2" +kind: rule +metadata: + name: stackdriver-tracing-rule +spec: + match: context.protocol == "http" || context.protocol == "grpc" # If omitted match is true. + actions: + - handler: stackdriver.handler + instances: + - stackdriver-span +--- +# For future Context Graph test. +# apiVersion: "config.istio.io/v1alpha2" +# kind: rule +# metadata: +# name: edgetosd +# spec: +# match: (context.reporter.kind | "inbound" == "inbound") && (context.protocol | "unknown" != "unknown") +# actions: +# - handler: stackdriver.handler +# instances: +# - default.edge +--- diff --git a/istio-1.5.0/samples/health-check/liveness-command.yaml b/istio-1.5.0/samples/health-check/liveness-command.yaml new file mode 100644 index 0000000..9ea9fe7 --- /dev/null +++ b/istio-1.5.0/samples/health-check/liveness-command.yaml @@ -0,0 +1,57 @@ +# Copyright 2017 Istio Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +################################################################################################## +# Liveness service +################################################################################################## +apiVersion: v1 +kind: Service +metadata: + name: liveness + labels: + app: liveness +spec: + ports: + - port: 80 + name: http + selector: + app: liveness +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: liveness +spec: + selector: + matchLabels: + app: liveness + template: + metadata: + labels: + app: liveness + spec: + containers: + - name: liveness + image: k8s.gcr.io/busybox + args: + - /bin/sh + - -c + - touch /tmp/healthy; sleep 3600 + livenessProbe: + exec: + command: + - cat + - /tmp/healthy + initialDelaySeconds: 5 + periodSeconds: 5 diff --git a/istio-1.5.0/samples/health-check/liveness-http-same-port.yaml b/istio-1.5.0/samples/health-check/liveness-http-same-port.yaml new file mode 100644 index 0000000..ff776fa --- /dev/null +++ b/istio-1.5.0/samples/health-check/liveness-http-same-port.yaml @@ -0,0 +1,39 @@ +apiVersion: v1 +kind: Service +metadata: + name: liveness-http + labels: + app: liveness-http +spec: + ports: + - name: http + port: 8001 + selector: + app: liveness-http +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: liveness-http +spec: + selector: + matchLabels: + app: liveness-http + version: v1 + template: + metadata: + labels: + app: liveness-http + version: v1 + spec: + containers: + - name: liveness-http + image: docker.io/istio/health:example + ports: + - containerPort: 8001 + livenessProbe: + httpGet: + path: /foo + port: 8001 + initialDelaySeconds: 5 + periodSeconds: 5 diff --git a/istio-1.5.0/samples/health-check/liveness-http.yaml b/istio-1.5.0/samples/health-check/liveness-http.yaml new file mode 100644 index 0000000..2ad1f6c --- /dev/null +++ b/istio-1.5.0/samples/health-check/liveness-http.yaml @@ -0,0 +1,39 @@ +apiVersion: v1 +kind: Service +metadata: + name: liveness-http + labels: + app: liveness-http +spec: + ports: + - name: http + port: 8001 + selector: + app: liveness-http +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: liveness-http +spec: + selector: + matchLabels: + app: liveness-http + version: v1 + template: + metadata: + labels: + app: liveness-http + version: v1 + spec: + containers: + - name: liveness-http + image: docker.io/istio/health:example + ports: + - containerPort: 8001 + livenessProbe: + httpGet: + path: /foo + port: 8002 + initialDelaySeconds: 5 + periodSeconds: 5 diff --git a/istio-1.5.0/samples/helloworld/README.md b/istio-1.5.0/samples/helloworld/README.md new file mode 100644 index 0000000..c980582 --- /dev/null +++ b/istio-1.5.0/samples/helloworld/README.md @@ -0,0 +1,90 @@ +# Helloworld service + +This sample includes two versions of a simple helloworld service that returns its version +and instance (hostname) when called. +It can be used as a test service when experimenting with version routing. + +This service is also used to demonstrate canary deployments working in conjunction with autoscaling. +See [Canary deployments using Istio](https://istio.io/blog/2017/0.1-canary.html). + +## Start the helloworld service + +The following commands assume you have +[automatic sidecar injection](https://istio.io/docs/setup/additional-setup/sidecar-injection/#automatic-sidecar-injection) +enabled in your cluster. +If not, you'll need to modify them to include +[manual sidecar injection](https://istio.io/docs/setup/additional-setup/sidecar-injection/#manual-sidecar-injection). + +To run both versions of the helloworld service, use the following command: + +```bash +kubectl apply -f helloworld.yaml +``` + +Alternatively, you can run just one version at a time by first defining the service: + +```bash +kubectl apply -f helloworld.yaml -l app=helloworld +``` + +and then deploying version v1, v2, or both: + +```bash +kubectl apply -f helloworld.yaml -l version=v1 +kubectl apply -f helloworld.yaml -l version=v2 +``` + +## Configure the helloworld gateway + +Apply the helloworld gateway configuration: + +```bash +kubectl apply -f helloworld-gateway.yaml +``` + +Follow [these instructions](https://istio.io/docs/tasks/traffic-management/ingress/ingress-control/#determining-the-ingress-ip-and-ports) +to set the INGRESS_HOST and INGRESS_PORT variables and then confirm the sample is running using curl: + +```bash +export GATEWAY_URL=$INGRESS_HOST:$INGRESS_PORT +curl http://$GATEWAY_URL/hello +``` + +## Autoscale the services + +Note that a Kubernetes [Horizontal Pod Autoscaler](https://kubernetes.io/docs/tasks/run-application/horizontal-pod-autoscale/) +only works if all containers in the pods request cpu. In this sample the deployment +containers in `helloworld.yaml` are configured with the request. +The injected istio-proxy containers also include cpu requests, +making the helloworld service ready for autoscaling. + +Enable autoscaling on both versions of the service: + +```bash +kubectl autoscale deployment helloworld-v1 --cpu-percent=50 --min=1 --max=10 +kubectl autoscale deployment helloworld-v2 --cpu-percent=50 --min=1 --max=10 +kubectl get hpa +``` + +## Generate load + +```bash +./loadgen.sh & +./loadgen.sh & # run it twice to generate lots of load +``` + +Wait for about 2 minutes and then check the number of replicas: + +```bash +kubectl get hpa +``` + +If the autoscaler is functioning correctly, the `REPLICAS` column should have a value > 1. + +## Cleanup + +```bash +kubectl delete -f helloworld.yaml +kubectl delete -f helloworld-gateway.yaml +kubectl delete hpa helloworld-v1 helloworld-v2 +``` diff --git a/istio-1.5.0/samples/helloworld/helloworld-gateway.yaml b/istio-1.5.0/samples/helloworld/helloworld-gateway.yaml new file mode 100644 index 0000000..43afc14 --- /dev/null +++ b/istio-1.5.0/samples/helloworld/helloworld-gateway.yaml @@ -0,0 +1,33 @@ +apiVersion: networking.istio.io/v1alpha3 +kind: Gateway +metadata: + name: helloworld-gateway +spec: + selector: + istio: ingressgateway # use istio default controller + servers: + - port: + number: 80 + name: http + protocol: HTTP + hosts: + - "*" +--- +apiVersion: networking.istio.io/v1alpha3 +kind: VirtualService +metadata: + name: helloworld +spec: + hosts: + - "*" + gateways: + - helloworld-gateway + http: + - match: + - uri: + exact: /hello + route: + - destination: + host: helloworld + port: + number: 5000 diff --git a/istio-1.5.0/samples/helloworld/helloworld.yaml b/istio-1.5.0/samples/helloworld/helloworld.yaml new file mode 100644 index 0000000..2563918 --- /dev/null +++ b/istio-1.5.0/samples/helloworld/helloworld.yaml @@ -0,0 +1,68 @@ +apiVersion: v1 +kind: Service +metadata: + name: helloworld + labels: + app: helloworld +spec: + ports: + - port: 5000 + name: http + selector: + app: helloworld +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: helloworld-v1 + labels: + version: v1 +spec: + replicas: 1 + selector: + matchLabels: + app: helloworld + version: v1 + template: + metadata: + labels: + app: helloworld + version: v1 + spec: + containers: + - name: helloworld + image: docker.io/istio/examples-helloworld-v1 + resources: + requests: + cpu: "100m" + imagePullPolicy: IfNotPresent #Always + ports: + - containerPort: 5000 +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: helloworld-v2 + labels: + version: v2 +spec: + replicas: 1 + selector: + matchLabels: + app: helloworld + version: v2 + template: + metadata: + labels: + app: helloworld + version: v2 + spec: + containers: + - name: helloworld + image: docker.io/istio/examples-helloworld-v2 + resources: + requests: + cpu: "100m" + imagePullPolicy: IfNotPresent #Always + ports: + - containerPort: 5000 diff --git a/istio-1.5.0/samples/helloworld/src/requirements.txt b/istio-1.5.0/samples/helloworld/src/requirements.txt new file mode 100644 index 0000000..ac286ea --- /dev/null +++ b/istio-1.5.0/samples/helloworld/src/requirements.txt @@ -0,0 +1,7 @@ +requests +flask +flask_json +flask_bootstrap +json2html +simplejson +gevent diff --git a/istio-1.5.0/samples/httpbin/README.md b/istio-1.5.0/samples/httpbin/README.md new file mode 100644 index 0000000..ab84877 --- /dev/null +++ b/istio-1.5.0/samples/httpbin/README.md @@ -0,0 +1,39 @@ +# Httpbin service + +This sample runs [httpbin](https://httpbin.org) as an Istio service. +Httpbin is a well known HTTP testing service that can be used for experimenting +with all kinds of Istio features. + +To use it: + +1. Install Istio by following the [istio install instructions](https://istio.io/docs/setup/). + +1. Start the httpbin service inside the Istio service mesh: + + If you have [automatic sidecar injection](https://istio.io/docs/setup/additional-setup/sidecar-injection/#automatic-sidecar-injection) enabled: + + ```bash + kubectl apply -f httpbin.yaml + ``` + + Otherwise manually inject the sidecars before applying: + + ```bash + kubectl apply -f <(istioctl kube-inject -f httpbin.yaml) + ``` + +Because the httpbin service is not exposed outside of the cluster +you cannot _curl_ it directly, however you can verify that it is working correctly using +a _curl_ command against `httpbin:8000` *from inside the cluster* using the public _dockerqa/curl_ +image from Docker hub: + +```bash +kubectl run -i --rm --restart=Never dummy --image=dockerqa/curl:ubuntu-trusty --command -- curl --silent httpbin:8000/html +kubectl run -i --rm --restart=Never dummy --image=dockerqa/curl:ubuntu-trusty --command -- curl --silent --head httpbin:8000/status/500 +time kubectl run -i --rm --restart=Never dummy --image=dockerqa/curl:ubuntu-trusty --command -- curl --silent httpbin:8000/delay/5 +``` + +You can also test the httpbin service by starting the [sleep service](../sleep) and calling httpbin from it. + +A third option is to access the service from outside of the mesh through an Ingress Gateway. +The [Ingress Gateways](https://istio.io/docs/tasks/traffic-management/ingress/ingress-control/) task explains how to do it. diff --git a/istio-1.5.0/samples/httpbin/httpbin-gateway.yaml b/istio-1.5.0/samples/httpbin/httpbin-gateway.yaml new file mode 100644 index 0000000..99ac6ee --- /dev/null +++ b/istio-1.5.0/samples/httpbin/httpbin-gateway.yaml @@ -0,0 +1,30 @@ +apiVersion: networking.istio.io/v1alpha3 +kind: Gateway +metadata: + name: httpbin-gateway +spec: + selector: + istio: ingressgateway + servers: + - port: + number: 80 + name: http + protocol: HTTP + hosts: + - "*" +--- +apiVersion: networking.istio.io/v1alpha3 +kind: VirtualService +metadata: + name: httpbin +spec: + hosts: + - "*" + gateways: + - httpbin-gateway + http: + - route: + - destination: + host: httpbin + port: + number: 8000 diff --git a/istio-1.5.0/samples/httpbin/httpbin-nodeport.yaml b/istio-1.5.0/samples/httpbin/httpbin-nodeport.yaml new file mode 100644 index 0000000..a42b55c --- /dev/null +++ b/istio-1.5.0/samples/httpbin/httpbin-nodeport.yaml @@ -0,0 +1,54 @@ +# Copyright 2017 Istio Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +################################################################################################## +# httpbin service +################################################################################################## +apiVersion: v1 +kind: Service +metadata: + name: httpbin + labels: + app: httpbin +spec: + type: NodePort + ports: + - name: http + port: 8000 + targetPort: 80 + selector: + app: httpbin +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: httpbin +spec: + replicas: 1 + selector: + matchLabels: + app: httpbin + version: v1 + template: + metadata: + labels: + app: httpbin + version: v1 + spec: + containers: + - image: docker.io/kennethreitz/httpbin + imagePullPolicy: IfNotPresent + name: httpbin + ports: + - containerPort: 80 diff --git a/istio-1.5.0/samples/httpbin/httpbin-vault.yaml b/istio-1.5.0/samples/httpbin/httpbin-vault.yaml new file mode 100644 index 0000000..d05e954 --- /dev/null +++ b/istio-1.5.0/samples/httpbin/httpbin-vault.yaml @@ -0,0 +1,54 @@ +# Copyright 2019 Istio Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +################################################################################################## +# httpbin service +################################################################################################## +apiVersion: v1 +kind: Service +metadata: + name: httpbin + labels: + app: httpbin +spec: + ports: + - name: http + port: 8000 + targetPort: 80 + selector: + app: httpbin +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: httpbin +spec: + replicas: 1 + selector: + matchLabels: + app: httpbin + version: v1 + template: + metadata: + labels: + app: httpbin + version: v1 + spec: + serviceAccountName: vault-citadel-sa + containers: + - image: docker.io/kennethreitz/httpbin + imagePullPolicy: IfNotPresent + name: httpbin + ports: + - containerPort: 80 diff --git a/istio-1.5.0/samples/httpbin/httpbin.yaml b/istio-1.5.0/samples/httpbin/httpbin.yaml new file mode 100644 index 0000000..46cf6b7 --- /dev/null +++ b/istio-1.5.0/samples/httpbin/httpbin.yaml @@ -0,0 +1,59 @@ +# Copyright 2017 Istio Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +################################################################################################## +# httpbin service +################################################################################################## +apiVersion: v1 +kind: ServiceAccount +metadata: + name: httpbin +--- +apiVersion: v1 +kind: Service +metadata: + name: httpbin + labels: + app: httpbin +spec: + ports: + - name: http + port: 8000 + targetPort: 80 + selector: + app: httpbin +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: httpbin +spec: + replicas: 1 + selector: + matchLabels: + app: httpbin + version: v1 + template: + metadata: + labels: + app: httpbin + version: v1 + spec: + serviceAccountName: httpbin + containers: + - image: docker.io/kennethreitz/httpbin + imagePullPolicy: IfNotPresent + name: httpbin + ports: + - containerPort: 80 diff --git a/istio-1.5.0/samples/httpbin/policy/keyval-template.yaml b/istio-1.5.0/samples/httpbin/policy/keyval-template.yaml new file mode 100644 index 0000000..c194bc5 --- /dev/null +++ b/istio-1.5.0/samples/httpbin/policy/keyval-template.yaml @@ -0,0 +1,10 @@ +# this config is created through command +# mixgen template -d $GOPATH/src/istio.io/istio/mixer/test/keyval/template_handler_service.descriptor_set -o $GOPATH/src/istio.io/istio/mixer/test/keyval/template.yaml -n keyval +apiVersion: "config.istio.io/v1alpha2" +kind: template +metadata: + name: keyval + namespace: istio-system +spec: + descriptor: "CvD6AgogZ29vZ2xlL3Byb3RvYnVmL2Rlc2NyaXB0b3IucHJvdG8SD2dvb2dsZS5wcm90b2J1ZiJNChFGaWxlRGVzY3JpcHRvclNldBI4CgRmaWxlGAEgAygLMiQuZ29vZ2xlLnByb3RvYnVmLkZpbGVEZXNjcmlwdG9yUHJvdG9SBGZpbGUi5AQKE0ZpbGVEZXNjcmlwdG9yUHJvdG8SEgoEbmFtZRgBIAEoCVIEbmFtZRIYCgdwYWNrYWdlGAIgASgJUgdwYWNrYWdlEh4KCmRlcGVuZGVuY3kYAyADKAlSCmRlcGVuZGVuY3kSKwoRcHVibGljX2RlcGVuZGVuY3kYCiADKAVSEHB1YmxpY0RlcGVuZGVuY3kSJwoPd2Vha19kZXBlbmRlbmN5GAsgAygFUg53ZWFrRGVwZW5kZW5jeRJDCgxtZXNzYWdlX3R5cGUYBCADKAsyIC5nb29nbGUucHJvdG9idWYuRGVzY3JpcHRvclByb3RvUgttZXNzYWdlVHlwZRJBCgllbnVtX3R5cGUYBSADKAsyJC5nb29nbGUucHJvdG9idWYuRW51bURlc2NyaXB0b3JQcm90b1IIZW51bVR5cGUSQQoHc2VydmljZRgGIAMoCzInLmdvb2dsZS5wcm90b2J1Zi5TZXJ2aWNlRGVzY3JpcHRvclByb3RvUgdzZXJ2aWNlEkMKCWV4dGVuc2lvbhgHIAMoCzIlLmdvb2dsZS5wcm90b2J1Zi5GaWVsZERlc2NyaXB0b3JQcm90b1IJZXh0ZW5zaW9uEjYKB29wdGlvbnMYCCABKAsyHC5nb29nbGUucHJvdG9idWYuRmlsZU9wdGlvbnNSB29wdGlvbnMSSQoQc291cmNlX2NvZGVfaW5mbxgJIAEoCzIfLmdvb2dsZS5wcm90b2J1Zi5Tb3VyY2VDb2RlSW5mb1IOc291cmNlQ29kZUluZm8SFgoGc3ludGF4GAwgASgJUgZzeW50YXgiuQYKD0Rlc2NyaXB0b3JQcm90bxISCgRuYW1lGAEgASgJUgRuYW1lEjsKBWZpZWxkGAIgAygLMiUuZ29vZ2xlLnByb3RvYnVmLkZpZWxkRGVzY3JpcHRvclByb3RvUgVmaWVsZBJDCglleHRlbnNpb24YBiADKAsyJS5nb29nbGUucHJvdG9idWYuRmllbGREZXNjcmlwdG9yUHJvdG9SCWV4dGVuc2lvbhJBCgtuZXN0ZWRfdHlwZRgDIAMoCzIgLmdvb2dsZS5wcm90b2J1Zi5EZXNjcmlwdG9yUHJvdG9SCm5lc3RlZFR5cGUSQQoJZW51bV90eXBlGAQgAygLMiQuZ29vZ2xlLnByb3RvYnVmLkVudW1EZXNjcmlwdG9yUHJvdG9SCGVudW1UeXBlElgKD2V4dGVuc2lvbl9yYW5nZRgFIAMoCzIvLmdvb2dsZS5wcm90b2J1Zi5EZXNjcmlwdG9yUHJvdG8uRXh0ZW5zaW9uUmFuZ2VSDmV4dGVuc2lvblJhbmdlEkQKCm9uZW9mX2RlY2wYCCADKAsyJS5nb29nbGUucHJvdG9idWYuT25lb2ZEZXNjcmlwdG9yUHJvdG9SCW9uZW9mRGVjbBI5CgdvcHRpb25zGAcgASgLMh8uZ29vZ2xlLnByb3RvYnVmLk1lc3NhZ2VPcHRpb25zUgdvcHRpb25zElUKDnJlc2VydmVkX3JhbmdlGAkgAygLMi4uZ29vZ2xlLnByb3RvYnVmLkRlc2NyaXB0b3JQcm90by5SZXNlcnZlZFJhbmdlUg1yZXNlcnZlZFJhbmdlEiMKDXJlc2VydmVkX25hbWUYCiADKAlSDHJlc2VydmVkTmFtZRp6Cg5FeHRlbnNpb25SYW5nZRIUCgVzdGFydBgBIAEoBVIFc3RhcnQSEAoDZW5kGAIgASgFUgNlbmQSQAoHb3B0aW9ucxgDIAEoCzImLmdvb2dsZS5wcm90b2J1Zi5FeHRlbnNpb25SYW5nZU9wdGlvbnNSB29wdGlvbnMaNwoNUmVzZXJ2ZWRSYW5nZRIUCgVzdGFydBgBIAEoBVIFc3RhcnQSEAoDZW5kGAIgASgFUgNlbmQifAoVRXh0ZW5zaW9uUmFuZ2VPcHRpb25zElgKFHVuaW50ZXJwcmV0ZWRfb3B0aW9uGOcHIAMoCzIkLmdvb2dsZS5wcm90b2J1Zi5VbmludGVycHJldGVkT3B0aW9uUhN1bmludGVycHJldGVkT3B0aW9uKgkI6AcQgICAgAIimAYKFEZpZWxkRGVzY3JpcHRvclByb3RvEhIKBG5hbWUYASABKAlSBG5hbWUSFgoGbnVtYmVyGAMgASgFUgZudW1iZXISQQoFbGFiZWwYBCABKA4yKy5nb29nbGUucHJvdG9idWYuRmllbGREZXNjcmlwdG9yUHJvdG8uTGFiZWxSBWxhYmVsEj4KBHR5cGUYBSABKA4yKi5nb29nbGUucHJvdG9idWYuRmllbGREZXNjcmlwdG9yUHJvdG8uVHlwZVIEdHlwZRIbCgl0eXBlX25hbWUYBiABKAlSCHR5cGVOYW1lEhoKCGV4dGVuZGVlGAIgASgJUghleHRlbmRlZRIjCg1kZWZhdWx0X3ZhbHVlGAcgASgJUgxkZWZhdWx0VmFsdWUSHwoLb25lb2ZfaW5kZXgYCSABKAVSCm9uZW9mSW5kZXgSGwoJanNvbl9uYW1lGAogASgJUghqc29uTmFtZRI3CgdvcHRpb25zGAggASgLMh0uZ29vZ2xlLnByb3RvYnVmLkZpZWxkT3B0aW9uc1IHb3B0aW9ucyK2AgoEVHlwZRIPCgtUWVBFX0RPVUJMRRABEg4KClRZUEVfRkxPQVQQAhIOCgpUWVBFX0lOVDY0EAMSDwoLVFlQRV9VSU5UNjQQBBIOCgpUWVBFX0lOVDMyEAUSEAoMVFlQRV9GSVhFRDY0EAYSEAoMVFlQRV9GSVhFRDMyEAcSDQoJVFlQRV9CT09MEAgSDwoLVFlQRV9TVFJJTkcQCRIOCgpUWVBFX0dST1VQEAoSEAoMVFlQRV9NRVNTQUdFEAsSDgoKVFlQRV9CWVRFUxAMEg8KC1RZUEVfVUlOVDMyEA0SDQoJVFlQRV9FTlVNEA4SEQoNVFlQRV9TRklYRUQzMhAPEhEKDVRZUEVfU0ZJWEVENjQQEBIPCgtUWVBFX1NJTlQzMhAREg8KC1RZUEVfU0lOVDY0EBIiQwoFTGFiZWwSEgoOTEFCRUxfT1BUSU9OQUwQARISCg5MQUJFTF9SRVFVSVJFRBACEhIKDkxBQkVMX1JFUEVBVEVEEAMiYwoUT25lb2ZEZXNjcmlwdG9yUHJvdG8SEgoEbmFtZRgBIAEoCVIEbmFtZRI3CgdvcHRpb25zGAIgASgLMh0uZ29vZ2xlLnByb3RvYnVmLk9uZW9mT3B0aW9uc1IHb3B0aW9ucyLjAgoTRW51bURlc2NyaXB0b3JQcm90bxISCgRuYW1lGAEgASgJUgRuYW1lEj8KBXZhbHVlGAIgAygLMikuZ29vZ2xlLnByb3RvYnVmLkVudW1WYWx1ZURlc2NyaXB0b3JQcm90b1IFdmFsdWUSNgoHb3B0aW9ucxgDIAEoCzIcLmdvb2dsZS5wcm90b2J1Zi5FbnVtT3B0aW9uc1IHb3B0aW9ucxJdCg5yZXNlcnZlZF9yYW5nZRgEIAMoCzI2Lmdvb2dsZS5wcm90b2J1Zi5FbnVtRGVzY3JpcHRvclByb3RvLkVudW1SZXNlcnZlZFJhbmdlUg1yZXNlcnZlZFJhbmdlEiMKDXJlc2VydmVkX25hbWUYBSADKAlSDHJlc2VydmVkTmFtZRo7ChFFbnVtUmVzZXJ2ZWRSYW5nZRIUCgVzdGFydBgBIAEoBVIFc3RhcnQSEAoDZW5kGAIgASgFUgNlbmQigwEKGEVudW1WYWx1ZURlc2NyaXB0b3JQcm90bxISCgRuYW1lGAEgASgJUgRuYW1lEhYKBm51bWJlchgCIAEoBVIGbnVtYmVyEjsKB29wdGlvbnMYAyABKAsyIS5nb29nbGUucHJvdG9idWYuRW51bVZhbHVlT3B0aW9uc1IHb3B0aW9ucyKnAQoWU2VydmljZURlc2NyaXB0b3JQcm90bxISCgRuYW1lGAEgASgJUgRuYW1lEj4KBm1ldGhvZBgCIAMoCzImLmdvb2dsZS5wcm90b2J1Zi5NZXRob2REZXNjcmlwdG9yUHJvdG9SBm1ldGhvZBI5CgdvcHRpb25zGAMgASgLMh8uZ29vZ2xlLnByb3RvYnVmLlNlcnZpY2VPcHRpb25zUgdvcHRpb25zIokCChVNZXRob2REZXNjcmlwdG9yUHJvdG8SEgoEbmFtZRgBIAEoCVIEbmFtZRIdCgppbnB1dF90eXBlGAIgASgJUglpbnB1dFR5cGUSHwoLb3V0cHV0X3R5cGUYAyABKAlSCm91dHB1dFR5cGUSOAoHb3B0aW9ucxgEIAEoCzIeLmdvb2dsZS5wcm90b2J1Zi5NZXRob2RPcHRpb25zUgdvcHRpb25zEjAKEGNsaWVudF9zdHJlYW1pbmcYBSABKAg6BWZhbHNlUg9jbGllbnRTdHJlYW1pbmcSMAoQc2VydmVyX3N0cmVhbWluZxgGIAEoCDoFZmFsc2VSD3NlcnZlclN0cmVhbWluZyK5CAoLRmlsZU9wdGlvbnMSIQoMamF2YV9wYWNrYWdlGAEgASgJUgtqYXZhUGFja2FnZRIwChRqYXZhX291dGVyX2NsYXNzbmFtZRgIIAEoCVISamF2YU91dGVyQ2xhc3NuYW1lEjUKE2phdmFfbXVsdGlwbGVfZmlsZXMYCiABKAg6BWZhbHNlUhFqYXZhTXVsdGlwbGVGaWxlcxJECh1qYXZhX2dlbmVyYXRlX2VxdWFsc19hbmRfaGFzaBgUIAEoCEICGAFSGWphdmFHZW5lcmF0ZUVxdWFsc0FuZEhhc2gSOgoWamF2YV9zdHJpbmdfY2hlY2tfdXRmOBgbIAEoCDoFZmFsc2VSE2phdmFTdHJpbmdDaGVja1V0ZjgSUwoMb3B0aW1pemVfZm9yGAkgASgOMikuZ29vZ2xlLnByb3RvYnVmLkZpbGVPcHRpb25zLk9wdGltaXplTW9kZToFU1BFRURSC29wdGltaXplRm9yEh0KCmdvX3BhY2thZ2UYCyABKAlSCWdvUGFja2FnZRI1ChNjY19nZW5lcmljX3NlcnZpY2VzGBAgASgIOgVmYWxzZVIRY2NHZW5lcmljU2VydmljZXMSOQoVamF2YV9nZW5lcmljX3NlcnZpY2VzGBEgASgIOgVmYWxzZVITamF2YUdlbmVyaWNTZXJ2aWNlcxI1ChNweV9nZW5lcmljX3NlcnZpY2VzGBIgASgIOgVmYWxzZVIRcHlHZW5lcmljU2VydmljZXMSNwoUcGhwX2dlbmVyaWNfc2VydmljZXMYKiABKAg6BWZhbHNlUhJwaHBHZW5lcmljU2VydmljZXMSJQoKZGVwcmVjYXRlZBgXIAEoCDoFZmFsc2VSCmRlcHJlY2F0ZWQSLwoQY2NfZW5hYmxlX2FyZW5hcxgfIAEoCDoFZmFsc2VSDmNjRW5hYmxlQXJlbmFzEioKEW9iamNfY2xhc3NfcHJlZml4GCQgASgJUg9vYmpjQ2xhc3NQcmVmaXgSKQoQY3NoYXJwX25hbWVzcGFjZRglIAEoCVIPY3NoYXJwTmFtZXNwYWNlEiEKDHN3aWZ0X3ByZWZpeBgnIAEoCVILc3dpZnRQcmVmaXgSKAoQcGhwX2NsYXNzX3ByZWZpeBgoIAEoCVIOcGhwQ2xhc3NQcmVmaXgSIwoNcGhwX25hbWVzcGFjZRgpIAEoCVIMcGhwTmFtZXNwYWNlElgKFHVuaW50ZXJwcmV0ZWRfb3B0aW9uGOcHIAMoCzIkLmdvb2dsZS5wcm90b2J1Zi5VbmludGVycHJldGVkT3B0aW9uUhN1bmludGVycHJldGVkT3B0aW9uIjoKDE9wdGltaXplTW9kZRIJCgVTUEVFRBABEg0KCUNPREVfU0laRRACEhAKDExJVEVfUlVOVElNRRADKgkI6AcQgICAgAJKBAgmECci0QIKDk1lc3NhZ2VPcHRpb25zEjwKF21lc3NhZ2Vfc2V0X3dpcmVfZm9ybWF0GAEgASgIOgVmYWxzZVIUbWVzc2FnZVNldFdpcmVGb3JtYXQSTAofbm9fc3RhbmRhcmRfZGVzY3JpcHRvcl9hY2Nlc3NvchgCIAEoCDoFZmFsc2VSHG5vU3RhbmRhcmREZXNjcmlwdG9yQWNjZXNzb3ISJQoKZGVwcmVjYXRlZBgDIAEoCDoFZmFsc2VSCmRlcHJlY2F0ZWQSGwoJbWFwX2VudHJ5GAcgASgIUghtYXBFbnRyeRJYChR1bmludGVycHJldGVkX29wdGlvbhjnByADKAsyJC5nb29nbGUucHJvdG9idWYuVW5pbnRlcnByZXRlZE9wdGlvblITdW5pbnRlcnByZXRlZE9wdGlvbioJCOgHEICAgIACSgQICBAJSgQICRAKIuIDCgxGaWVsZE9wdGlvbnMSQQoFY3R5cGUYASABKA4yIy5nb29nbGUucHJvdG9idWYuRmllbGRPcHRpb25zLkNUeXBlOgZTVFJJTkdSBWN0eXBlEhYKBnBhY2tlZBgCIAEoCFIGcGFja2VkEkcKBmpzdHlwZRgGIAEoDjIkLmdvb2dsZS5wcm90b2J1Zi5GaWVsZE9wdGlvbnMuSlNUeXBlOglKU19OT1JNQUxSBmpzdHlwZRIZCgRsYXp5GAUgASgIOgVmYWxzZVIEbGF6eRIlCgpkZXByZWNhdGVkGAMgASgIOgVmYWxzZVIKZGVwcmVjYXRlZBIZCgR3ZWFrGAogASgIOgVmYWxzZVIEd2VhaxJYChR1bmludGVycHJldGVkX29wdGlvbhjnByADKAsyJC5nb29nbGUucHJvdG9idWYuVW5pbnRlcnByZXRlZE9wdGlvblITdW5pbnRlcnByZXRlZE9wdGlvbiIvCgVDVHlwZRIKCgZTVFJJTkcQABIICgRDT1JEEAESEAoMU1RSSU5HX1BJRUNFEAIiNQoGSlNUeXBlEg0KCUpTX05PUk1BTBAAEg0KCUpTX1NUUklORxABEg0KCUpTX05VTUJFUhACKgkI6AcQgICAgAJKBAgEEAUicwoMT25lb2ZPcHRpb25zElgKFHVuaW50ZXJwcmV0ZWRfb3B0aW9uGOcHIAMoCzIkLmdvb2dsZS5wcm90b2J1Zi5VbmludGVycHJldGVkT3B0aW9uUhN1bmludGVycHJldGVkT3B0aW9uKgkI6AcQgICAgAIiwAEKC0VudW1PcHRpb25zEh8KC2FsbG93X2FsaWFzGAIgASgIUgphbGxvd0FsaWFzEiUKCmRlcHJlY2F0ZWQYAyABKAg6BWZhbHNlUgpkZXByZWNhdGVkElgKFHVuaW50ZXJwcmV0ZWRfb3B0aW9uGOcHIAMoCzIkLmdvb2dsZS5wcm90b2J1Zi5VbmludGVycHJldGVkT3B0aW9uUhN1bmludGVycHJldGVkT3B0aW9uKgkI6AcQgICAgAJKBAgFEAYingEKEEVudW1WYWx1ZU9wdGlvbnMSJQoKZGVwcmVjYXRlZBgBIAEoCDoFZmFsc2VSCmRlcHJlY2F0ZWQSWAoUdW5pbnRlcnByZXRlZF9vcHRpb24Y5wcgAygLMiQuZ29vZ2xlLnByb3RvYnVmLlVuaW50ZXJwcmV0ZWRPcHRpb25SE3VuaW50ZXJwcmV0ZWRPcHRpb24qCQjoBxCAgICAAiKcAQoOU2VydmljZU9wdGlvbnMSJQoKZGVwcmVjYXRlZBghIAEoCDoFZmFsc2VSCmRlcHJlY2F0ZWQSWAoUdW5pbnRlcnByZXRlZF9vcHRpb24Y5wcgAygLMiQuZ29vZ2xlLnByb3RvYnVmLlVuaW50ZXJwcmV0ZWRPcHRpb25SE3VuaW50ZXJwcmV0ZWRPcHRpb24qCQjoBxCAgICAAiLgAgoNTWV0aG9kT3B0aW9ucxIlCgpkZXByZWNhdGVkGCEgASgIOgVmYWxzZVIKZGVwcmVjYXRlZBJxChFpZGVtcG90ZW5jeV9sZXZlbBgiIAEoDjIvLmdvb2dsZS5wcm90b2J1Zi5NZXRob2RPcHRpb25zLklkZW1wb3RlbmN5TGV2ZWw6E0lERU1QT1RFTkNZX1VOS05PV05SEGlkZW1wb3RlbmN5TGV2ZWwSWAoUdW5pbnRlcnByZXRlZF9vcHRpb24Y5wcgAygLMiQuZ29vZ2xlLnByb3RvYnVmLlVuaW50ZXJwcmV0ZWRPcHRpb25SE3VuaW50ZXJwcmV0ZWRPcHRpb24iUAoQSWRlbXBvdGVuY3lMZXZlbBIXChNJREVNUE9URU5DWV9VTktOT1dOEAASEwoPTk9fU0lERV9FRkZFQ1RTEAESDgoKSURFTVBPVEVOVBACKgkI6AcQgICAgAIimgMKE1VuaW50ZXJwcmV0ZWRPcHRpb24SQQoEbmFtZRgCIAMoCzItLmdvb2dsZS5wcm90b2J1Zi5VbmludGVycHJldGVkT3B0aW9uLk5hbWVQYXJ0UgRuYW1lEikKEGlkZW50aWZpZXJfdmFsdWUYAyABKAlSD2lkZW50aWZpZXJWYWx1ZRIsChJwb3NpdGl2ZV9pbnRfdmFsdWUYBCABKARSEHBvc2l0aXZlSW50VmFsdWUSLAoSbmVnYXRpdmVfaW50X3ZhbHVlGAUgASgDUhBuZWdhdGl2ZUludFZhbHVlEiEKDGRvdWJsZV92YWx1ZRgGIAEoAVILZG91YmxlVmFsdWUSIQoMc3RyaW5nX3ZhbHVlGAcgASgMUgtzdHJpbmdWYWx1ZRInCg9hZ2dyZWdhdGVfdmFsdWUYCCABKAlSDmFnZ3JlZ2F0ZVZhbHVlGkoKCE5hbWVQYXJ0EhsKCW5hbWVfcGFydBgBIAIoCVIIbmFtZVBhcnQSIQoMaXNfZXh0ZW5zaW9uGAIgAigIUgtpc0V4dGVuc2lvbiKnAgoOU291cmNlQ29kZUluZm8SRAoIbG9jYXRpb24YASADKAsyKC5nb29nbGUucHJvdG9idWYuU291cmNlQ29kZUluZm8uTG9jYXRpb25SCGxvY2F0aW9uGs4BCghMb2NhdGlvbhIWCgRwYXRoGAEgAygFQgIQAVIEcGF0aBIWCgRzcGFuGAIgAygFQgIQAVIEc3BhbhIpChBsZWFkaW5nX2NvbW1lbnRzGAMgASgJUg9sZWFkaW5nQ29tbWVudHMSKwoRdHJhaWxpbmdfY29tbWVudHMYBCABKAlSEHRyYWlsaW5nQ29tbWVudHMSOgoZbGVhZGluZ19kZXRhY2hlZF9jb21tZW50cxgGIAMoCVIXbGVhZGluZ0RldGFjaGVkQ29tbWVudHMi0QEKEUdlbmVyYXRlZENvZGVJbmZvEk0KCmFubm90YXRpb24YASADKAsyLS5nb29nbGUucHJvdG9idWYuR2VuZXJhdGVkQ29kZUluZm8uQW5ub3RhdGlvblIKYW5ub3RhdGlvbhptCgpBbm5vdGF0aW9uEhYKBHBhdGgYASADKAVCAhABUgRwYXRoEh8KC3NvdXJjZV9maWxlGAIgASgJUgpzb3VyY2VGaWxlEhQKBWJlZ2luGAMgASgFUgViZWdpbhIQCgNlbmQYBCABKAVSA2VuZEKPAQoTY29tLmdvb2dsZS5wcm90b2J1ZkIQRGVzY3JpcHRvclByb3Rvc0gBWj5naXRodWIuY29tL2dvbGFuZy9wcm90b2J1Zi9wcm90b2MtZ2VuLWdvL2Rlc2NyaXB0b3I7ZGVzY3JpcHRvcvgBAaICA0dQQqoCGkdvb2dsZS5Qcm90b2J1Zi5SZWZsZWN0aW9uSqrAAgoHEgUnAOcGAQqqDwoBDBIDJwASMsEMIFByb3RvY29sIEJ1ZmZlcnMgLSBHb29nbGUncyBkYXRhIGludGVyY2hhbmdlIGZvcm1hdAogQ29weXJpZ2h0IDIwMDggR29vZ2xlIEluYy4gIEFsbCByaWdodHMgcmVzZXJ2ZWQuCiBodHRwczovL2RldmVsb3BlcnMuZ29vZ2xlLmNvbS9wcm90b2NvbC1idWZmZXJzLwoKIFJlZGlzdHJpYnV0aW9uIGFuZCB1c2UgaW4gc291cmNlIGFuZCBiaW5hcnkgZm9ybXMsIHdpdGggb3Igd2l0aG91dAogbW9kaWZpY2F0aW9uLCBhcmUgcGVybWl0dGVkIHByb3ZpZGVkIHRoYXQgdGhlIGZvbGxvd2luZyBjb25kaXRpb25zIGFyZQogbWV0OgoKICAgICAqIFJlZGlzdHJpYnV0aW9ucyBvZiBzb3VyY2UgY29kZSBtdXN0IHJldGFpbiB0aGUgYWJvdmUgY29weXJpZ2h0CiBub3RpY2UsIHRoaXMgbGlzdCBvZiBjb25kaXRpb25zIGFuZCB0aGUgZm9sbG93aW5nIGRpc2NsYWltZXIuCiAgICAgKiBSZWRpc3RyaWJ1dGlvbnMgaW4gYmluYXJ5IGZvcm0gbXVzdCByZXByb2R1Y2UgdGhlIGFib3ZlCiBjb3B5cmlnaHQgbm90aWNlLCB0aGlzIGxpc3Qgb2YgY29uZGl0aW9ucyBhbmQgdGhlIGZvbGxvd2luZyBkaXNjbGFpbWVyCiBpbiB0aGUgZG9jdW1lbnRhdGlvbiBhbmQvb3Igb3RoZXIgbWF0ZXJpYWxzIHByb3ZpZGVkIHdpdGggdGhlCiBkaXN0cmlidXRpb24uCiAgICAgKiBOZWl0aGVyIHRoZSBuYW1lIG9mIEdvb2dsZSBJbmMuIG5vciB0aGUgbmFtZXMgb2YgaXRzCiBjb250cmlidXRvcnMgbWF5IGJlIHVzZWQgdG8gZW5kb3JzZSBvciBwcm9tb3RlIHByb2R1Y3RzIGRlcml2ZWQgZnJvbQogdGhpcyBzb2Z0d2FyZSB3aXRob3V0IHNwZWNpZmljIHByaW9yIHdyaXR0ZW4gcGVybWlzc2lvbi4KCiBUSElTIFNPRlRXQVJFIElTIFBST1ZJREVEIEJZIFRIRSBDT1BZUklHSFQgSE9MREVSUyBBTkQgQ09OVFJJQlVUT1JTCiAiQVMgSVMiIEFORCBBTlkgRVhQUkVTUyBPUiBJTVBMSUVEIFdBUlJBTlRJRVMsIElOQ0xVRElORywgQlVUIE5PVAogTElNSVRFRCBUTywgVEhFIElNUExJRUQgV0FSUkFOVElFUyBPRiBNRVJDSEFOVEFCSUxJVFkgQU5EIEZJVE5FU1MgRk9SCiBBIFBBUlRJQ1VMQVIgUFVSUE9TRSBBUkUgRElTQ0xBSU1FRC4gSU4gTk8gRVZFTlQgU0hBTEwgVEhFIENPUFlSSUdIVAogT1dORVIgT1IgQ09OVFJJQlVUT1JTIEJFIExJQUJMRSBGT1IgQU5ZIERJUkVDVCwgSU5ESVJFQ1QsIElOQ0lERU5UQUwsCiBTUEVDSUFMLCBFWEVNUExBUlksIE9SIENPTlNFUVVFTlRJQUwgREFNQUdFUyAoSU5DTFVESU5HLCBCVVQgTk9UCiBMSU1JVEVEIFRPLCBQUk9DVVJFTUVOVCBPRiBTVUJTVElUVVRFIEdPT0RTIE9SIFNFUlZJQ0VTOyBMT1NTIE9GIFVTRSwKIERBVEEsIE9SIFBST0ZJVFM7IE9SIEJVU0lORVNTIElOVEVSUlVQVElPTikgSE9XRVZFUiBDQVVTRUQgQU5EIE9OIEFOWQogVEhFT1JZIE9GIExJQUJJTElUWSwgV0hFVEhFUiBJTiBDT05UUkFDVCwgU1RSSUNUIExJQUJJTElUWSwgT1IgVE9SVAogKElOQ0xVRElORyBORUdMSUdF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bm5vdAogc3RvcmUgdGhlIHZhbHVlcyBpbiB0aGVtLiAgSW5zdGVhZCBpdCBzdG9yZXMgdGhlbSBpbiBhIGZpZWxkIGluIHRoZSAqT3B0aW9ucwogbWVzc2FnZSBjYWxsZWQgdW5pbnRlcnByZXRlZF9vcHRpb24uIFRoaXMgZmllbGQgbXVzdCBoYXZlIHRoZSBzYW1lIG5hbWUKIGFjcm9zcyBhbGwgKk9wdGlvbnMgbWVzc2FnZXMuIFdlIHRoZW4gdXNlIHRoaXMgZmllbGQgdG8gcG9wdWxhdGUgdGhlCiBleHRlbnNpb25zIHdoZW4gd2UgYnVpbGQgYSBkZXNjcmlwdG9yLCBhdCB3aGljaCBwb2ludCBhbGwgcHJvdG9zIGhhdmUgYmVlbgogcGFyc2VkIGFuZCBzbyBhbGwgZXh0ZW5zaW9ucyBhcmUga25vd24uCgogRXh0ZW5zaW9uIG51bWJlcnMgZm9yIGN1c3RvbSBvcHRpb25zIG1heSBiZSBjaG9zZW4gYXMgZm9sbG93czoKICogRm9yIG9wdGlvbnMgd2hpY2ggd2lsbCBvbmx5IGJlIHVzZWQgd2l0aGluIGEgc2luZ2xlIGFwcGxpY2F0aW9uIG9yCiAgIG9yZ2FuaXphdGlvbiwgb3IgZm9yIGV4cGVyaW1lbnRhbCBvcHRpb25zLCB1c2UgZmllbGQgbnVtYmVycyA1MDAwMAogICB0aHJvdWdoIDk5OTk5LiAgSXQgaXMgdXAgdG8geW91IHRvIGVuc3VyZSB0aGF0IHlvdSBkbyBub3QgdXNlIHRoZQogICBzYW1lIG51bWJlciBmb3IgbXVsdGlwbGUgb3B0aW9ucy4KICogRm9yIG9wdGlvbnMgd2hpY2ggd2lsbCBiZSBwdWJsaXNoZWQgYW5kIHVzZWQgcHVibGljbHkgYnkgbXVsdGlwbGUKICAgaW5kZXBlbmRlbnQgZW50aXRpZXMsIGUtbWFpbCBwcm90b2J1Zi1nbG9iYWwtZXh0ZW5zaW9uLXJlZ2lzdHJ5QGdvb2dsZS5jb20KICAgdG8gcmVzZXJ2ZSBleHRlbnNpb24gbnVtYmVycy4gU2ltcGx5IHByb3ZpZGUgeW91ciBwcm9qZWN0IG5hbWUgKGUuZy4KICAgT2JqZWN0aXZlLUMgcGx1Z2luKSBhbmQgeW91ciBwcm9qZWN0IHdlYnNpdGUgKGlmIGF2YWlsYWJsZSkgLS0gdGhlcmUncyBubwogICBuZWVkIHRvIGV4cGxhaW4gaG93IHlvdSBpbnRlbmQgdG8gdXNlIHRoZW0uIFVzdWFsbHkgeW91IG9ubHkgbmVlZCBvbmUKICAgZXh0ZW5zaW9uIG51bWJlci4gWW91IGNhbiBkZWNsYXJlIG11bHRpcGxlIG9wdGlvbnMgd2l0aCBvbmx5IG9uZSBleHRlbnNpb24KICAgbnVtYmVyIGJ5IHB1dHRpbmcgdGhlbSBpbiBhIHN1Yi1tZXNzYWdlLiBTZWUgdGhlIEN1c3RvbSBPcHRpb25zIHNlY3Rpb24gb2YKICAgdGhlIGRvY3MgZm9yIGV4YW1wbGVzOgogICBodHRwczovL2RldmVsb3BlcnMuZ29vZ2xlLmNvbS9wcm90b2NvbC1idWZmZXJzL2RvY3MvcHJvdG8jb3B0aW9ucwogICBJZiB0aGlzIHR1cm5zIG91dCB0byBiZSBwb3B1bGFyLCBhIHdlYiBzZXJ2aWNlIHdpbGwgYmUgc2V0IHVwCiAgIHRvIGF1dG9tYXRpY2FsbHkgYXNzaWduIG9wdGlvbiBudW1iZXJzLgoKCwoDBAoBEgS9AggTCvQBCgQECgIAEgTDAgIjGuUBIFNldHMgdGhlIEphdmEgcGFja2FnZSB3aGVyZSBjbGFzc2VzIGdlbmVyYXRlZCBmcm9tIHRoaXMgLnByb3RvIHdpbGwgYmUKIHBsYWNlZC4gIEJ5IGRlZmF1bHQsIHRoZSBwcm90byBwYWNrYWdlIGlzIHVzZWQsIGJ1dCB0aGlzIGlzIG9mdGVuCiBpbmFwcHJvcHJpYXRlIGJlY2F1c2UgcHJvdG8gcGFja2FnZXMgZG8gbm90IG5vcm1hbGx5IHN0YXJ0IHdpdGggYmFja3dhcmRzCiBkb21haW4gbmFtZXMuCgoNCgUECgIABBIEwwICCgoNCgUECgIABRIEwwILEQoNCgUECgIAARIEwwISHgoNCgUECgIAAxIEwwIhIgq/AgoEBAoCARIEywICKxqwAiBJZiBzZXQsIGFsbCB0aGUgY2xhc3NlcyBmcm9tIHRoZSAucHJvdG8gZmlsZSBhcmUgd3JhcHBlZCBpbiBhIHNpbmdsZQogb3V0ZXIgY2xh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CgUAEgSpAw0YCg0KBQQKBQABEgSpAw0RCg0KBQQKBQACEgSpAxUYCgsKAwQKCRIEqwMLDgoMCgQECgkAEgSrAwsNCg0KBQQKCQABEgSrAwsNCg0KBQQKCQACEgSrAwsNCgwKAgQLEgauAwDtAwEKCwoDBAsBEgSuAwgWCtgFCgQECwIAEgTBAwI8GskFIFNldCB0cnVlIHRvIHVzZSB0aGUgb2xkIHByb3RvMSBNZXNzYWdlU2V0IHdpcmUgZm9ybWF0IGZvciBleHRlbnNpb25zLgogVGhpcyBpcyBwcm92aWRlZCBmb3IgYmFja3dhcmRzLWNvbXBhdGliaWxpdHkgd2l0aCB0aGUgTWVzc2FnZVNldCB3aXJlCiBmb3JtYXQuICBZb3Ugc2hvdWxkIG5vdCB1c2UgdGhpcyBmb3IgYW55IG90aGVyIHJlYXNvbjogIEl0J3MgbGVzcwogZWZmaWNpZW50LCBoYXMgZmV3ZXIgZmVhdHVyZXMsIGFuZCBpcyBtb3JlIGNvbXBsaWNhdGVkLgoKIFRoZSBtZXNzYWdlIG11c3QgYmUgZGVmaW5lZCBleGFjdGx5IGFzIGZvbGxvd3M6CiAgIG1lc3NhZ2UgRm9vIHsKICAgICBvcHRpb24gbWVzc2FnZV9zZXRfd2lyZV9mb3JtYXQgPSB0cnVlOwogICAgIGV4dGVuc2lvbnMgNCB0byBtYXg7CiAgIH0KIE5vdGUgdGhhdCB0aGUgbWVzc2FnZSBjYW5ub3QgaGF2ZSBhbnkgZGVmaW5lZCBmaWVsZHM7IE1lc3NhZ2VTZXRzIG9ubHkKIGhhdmUgZXh0ZW5zaW9ucy4KCiBBbGwgZXh0ZW5zaW9ucyBvZiB5b3VyIHR5cGUgbXVzdCBiZSBzaW5ndWxhciBtZXNzYWdlczsgZS5nLiB0aGV5IGNhbm5vdAogYmUgaW50MzJzLCBlbnVtcywgb3IgcmVwZWF0ZWQgbWVzc2FnZXMuCgogQmVjYXVzZSB0aGlzIGlzIGFuIG9wdGlvbiwgdGhlIGFib3ZlIHR3byByZXN0cmljdGlvbnMgYXJlIG5vdCBlbmZvcmNlZCBieQogdGhlIHByb3RvY29sIGNvbXBpbGVyLgoKDQoFBAsCAAQSBMEDAgoKDQoFBAsCAAUSBMEDCw8KDQoFBAsCAAESBMEDECcKDQoFBAsCAAMSBMEDKisKDQoFBAsCAAgSBMEDLDsKDQoFBAsCAAcSBMEDNToK6wEKBAQLAgESBMYDAkQa3AEgRGlzYWJsZXMgdGhlIGdlbmVyYXRpb24gb2YgdGhlIHN0YW5kYXJkICJkZXNjcmlwdG9yKCkiIGFjY2Vzc29yLCB3aGljaCBjYW4KIGNvbmZsaWN0IHdpdGggYSBmaWVsZCBvZiB0aGUgc2FtZSBuYW1lLiAgVGhpcyBpcyBtZWFudCB0byBtYWtlIG1pZ3JhdGlvbgogZnJvbSBwcm90bzEgZWFzaWVyOyBuZXcgY29kZSBzaG91bGQgYXZvaWQgZmllbGRzIG5hbWVkICJkZXNjcmlwdG9yIi4KCg0KBQQLAgEEEgTGAwIKCg0KBQQLAgEFEgTGAwsPCg0KBQQLAgEBEgTGAxAvCg0KBQQLAgEDEgTGAzIzCg0KBQQLAgEIEgTGAzRDCg0KBQQLAgEHEgTGAz1CCu4BCgQECwICEgTMAwIvGt8BIElzIHRoaXMgbWVzc2FnZSBkZXByZWNhdGVkPwogRGVwZW5kaW5nIG9uIHRoZSB0YXJnZXQgcGxhdGZvcm0sIHRoaXMgY2FuIGVtaXQgRGVwcmVjYXRlZCBhbm5vdGF0aW9ucwogZm9yIHRoZSBtZXNzYWdlLCBvciBpdCB3aWxsIGJlIGNvbXBsZXRlbHkgaWdub3JlZDsgaW4gdGhlIHZlcnkgbGVhc3QsCiB0aGlzIGlzIGEgZm9ybWFsaXphdGlvbiBmb3IgZGVwcmVjYXRpbmcgbWVzc2FnZXMuCgoNCgUECwICBBIEzAMCCgoNCgUECwICBRIEzAMLDwoNCgUECwICARIEzAMQGgoNCgUECwICAxIEzAMdHgoNCgUECwICCBIEzAMfLgoNCgUECwICBxIEzAMoLQqeBgoEBAsCAxIE4wMCHhqPBiBXaGV0aGVyIHRoZSBtZXNzYWdlIGlzIGFuIGF1dG9tYXRpY2FsbHkgZ2VuZXJhdGVkIG1hcCBlbnRyeSB0eXBlIGZvciB0aGUKIG1hcHMgZmllbGQuCgogRm9yIG1hcHMgZmllbGRzOgogICAgIG1hcDxLZXlUeXBlLCBWYWx1ZVR5cGU+IG1hcF9maWVsZCA9IDE7CiBUaGUgcGFyc2VkIGRlc2NyaXB0b3IgbG9va3MgbGlrZToKICAgICBtZXNzYWdlIE1hcEZpZWxkRW50cnkgewogICAgICAgICBvcHRpb24gbWFwX2VudHJ5ID0gdHJ1ZTsKICAgICAgICAgb3B0aW9uYWwgS2V5VHlwZSBrZXkgPSAxOwogICAgICAgICBvcHRpb25hbCBWYWx1ZVR5cGUgdmFsdWUgPSAyOwogICAgIH0KICAgICByZXBlYXRlZCBNYXBGaWVsZEVudHJ5IG1hcF9maWVsZCA9IDE7CgogSW1wbGVtZW50YXRpb25zIG1heSBjaG9vc2Ugbm90IHRvIGdlbmVyYXRlIHRoZSBtYXBfZW50cnk9dHJ1ZSBtZXNzYWdlLCBidXQKIHVzZSBhIG5hdGl2ZSBtYXAgaW4gdGhlIHRhcmdldCBsYW5ndWFnZSB0byBob2xkIHRoZSBrZXlzIGFuZCB2YWx1ZXMuCiBUaGUgcmVmbGVjdGlvbiBBUElzIGluIHN1Y2ggaW1wbGVtZW50aW9ucyBzdGlsbCBuZWVkIHRvIHdvcmsgYXMKIGlmIHRoZSBmaWVsZCBpcyBhIHJlcGVhdGVkIG1lc3NhZ2UgZmllbGQuCgogTk9URTogRG8gbm90IHNldCB0aGUgb3B0aW9uIGluIC5wcm90byBmaWxlcy4gQWx3YXlzIHVzZSB0aGUgbWFwcyBzeW50YXgKIGluc3RlYWQuIFRoZSBvcHRpb24gc2hvdWxkIG9ubHkgYmUgaW1wbGljaXRseSBzZXQgYnkgdGhlIHByb3RvIGNvbXBpbGVyCiBwYXJzZXIuCgoNCgUECwIDBBIE4wMCCgoNCgUECwIDBRIE4wMLDwoNCgUECwIDARIE4wMQGQoNCgUECwIDAxIE4wMcHQokCgMECwkSBOUDCw0iFyBqYXZhbGl0ZV9zZXJpYWxpemFibGUKCgwKBAQLCQASBOUDCwwKDQoFBAsJAAESBOUDCwwKDQoFBAsJAAISBOUDCwwKHwoDBAsJEgTmAwsNIhIgamF2YW5hbm9fYXNfbGl0ZQoKDAoEBAsJARIE5gMLDAoNCgUECwkBARIE5gMLDAoNCgUECwkBAhIE5gMLDApPCgQECwIEEgTpAwI6GkEgVGhlIHBhcnNlciBzdG9yZXMgb3B0aW9ucyBpdCBkb2Vzbid0IHJlY29nbml6ZSBoZXJlLiBTZWUgYWJvdmUuCgoNCgUECwIEBBIE6QMCCgoNCgUECwIEBhIE6QMLHgoNCgUECwIEARIE6QMfMwoNCgUECwIEAxIE6QM2OQpaCgMECwUSBOwDAhkaTSBDbGllbnRzIGNhbiBkZWZpbmUgY3VzdG9tIG9wdGlvbnMgaW4gZXh0ZW5zaW9ucyBvZiB0aGlzIG1lc3NhZ2UuIFNlZSBhYm92ZS4KCgwKBAQLBQASBOwDDRgKDQoFBAsFAAESBOwDDREKDQoFBAsFAAISBOwDFRgKDAoCBAwSBu8DAMoEAQoLCgMEDAESBO8DCBQKowIKBAQMAgASBPQDAi4alAIgVGhlIGN0eXBlIG9wdGlvbiBpbnN0cnVjdHMgdGhlIEMrKyBjb2RlIGdlbmVyYXRvciB0byB1c2UgYSBkaWZmZXJlbnQKIHJlcHJlc2VudGF0aW9uIG9mIHRoZSBmaWVsZCB0aGFuIGl0IG5vcm1hbGx5IHdvdWxkLiAgU2VlIHRoZSBzcGVjaWZpYwogb3B0aW9ucyBiZWxvdy4gIFRoaXMgb3B0aW9uIGlzIG5vdCB5ZXQgaW1wbGVtZW50ZWQgaW4gdGhlIG9wZW4gc291cmNlCiByZWxlYXNlIC0tIHNvcnJ5LCB3ZSdsbCB0cnkgdG8gaW5jbHVkZSBpdCBpbiBhIGZ1dHVyZSB2ZXJzaW9uIQoKDQoFBAwCAAQSBPQDAgoKDQoFBAwCAAYSBPQDCxAKDQoFBAwCAAESBPQDERYKDQoFBAwCAAMSBPQDGRoKDQoFBAwCAAgSBPQDGy0KDQoFBAwCAAcSBPQDJiwKDgoEBAwEABIG9QMC/AMDCg0KBQQMBAABEgT1AwcMCh8KBgQMBAACABIE9wMEDxoPIERlZmF1bHQgbW9kZS4KCg8KBwQMBAACAAESBPcDBAoKDwoHBAwEAAIAAhIE9wMNDgoOCgYEDAQAAgESBPkDBA0KDwoHBAwEAAIBARIE+QMECAoPCgcEDAQAAgECEgT5AwsMCg4KBgQMBAACAhIE+wMEFQoPCgcEDAQAAgIBEgT7AwQQCg8KBwQMBAACAgISBPsDExQK2gIKBAQMAgESBIIEAhsaywIgVGhlIHBhY2tlZCBvcHRpb24gY2FuIGJlIGVuYWJsZWQgZm9yIHJlcGVhdGVkIHByaW1pdGl2ZSBmaWVsZHMgdG8gZW5hYmxlCiBhIG1vcmUgZWZmaWNpZW50IHJlcHJlc2VudGF0aW9uIG9uIHRoZSB3aXJlLiBSYXRoZXIgdGhhbiByZXBlYXRlZGx5CiB3cml0aW5nIHRoZSB0YWcgYW5kIHR5cGUgZm9yIGVhY2ggZWxlbWVudCwgdGhlIGVudGlyZSBhcnJheSBpcyBlbmNvZGVkIGFzCiBhIHNpbmdsZSBsZW5ndGgtZGVsaW1pdGVkIGJsb2IuIEluIHByb3RvMywgb25seSBleHBsaWNpdCBzZXR0aW5nIGl0IHRvCiBmYWxzZSB3aWxsIGF2b2lkIHVzaW5nIHBhY2tlZCBlbmNvZGluZy4KCg0KBQQMAgEEEgSCBAIKCg0KBQQMAgEFEgSCBAsPCg0KBQQMAgEBEgSCBBAWCg0KBQQMAgEDEgSCBBkaCpoFCgQEDAICEgSPBAIzGosFIFRoZSBqc3R5cGUgb3B0aW9uIGRldGVybWluZXMgdGhlIEphdmFTY3JpcHQgdHlwZSB1c2VkIGZvciB2YWx1ZXMgb2YgdGhlCiBmaWVsZC4gIFRoZSBvcHRpb24gaXMgcGVybWl0dGVkIG9ubHkgZm9yIDY0IGJpdCBpbnRlZ3JhbCBhbmQgZml4ZWQgdHlwZXMKIChpbnQ2NCwgdWludDY0LCBzaW50NjQsIGZpeGVkNjQsIHNmaXhlZDY0KS4gIEEgZmllbGQgd2l0aCBqc3R5cGUgSlNfU1RSSU5HCiBpcyByZXByZXNlbnRlZCBhcyBKYXZhU2NyaXB0IHN0cmluZywgd2hpY2ggYXZvaWRzIGxvc3Mgb2YgcHJlY2lzaW9uIHRoYXQKIGNhbiBoYXBwZW4gd2hlbiBhIGxhcmdlIHZhbHVlIGlzIGNvbnZlcnRlZCB0byBhIGZsb2F0aW5nIHBvaW50IEphdmFTY3JpcHQuCiBTcGVjaWZ5aW5nIEpTX05VTUJFUiBmb3IgdGhlIGpzdHlwZSBjYXVzZXMgdGhlIGdlbmVyYXRlZCBKYXZhU2NyaXB0IGNvZGUgdG8KIHVzZSB0aGUgSmF2YVNjcmlwdCAibnVtYmVyIiB0eXBlLiAgVGhlIGJlaGF2aW9yIG9mIHRoZSBkZWZhdWx0IG9wdGlvbgogSlNfTk9STUFMIGlzIGltcGxlbWVudGF0aW9uIGRlcGVuZGVudC4KCiBUaGlzIG9wdGlvbiBpcyBhbiBlbnVtIHRvIHBlcm1pdCBhZGRpdGlvbmFsIHR5cGVzIHRvIGJlIGFkZGVkLCBlLmcuCiBnb29nLm1hdGguSW50ZWdlci4KCg0KBQQMAgIEEgSPBAIKCg0KBQQMAgIGEgSPBAsRCg0KBQQMAgIBEgSPBBIYCg0KBQQMAgIDEgSPBBscCg0KBQQMAgIIEgSPBB0yCg0KBQQMAgIHEgSPBCgxCg4KBAQMBAESBpAEApkEAwoNCgUEDAQBARIEkAQHDQonCgYEDAQBAgASBJIEBBIaFyBVc2UgdGhlIGRlZmF1bHQgdHlwZS4KCg8KBwQMBAECAAESBJIEBA0KDwoHBAwEAQIAAhIEkgQQEQopCgYEDAQBAgESBJUEBBIaGSBVc2UgSmF2YVNjcmlwdCBzdHJpbmdzLgoKDwoHBAwEAQIBARIElQQEDQoPCgcEDAQBAgECEgSVBBARCikKBgQMBAECAhIEmAQEEhoZIFVzZSBKYXZhU2NyaXB0IG51bWJlcnMuCgoPCgcEDAQBAgIBEgSYBAQNCg8KBwQMBAECAgISBJgEEBEK7wwKBAQMAgMSBLcEAika4AwgU2hvdWxkIHRoaXMgZmllbGQgYmUgcGFyc2VkIGxhemlseT8gIExhenkgYXBwbGllcyBvbmx5IHRvIG1lc3NhZ2UtdHlwZQogZmllbGRzLiAgSXQgbWVhbnMgdGhhdCB3aGVuIHRoZSBvdXRlciBtZXNzYWdlIGlzIGluaXRpYWxseSBwYXJzZWQsIHRoZQogaW5uZXIgbWVzc2FnZSdzIGNvbnRlbnRzIHdpbGwgbm90IGJlIHBhcnNlZCBidXQgaW5zdGVhZCBzdG9yZWQgaW4gZW5jb2RlZAogZm9ybS4gIFRoZSBpbm5lciBtZXNzYWdlIHdpbGwgYWN0dWFsbHkgYmUgcGFyc2VkIHdoZW4gaXQgaXMgZmlyc3QgYWNjZXNzZWQuCgogVGhpcyBpcyBvbmx5IGEgaGludC4gIEltcGxlbWVudGF0aW9ucyBhcmUgZnJlZSB0byBjaG9vc2Ugd2hldGhlciB0byB1c2UKIGVhZ2VyIG9yIGxhenkgcGFyc2luZyByZWdhcmRsZXNzIG9mIHRoZSB2YWx1ZSBvZiB0aGlzIG9wdGlvbi4gIEhvd2V2ZXIsCiBzZXR0aW5nIHRoaXMgb3B0aW9uIHRydWUgc3VnZ2VzdHMgdGhhdCB0aGUgcHJvdG9jb2wgYXV0aG9yIGJlbGlldmVzIHRoYXQKIHVzaW5nIGxhenkgcGFyc2luZyBvbiB0aGlzIGZpZWxkIGlzIHdvcnRoIHRoZSBhZGRpdGlvbmFsIGJvb2trZWVwaW5nCiBvdmVyaGVhZCB0eXBpY2FsbHkgbmVlZGVkIHRvIGltcGxlbWVudCBpdC4KCiBUaGlzIG9wdGlvbiBkb2VzIG5vdCBhZmZlY3QgdGhlIHB1YmxpYyBpbnRlcmZhY2Ugb2YgYW55IGdlbmVyYXRlZCBjb2RlOwogYWxsIG1ldGhvZCBzaWduYXR1cmVzIHJlbWFpbiB0aGUgc2FtZS4gIEZ1cnRoZXJtb3JlLCB0aHJlYWQtc2FmZXR5IG9mIHRoZQogaW50ZXJmYWNlIGlzIG5vdCBhZmZlY3RlZCBieSB0aGlzIG9wdGlvbjsgY29uc3QgbWV0aG9kcyByZW1haW4gc2FmZSB0bwogY2FsbCBmcm9tIG11bHRpcGxlIHRocmVhZHMgY29uY3VycmVudGx5LCB3aGlsZSBub24tY29uc3QgbWV0aG9kcyBjb250aW51ZQogdG8gcmVxdWlyZSBleGNsdXNpdmUgYWNjZXNzLgoKCiBOb3RlIHRoYXQgaW1wbGVtZW50YXRpb25zIG1heSBjaG9vc2Ugbm90IHRvIGNoZWNrIHJlcXVpcmVkIGZpZWxkcyB3aXRoaW4KIGEgbGF6eSBzdWItbWVzc2FnZS4gIFRoYXQgaXMsIGNhbGxpbmcgSXNJbml0aWFsaXplZCgpIG9uIHRoZSBvdXRlciBtZXNzYWdlCiBtYXkgcmV0dXJuIHRydWUgZXZlbiBpZiB0aGUgaW5uZXIgbWVzc2FnZSBoYXMgbWlzc2luZyByZXF1aXJlZCBmaWVsZHMuCiBUaGlzIGlzIG5lY2Vzc2FyeSBiZWNhdXNlIG90aGVyd2lzZSB0aGUgaW5uZXIgbWVzc2FnZSB3b3VsZCBoYXZlIHRvIGJlCiBwYXJzZWQgaW4gb3JkZXIgdG8gcGVyZm9ybSB0aGUgY2hlY2ssIGRlZmVhdGluZyB0aGUgcHVycG9zZSBvZiBsYXp5CiBwYXJzaW5nLiAgQW4gaW1wbGVtZW50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dCByZWNvZ25pemUuIFRoaXMgb25seQogYXBwZWFycyBpbiBvcHRpb25zIHByb3RvcyBjcmVhdGVkIGJ5IHRoZSBjb21waWxlcjo6UGFyc2VyIGNsYXNzLgogRGVzY3JpcHRvclBvb2wgcmVzb2x2ZXMgdGhlc2Ugd2hlbiBidWlsZGluZyBEZXNjcmlwdG9yIG9iamVjdHMuIFRoZXJlZm9yZSwKIG9wdGlvbnMgcHJvdG9zIGluIGRlc2NyaXB0b3Igb2JqZWN0cyAoZS5nLiByZXR1cm5lZCBieSBEZXNjcmlwdG9yOjpvcHRpb25zKCksCiBvciBwcm9kdWNlZCBieSBEZXNjcmlwdG9yOjpDb3B5VG8oKSkgd2lsbCBuZXZlciBoYXZlIFVuaW50ZXJwcmV0ZWRPcHRpb25zCiBpbiB0aGVtLgoKCwoDBBIBEgSxBQgbCssCCgQEEgMAEga3BQK6BQMaugIgVGhlIG5hbWUgb2YgdGhlIHVuaW50ZXJwcmV0ZWQgb3B0aW9uLiAgRWFjaCBzdHJpbmcgcmVwcmVzZW50cyBhIHNlZ21lbnQgaW4KIGEgZG90LXNlcGFyYXRlZCBuYW1lLiAgaXNfZXh0ZW5zaW9uIGlzIHRydWUgaWZmIGEgc2VnbWVudCByZXByZXNlbnRzIGFuCiBleHRlbnNpb24gKGRlbm90ZWQgd2l0aCBwYXJlbnRoZXNlcyBpbiBvcHRpb25zIHNwZWNzIGluIC5wcm90byBmaWxlcykuCiBFLmcuLHsgWyJmb28iLCBmYWxzZV0sIFsiYmFyLmJheiIsIHRydWVdLCBbInF1eCIsIGZhbHNlXSB9IHJlcHJlc2VudHMKICJmb28uKGJhci5iYXopLnF1eCIuCgoNCgUEEgMAARIEtwUKEgoOCgYEEgMAAgASBLgFBCIKDwoHBBIDAAIABBIEuAUEDAoPCgcEEgMAAgAFEgS4BQ0TCg8KBwQSAwACAAESBLgFFB0KDwoHBBIDAAIAAxIEuAUgIQoOCgYEEgMAAgESBLkFBCMKDwoHBBIDAAIBBBIEuQUEDAoPCgcEEgMAAgEFEgS5BQ0RCg8KBwQSAwACAQESBLkFEh4KDwoHBBIDAAIBAxIEuQUhIgoMCgQEEgIAEgS7BQIdCg0KBQQSAgAEEgS7BQIKCg0KBQQSAgAGEgS7BQsTCg0KBQQSAgABEgS7BRQYCg0KBQQSAgADEgS7BRscCpwBCgQEEgIBEgS/BQInGo0BIFRoZSB2YWx1ZSBvZiB0aGUgdW5pbnRlcnByZXRlZCBvcHRpb24sIGluIHdoYXRldmVyIHR5cGUgdGhlIHRva2VuaXplcgogaWRlbnRpZmllZCBpdCBhcyBkdXJpbmcgcGFyc2luZy4gRXhhY3RseSBvbmUgb2YgdGhlc2Ugc2hvdWxkIGJlIHNldC4KCg0KBQQSAgEEEgS/BQIKCg0KBQQSAgEFEgS/BQsRCg0KBQQSAgEBEgS/BRIiCg0KBQQSAgEDEgS/BSUmCgwKBAQSAgISBMAFAikKDQoFBBICAgQSBMAFAgoKDQoFBBICAgUSBMAFCxEKDQoFBBICAgESBMAFEiQKDQoFBBICAgMSBMAFJygKDAoEBBICAxIEwQUCKAoNCgUEEgIDBBIEwQUCCgoNCgUEEgIDBRIEwQULEAoNCgUEEgIDARIEwQURIwoNCgUEEgIDAxIEwQUmJwoMCgQEEgIEEgTCBQIjCg0KBQQSAgQEEgTCBQIKCg0KBQQSAgQFEgTCBQsRCg0KBQQSAgQBEgTCBRIeCg0KBQQSAgQDEgTCBSEiCgwKBAQSAgUSBMMFAiIKDQoFBBICBQQSBMMFAgoKDQoFBBICBQUSBMMFCxAKDQoFBBICBQESBMMFER0KDQoFBBICBQMSBMMFICEKDAoEBBICBhIExAUCJgoNCgUEEgIGBBIExAUCCgoNCgUEEgIGBRIExAULEQoNCgUEEgIGARIExAUSIQoNCgUEEgIGAxIExAUkJQraAQoCBBMSBswFAM0GARpqIEVuY2Fwc3VsYXRlcyBpbmZvcm1hdGlvbiBhYm91dCB0aGUgb3JpZ2luYWwgc291cmNlIGZpbGUgZnJvbSB3aGljaCBhCiBGaWxlRGVzY3JpcHRvclByb3RvIHdhcyBnZW5lcmF0ZWQuCjJgID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT0KIE9wdGlvbmFsIHNvdXJjZSBjb2RlIGluZm8KCgsKAwQTARIEzAUIFgqCEQoEBBMCABIE+AUCIRrzECBBIExvY2F0aW9uIGlkZW50aWZpZXMgYSBwaWVjZSBvZiBzb3VyY2UgY29kZSBpbiBhIC5wcm90byBmaWxlIHdoaWNoCiBjb3JyZXNwb25kcyB0byBhIHBhcnRpY3VsYXIgZGVmaW5pdGlvbi4gIFRoaXMgaW5mb3JtYXRpb24gaXMgaW50ZW5kZWQKIHRvIGJlIHVzZWZ1bCB0byBJREVzLCBjb2RlIGluZGV4ZXJzLCBkb2N1bWVudGF0aW9uIGdlbmVyYXRvcnMsIGFuZCBzaW1pbGFyCiB0b29scy4KCiBGb3IgZXhhbXBsZSwgc2F5IHdlIGhhdmUgYSBmaWxlIGxpa2U6CiAgIG1lc3NhZ2UgRm9vIHsKICAgICBvcHRpb25hbCBzdHJpbmcgZm9vID0gMTsKICAgfQogTGV0J3MgbG9vayBhdCBqdXN0IHRoZSBmaWVsZCBkZWZpbml0aW9uOgogICBvcHRpb25hbCBzdHJpbmcgZm9vID0gMTsKICAgXiAgICAgICBeXiAgICAgXl4gIF4gIF5eXgogICBhICAgICAgIGJjICAgICBkZSAgZiAgZ2hpCiBXZSBoYXZlIHRoZSBmb2xsb3dpbmcgbG9jYXRpb25zOgogICBzcGFuICAgcGF0aCAgICAgICAgICAgICAgIHJlcHJlc2VudHMKICAgW2EsaSkgIFsgNCwgMCwgMiwgMCBdICAgICBUaGUgd2hvbGUgZmllbGQgZGVmaW5pdGlvbi4KICAgW2EsYikgIFsgNCwgMCwgMiwgMCwgNCBdICBUaGUgbGFiZWwgKG9wdGlvbmFsKS4KICAgW2MsZCkgIFsgNCwgMCwgMiwgMCwgNSBdICBUaGUgdHlwZSAoc3RyaW5nKS4KICAgW2UsZikgIFsgNCwgMCwgMiwgMCwgMSBdICBUaGUgbmFtZSAoZm9vKS4KICAgW2csaCkgIFsgNCwgMCwgMiwgMCwgMyBdICBUaGUgbnVtYmVyICgxKS4KCiBOb3RlczoKIC0gQSBsb2NhdGlvbiBtYXkgcmVmZXIgdG8gYSByZXBlYXRlZCBmaWVsZCBpdHNlbGYgKGkuZS4gbm90IHRvIGFueQogICBwYXJ0aWN1bGFyIGluZGV4IHdpdGhpbiBpdCkuICBUaGlzIGlzIHVzZWQgd2hlbmV2ZXIgYSBzZXQgb2YgZWxlbWVudHMgYXJlCiAgIGxvZ2ljYWxseSBlbmNsb3NlZCBpbiBhIHNpbmdsZSBjb2RlIHNlZ21lbnQuICBGb3IgZXhhbXBsZSwgYW4gZW50aXJlCiAgIGV4dGVuZCBibG9jayAocG9zc2libHkgY29udGFpbmluZyBtdWx0aXBsZSBleHRlbnNpb24gZGVmaW5pdGlvbnMpIHdpbGwKICAgaGF2ZSBhbiBvdXRlciBsb2NhdGlvbiB3aG9zZSBwYXRoIHJlZmVycyB0byB0aGUgImV4dGVuc2lvbnMiIHJlcGVhdGVkCiAgIGZpZWxkIHdpdGhvdXQgYW4gaW5kZXguCiAtIE11bHRpcGxlIGxvY2F0aW9ucyBtYXkgaGF2ZSB0aGUgc2FtZSBwYXRoLiAgVGhpcyBoYXBwZW5zIHdoZW4gYSBzaW5nbGUKICAgbG9naWNhbCBkZWNsYXJhdGlvbiBpcyBzcHJlYWQgb3V0IGFjcm9zcyBtdWx0aXBsZSBwbGFjZXMuICBUaGUgbW9zdAogICBvYnZpb3VzIGV4YW1wbGUgaXMgdGhlICJleHRlbmQiIGJsb2NrIGFnYWluIC0tIHRoZXJlIG1heSBiZSBtdWx0aXBsZQogICBleHRlbmQgYmxvY2tzIGluIHRoZSBzYW1lIHNjb3BlLCBlYWNoIG9mIHdoaWNoIHdpbGwgaGF2ZSB0aGUgc2FtZSBwYXRoLgogLSBBIGxvY2F0aW9uJ3Mgc3BhbiBpcyBub3QgYWx3YXlzIGEgc3Vic2V0IG9mIGl0cyBwYXJlbnQncyBzcGFuLiAgRm9yCiAgIGV4YW1wbGUsIHRoZSAiZXh0ZW5kZWUiIG9mIGFuIGV4dGVuc2lvbiBkZWNsYXJhdGlvbiBhcHBlYXJzIGF0IHRoZQogICBiZWdpbm5pbmcgb2YgdGhlICJleHRlbmQiIGJsb2NrIGFuZCBpcyBzaGFyZWQgYnkgYWxsIGV4dGVuc2lvbnMgd2l0aGluCiAgIHRoZSBibG9jay4KIC0gSnVzdCBiZWNhdXNlIGEgbG9jYXRpb24ncyBzcGFuIGlzIGEgc3Vic2V0IG9mIHNvbWUgb3RoZXIgbG9jYXRpb24ncyBzcGFuCiAgIGRvZXMgbm90IG1lYW4gdGhhdCBpdCBpcyBhIGRlc2NlbmRlbnQuICBGb3IgZXhhbXBsZSwgYSAiZ3JvdXAiIGRlZmluZXMKICAgYm90aCBhIHR5cGUgYW5kIGEgZmllbGQgaW4gYSBzaW5nbGUgZGVjbGFyYXRpb24uICBUaHVzLCB0aGUgbG9jYXRpb25zCiAgIGNvcnJlc3BvbmRpbmcgdG8gdGhlIHR5cGUgYW5kIGZpZWxkIGFuZCB0aGVpciBjb21wb25lbnRzIHdpbGwgb3ZlcmxhcC4KIC0gQ29kZSB3aGljaCB0cmllcyB0byBpbnRlcnByZXQgbG9jYXRpb25zIHNob3VsZCBwcm9iYWJseSBiZSBkZXNpZ25lZCB0bwogICBpZ25vcmUgdGhvc2UgdGhhdCBpdCBkb2Vzbid0IHVuZGVyc3RhbmQsIGFzIG1vcmUgdHlwZXMgb2YgbG9jYXRpb25zIGNvdWxkCiAgIGJlIHJlY29yZGVkIGluIHRoZSBmdXR1cmUuCgoNCgUEEwIABBIE+AUCCgoNCgUEEwIABhIE+AULEwoNCgUEEwIAARIE+AUUHAoNCgUEEwIAAxIE+AUfIAoOCgQEEwMAEgb5BQLMBgMKDQoFBBMDAAESBPkFChIKgwcKBgQTAwACABIEkQYEKhryBiBJZGVudGlmaWVzIHdoaWNoIHBhcnQgb2YgdGhlIEZpbGVEZXNjcmlwdG9yUHJvdG8gd2FzIGRlZmluZWQgYXQgdGhpcwogbG9jYXRpb24uCgogRWFjaCBlbGVtZW50IGlzIGEgZmllbGQgbnVtYmVyIG9yIGFuIGluZGV4LiAgVGhleSBmb3JtIGEgcGF0aCBmcm9tCiB0aGUgcm9vdCBGaWxlRGVzY3JpcHRvclByb3RvIHRvIHRoZSBwbGFjZSB3aGVyZSB0aGUgZGVmaW5pdGlvbi4gIEZvcgogZXhhbXBsZSwgdGhpcyBwYXRoOgogICBbIDQsIDMsIDIsIDcsIDEgXQogcmVmZXJzIHRvOgogICBmaWxlLm1lc3NhZ2VfdHlwZSgzKSAgLy8gNCwgMwogICAgICAgLmZpZWxkKDcpICAgICAgICAgLy8gMiwgNwogICAgICAgLm5hbWUoKSAgICAgICAgICAgLy8gMQogVGhpcyBpcyBiZWNhdXNlIEZpbGVEZXNjcmlwdG9yUHJvdG8ubWVzc2FnZV90eXBlIGhhcyBmaWVsZCBudW1iZXIgNDoKICAgcmVwZWF0ZWQgRGVzY3JpcHRvclByb3RvIG1lc3NhZ2VfdHlwZSA9IDQ7CiBhbmQgRGVzY3JpcHRvclByb3RvLmZpZWxkIGhhcyBmaWVsZCBudW1iZXIgMjoKICAgcmVwZWF0ZWQgRmllbGREZXNjcmlwdG9yUHJvdG8gZmllbGQgPSAyOwogYW5kIEZpZWxkRGVzY3JpcHRvclByb3RvLm5hbWUgaGFzIGZpZWxkIG51bWJlciAxOgogICBvcHRpb25hbCBzdHJpbmcgbmFtZSA9IDE7CgogVGh1cywgdGhlIGFib3ZlIHBhdGggZ2l2ZXMgdGhlIGxvY2F0aW9uIG9mIGEgZmllbGQgbmFtZS4gIElmIHdlIHJlbW92ZWQKIHRoZSBsYXN0IGVsZW1lbnQ6CiAgIFsgNCwgMywgMiwgNyBdCiB0aGlzIHBhdGggcmVmZXJzIHRvIHRoZSB3aG9sZSBmaWVsZCBkZWNsYXJhdGlvbiAoZnJvbSB0aGUgYmVnaW5uaW5nCiBvZiB0aGUgbGFiZWwgdG8gdGhlIHRlcm1pbmF0aW5nIHNlbWljb2xvbikuCgoPCgcEEwMAAgAEEgSRBgQMCg8KBwQTAwACAAUSBJEGDRIKDwoHBBMDAAIAARIEkQYTFwoPCgcEEwMAAgADEgSRBhobCg8KBwQTAwACAAgSBJEGHCkKEgoKBBMDAAIACOcHABIEkQYdKAoTCgsEEwMAAgAI5wcAAhIEkQYdIwoUCgwEEwMAAgAI5wcAAgASBJEGHSMKFQoNBBMDAAIACOcHAAIAARIEkQYdIwoTCgsEEwMAAgAI5wcAAxIEkQYkKArSAgoGBBMDAAIBEgSYBgQqGsECIEFsd2F5cyBoYXMgZXhhY3RseSB0aHJlZSBvciBmb3VyIGVsZW1lbnRzOiBzdGFydCBsaW5lLCBzdGFydCBjb2x1bW4sCiBlbmQgbGluZSAob3B0aW9uYWwsIG90aGVyd2lzZSBhc3N1bWVkIHNhbWUgYXMgc3RhcnQgbGluZSksIGVuZCBjb2x1bW4uCiBUaGVzZSBhcmUgcGFja2VkIGludG8gYSBzaW5nbGUgZmllbGQgZm9yIGVmZmljaWVuY3kuICBOb3RlIHRoYXQgbGluZQogYW5kIGNvbHVtbiBudW1iZXJzIGFyZSB6ZXJvLWJhc2VkIC0tIHR5cGljYWxseSB5b3Ugd2lsbCB3YW50IHRvIGFkZAogMSB0byBlYWNoIGJlZm9yZSBkaXNwbGF5aW5nIHRvIGEgdXNlci4KCg8KBwQTAwACAQQSBJgGBAwKDwoHBBMDAAIBBRIEmAYNEgoPCgcEEwMAAgEBEgSYBhMXCg8KBwQTAwACAQMSBJgGGhsKDwoHBBMDAAIBCBIEmAYcKQoSCgoEEwMAAgEI5wcAEgSYBh0oChMKCwQTAwACAQjnBwACEgSYBh0jChQKDAQTAwACAQjnBwACABIEmAYdIwoVCg0EEwMAAgEI5wcAAgABEgSYBh0jChMKCwQTAwACAQjnBwADEgSYBiQoCqUMCgYEEwMAAgISBMkGBCkalAwgSWYgdGhpcyBTb3VyY2VDb2RlSW5mbyByZXByZXNlbnRzIGEgY29tcGxldGUgZGVjbGFyYXRpb24sIHRoZXNlIGFyZSBhbnkKIGNvbW1lbnRzIGFwcGVhcmluZyBiZWZvcmUgYW5kIGFmdGVyIHRoZSBkZWNsYXJhdGlvbiB3aGljaCBhcHBlYXIgdG8gYmUKIGF0dGFjaGVkIHRvIHRoZSBkZWNsYXJhdGlvbi4KCiBBIHNlcmllcyBvZiBsaW5lIGNvbW1lbnRzIGFwcGVhcmluZyBvbiBjb25zZWN1dGl2ZSBsaW5lcywgd2l0aCBubyBvdGhlcgogdG9rZW5zIGFwcGVhcmluZyBvbiB0aG9zZSBsaW5lcywgd2lsbCBiZSB0cmVhdGVkIGFzIGEgc2luZ2xlIGNvbW1lbnQuCgogbGVhZGluZ19kZXRhY2hlZF9jb21tZW50cyB3aWxsIGtlZXAgcGFyYWdyYXBocyBvZiBjb21tZW50cyB0aGF0IGFwcGVhcgogYmVmb3JlIChidXQgbm90IGNvbm5lY3RlZCB0bykgdGhlIGN1cnJlbnQgZWxlbWVudC4gRWFjaCBwYXJhZ3JhcGgsCiBzZXBhcmF0ZWQgYnkgZW1wdHkgbGluZXMsIHdpbGwgYmUgb25lIGNvbW1lbnQgZWxlbWVudCBpbiB0aGUgcmVwZWF0ZWQKIGZpZWxkLgoKIE9ubHkgdGhlIGNvbW1lbnQgY29udGVudCBpcyBwcm92aWRlZDsgY29tbWVudCBtYXJrZXJzIChlLmcuIC8vKSBhcmUKIHN0cmlwcGVkIG91dC4gIEZvciBibG9jayBjb21tZW50cywgbGVhZGluZyB3aGl0ZXNwYWNlIGFuZCBhbiBhc3Rlcmlzawogd2lsbCBiZSBzdHJpcHBlZCBmcm9tIHRoZSBiZWdpbm5pbmcgb2YgZWFjaCBsaW5lIG90aGVyIHRoYW4gdGhlIGZpcnN0LgogTmV3bGluZXMgYXJlIGluY2x1ZGVkIGluIHRoZSBvdXRwdXQuCgogRXhhbXBsZXM6CgogICBvcHRpb25hbCBpbnQzMiBmb28gPSAxOyAgLy8gQ29tbWVudCBhdHRhY2hlZCB0byBmb28uCiAgIC8vIENvbW1lbnQgYXR0YWNoZWQgdG8gYmFyLgogICBvcHRpb25hbCBpbnQzMiBiYXIgPSAyOwoKICAgb3B0aW9uYWwgc3RyaW5nIGJheiA9IDM7CiAgIC8vIENvbW1lbnQgYXR0YWNoZWQgdG8gYmF6LgogICAvLyBBbm90aGVyIGxpbmUgYXR0YWNoZWQgdG8gYmF6LgoKICAgLy8gQ29tbWVudCBhdHRhY2hlZCB0byBxdXguCiAgIC8vCiAgIC8vIEFub3RoZXIgbGluZSBhdHRhY2hlZCB0byBxdXguCiAgIG9wdGlvbmFsIGRvdWJsZSBxdXggPSA0OwoKICAgLy8gRGV0YWNoZWQgY29tbWVudCBmb3IgY29yZ2UuIFRoaXMgaXMgbm90IGxlYWRpbmcgb3IgdHJhaWxpbmcgY29tbWVudHMKICAgLy8gdG8gcXV4IG9yIGNvcmdlIGJlY2F1c2UgdGhlcmUgYXJlIGJsYW5rIGxpbmVzIHNlcGFyYXRpbmcgaXQgZnJvbQogICAvLyBib3RoLgoKICAgLy8gRGV0YWNoZWQgY29tbWVudCBmb3IgY29yZ2UgcGFyYWdyYXBoIDIuCgogICBvcHRpb25hbCBzdHJpbmcgY29yZ2UgPSA1OwogICAvKiBCbG9jayBjb21tZW50IGF0dGFjaGVkCiAgICAqIHRvIGNvcmdlLiAgTGVhZGluZyBhc3Rlcmlza3MKICAgICogd2lsbCBiZSByZW1vdmVkLiAqLwogICAvKiBCbG9jayBjb21tZW50IGF0dGFjaGVkIHRvCiAgICAqIGdyYXVsdC4gKi8KICAgb3B0aW9uYWwgaW50MzIgZ3JhdWx0ID0gNjsKCiAg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bGUucHJvdG9idWYuRW51bU9wdGlvbnMYseQDIAEoCFIRZ29wcm90b0VudW1QcmVmaXg6UgoVZ29wcm90b19lbnVtX3N0cmluZ2VyEhwuZ29vZ2xlLnByb3RvYnVmLkVudW1PcHRpb25zGMXkAyABKAhSE2dvcHJvdG9FbnVtU3RyaW5nZXI6QwoNZW51bV9zdHJpbmdlchIcLmdvb2dsZS5wcm90b2J1Zi5FbnVtT3B0aW9ucxjG5AMgASgIUgxlbnVtU3RyaW5nZXI6RwoPZW51bV9jdXN0b21uYW1lEhwuZ29vZ2xlLnByb3RvYnVmLkVudW1PcHRpb25zGMfkAyABKAlSDmVudW1DdXN0b21uYW1lOjoKCGVudW1kZWNsEhwuZ29vZ2xlLnByb3RvYnVmLkVudW1PcHRpb25zGMjkAyABKAhSCGVudW1kZWNsOlYKFGVudW12YWx1ZV9jdXN0b21uYW1lEiEuZ29vZ2xlLnByb3RvYnVmLkVudW1WYWx1ZU9wdGlvbnMY0YMEIAEoCVITZW51bXZhbHVlQ3VzdG9tbmFtZTpOChNnb3Byb3RvX2dldHRlcnNfYWxsEhwuZ29vZ2xlLnByb3RvYnVmLkZpbGVPcHRpb25zGJnsAyABKAhSEWdvcHJvdG9HZXR0ZXJzQWxsOlUKF2dvcHJvdG9fZW51bV9wcmVmaXhfYWxsEhwuZ29vZ2xlLnByb3RvYnVmLkZpbGVPcHRpb25zGJrsAyABKAhSFGdvcHJvdG9FbnVtUHJlZml4QWxsOlAKFGdvcHJvdG9fc3RyaW5nZXJfYWxsEhwuZ29vZ2xlLnByb3RvYnVmLkZpbGVPcHRpb25zGJvsAyABKAhSEmdvcHJvdG9TdHJpbmdlckFsbDpKChF2ZXJib3NlX2VxdWFsX2FsbBIcLmdvb2dsZS5wcm90b2J1Zi5GaWxlT3B0aW9ucxic7AMgASgIUg92ZXJib3NlRXF1YWxBbGw6OQoIZmFjZV9hbGwSHC5nb29nbGUucHJvdG9idWYuRmlsZU9wdGlvbnMYnewDIAEoCFIHZmFjZUFsbDpBCgxnb3N0cmluZ19hbGwSHC5nb29nbGUucHJvdG9idWYuRmlsZU9wdGlvbnMYnuwDIAEoCFILZ29zdHJpbmdBbGw6QQoMcG9wdWxhdGVfYWxsEhwuZ29vZ2xlLnByb3RvYnVmLkZpbGVPcHRpb25zGJ/sAyABKAhSC3BvcHVsYXRlQWxsOkEKDHN0cmluZ2VyX2FsbBIcLmdvb2dsZS5wcm90b2J1Zi5GaWxlT3B0aW9ucxig7AMgASgIUgtzdHJpbmdlckFsbDo/Cgtvbmx5b25lX2FsbBIcLmdvb2dsZS5wcm90b2J1Zi5GaWxlT3B0aW9ucxih7AMgASgIUgpvbmx5b25lQWxsOjsKCWVxdWFsX2FsbBIcLmdvb2dsZS5wcm90b2J1Zi5GaWxlT3B0aW9ucxil7AMgASgIUghlcXVhbEFsbDpHCg9kZXNjcmlwdGlvbl9hbGwSHC5nb29nbGUucHJvdG9idWYuRmlsZU9wdGlvbnMYpuwDIAEoCFIOZGVzY3JpcHRpb25BbGw6PwoLdGVzdGdlbl9hbGwSHC5nb29nbGUucHJvdG9idWYuRmlsZU9wdGlvbnMYp+wDIAEoCFIKdGVzdGdlbkFsbDpBCgxiZW5jaGdlbl9hbGwSHC5nb29nbGUucHJvdG9idWYuRmlsZU9wdGlvbnMYqOwDIAEoCFILYmVuY2hnZW5BbGw6QwoNbWFyc2hhbGVyX2FsbBIcLmdvb2dsZS5wcm90b2J1Zi5GaWxlT3B0aW9ucxip7AMgASgIUgxtYXJzaGFsZXJBbGw6RwoPdW5tYXJzaGFsZXJfYWxsEhwuZ29vZ2xlLnByb3RvYnVmLkZpbGVPcHRpb25zGKrsAyABKAhSDnVubWFyc2hhbGVyQWxsOlAKFHN0YWJsZV9tYXJzaGFsZXJfYWxsEhwuZ29vZ2xlLnByb3RvYnVmLkZpbGVPcHRpb25zGKvsAyABKAhSEnN0YWJsZU1hcnNoYWxlckFsbDo7CglzaXplcl9hbGwSHC5nb29nbGUucHJvdG9idWYuRmlsZU9wdGlvbnMYrOwDIAEoCFIIc2l6ZXJBbGw6WQoZZ29wcm90b19lbnVtX3N0cmluZ2VyX2FsbBIcLmdvb2dsZS5wcm90b2J1Zi5GaWxlT3B0aW9ucxit7AMgASgIUhZnb3Byb3RvRW51bVN0cmluZ2VyQWxsOkoKEWVudW1fc3RyaW5nZXJfYWxsEhwuZ29vZ2xlLnByb3RvYnVmLkZpbGVPcHRpb25zGK7sAyABKAhSD2VudW1TdHJpbmdlckFsbDpQChR1bnNhZmVfbWFyc2hhbGVyX2FsbBIcLmdvb2dsZS5wcm90b2J1Zi5GaWxlT3B0aW9ucxiv7AMgASgIUhJ1bnNhZmVNYXJzaGFsZXJBbGw6VAoWdW5zYWZlX3VubWFyc2hhbGVyX2FsbBIcLmdvb2dsZS5wcm90b2J1Zi5GaWxlT3B0aW9ucxiw7AMgASgIUhR1bnNhZmVVbm1hcnNoYWxlckFsbDpbChpnb3Byb3RvX2V4dGVuc2lvbnNfbWFwX2FsbBIcLmdvb2dsZS5wcm90b2J1Zi5GaWxlT3B0aW9ucxix7AMgASgIUhdnb3Byb3RvRXh0ZW5zaW9uc01hcEFsbDpYChhnb3Byb3RvX3VucmVjb2duaXplZF9hbGwSHC5nb29nbGUucHJvdG9idWYuRmlsZU9wdGlvbnMYsuwDIAEoCFIWZ29wcm90b1VucmVjb2duaXplZEFsbDpJChBnb2dvcHJvdG9faW1wb3J0EhwuZ29vZ2xlLnByb3RvYnVmLkZpbGVPcHRpb25zGLPsAyABKAhSD2dvZ29wcm90b0ltcG9ydDpFCg5wcm90b3NpemVyX2FsbBIcLmdvb2dsZS5wcm90b2J1Zi5GaWxlT3B0aW9ucxi07AMgASgIUg1wcm90b3NpemVyQWxsOj8KC2NvbXBhcmVfYWxsEhwuZ29vZ2xlLnByb3RvYnVmLkZpbGVPcHRpb25zGLXsAyABKAhSCmNvbXBhcmVBbGw6QQoMdHlwZWRlY2xfYWxsEhwuZ29vZ2xlLnByb3RvYnVmLkZpbGVPcHRpb25zGLbsAyABKAhSC3R5cGVkZWNsQWxsOkEKDGVudW1kZWNsX2FsbBIcLmdvb2dsZS5wcm90b2J1Zi5GaWxlT3B0aW9ucxi37AMgASgIUgtlbnVtZGVjbEFsbDpRChRnb3Byb3RvX3JlZ2lzdHJhdGlvbhIcLmdvb2dsZS5wcm90b2J1Zi5GaWxlT3B0aW9ucxi47AMgASgIUhNnb3Byb3RvUmVnaXN0cmF0aW9uOkcKD21lc3NhZ2VuYW1lX2FsbBIcLmdvb2dsZS5wcm90b2J1Zi5GaWxlT3B0aW9ucxi57AMgASgIUg5tZXNzYWdlbmFtZUFsbDpKCg9nb3Byb3RvX2dldHRlcnMSHy5nb29nbGUucHJvdG9idWYuTWVzc2FnZU9wdGlvbnMYgfQDIAEoCFIOZ29wcm90b0dldHRlcnM6TAoQZ29wcm90b19zdHJpbmdlchIfLmdvb2dsZS5wcm90b2J1Zi5NZXNzYWdlT3B0aW9ucxiD9AMgASgIUg9nb3Byb3RvU3RyaW5nZXI6RgoNdmVyYm9zZV9lcXVhbBIfLmdvb2dsZS5wcm90b2J1Zi5NZXNzYWdlT3B0aW9ucxiE9AMgASgIUgx2ZXJib3NlRXF1YWw6NQoEZmFjZRIfLmdvb2dsZS5wcm90b2J1Zi5NZXNzYWdlT3B0aW9ucxiF9AMgASgIUgRmYWNlOj0KCGdvc3RyaW5nEh8uZ29vZ2xlLnByb3RvYnVmLk1lc3NhZ2VPcHRpb25zGIb0AyABKAhSCGdvc3RyaW5nOj0KCHBvcHVsYXRlEh8uZ29vZ2xlLnByb3RvYnVmLk1lc3NhZ2VPcHRpb25zGIf0AyABKAhSCHBvcHVsYXRlOj0KCHN0cmluZ2VyEh8uZ29vZ2xlLnByb3RvYnVmLk1lc3NhZ2VPcHRpb25zGMCLBCABKAhSCHN0cmluZ2VyOjsKB29ubHlvbmUSHy5nb29nbGUucHJvdG9idWYuTWVzc2FnZU9wdGlvbnMYifQDIAEoCFIHb25seW9uZTo3CgVlcXVhbBIfLmdvb2dsZS5wcm90b2J1Zi5NZXNzYWdlT3B0aW9ucxiN9AMgASgIUgVlcXVhbDpDCgtkZXNjcmlwdGlvbhIfLmdvb2dsZS5wcm90b2J1Zi5NZXNzYWdlT3B0aW9ucxiO9AMgASgIUgtkZXNjcmlwdGlvbjo7Cgd0ZXN0Z2VuEh8uZ29vZ2xlLnByb3RvYnVmLk1lc3NhZ2VPcHRpb25zGI/0AyABKAhSB3Rlc3RnZW46PQoIYmVuY2hnZW4SHy5nb29nbGUucHJvdG9idWYuTWVzc2FnZU9wdGlvbnMYkPQDIAEoCFIIYmVuY2hnZW46PwoJbWFyc2hhbGVyEh8uZ29vZ2xlLnByb3RvYnVmLk1lc3NhZ2VPcHRpb25zGJH0AyABKAhSCW1hcnNoYWxlcjpDCgt1bm1hcnNoYWxlchIfLmdvb2dsZS5wcm90b2J1Zi5NZXNzYWdlT3B0aW9ucxiS9AMgASgIUgt1bm1hcnNoYWxlcjpMChBzdGFibGVfbWFyc2hhbGVyEh8uZ29vZ2xlLnByb3RvYnVmLk1lc3NhZ2VPcHRpb25zGJP0AyABKAhSD3N0YWJsZU1hcnNoYWxlcjo3CgVzaXplchIfLmdvb2dsZS5wcm90b2J1Zi5NZXNzYWdlT3B0aW9ucxiU9AMgASgIUgVzaXplcjpMChB1bnNhZmVfbWFyc2hhbGVyEh8uZ29vZ2xlLnByb3RvYnVmLk1lc3NhZ2VPcHRpb25zGJf0AyABKAhSD3Vuc2FmZU1hcnNoYWxlcjpQChJ1bnNhZmVfdW5tYXJzaGFsZXISHy5nb29nbGUucHJvdG9idWYuTWVzc2FnZU9wdGlvbnMYmPQDIAEoCFIRdW5zYWZlVW5tYXJzaGFsZXI6VwoWZ29wcm90b19leHRlbnNpb25zX21hcBIfLmdvb2dsZS5wcm90b2J1Zi5NZXNzYWdlT3B0aW9ucxiZ9AMgASgIUhRnb3Byb3RvRXh0ZW5zaW9uc01hcDpUChRnb3Byb3RvX3VucmVjb2duaXplZBIfLmdvb2dsZS5wcm90b2J1Zi5NZXNzYWdlT3B0aW9ucxia9AMgASgIUhNnb3Byb3RvVW5yZWNvZ25pemVkOkEKCnByb3Rvc2l6ZXISHy5nb29nbGUucHJvdG9idWYuTWVzc2FnZU9wdGlvbnMYnPQDIAEoCFIKcHJvdG9zaXplcjo7Cgdjb21wYXJlEh8uZ29vZ2xlLnByb3RvYnVmLk1lc3NhZ2VPcHRpb25zGJ30AyABKAhSB2NvbXBhcmU6PQoIdHlwZWRlY2wSHy5nb29nbGUucHJvdG9idWYuTWVzc2FnZU9wdGlvbnMYnvQDIAEoCFIIdHlwZWRlY2w6QwoLbWVzc2FnZW5hbWUSHy5nb29nbGUucHJvdG9idWYuTWVzc2FnZU9wdGlvbnMYofQDIAEoCFILbWVzc2FnZW5hbWU6OwoIbnVsbGFibGUSHS5nb29nbGUucHJvdG9idWYuRmllbGRPcHRpb25zGOn7AyABKAhSCG51bGxhYmxlOjUKBWVtYmVkEh0uZ29vZ2xlLnByb3RvYnVmLkZpZWxkT3B0aW9ucxjq+wMgASgIUgVlbWJlZDo/CgpjdXN0b210eXBlEh0uZ29vZ2xlLnByb3RvYnVmLkZpZWxkT3B0aW9ucxjr+wMgASgJUgpjdXN0b210eXBlOj8KCmN1c3RvbW5hbWUSHS5nb29nbGUucHJvdG9idWYuRmllbGRPcHRpb25zGOz7AyABKAlSCmN1c3RvbW5hbWU6OQoHanNvbnRhZxIdLmdvb2dsZS5wcm90b2J1Zi5GaWVsZE9wdGlvbnMY7fsDIAEoCVIHanNvbnRhZzo7Cghtb3JldGFncxIdLmdvb2dsZS5wcm90b2J1Zi5GaWVsZE9wdGlvbnMY7vsDIAEoCVIIbW9yZXRhZ3M6OwoIY2FzdHR5cGUSHS5nb29nbGUucHJvdG9idWYuRmllbGRPcHRpb25zGO/7AyABKAlSCGNhc3R0eXBlOjkKB2Nhc3RrZXkSHS5nb29nbGUucHJvdG9idWYuRmllbGRPcHRpb25zGPD7AyABKAlSB2Nhc3RrZXk6PQoJY2FzdHZhbHVlEh0uZ29vZ2xlLnByb3RvYnVmLkZpZWxkT3B0aW9ucxjx+wMgASgJUgljYXN0dmFsdWU6OQoHc3RkdGltZRIdLmdvb2dsZS5wcm90b2J1Zi5GaWVsZE9wdGlvbnMY8vsDIAEoCFIHc3RkdGltZTpBCgtzdGRkdXJhdGlvbhIdLmdvb2dsZS5wcm90b2J1Zi5GaWVsZE9wdGlvbnMY8/sDIAEoCFILc3RkZHVyYXRpb25CRQoTY29tLmdvb2dsZS5wcm90b2J1ZkIKR29Hb1Byb3Rvc1oiZ2l0aHViLmNvbS9nb2dvL3Byb3RvYnVmL2dvZ29wcm90b0qaNQoHEgUcAIcBAQr8CgoBDBIDHAASMvEKIFByb3RvY29sIEJ1ZmZlcnMgZm9yIEdvIHdpdGggR2FkZ2V0cwoKIENvcHlyaWdodCAoYykgMjAxMywgVGhlIEdvR28gQXV0aG9ycy4gQWxsIHJpZ2h0cyByZXNlcnZlZC4KIGh0dHA6Ly9naXRodWIuY29tL2dvZ28vcHJvdG9idWYKCiBSZWRpc3RyaWJ1dGlvbiBhbmQgdXNlIGluIHNvdXJjZSBhbmQgYmluYXJ5IGZvcm1zLCB3aXRoIG9yIHdpdGhvdXQKIG1vZGlmaWNhdGlvbiwgYXJlIHBlcm1pdHRlZCBwcm92aWRlZCB0aGF0IHRoZSBmb2xsb3dpbmcgY29uZGl0aW9ucyBhcmUKIG1ldDoKCiAgICAgKiBSZWRpc3RyaWJ1dGlvbnMgb2Ygc291cmNlIGNvZGUgbXVzdCByZXRhaW4gdGhlIGFib3ZlIGNvcHlyaWdodAogbm90aWNlLCB0aGlzIGxpc3Qgb2YgY29uZGl0aW9ucyBhbmQgdGhlIGZvbGxvd2luZyBkaXNjbGFpbWVyLgogICAgICogUmVkaXN0cmlidXRpb25zIGluIGJpbmFyeSBmb3JtIG11c3QgcmVwcm9kdWNlIHRoZSBhYm92ZQogY29weXJpZ2h0IG5vdGljZSwgdGhpcyBsaXN0IG9mIGNvbmRpdGlvbnMgYW5kIHRoZSBmb2xsb3dpbmcgZGlzY2xhaW1lcgogaW4gdGhlIGRvY3VtZW50YXRpb24gYW5kL29yIG90aGVyIG1hdGVyaWFscyBwcm92aWRlZCB3aXRoIHRoZQogZGlzdHJpYnV0aW9uLgoKIFRISVMgU09GVFdBUkUgSVMgUFJPVklERUQgQlkgVEhFIENPUFlSSUdIVCBIT0xERVJTIEFORCBDT05UUklCVVRPUlMKICJBUyBJUyIgQU5EIEFOWSBFWFBSRVNTIE9SIElNUExJRUQgV0FSUkFOVElFUywgSU5DTFVESU5HLCBCVVQgTk9UCiBMSU1JVEVEIFRPLCBUSEUgSU1QTElFRCBXQVJSQU5USUVTIE9GIE1FUkNIQU5UQUJJTElUWSBBTkQgRklUTkVTUyBGT1IKIEEgUEFSVElDVUxBUiBQVVJQT1NFIEFSRSBESVNDTEFJTUVELiBJTiBOTyBFVkVOVCBTSEFMTCBUSEUgQ09QWVJJR0hUCiBPV05FUiBPUiBDT05UUklCVVRPUlMgQkUgTElBQkxFIEZPUiBBTlkgRElSRUNULCBJTkRJUkVDVCwgSU5DSURFTlRBTCwKIFNQRUNJQUwsIEVYRU1QTEFSWSwgT1IgQ09OU0VRVUVOVElBTCBEQU1BR0VTIChJTkNMVURJTkcsIEJVVCBOT1QKIExJTUlURUQgVE8sIFBST0NVUkVNRU5UIE9GIFNVQlNUSVRVVEUgR09PRFMgT1IgU0VSVklDRVM7IExPU1MgT0YgVVNFLAogREFUQSwgT1IgUFJPRklUUzsgT1IgQlVTSU5FU1MgSU5URVJSVVBUSU9OKSBIT1dFVkVSIENBVVNFRCBBTkQgT04gQU5ZCiBUSEVPUlkgT0YgTElBQklMSVRZLCBXSEVUSEVSIElOIENPTlRSQUNULCBTVFJJQ1QgTElBQklM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B0USBIUBCCYKCgoDB0UCEgN6ByMKCwoDB0UEEgSFAQgQCgsKAwdFBRIEhQERFQoLCgMHRQESBIUBFh0KCwoDB0UDEgSFASAlCgoKAgdGEgSGAQgqCgoKAwdGAhIDegcjCgsKAwdGBBIEhgEIEAoLCgMHRgUSBIYBERUKCwoDB0YBEgSGARYhCgsKAwdGAxIEhgEkKQqMFwosbWl4ZXIvYWRhcHRlci9tb2RlbC92MWJldGExL2V4dGVuc2lvbnMucHJvdG8SIWlzdGlvLm1peGVyLmFkYXB0ZXIubW9kZWwudjFiZXRhMRogZ29vZ2xlL3Byb3RvYnVmL2Rlc2NyaXB0b3IucHJvdG8quAEKD1RlbXBsYXRlVmFyaWV0eRIaChZURU1QTEFURV9WQVJJRVRZX0NIRUNLEAASGwoXVEVNUExBVEVfVkFSSUVUWV9SRVBPUlQQARIaChZURU1QTEFURV9WQVJJRVRZX1FVT1RBEAISKAokVEVNUExBVEVfVkFSSUVUWV9BVFRSSUJVVEVfR0VORVJBVE9SEAMSJgoiVEVNUExBVEVfVkFSSUVUWV9DSEVDS19XSVRIX09VVFBVVBAEOn4KEHRlbXBsYXRlX3ZhcmlldHkSHC5nb29nbGUucHJvdG9idWYuRmlsZU9wdGlvbnMYr8q8IiABKA4yMi5pc3Rpby5taXhlci5hZGFwdGVyLm1vZGVsLnYxYmV0YTEuVGVtcGxhdGVWYXJpZXR5Ug90ZW1wbGF0ZVZhcmlldHk6RAoNdGVtcGxhdGVfbmFtZRIcLmdvb2dsZS5wcm90b2J1Zi5GaWxlT3B0aW9ucxjQy7wiIAEoCVIMdGVtcGxhdGVOYW1lQipaKGlzdGlvLmlvL2FwaS9taXhlci9hZGFwdGVyL21vZGVsL3YxYmV0YTFK4RIKBhIEDgAyAQq/BAoBDBIDDgASMrQEIENvcHlyaWdodCAyMDE4IElzdGlvIEF1dGhvcnMKCiBMaWNlbnNlZCB1bmRlciB0aGUgQXBhY2hlIExpY2Vuc2UsIFZlcnNpb24gMi4wICh0aGUgIkxpY2Vuc2UiKTsKIHlvdSBtYXkgbm90IHVzZSB0aGlzIGZpbGUgZXhjZXB0IGluIGNvbXBsaWFuY2Ugd2l0aCB0aGUgTGljZW5zZS4KIFlvdSBtYXkgb2J0YWluIGEgY29weSBvZiB0aGUgTGljZW5zZSBhdAoKICAgICBodHRwOi8vd3d3LmFwYWNoZS5vcmcvbGljZW5zZXMvTElDRU5TRS0yLjAKCiBVbmxlc3MgcmVxdWlyZWQgYnkgYXBwbGljYWJsZSBsYXcgb3IgYWdyZWVkIHRvIGluIHdyaXRpbmcsIHNvZnR3YXJlCiBkaXN0cmlidXRlZCB1bmRlciB0aGUgTGljZW5zZSBpcyBkaXN0cmlidXRlZCBvbiBhbiAiQVMgSVMiIEJBU0lTLAogV0lUSE9VVCBXQVJSQU5USUVTIE9SIENPTkRJVElPTlMgT0YgQU5ZIEtJTkQsIGVpdGhlciBleHByZXNzIG9yIGltcGxpZWQuCiBTZWUgdGhlIExpY2Vuc2UgZm9yIHRoZSBzcGVjaWZpYyBsYW5ndWFnZSBnb3Zlcm5pbmcgcGVybWlzc2lvbnMgYW5kCiBsaW1pdGF0aW9ucyB1bmRlciB0aGUgTGljZW5zZS4KCggKAQISAxAIKQoICgEIEgMSAD0KCwoECOcHABIDEgA9CgwKBQjnBwACEgMSBxEKDQoGCOcHAAIAEgMSBxEKDgoHCOcHAAIAARIDEgcRCgwKBQjnBwAHEgMSEjwKCQoCAwASAxQHKQp5CgIFABIEGAAoARptIFRoZSBhdmFpbGFibGUgdmFyaWV0aWVzIG9mIHRlbXBsYXRlcywgY29udHJvbGxpbmcgdGhlIHNlbWFudGljcyBvZiB3aGF0IGFuIGFkYXB0ZXIgZG9lcyB3aXRoIGVhY2ggaW5zdGFuY2UuCgoKCgMFAAESAxgFFArHAQoEBQACABIDGwQfGrkBIE1ha2VzIHRoZSB0ZW1wbGF0ZSBhcHBsaWNhYmxlIGZvciBNaXhlcidzIGNoZWNrIGNhbGxzLiBJbnN0YW5jZXMgb2Ygc3VjaCB0ZW1wbGF0ZSBhcmUgY3JlYXRlZCBkdXJpbmcKIGNoZWNrIGNhbGxzIGluIE1peGVyIGFuZCBwYXNzZWQgdG8gdGhlIGhhbmRsZXJzIGJhc2VkIG9uIHRoZSBydWxlIGNvbmZpZ3VyYXRpb25zLgoKDAoFBQACAAESAxsEGgoMCgUFAAIAAhIDGx0eCskBCgQFAAIBEgMeBCAauwEgTWFrZXMgdGhlIHRlbXBsYXRlIGFwcGxpY2FibGUgZm9yIE1peGVyJ3MgcmVwb3J0IGNhbGxzLiBJbnN0YW5jZXMgb2Ygc3VjaCB0ZW1wbGF0ZSBhcmUgY3JlYXRlZCBkdXJpbmcKIHJlcG9ydCBjYWxscyBpbiBNaXhlciBhbmQgcGFzc2VkIHRvIHRoZSBoYW5kbGVycyBiYXNlZCBvbiB0aGUgcnVsZSBjb25maWd1cmF0aW9ucy4KCgwKBQUAAgEBEgMeBBsKDAoFBQACAQISAx4eHwrNAQoEBQACAhIDIQQfGr8BIE1ha2VzIHRoZSB0ZW1wbGF0ZSBhcHBsaWNhYmxlIGZvciBNaXhlcidzIHF1b3RhIGNhbGxzLiBJbnN0YW5jZXMgb2Ygc3VjaCB0ZW1wbGF0ZSBhcmUgY3JlYXRlZCBkdXJpbmcKIHF1b3RhIGNoZWNrIGNhbGxzIGluIE1peGVyIGFuZCBwYXNzZWQgdG8gdGhlIGhhbmRsZXJzIGJhc2VkIG9uIHRoZSBydWxlIGNvbmZpZ3VyYXRpb25zLgoKDAoFBQACAgESAyEEGgoMCgUFAAICAhIDIR0eCusBCgQFAAIDEgMkBC0a3QEgTWFrZXMgdGhlIHRlbXBsYXRlIGFwcGxpY2FibGUgZm9yIE1peGVyJ3MgYXR0cmlidXRlIGdlbmVyYXRpb24gcGhhc2UuIEluc3RhbmNlcyBvZiBzdWNoIHRlbXBsYXRlIGFyZSBjcmVhdGVkIGR1cmluZwogcHJlLXByb2Nlc3NpbmcgYXR0cmlidXRlIGdlbmVyYXRpb24gcGhhc2UgYW5kIHBhc3NlZCB0byB0aGUgaGFuZGxlcnMgYmFzZWQgb24gdGhlIHJ1bGUgY29uZmlndXJhdGlvbnMuCgoMCgUFAAIDARIDJAQoCgwKBQUAAgMCEgMkKywKugEKBAUAAgQSAycEKxqsASBNYWtlcyB0aGUgdGVtcGxhdGUgYXBwbGljYWJsZSBmb3IgTWl4ZXIncyBjaGVjayBjYWxscy4gSW5zdGFuY2VzIG9mIHN1Y2ggdGVtcGxhdGUgYXJlIGNyZWF0ZWQgZHVyaW5nCiBjaGVjayBjYWxscyBpbiBNaXhlciBhbmQgcGFzc2VkIHRvIHRoZSBoYW5kbGVycyB0aGF0IHByb2R1Y2UgdmFsdWVzLgoKDAoFBQACBAESAycEJgoMCgUFAAIEAhIDJykqCjEKAQcSBCsAMgEaJiBGaWxlIGxldmVsIG9wdGlvbnMgZm9yIHRoZSB0ZW1wbGF0ZS4KCjYKAgcAEgMtBDAaKyBSZXF1aXJlZDogb3B0aW9uIGZvciB0aGUgVGVtcGxhdGVWYXJpZXR5LgoKCgoDBwACEgMrByIKCwoDBwAEEgQtBCskCgoKAwcABhIDLQQTCgoKAwcAARIDLRQkCgoKAwcAAxIDLScvCqQBCgIHARIDMQQkGpgBIE9wdGlvbmFsOiBvcHRpb24gZm9yIHRoZSB0ZW1wbGF0ZSBuYW1lLgogSWYgbm90IHNwZWNpZmllZCwgdGhlIGxhc3Qgc2VnbWVudCBvZiB0aGUgdGVtcGxhdGUgcHJvdG8ncyBwYWNrYWdlIG5hbWUgaXMgdXNlZCB0bwogZGVyaXZlIHRoZSB0ZW1wbGF0ZSBuYW1lLgoKCgoDBwECEgMrByIKCwoDBwEEEgQxBC0wCgoKAwcBBRIDMQQKCgoKAwcBARIDMQsYCgoKAwcBAxIDMRsjYgZwcm90bzMK3CwKGWdvb2dsZS9wcm90b2J1Zi9hbnkucHJvdG8SD2dvb2dsZS5wcm90b2J1ZiI2CgNBbnkSGQoIdHlwZV91cmwYASABKAlSB3R5cGVVcmwSFAoFdmFsdWUYAiABKAxSBXZhbHVlQm8KE2NvbS5nb29nbGUucHJvdG9idWZCCEFueVByb3RvUAFaJWdpdGh1Yi5jb20vZ29sYW5nL3Byb3RvYnVmL3B0eXBlcy9hbnmiAgNHUEKqAh5Hb29nbGUuUHJvdG9idWYuV2VsbEtub3duVHlwZXNK/CoKBxIFHgCUAQEKzAwKAQwSAx4AEjLBDCBQcm90b2NvbCBCdWZmZXJzIC0gR29vZ2xlJ3MgZGF0YSBpbnRlcmNoYW5nZSBmb3JtYXQKIENvcHlyaWdodCAyMDA4IEdvb2dsZSBJbmMuICBBbGwgcmlnaHRzIHJlc2VydmVkLgogaHR0cHM6Ly9kZXZlbG9wZXJzLmdvb2dsZS5jb20vcHJvdG9jb2wtYnVmZmVycy8KCiBSZWRpc3RyaWJ1dGlvbiBhbmQgdXNlIGluIHNvdXJjZSBhbmQgYmluYXJ5IGZvcm1zLCB3aXRoIG9yIHdpdGhvdXQKIG1vZGlmaWNhdGlvbiwgYXJlIHBlcm1pdHRlZCBwcm92aWRlZCB0aGF0IHRoZSBmb2xsb3dpbmcgY29uZGl0aW9ucyBhcmUKIG1ldDoKCiAgICAgKiBSZWRpc3RyaWJ1dGlvbnMgb2Ygc291cmNlIGNvZGUgbXVzdCByZXRhaW4gdGhlIGFib3ZlIGNvcHlyaWdodAogbm90aWNlLCB0aGlzIGxpc3Qgb2YgY29uZGl0aW9ucyBhbmQgdGhlIGZvbGxvd2luZyBkaXNjbGFpbWVyLgogICAgICogUmVkaXN0cmlidXRpb25zIGluIGJpbmFyeSBmb3JtIG11c3QgcmVwcm9kdWNlIHRoZSBhYm92ZQogY29weXJpZ2h0IG5vdGljZSwgdGhpcyBsaXN0IG9mIGNvbmRpdGlvbnMgYW5kIHRoZSBmb2xsb3dpbmcgZGlzY2xhaW1lcgogaW4gdGhlIGRvY3VtZW50YXRpb24gYW5kL29yIG90aGVyIG1hdGVyaWFscyBwcm92aWRlZCB3aXRoIHRoZQogZGlzdHJpYnV0aW9uLgogICAgICogTmVpdGhlciB0aGUgbmFtZSBvZiBHb29nbGUgSW5jLiBub3IgdGhlIG5hbWVzIG9mIGl0cwogY29udHJpYnV0b3JzIG1heSBiZSB1c2VkIHRvIGVuZG9yc2Ugb3IgcHJvbW90ZSBwcm9kdWN0cyBkZXJpdmVkIGZyb20KIHRoaXMgc29mdHdhcmUgd2l0aG91dCBzcGVjaWZpYyBwcmlvciB3cml0dGVuIHBlcm1pc3Npb24uCgogVEhJUyBTT0ZUV0FSRSBJUyBQUk9WSURFRCBCWSBUSEUgQ09QWVJJR0hUIEhPTERFUlMgQU5EIENPTlRSSUJVVE9SUwogIkFTIElTIiBBTkQgQU5ZIEVYUFJFU1MgT1IgSU1QTElFRCBXQVJSQU5USUVTLCBJTkNMVURJTkcsIEJVVCBOT1QKIExJTUlURUQgVE8sIFRIRSBJTVBMSUVEIFdBUlJBTlRJRVMgT0YgTUVSQ0hBTlRBQklMSVRZIEFORCBGSVRORVNTIEZPUgogQSBQQVJUSUNVTEFSIFBVUlBPU0UgQVJFIERJU0NMQUlNRUQuIElOIE5PIEVWRU5UIFNIQUxMIFRIRSBDT1BZUklHSFQKIE9XTkVSIE9SIENPTlRSSUJVVE9SUyBCRSBMSUFCTEUgRk9SIEFO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cGFjayBhIG1lc3NhZ2UgaW4gR28KCiAgICAgIGZvbyA6PSAmcGIuRm9vey4uLn0KICAgICAgYW55LCBlcnIgOj0gcHR5cGVzLk1hcnNoYWxBbnkoZm9vKQogICAgICAuLi4KICAgICAgZm9vIDo9ICZwYi5Gb297fQogICAgICBpZiBlcnIgOj0gcHR5cGVzLlVubWFyc2hhbEFueShhbnksIGZvbyk7IGVyciAhPSBuaWwgewogICAgICAgIC4uLgogICAgICB9CgogVGhlIHBhY2sgbWV0aG9kcyBwcm92aWRlZCBieSBwcm90b2J1ZiBsaWJyYXJ5IHdpbGwgYnkgZGVmYXVsdCB1c2UKICd0eXBlLmdvb2dsZWFwaXMuY29tL2Z1bGwudHlwZS5uYW1lJyBhcyB0aGUgdHlwZSBVUkwgYW5kIHRoZSB1bnBhY2sKIG1ldGhvZHMgb25seSB1c2UgdGhlIGZ1bGx5IHF1YWxpZmllZCB0eXBlIG5hbWUgYWZ0ZXIgdGhlIGxhc3QgJy8nCiBpbiB0aGUgdHlwZSBVUkwsIGZvciBleGFtcGxlICJmb28uYmFyLmNvbS94L3kueiIgd2lsbCB5aWVsZCB0eXBlCiBuYW1lICJ5LnoiLgoKCiBKU09OCiA9PT09CiBUaGUgSlNPTiByZXByZXNlbnRhdGlvbiBvZiBhbiBgQW55YCB2YWx1ZSB1c2VzIHRoZSByZWd1bGFyCiByZXByZXNlbnRhdGlvbiBvZiB0aGUgZGVzZXJpYWxpemVkLCBlbWJlZGRlZCBtZXNzYWdlLCB3aXRoIGFuCiBhZGRpdGlvbmFsIGZpZWxkIGBAdHlwZWAgd2hpY2ggY29udGFpbnMgdGhlIHR5cGUgVVJMLiBFeGFtcGxlOgoKICAgICBwYWNrYWdlIGdvb2dsZS5wcm9maWxlOwogICAgIG1lc3NhZ2UgUGVyc29uIHsKICAgICAgIHN0cmluZyBmaXJzdF9uYW1lID0gMTsKICAgICAgIHN0cmluZyBsYXN0X25hbWUgPSAyOwogICAgIH0KCiAgICAgewogICAgICAgIkB0eXBlIjogInR5cGUuZ29vZ2xlYXBpcy5jb20vZ29vZ2xlLnByb2ZpbGUuUGVyc29uIiwKICAgICAgICJmaXJzdE5hbWUiOiA8c3RyaW5nPiwKICAgICAgICJsYXN0TmFtZSI6IDxzdHJpbmc+CiAgICAgfQoKIElmIHRoZSBlbWJlZGRlZCBtZXNzYWdlIHR5cGUgaXMgd2VsbC1rbm93biBhbmQgaGFzIGEgY3VzdG9tIEpTT04KIHJlcHJlc2VudGF0aW9uLCB0aGF0IHJlcHJlc2VudGF0aW9uIHdpbGwgYmUgZW1iZWRkZWQgYWRkaW5nIGEgZmllbGQKIGB2YWx1ZWAgd2hpY2ggaG9sZHMgdGhlIGN1c3RvbSBKU09OIGluIGFkZGl0aW9uIHRvIHRoZSBgQHR5cGVgCiBmaWVsZC4gRXhhbXBsZSAoZm9yIG1lc3NhZ2UgW2dvb2dsZS5wcm90b2J1Zi5EdXJhdGlvbl1bXSk6CgogICAgIHsKICAgICAgICJAdHlwZSI6ICJ0eXBlLmdvb2dsZWFwaXMuY29tL2dvb2dsZS5wcm90b2J1Zi5EdXJhdGlvbiIsCiAgICAgICAidmFsdWUiOiAiMS4yMTJzIgogICAgIH0KCgoKCgMEAAESA3kICwrkBwoEBAACABIEkAECFhrVByBBIFVSTC9yZXNvdXJjZSBuYW1lIHdob3NlIGNvbnRlbnQgZGVzY3JpYmVzIHRoZSB0eXBlIG9mIHRoZQogc2VyaWFsaXplZCBwcm90b2NvbCBidWZmZXIgbWVzc2FnZS4KCiBGb3IgVVJMcyB3aGljaCB1c2UgdGhlIHNjaGVtZSBgaHR0cGAsIGBodHRwc2AsIG9yIG5vIHNjaGVtZSwgdGhlCiBmb2xsb3dpbmcgcmVzdHJpY3Rpb25zIGFuZCBpbnRlcnByZXRhdGlvbnMgYXBwbHk6CgogKiBJZiBubyBzY2hlbWUgaXMgcHJvdmlkZWQsIGBodHRwc2AgaXMgYXNzdW1lZC4KICogVGhlIGxhc3Qgc2VnbWVudCBvZiB0aGUgVVJMJ3MgcGF0aCBtdXN0IHJlcHJlc2VudCB0aGUgZnVsbHkKICAgcXVhbGlmaWVkIG5hbWUgb2YgdGhlIHR5cGUgKGFzIGluIGBwYXRoL2dvb2dsZS5wcm90b2J1Zi5EdXJhdGlvbmApLgogICBUaGUgbmFtZSBzaG91bGQgYmUgaW4gYSBjYW5vbmljYWwgZm9ybSAoZS5nLiwgbGVhZGluZyAiLiIgaXMKICAgbm90IGFjY2VwdGVkKS4KICogQW4gSFRUUCBHRVQgb24gdGhlIFVSTCBtdXN0IHlpZWxkIGEgW2dvb2dsZS5wcm90b2J1Zi5UeXBlXVtdCiAgIHZhbHVlIGluIGJpbmFyeSBmb3JtYXQsIG9yIHByb2R1Y2UgYW4gZXJyb3IuCiAqIEFwcGxpY2F0aW9ucyBhcmUgYWxsb3dlZCB0byBjYWNoZSBsb29rdXAgcmVzdWx0cyBiYXNlZCBvbiB0aGUKICAgVVJMLCBvciBoYXZlIHRoZW0gcHJlY29tcGlsZWQgaW50byBhIGJpbmFyeSB0byBhdm9pZCBhbnkKICAgbG9va3VwLiBUaGVyZWZvcmUsIGJpbmFyeSBjb21wYXRpYmlsaXR5IG5lZWRzIHRvIGJlIHByZXNlcnZlZAogICBvbiBjaGFuZ2VzIHRvIHR5cGVzLiAoVXNlIHZlcnNpb25lZCB0eXBlIG5hbWVzIHRvIG1hbmFnZQogICBicmVha2luZyBjaGFuZ2VzLikKCiBTY2hlbWVzIG90aGVyIHRoYW4gYGh0dHBgLCBgaHR0cHNgIChvciB0aGUgZW1wdHkgc2NoZW1lKSBtaWdodCBiZQogdXNlZCB3aXRoIGltcGxlbWVudGF0aW9uIHNwZWNpZmljIHNlbWFudGljcy4KCgoOCgUEAAIABBIFkAECeQ0KDQoFBAACAAUSBJABAggKDQoFBAACAAESBJABCREKDQoFBAACAAMSBJABFBUKVwoEBAACARIEkwECEhpJIE11c3QgYmUgYSB2YWxpZCBzZXJpYWxpemVkIHByb3RvY29sIGJ1ZmZlciBvZiB0aGUgYWJvdmUgc3BlY2lmaWVkIHR5cGUuCgoPCgUEAAIBBBIGkwECkAEWCg0KBQQAAgEFEgSTAQIHCg0KBQQAAgEBEgSTAQgNCg0KBQQAAgEDEgSTARARYgZwcm90bzMKmikKHmdvb2dsZS9wcm90b2J1Zi9kdXJhdGlvbi5wcm90bxIPZ29vZ2xlLnByb3RvYnVmIjoKCER1cmF0aW9uEhgKB3NlY29uZHMYASABKANSB3NlY29uZHMSFAoFbmFub3MYAiABKAVSBW5hbm9zQnwKE2NvbS5nb29nbGUucHJvdG9idWZCDUR1cmF0aW9uUHJvdG9QAVoqZ2l0aHViLmNvbS9nb2xhbmcvcHJvdG9idWYvcHR5cGVzL2R1cmF0aW9u+AEBogIDR1BCqgIeR29vZ2xlLlByb3RvYnVmLldlbGxLbm93blR5cGVzSqQnCgYSBB4AdAEKzAwKAQwSAx4AEjLBDCBQcm90b2NvbCBCdWZmZXJzIC0gR29vZ2xlJ3MgZGF0YSBpbnRlcmNoYW5nZSBmb3JtYXQKIENvcHlyaWdodCAyMDA4IEdvb2dsZSBJbmMuICBBbGwgcmlnaHRzIHJlc2VydmVkLgogaHR0cHM6Ly9kZXZlbG9wZXJzLmdvb2dsZS5jb20vcHJvdG9jb2wtYnVmZmVycy8KCiBSZWRpc3RyaWJ1dGlvbiBhbmQgdXNlIGluIHNvdXJjZSBhbmQgYmluYXJ5IGZvcm1zLCB3aXRoIG9yIHdpdGhvdXQKIG1vZGlmaWNhdGlvbiwgYXJlIHBlcm1pdHRlZCBwcm92aWRlZCB0aGF0IHRoZSBmb2xsb3dpbmcgY29uZGl0aW9ucyBhcmUKIG1ldDoKCiAgICAgKiBSZWRpc3RyaWJ1dGlvbnMgb2Ygc291cmNlIGNvZGUgbXVzdCByZXRhaW4gdGhlIGFib3ZlIGNvcHlyaWdodAogbm90aWNlLCB0aGlzIGxpc3Qgb2YgY29uZGl0aW9ucyBhbmQgdGhlIGZvbGxvd2luZyBkaXNjbGFpbWVyLgogICAgICogUmVkaXN0cmlidXRpb25zIGluIGJpbmFyeSBmb3JtIG11c3QgcmVwcm9kdWNlIHRoZSBhYm92ZQogY29weXJpZ2h0IG5vdGljZSwgdGhpcyBsaXN0IG9mIGNvbmRpdGlvbnMgYW5kIHRoZSBmb2xsb3dpbmcgZGlzY2xhaW1lcgogaW4gdGhlIGRvY3VtZW50YXRpb24gYW5kL29yIG90aGVyIG1hdGVyaWFscyBwcm92aWRlZCB3aXRoIHRoZQogZGlzdHJpYnV0aW9uLgogICAgICogTmVpdGhlciB0aGUgbmFtZSBvZiBHb29nbGUgSW5jLiBub3IgdGhlIG5hbWVzIG9mIGl0cwogY29udHJpYnV0b3JzIG1heSBiZSB1c2VkIHRvIGVuZG9yc2Ugb3IgcHJvbW90ZSBwcm9kdWN0cyBkZXJpdmVkIGZyb20KIHRoaXMgc29mdHdhcmUgd2l0aG91dCBzcGVjaWZpYyBwcmlvciB3cml0dGVuIHBlcm1pc3Npb24uCgogVEhJUyBTT0ZUV0FSRSBJUyBQUk9WSURFRCBCWSBUSEUgQ09QWVJJR0hUIEhPTERFUlMgQU5EIENPTlRSSUJVVE9SUwogIkFTIElTIiBBTkQgQU5ZIEVYUFJFU1MgT1IgSU1QTElFRCBXQVJSQU5USUVTLCBJTkNMVURJTkcsIEJVVCBOT1QKIExJTUlURUQgVE8sIFRIRSBJTVBMSUVEIFdBUlJBTlRJRVMgT0YgTUVSQ0hBTlRBQklMSVRZIEFORCBGSVRORVNTIEZPUgogQSBQQVJUSUNVTEFSIFBVUlBPU0UgQVJFIERJU0NMQUlNRUQuIElOIE5PIEVWRU5UIFNIQUxMIFRIRSBDT1BZUklHSFQKIE9XTkVSIE9SIENPTlRSSUJVVE9SUyBCRSBMSUFCTEUgRk9SIEFOWSBESVJFQ1QsIElORElSRUNULCBJTkNJREVOVEFMLAogU1BFQ0lBTCwgRVhFTVBMQVJZLCBPUiBDT05TRVFVRU5USUFMIERBTUFHRVMgKElOQ0xVRElORywgQlVUIE5PVAogTElNSVRFRCBUTywgUFJPQ1VSRU1FTlQgT0YgU1VCU1RJVFVURSBHT09EUyBPUiBTRVJWSUNFUzsgTE9TUyBPRiBVU0UsCiBEQVRBLCBPUiBQUk9GSVRTOyBPUiBCVVNJTkVTUyBJTlRFUlJVUFRJT04pIEhPV0VWRVIgQ0FVU0VEIEFORCBPTiBBTlkKIFRIRU9SWSBPRiBMSUFCSUxJVFksIFdIRVRIRVIgSU4gQ09OVFJBQ1QsIFNUUklDVCBMSUFCSUxJVFksIE9SIFRPUlQKIChJTkNMVURJTkcgTkVHTElHRU5DRSBPUiBPVEhFUldJU0UpIEFSSVNJTkcgSU4gQU5ZIFdBWSBPVVQgT0YgVEhFIFVTRQogT0YgVEhJUyBTT0ZUV0FSRSwgRVZFTiBJRiBBRFZJU0VEIE9GIFRIRSBQT1NTSUJJTElUWSBPRiBTVUNIIERBTUFHRS4KCggKAQISAyAIFwoICgEIEgMiADsKCwoECOcHABIDIgA7CgwKBQjnBwACEgMiBxcKDQoGCOcHAAIAEgMiBxcKDgoHCOcHAAIAARIDIgcXCgwKBQjnBwAHEgMiGjoKCAoBCBIDIwAfCgsKBAjnBwESAyMAHwoMCgUI5wcBAhIDIwcXCg0KBgjnBwECABIDIwcXCg4KBwjnBwECAAESAyMHFwoMCgUI5wcBAxIDIxoeCggKAQgSAyQAQQoLCgQI5wcCEgMkAEEKDAoFCOcHAgISAyQHEQoNCgYI5wcCAgASAyQHEQoOCgcI5wcCAgABEgMkBxEKDAoFCOcHAgcSAyQUQAoICgEIEgMlACwKCwoECOcHAxIDJQAsCgwKBQjnBwMCEgMlBxMKDQoGCOcHAwIAEgMlBxMKDgoHCOcHAwIAARIDJQcTCgwKBQjnBwMHEgMlFisKCAoBCBIDJgAuCgsKBAjnBwQSAyYALgoMCgUI5wcEAhIDJgcbCg0KBgjnBwQCABIDJgcbCg4KBwjnBwQCAAESAyYHGwoMCgUI5wcEBxIDJh4tCggKAQgSAycAIgoLCgQI5wcFEgMnACIKDAoFCOcHBQISAycHGgoNCgYI5wcFAgASAycHGgoOCgcI5wcFAgABEgMnBxoKDAoFCOcHBQMSAycdIQoICgEIEgMoACEKCwoECOcHBhIDKAAhCgwKBQjnBwYCEgMoBxgKDQoGCOcHBgIAEgMoBxgKDgoHCOcHBgIAARIDKAcYCgwKBQjnBwYHEgMoGyAKnxAKAgQAEgRmAHQBGpIQIEEgRHVyYXRpb24gcmVwcmVzZW50cyBhIHNpZ25lZCwgZml4ZWQtbGVuZ3RoIHNwYW4gb2YgdGltZSByZXByZXNlbnRlZAogYXMgYSBjb3VudCBvZiBzZWNvbmRzIGFuZCBmcmFjdGlvbnMgb2Ygc2Vjb25kcyBhdCBuYW5vc2Vjb25kCiByZXNvbHV0aW9uLiBJdCBpcyBpbmRlcGVuZGVudCBvZiBhbnkgY2FsZW5kYXIgYW5kIGNvbmNlcHRzIGxpa2UgImRheSIKIG9yICJtb250aCIuIEl0IGlzIHJlbGF0ZWQgdG8gVGltZXN0YW1wIGluIHRoYXQgdGhlIGRpZmZlcmVuY2UgYmV0d2VlbgogdHdvIFRpbWVzdGFtcCB2YWx1ZXMgaXMgYSBEdXJhdGlvbiBhbmQgaXQgY2FuIGJlIGFkZGVkIG9yIHN1YnRyYWN0ZWQKIGZyb20gYSBUaW1lc3RhbXAuIFJhbmdlIGlzIGFwcHJveGltYXRlbHkgKy0xMCwwMDAgeWVhcnMuCgogIyBFeGFtcGxlcwoKIEV4YW1wbGUgMTogQ29tcHV0ZSBEdXJhdGlvbiBmcm9tIHR3byBUaW1lc3RhbXBzIGluIHBzZXVkbyBjb2RlLgoKICAgICBUaW1lc3RhbXAgc3RhcnQgPSAuLi47CiAgICAgVGltZXN0YW1wIGVuZCA9IC4uLjsKICAgICBEdXJhdGlvbiBkdXJhdGlvbiA9IC4uLjsKCiAgICAgZHVyYXRpb24uc2Vjb25kcyA9IGVuZC5zZWNvbmRzIC0gc3RhcnQuc2Vjb25kczsKICAgICBkdXJhdGlvbi5uYW5vcyA9IGVuZC5uYW5vcyAtIHN0YXJ0Lm5hbm9zOwoKICAgICBpZiAoZHVyYXRpb24uc2Vjb25kcyA8IDAgJiYgZHVyYXRpb24ubmFub3MgPiAwKSB7CiAgICAgICBkdXJhdGlvbi5zZWNvbmRzICs9IDE7CiAgICAgICBkdXJhdGlvbi5uYW5vcyAtPSAxMDAwMDAwMDAwOwogICAgIH0gZWxzZSBpZiAoZHVyYXRpb25zLnNlY29uZHMgPiAwICYmIGR1cmF0aW9uLm5hbm9zIDwgMCkgewogICAgICAgZHVyYXRpb24uc2Vjb25kcyAtPSAxOwogICAgICAgZHVyYXRpb24ubmFub3MgKz0gMTAwMDAwMDAwMDsKICAgICB9CgogRXhhbXBsZSAyOiBDb21wdXRlIFRpbWVzdGFtcCBmcm9tIFRpbWVzdGFtcCArIER1cmF0aW9uIGluIHBzZXVkbyBjb2RlLgoKICAgICBUaW1lc3RhbXAgc3RhcnQgPSAuLi47CiAgICAgRHVyYXRpb24gZHVyYXRpb24gPSAuLi47CiAgICAgVGltZXN0YW1wIGVuZCA9IC4uLjsKCiAgICAgZW5kLnNlY29uZHMgPSBzdGFydC5zZWNvbmRzICsgZHVyYXRpb24uc2Vjb25kczsKICAgICBlbmQubmFub3MgPSBzdGFydC5uYW5vcyArIGR1cmF0aW9uLm5hbm9zOwoKICAgICBpZiAoZW5kLm5hbm9zIDwgMCkgewogICAgICAgZW5kLnNlY29uZHMgLT0gMTsKICAgICAgIGVuZC5uYW5vcyArPSAxMDAwMDAwMDAwOwogICAgIH0gZWxzZSBpZiAoZW5kLm5hbm9zID49IDEwMDAwMDAwMDApIHsKICAgICAgIGVuZC5zZWNvbmRzICs9IDE7CiAgICAgICBlbmQubmFub3MgLT0gMTAwMDAwMDAwMDsKICAgICB9CgogRXhhbXBsZSAzOiBDb21wdXRlIER1cmF0aW9uIGZyb20gZGF0ZXRpbWUudGltZWRlbHRhIGluIFB5dGhvbi4KCiAgICAgdGQgPSBkYXRldGltZS50aW1lZGVsdGEoZGF5cz0zLCBtaW51dGVzPTEwKQogICAgIGR1cmF0aW9uID0gRHVyYXRpb24oKQogICAgIGR1cmF0aW9uLkZyb21UaW1lZGVsdGEodGQpCgogIyBKU09OIE1hcHBpbmcKCiBJbiBKU09OIGZvcm1hdCwgdGhlIER1cmF0aW9uIHR5cGUgaXMgZW5jb2RlZCBhcyBhIHN0cmluZyByYXRoZXIgdGhhbiBhbgogb2JqZWN0LCB3aGVyZSB0aGUgc3RyaW5nIGVuZHMgaW4gdGhlIHN1ZmZpeCAicyIgKGluZGljYXRpbmcgc2Vjb25kcykgYW5kCiBpcyBwcmVjZWRlZCBieSB0aGUgbnVtYmVyIG9mIHNlY29uZHMsIHdpdGggbmFub3NlY29uZHMgZXhwcmVzc2VkIGFzCiBmcmFjdGlvbmFsIHNlY29uZHMuIEZvciBleGFtcGxlLCAzIHNlY29uZHMgd2l0aCAwIG5hbm9zZWNvbmRzIHNob3VsZCBiZQogZW5jb2RlZCBpbiBKU09OIGZvcm1hdCBhcyAiM3MiLCB3aGlsZSAzIHNlY29uZHMgYW5kIDEgbmFub3NlY29uZCBzaG91bGQKIGJlIGV4cHJlc3NlZCBpbiBKU09OIGZvcm1hdCBhcyAiMy4wMDAwMDAwMDFzIiwgYW5kIDMgc2Vjb25kcyBhbmQgMQogbWljcm9zZWNvbmQgc2hvdWxkIGJlIGV4cHJlc3NlZCBpbiBKU09OIGZvcm1hdCBhcyAiMy4wMDAwMDFzIi4KCgoKCgoDBAABEgNmCBAK3AEKBAQAAgASA2sCFBrOASBTaWduZWQgc2Vjb25kcyBvZiB0aGUgc3BhbiBvZiB0aW1lLiBNdXN0IGJlIGZyb20gLTMxNSw1NzYsMDAwLDAwMAogdG8gKzMxNSw1NzYsMDAwLDAwMCBpbmNsdXNpdmUuIE5vdGU6IHRoZXNlIGJvdW5kcyBhcmUgY29tcHV0ZWQgZnJvbToKIDYwIHNlYy9taW4gKiA2MCBtaW4vaHIgKiAyNCBoci9kYXkgKiAzNjUuMjUgZGF5cy95ZWFyICogMTAwMDAgeWVhcnMKCg0KBQQAAgAEEgRrAmYSCgwKBQQAAgAFEgNrAgcKDAoFBAACAAESA2sIDwoMCgUEAAIAAxIDaxITCoMDCgQEAAIBEgNzAhIa9QIgU2lnbmVkIGZyYWN0aW9ucyBvZiBhIHNlY29uZCBhdCBuYW5vc2Vjb25kIHJlc29sdXRpb24gb2YgdGhlIHNwYW4KIG9mIHRpbWUuIER1cmF0aW9ucyBsZXNzIHRoYW4gb25lIHNlY29uZCBhcmUgcmVwcmVzZW50ZWQgd2l0aCBhIDAKIGBzZWNvbmRzYCBmaWVsZCBhbmQgYSBwb3NpdGl2ZSBvciBuZWdhdGl2ZSBgbmFub3NgIGZpZWxkLiBGb3IgZHVyYXRpb25zCiBvZiBvbmUgc2Vjb25kIG9yIG1vcmUsIGEgbm9uLXplcm8gdmFsdWUgZm9yIHRoZSBgbmFub3NgIGZpZWxkIG11c3QgYmUKIG9mIHRoZSBzYW1lIHNpZ24gYXMgdGhlIGBzZWNvbmRzYCBmaWVsZC4gTXVzdCBiZSBmcm9tIC05OTksOTk5LDk5OQogdG8gKzk5OSw5OTksOTk5IGluY2x1c2l2ZS4KCg0KBQQAAgEEEgRzAmsUCgwKBQQAAgEFEgNzAgcKDAoFBAACAQESA3MIDQoMCgUEAAIBAxIDcxARYgZwcm90bzMKqyIKF2dvb2dsZS9ycGMvc3RhdHVzLnByb3RvEgpnb29nbGUucnBjGhlnb29nbGUvcHJvdG9idWYvYW55LnByb3RvImYKBlN0YXR1cxISCgRjb2RlGAEgASgFUgRjb2RlEhgKB21lc3NhZ2UYAiABKAlSB21lc3NhZ2USLgoHZGV0YWlscxgDIAMoCzIULmdvb2dsZS5wcm90b2J1Zi5BbnlSB2RldGFpbHNCKgoOY29tLmdvb2dsZS5ycGNCC1N0YXR1c1Byb3RvUAFaA3JwY6ICA1JQQ0rMIAoGEgQOAFsBCr0ECgEMEgMOABIysgQgQ29weXJpZ2h0IDIwMTcgR29vZ2xlIEluYy4KCiBMaWNlbnNlZCB1bmRlciB0aGUgQXBhY2hlIExpY2Vuc2UsIFZlcnNpb24gMi4wICh0aGUgIkxpY2Vuc2UiKTsKIHlvdSBtYXkgbm90IHVzZSB0aGlzIGZpbGUgZXhjZXB0IGluIGNvbXBsaWFuY2Ugd2l0aCB0aGUgTGljZW5zZS4KIFlvdSBtYXkgb2J0YWluIGEgY29weSBvZiB0aGUgTGljZW5zZSBhdAoKICAgICBodHRwOi8vd3d3LmFwYWNoZS5vcmcvbGljZW5zZXMvTElDRU5TRS0yLjAKCiBVbmxlc3MgcmVxdWlyZWQgYnkgYXBwbGljYWJsZSBsYXcgb3IgYWdyZWVkIHRvIGluIHdyaXRpbmcsIHNvZnR3YXJlCiBkaXN0cmlidXRlZCB1bmRlciB0aGUgTGljZW5zZSBpcyBkaXN0cmlidXRlZCBvbiBhbiAiQVMgSVMiIEJBU0lTLAogV0lUSE9VVCBXQVJSQU5USUVTIE9SIENPTkRJVElPTlMgT0YgQU5ZIEtJTkQsIGVpdGhlciBleHByZXNzIG9yIGltcGxpZWQuCiBTZWUgdGhlIExpY2Vuc2UgZm9yIHRoZSBzcGVjaWZpYyBsYW5ndWFnZSBnb3Zlcm5pbmcgcGVybWlzc2lvbnMgYW5kCiBsaW1pdGF0aW9ucyB1bmRlciB0aGUgTGljZW5zZS4KCggKAQISAxAIEgoJCgIDABIDEgciCggKAQgSAxQAGgoLCgQI5wcAEgMUABoKDAoFCOcHAAISAxQHEQoNCgYI5wcAAgASAxQHEQoOCgcI5wcAAgABEgMUBxEKDAoFCOcHAAcSAxQUGQoICgEIEgMVACIKCwoECOcHARIDFQAiCgwKBQjnBwECEgMVBxoKDQoGCOcHAQIAEgMVBxoKDgoHCOcHAQIAARIDFQcaCgwKBQjnBwEDEgMVHSEKCAoBCBIDFgAsCgsKBAjnBwISAxYALAoMCgUI5wcCAhIDFgcbCg0KBgjnBwICABIDFgcbCg4KBwjnBwICAAESAxYHGwoMCgUI5wcCBxIDFh4rCggKAQgSAxcAJwoLCgQI5wcDEgMXACcKDAoFCOcHAwISAxcHEwoNCgYI5wcDAgASAxcHEwoOCgcI5wcDAgABEgMXBxMKDAoFCOcHAwcSAxcWJgoICgEIEgMYACEKCwoECOcHBBIDGAAhCgwKBQjnBwQCEgMYBxgKDQoGCOcHBAIAEgMYBxgKDgoHCOcHBAIAARIDGAcYCgwKBQjnBwQHEgMYGyAKzRMKAgQAEgRPAFsBGsATIFRoZSBgU3RhdHVzYCB0eXBlIGRlZmluZXMgYSBsb2dpY2FsIGVycm9yIG1vZGVsIHRoYXQgaXMgc3VpdGFibGUgZm9yIGRpZmZlcmVudAogcHJvZ3JhbW1pbmcgZW52aXJvbm1lbnRzLCBpbmNsdWRpbmcgUkVTVCBBUElzIGFuZCBSUEMgQVBJcy4gSXQgaXMgdXNlZCBieQogW2dSUENdKGh0dHBzOi8vZ2l0aHViLmNvbS9ncnBjKS4gVGhlIGVycm9yIG1vZGVsIGlzIGRlc2lnbmVkIHRvIGJlOgoKIC0gU2ltcGxlIHRvIHVzZSBhbmQgdW5kZXJzdGFuZCBmb3IgbW9zdCB1c2VycwogLSBGbGV4aWJsZSBlbm91Z2ggdG8gbWVldCB1bmV4cGVjdGVkIG5lZWRzCgogIyBPdmVydmlldwoKIFRoZSBgU3RhdHVzYCBtZXNzYWdlIGNvbnRhaW5zIHRocmVlIHBpZWNlcyBvZiBkYXRhOiBlcnJvciBjb2RlLCBlcnJvciBtZXNzYWdlLAogYW5kIGVycm9yIGRldGFpbHMuIFRoZSBlcnJvciBjb2RlIHNob3VsZCBiZSBhbiBlbnVtIHZhbHVlIG9mCiBbZ29vZ2xlLnJwYy5Db2RlXVtnb29nbGUucnBjLkNvZGVdLCBidXQgaXQgbWF5IGFjY2VwdCBhZGRpdGlvbmFsIGVycm9yIGNvZGVzIGlmIG5lZWRlZC4gIFRoZQogZXJyb3IgbWVzc2FnZSBzaG91bGQgYmUgYSBkZXZlbG9wZXItZmFjaW5nIEVuZ2xpc2ggbWVzc2FnZSB0aGF0IGhlbHBzCiBkZXZlbG9wZXJzICp1bmRlcnN0YW5kKiBhbmQgKnJlc29sdmUqIHRoZSBlcnJvci4gSWYgYSBsb2NhbGl6ZWQgdXNlci1mYWNpbmcKIGVycm9yIG1lc3NhZ2UgaXMgbmVlZGVkLCBwdXQgdGhlIGxvY2FsaXplZCBtZXNzYWdlIGluIHRoZSBlcnJvciBkZXRhaWxzIG9yCiBsb2NhbGl6ZSBpdCBpbiB0aGUgY2xpZW50LiBUaGUgb3B0aW9uYWwgZXJyb3IgZGV0YWlscyBtYXkgY29udGFpbiBhcmJpdHJhcnkKIGluZm9ybWF0aW9uIGFib3V0IHRoZSBlcnJvci4gVGhlcmUgaXMgYSBwcmVkZWZpbmVkIHNldCBvZiBlcnJvciBkZXRhaWwgdHlwZXMKIGluIHRoZSBwYWNrYWdlIGBnb29nbGUucnBjYCB0aGF0IGNhbiBiZSB1c2VkIGZvciBjb21tb24gZXJyb3IgY29uZGl0aW9ucy4KCiAjIExhbmd1YWdlIG1hcHBpbmcKCiBUaGUgYFN0YXR1c2AgbWVzc2FnZSBpcyB0aGUgbG9naWNhbCByZXByZXNlbnRhdGlvbiBvZiB0aGUgZXJyb3IgbW9kZWwsIGJ1dCBpdAogaXMgbm90IG5lY2Vzc2FyaWx5IHRoZSBhY3R1YWwgd2lyZSBmb3JtYXQuIFdoZW4gdGhlIGBTdGF0dXNgIG1lc3NhZ2UgaXMKIGV4cG9zZWQgaW4gZGlmZmVyZW50IGNsaWVudCBsaWJyYXJpZXMgYW5kIGRpZmZlcmVudCB3aXJlIHByb3RvY29scywgaXQgY2FuIGJlCiBtYXBwZWQgZGlmZmVyZW50bHkuIEZvciBleGFtcGxlLCBpdCB3aWxsIGxpa2VseSBiZSBtYXBwZWQgdG8gc29tZSBleGNlcHRpb25zCiBpbiBKYXZhLCBidXQgbW9yZSBsaWtlbHkgbWFwcGVkIHRvIHNvbWUgZXJyb3IgY29kZXMgaW4gQy4KCiAjIE90aGVyIHVzZXMKCiBUaGUgZXJyb3IgbW9kZWwgYW5kIHRoZSBgU3RhdHVzYCBtZXNzYWdlIGNhbiBiZSB1c2VkIGluIGEgdmFyaWV0eSBvZgogZW52aXJvbm1lbnRzLCBlaXRoZXIgd2l0aCBvciB3aXRob3V0IEFQSXMsIHRvIHByb3ZpZGUgYQogY29uc2lzdGVudCBkZXZlbG9wZXIgZXhwZXJpZW5jZSBhY3Jvc3MgZGlmZmVyZW50IGVudmlyb25tZW50cy4KCiBFeGFtcGxlIHVzZXMgb2YgdGhpcyBlcnJvciBtb2RlbCBpbmNsdWRlOgoKIC0gUGFydGlhbCBlcnJvcnMuIElmIGEgc2VydmljZSBuZWVkcyB0byByZXR1cm4gcGFydGlhbCBlcnJvcnMgdG8gdGhlIGNsaWVudCwKICAgICBpdCBtYXkgZW1iZWQgdGhlIGBTdGF0dXNgIGluIHRoZSBub3JtYWwgcmVzcG9uc2UgdG8gaW5kaWNhdGUgdGhlIHBhcnRpYWwKICAgICBlcnJvcnMuCgogLSBXb3JrZmxvdyBlcnJvcnMuIEEgdHlwaWNhbCB3b3JrZmxvdyBoYXMgbXVsdGlwbGUgc3RlcHMuIEVhY2ggc3RlcCBtYXkKICAgICBoYXZlIGEgYFN0YXR1c2AgbWVzc2FnZSBmb3IgZXJyb3IgcmVwb3J0aW5nLgoKIC0gQmF0Y2ggb3BlcmF0aW9ucy4gSWYgYSBjbGllbnQgdXNlcyBiYXRjaCByZXF1ZXN0IGFuZCBiYXRjaCByZXNwb25zZSwgdGhlCiAgICAgYFN0YXR1c2AgbWVzc2FnZSBzaG91bGQgYmUgdXNlZCBkaXJlY3RseSBpbnNpZGUgYmF0Y2ggcmVzcG9uc2UsIG9uZSBmb3IKICAgICBlYWNoIGVycm9yIHN1Yi1yZXNwb25zZS4KCiAtIEFzeW5jaHJvbm91cyBvcGVyYXRpb25zLiBJZiBhbiBBUEkgY2FsbCBlbWJlZHMgYXN5bmNocm9ub3VzIG9wZXJhdGlvbgogICAgIHJlc3VsdHMgaW4gaXRzIHJlc3BvbnNlLCB0aGUgc3RhdHVzIG9mIHRob3NlIG9wZXJhdGlvbnMgc2hvdWxkIGJlCiAgICAgcmVwcmVzZW50ZWQgZGlyZWN0bHkgdXNpbmcgdGhlIGBTdGF0dXNgIG1lc3NhZ2UuCgogLSBMb2dnaW5nLiBJZiBzb21lIEFQSSBlcnJvcnMgYXJlIHN0b3JlZCBpbiBsb2dzLCB0aGUgbWVzc2FnZSBgU3RhdHVzYCBjb3VsZAogICAgIGJlIHVzZWQgZGlyZWN0bHkgYWZ0ZXIgYW55IHN0cmlwcGluZyBuZWVkZWQgZm9yIHNlY3VyaXR5L3ByaXZhY3kgcmVhc29ucy4KCgoKAwQAARIDTwgOCmQKBAQAAgASA1ECERpXIFRoZSBzdGF0dXMgY29kZSwgd2hpY2ggc2hvdWxkIGJlIGFuIGVudW0gdmFsdWUgb2YgW2dvb2dsZS5ycGMuQ29kZV1bZ29vZ2xlLnJwYy5Db2RlXS4KCg0KBQQAAgAEEgRRAk8QCgwKBQQAAgAFEgNRAgcKDAoFBAACAAESA1EIDAoMCgUEAAIAAxIDUQ8QCusBCgQEAAIBEgNWAhUa3QEgQSBkZXZlbG9wZXItZmFjaW5nIGVycm9yIG1lc3NhZ2UsIHdoaWNoIHNob3VsZCBiZSBpbiBFbmdsaXNoLiBBbnkKIHVzZXItZmFjaW5nIGVycm9yIG1lc3NhZ2Ugc2hvdWxkIGJlIGxvY2FsaXplZCBhbmQgc2VudCBpbiB0aGUKIFtnb29nbGUucnBjLlN0YXR1cy5kZXRhaWxzXVtnb29nbGUucnBjLlN0YXR1cy5kZXRhaWxzXSBmaWVsZCwgb3IgbG9jYWxpemVkIGJ5IHRoZSBjbGllbnQuCgoNCgUEAAIBBBIEVgJREQoMCgUEAAIBBRIDVgIICgwKBQQAAgEBEgNWCRAKDAoFBAACAQMSA1YTFAp5CgQEAAICEgNaAisabCBBIGxpc3Qgb2YgbWVzc2FnZXMgdGhhdCBjYXJyeSB0aGUgZXJyb3IgZGV0YWlscy4gIFRoZXJlIGlzIGEgY29tbW9uIHNldCBvZgogbWVzc2FnZSB0eXBlcyBmb3IgQVBJcyB0byB1c2UuCgoMCgUEAAICBBIDWgIKCgwKBQQAAgIGEgNaCx4KDAoFBAACAgESA1ofJgoMCgUEAAICAxIDWikqYgZwcm90bzMKvBEKJ21peGVyL2FkYXB0ZXIvbW9kZWwvdjFiZXRhMS9jaGVjay5wcm90bxIhaXN0aW8ubWl4ZXIuYWRhcHRlci5tb2RlbC52MWJldGExGhRnb2dvcHJvdG8vZ29nby5wcm90bxoeZ29vZ2xlL3Byb3RvYnVmL2R1cmF0aW9uLnByb3RvGhdnb29nbGUvcnBjL3N0YXR1cy5wcm90byKzAQoLQ2hlY2tSZXN1bHQSMAoGc3RhdHVzGAEgASgLMhIuZ29vZ2xlLnJwYy5TdGF0dXNCBMjeHwBSBnN0YXR1cxJKCg52YWxpZF9kdXJhdGlvbhgCIAEoCzIZLmdvb2dsZS5wcm90b2J1Zi5EdXJhdGlvbkIIyN4fAJjfHwFSDXZhbGlkRHVyYXRpb24SJgoPdmFsaWRfdXNlX2NvdW50GAMgASgFUg12YWxpZFVzZUNvdW50QjZaKGlzdGlvLmlvL2FwaS9taXhlci9hZGFwdGVyL21vZGVsL3YxYmV0YTHI4R4AqOIe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CgUEAAICBRIDJAIHCgwKBQQAAgIBEgMkCBcKDAoFBAACAgMSAyQaG2IGcHJvdG8zCoEhCjBtaXhlci90ZXN0L2tleXZhbC90ZW1wbGF0ZV9oYW5kbGVyX3NlcnZpY2UucHJvdG8SBmtleXZhbBoUZ29nb3Byb3RvL2dvZ28ucHJvdG8aLG1peGVyL2FkYXB0ZXIvbW9kZWwvdjFiZXRhMS9leHRlbnNpb25zLnByb3RvGhlnb29nbGUvcHJvdG9idWYvYW55LnByb3RvGidtaXhlci9hZGFwdGVyL21vZGVsL3YxYmV0YTEvY2hlY2sucHJvdG8ingEKE0hhbmRsZUtleXZhbFJlcXVlc3QSLwoIaW5zdGFuY2UYASABKAsyEy5rZXl2YWwuSW5zdGFuY2VNc2dSCGluc3RhbmNlEjsKDmFkYXB0ZXJfY29uZmlnGAIgASgLMhQuZ29vZ2xlLnByb3RvYnVmLkFueVINYWRhcHRlckNvbmZpZxIZCghkZWR1cF9pZBgDIAEoCVIHZGVkdXBJZCKJAQoUSGFuZGxlS2V5dmFsUmVzcG9uc2USRgoGcmVzdWx0GAEgASgLMi4uaXN0aW8ubWl4ZXIuYWRhcHRlci5tb2RlbC52MWJldGExLkNoZWNrUmVzdWx0UgZyZXN1bHQSKQoGb3V0cHV0GAIgASgLMhEua2V5dmFsLk91dHB1dE1zZ1IGb3V0cHV0IiEKCU91dHB1dE1zZxIUCgV2YWx1ZRgCIAEoCVIFdmFsdWUiNgoLSW5zdGFuY2VNc2cSFQoEbmFtZRivyrwiIAEoCVIEbmFtZRIQCgNrZXkYASABKAlSA2tleSIGCgRUeXBlIiEKDUluc3RhbmNlUGFyYW0SEAoDa2V5GAEgASgJUgNrZXkyYAoTSGFuZGxlS2V5dmFsU2VydmljZRJJCgxIYW5kbGVLZXl2YWwSGy5rZXl2YWwuSGFuZGxlS2V5dmFsUmVxdWVzdBocLmtleXZhbC5IYW5kbGVLZXl2YWxSZXNwb25zZUIe+NLkkwIEgt3kkwIGa2V5dmFsyOEeAKjiHgDw4R4ASv8aCgYSBBAAZQEK8gQKAQwSAxAAEjK0BCBDb3B5cmlnaHQgMjAxNyBJc3RpbyBBdXRob3JzCgogTGljZW5zZWQgdW5kZXIgdGhlIEFwYWNoZSBMaWNlbnNlLCBWZXJzaW9uIDIuMCAodGhlICJMaWNlbnNlIik7CiB5b3UgbWF5IG5vdCB1c2UgdGhpcyBmaWxlIGV4Y2VwdCBpbiBjb21wbGlhbmNlIHdpdGggdGhlIExpY2Vuc2UuCiBZb3UgbWF5IG9idGFpbiBhIGNvcHkgb2YgdGhlIExpY2Vuc2UgYXQKCiAgICAgaHR0cDovL3d3dy5hcGFjaGUub3JnL2xpY2Vuc2VzL0xJQ0VOU0UtMi4wCgogVW5sZXNzIHJlcXVpcmVkIGJ5IGFwcGxpY2FibGUgbGF3IG9yIGFncmVlZCB0byBpbiB3cml0aW5nLCBzb2Z0d2FyZQogZGlzdHJpYnV0ZWQgdW5kZXIgdGhlIExpY2Vuc2UgaXMgZGlzdHJpYnV0ZWQgb24gYW4gIkFTIElTIiBCQVNJUywKIFdJVEhPVVQgV0FSUkFOVElFUyBPUiBDT05ESVRJT05TIE9GIEFOWSBLSU5ELCBlaXRoZXIgZXhwcmVzcyBvciBpbXBsaWVkLgogU2VlIHRoZSBMaWNlbnNlIGZvciB0aGUgc3BlY2lmaWMgbGFuZ3VhZ2UgZ292ZXJuaW5nIHBlcm1pc3Npb25zIGFuZAogbGltaXRhdGlvbnMgdW5kZXIgdGhlIExpY2Vuc2UuCjIxIFRISVMgRklMRSBJUyBBVVRPTUFUSUNBTExZIEdFTkVSQVRFRCBCWSBNSVhHRU4uCgobCgECEgMWCA4aEQogSW5wdXQgdGVtcGxhdGUKCgkKAgMAEgMZBx0KCQoCAwESAxoHNQoJCgIDAhIDGwciCgkKAgMDEgMcBzAKCAoBCBIDHwBhCgsKBAjnBwASAx8AYQoMCgUI5wcAAhIDHwc7Cg0KBgjnBwACABIDHwc7Cg4KBwjnBwACAAESAx8IOgoMCgUI5wcAAxIDHz5gCggKAQgSAyAARAoLCgQI5wcBEgMgAEQKDAoFCOcHAQISAyAHOAoNCgYI5wcBAgASAyAHOAoOCgcI5wcBAgABEgMgCDcKDAoFCOcHAQcSAyA7QwoICgEIEgMiAC8KCwoECOcHAhIDIgAvCgwKBQjnBwICEgMiByYKDQoGCOcHAgIAEgMiByYKDgoHCOcHAgIAARIDIgglCgwKBQjnBwIDEgMiKS4KCAoBCBIDIwAlCgsKBAjnBwMSAyMAJQoMCgUI5wcDAhIDIwccCg0KBgjnBwMCABIDIwccCg4KBwjnBwMCAAESAyMIGwoMCgUI5wcDAxIDIx8kCggKAQgSAyQAKAoLCgQI5wcEEgMkACgKDAoFCOcHBAISAyQHHwoNCgYI5wcEAgASAyQHHwoOCgcI5wcEAgABEgMkCB4KDAoFCOcHBAMSAyQiJwpyCgIGABIEJwArARpmIEhhbmRsZUtleXZhbFNlcnZpY2UgaXMgaW1wbGVtZW50ZWQgYnkgYmFja2VuZHMgdGhhdCB3YW50cyB0byBoYW5kbGUgcmVxdWVzdC10aW1lICdrZXl2YWwnIGluc3RhbmNlcy4KCgoKAwYAARIDJwgbCmwKBAYAAgASAykESRpfIEhhbmRsZUtleXZhbCBpcyBjYWxsZWQgYnkgTWl4ZXIgYXQgcmVxdWVzdC10aW1lIHRvIGRlbGl2ZXIgJ2tleXZhbCcgaW5zdGFuY2VzIHRvIHRoZSBiYWNrZW5kLgoKDAoFBgACAAESAykIFAoMCgUGAAIAAhIDKRUoCgwKBQYAAgADEgMpM0cKNgoCBAASBC4APQEaKiBSZXF1ZXN0IG1lc3NhZ2UgZm9yIEhhbmRsZUtleXZhbCBtZXRob2QuCgoKCgMEAAESAy4IGwohCgQEAAIAEgMxBB0aFCAna2V5dmFsJyBpbnN0YW5jZS4KCg0KBQQAAgAEEgQxBC4dCgwKBQQAAgAGEgMxBA8KDAoFBAACAAESAzEQGAoMCgUEAAIAAxIDMRscCrkECgQEAAIBEgM5BCsaqwQgQWRhcHRlciBzcGVjaWZpYyBoYW5kbGVyIGNvbmZpZ3VyYXRpb24uCgogTm90ZTogQmFja2VuZHMgY2FuIGFsc28gaW1wbGVtZW50IFtJbmZyYXN0cnVjdHVyZUJhY2tlbmRdW2h0dHBzOi8vaXN0aW8uaW8vZG9jcy9yZWZlcmVuY2UvY29uZmlnL21peGVyL2lzdGlvLm1peGVyLmFkYXB0ZXIubW9kZWwudjFiZXRhMS5odG1sI0luZnJhc3RydWN0dXJlQmFja2VuZF0KIHNlcnZpY2UgYW5kIHRoZXJlZm9yZSBvcHQgdG8gcmVjZWl2ZSBoYW5kbGVyIGNvbmZpZ3VyYXRpb24gZHVyaW5nIHNlc3Npb24gY3JlYXRpb24gdGhyb3VnaCBbSW5mcmFzdHJ1Y3R1cmVCYWNrZW5kLkNyZWF0ZVNlc3Npb25dW1RPRE86IExpbmsgdG8gdGhpcyBmcmFnbWVudF0KIGNhbGwuIEluIHRoYXQgY2FzZSwgYWRhcHRlcl9jb25maWcgd2lsbCBoYXZlIHR5cGVfdXJsIGFzICdnb29nbGUucHJvdG9idWYuQW55LnR5cGVfdXJsJyBhbmQgd291bGQgY29udGFpbiBzdHJpbmcKIHZhbHVlIG9mIHNlc3Npb25faWQgKHJldHVybmVkIGZyb20gSW5mcmFzdHJ1Y3R1cmVCYWNrZW5kLkNyZWF0ZVNlc3Npb24pLgoKDQoFBAACAQQSBDkEMR0KDAoFBAACAQYSAzkEFwoMCgUEAAIBARIDORgmCgwKBQQAAgEDEgM5KSoKOgoEBAACAhIDPAQYGi0gSWQgdG8gZGVkdXBlIGlkZW50aWNhbCByZXF1ZXN0cyBmcm9tIE1peGVyLgoKDQoFBAACAgQSBDwEOSsKDAoFBAACAgUSAzwECgoMCgUEAAICARIDPAsTCgwKBQQAAgIDEgM8FhcKCgoCBAESBD8AQgEKCgoDBAEBEgM/CBwKCwoEBAECABIDQAQ9Cg0KBQQBAgAEEgRABD8eCgwKBQQBAgAGEgNABDEKDAoFBAECAAESA0AyOAoMCgUEAQIAAxIDQDs8CgsKBAQBAgESA0EEGQoNCgUEAQIBBBIEQQRAPQoMCgUEAQIBBhIDQQQNCgwKBQQBAgEBEgNBDhQKDAoFBAECAQMSA0EXGAo8CgIEAhIERQBKARowIENvbnRhaW5zIG91dHB1dCBwYXlsb2FkIGZvciAna2V5dmFsJyB0ZW1wbGF0ZS4KCgoKAwQCARIDRQgRCh4KBAQCAgASA0gEFRoRIHZhbHVlIHRvIHJldHVybgoKDQoFBAICAAQSBEgERRMKDAoFBAICAAUSA0gECgoMCgUEAgIAARIDSAsQCgwKBQQCAgADEgNIExQKqAEKAgQDEgROAFYBGpsBIENvbnRhaW5zIGluc3RhbmNlIHBheWxvYWQgZm9yICdrZXl2YWwnIHRlbXBsYXRlLiBUaGlzIGlzIHBhc3NlZCB0byBpbmZyYXN0cnVjdHVyZSBiYWNrZW5kcyBkdXJpbmcgcmVxdWVzdC10aW1lCiB0aHJvdWdoIEhhbmRsZUtleXZhbFNlcnZpY2UuSGFuZGxlS2V5dmFsLgoKCgoDBAMBEgNOCBMKQgoEBAMCABIDUQQbGjUgTmFtZSBvZiB0aGUgaW5zdGFuY2UgYXMgc3BlY2lmaWVkIGluIGNvbmZpZ3VyYXRpb24uCgoNCgUEAwIABBIEUQROFQoMCgUEAwIABRIDUQQKCgwKBQQDAgABEgNRCw8KDAoFBAMCAAMSA1ESGgoZCgQEAwIBEgNUBBMaDCBsb29rdXAga2V5CgoNCgUEAwIBBBIEVARRGwoMCgUEAwIBBRIDVAQKCgwKBQQDAgEBEgNUCw4KDAoFBAMCAQMSA1QREgrwAQoCBAQSBFoAXAEa4wEgQ29udGFpbnMgaW5mZXJyZWQgdHlwZSBpbmZvcm1hdGlvbiBhYm91dCBzcGVjaWZpYyBpbnN0YW5jZSBvZiAna2V5dmFsJyB0ZW1wbGF0ZS4gVGhpcyBpcyBwYXNzZWQgdG8KIGluZnJhc3RydWN0dXJlIGJhY2tlbmRzIGR1cmluZyBjb25maWd1cmF0aW9uLXRpbWUgdGhyb3VnaCBbSW5mcmFzdHJ1Y3R1cmVCYWNrZW5kLkNyZWF0ZVNlc3Npb25dW1RPRE86IExpbmsgdG8gdGhpcyBmcmFnbWVudF0uCgoKCgMEBAESA1oIDApNCgIEBRIEYABlARpBIFJlcHJlc2VudHMgaW5zdGFuY2UgY29uZmlndXJhdGlvbiBzY2hlbWEgZm9yICdrZXl2YWwnIHRlbXBsYXRlLgoKCgoDBAUBEgNgCBUKGQoEBAUCABIDYwQTGgwgbG9va3VwIGtleQoKDQoFBAUCAAQSBGMEYBcKDAoFBAUCAAUSA2MECgoMCgUEBQIAARIDYwsOCgwKBQQFAgADEgNjERJiBnByb3RvMw==" +--- diff --git a/istio-1.5.0/samples/httpbin/policy/keyval.yaml b/istio-1.5.0/samples/httpbin/policy/keyval.yaml new file mode 100644 index 0000000..d3a56ba --- /dev/null +++ b/istio-1.5.0/samples/httpbin/policy/keyval.yaml @@ -0,0 +1,14 @@ +# this config is created through command +# mixgen adapter -c $GOPATH/src/istio.io/istio/mixer/test/keyval/config.proto_descriptor -o $GOPATH/src/istio.io/istio/mixer/test/keyval -s=false -n keyval -t keyval +apiVersion: "config.istio.io/v1alpha2" +kind: adapter +metadata: + name: keyval + namespace: istio-system +spec: + description: + session_based: false + templates: + - keyval + config: CsgCCh5taXhlci90ZXN0L2tleXZhbC9jb25maWcucHJvdG8SBmtleXZhbCJzCgZQYXJhbXMSLwoFdGFibGUYASADKAsyGS5rZXl2YWwuUGFyYW1zLlRhYmxlRW50cnlSBXRhYmxlGjgKClRhYmxlRW50cnkSEAoDa2V5GAEgASgJUgNrZXkSFAoFdmFsdWUYAiABKAlSBXZhbHVlOgI4AUqgAQoGEgQAAAgBCggKAQwSAwAAEgoICgECEgMCCA4KIAoCBAASBAUACAEaFCBBZGFwdGVyIHBhcmFtZXRlcnMKCgoKAwQAARIDBQgOChsKBAQAAgASAwcCIBoOIExvb2t1cCB0YWJsZQoKDQoFBAACAAQSBAcCBRAKDAoFBAACAAYSAwcCFQoMCgUEAAIAARIDBxYbCgwKBQQAAgADEgMHHh9iBnByb3RvMw== +--- diff --git a/istio-1.5.0/samples/httpbin/sample-client/fortio-deploy.yaml b/istio-1.5.0/samples/httpbin/sample-client/fortio-deploy.yaml new file mode 100644 index 0000000..06aef93 --- /dev/null +++ b/istio-1.5.0/samples/httpbin/sample-client/fortio-deploy.yaml @@ -0,0 +1,41 @@ +apiVersion: v1 +kind: Service +metadata: + name: fortio + labels: + app: fortio +spec: + ports: + - port: 8080 + name: http + selector: + app: fortio +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: fortio-deploy +spec: + replicas: 1 + selector: + matchLabels: + app: fortio + template: + metadata: + annotations: + # This annotation causes Envoy to serve cluster.outbound statistics via 15000/stats + # in addition to the stats normally served by Istio. The Circuit Breaking example task + # gives an example of inspecting Envoy stats. + sidecar.istio.io/statsInclusionPrefixes: cluster.outbound,cluster_manager,listener_manager,http_mixer_filter,tcp_mixer_filter,server,cluster.xds-grpc + labels: + app: fortio + spec: + containers: + - name: fortio + image: fortio/fortio:latest_release + imagePullPolicy: Always + ports: + - containerPort: 8080 + name: http-fortio + - containerPort: 8079 + name: grpc-ping diff --git a/istio-1.5.0/samples/https/default.conf b/istio-1.5.0/samples/https/default.conf new file mode 100644 index 0000000..4a5b420 --- /dev/null +++ b/istio-1.5.0/samples/https/default.conf @@ -0,0 +1,10 @@ +server { + listen 443 ssl; + + root /usr/share/nginx/html; + index index.html; + + server_name localhost; + ssl_certificate /etc/nginx/ssl/tls.crt; + ssl_certificate_key /etc/nginx/ssl/tls.key; +} diff --git a/istio-1.5.0/samples/https/nginx-app.yaml b/istio-1.5.0/samples/https/nginx-app.yaml new file mode 100644 index 0000000..aece09e --- /dev/null +++ b/istio-1.5.0/samples/https/nginx-app.yaml @@ -0,0 +1,43 @@ +apiVersion: v1 +kind: Service +metadata: + name: my-nginx + labels: + app: nginx +spec: + type: NodePort + ports: + - port: 443 + name: https + selector: + app: nginx +--- +apiVersion: v1 +kind: ReplicationController +metadata: + name: my-nginx +spec: + replicas: 1 + template: + metadata: + labels: + app: nginx + spec: + volumes: + - name: secret-volume + secret: + secretName: nginxsecret + - name: configmap-volume + configMap: + name: nginxconfigmap + containers: + - name: nginxhttps + image: ymqytw/nginxhttps:1.5 + command: ["/home/auto-reload-nginx.sh"] + ports: + - containerPort: 443 + volumeMounts: + - mountPath: /etc/nginx/ssl + name: secret-volume + - mountPath: /etc/nginx/conf.d + name: configmap-volume diff --git a/istio-1.5.0/samples/kubernetes-blog/bookinfo-ratings.yaml b/istio-1.5.0/samples/kubernetes-blog/bookinfo-ratings.yaml new file mode 100644 index 0000000..eae30a6 --- /dev/null +++ b/istio-1.5.0/samples/kubernetes-blog/bookinfo-ratings.yaml @@ -0,0 +1,49 @@ +# Copyright 2017 Istio Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +################################################################################################## +# Ratings service +################################################################################################## +apiVersion: v1 +kind: Service +metadata: + name: ratings + labels: + app: ratings +spec: + ports: + - port: 9080 + name: http + selector: + app: ratings +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: ratings-v1 +spec: + replicas: 1 + template: + metadata: + labels: + app: ratings + version: v1 + spec: + containers: + - name: ratings + image: docker.io/istio/examples-bookinfo-ratings-v1:0.2.3 + imagePullPolicy: IfNotPresent + ports: + - containerPort: 9080 +--- diff --git a/istio-1.5.0/samples/kubernetes-blog/bookinfo-reviews-v2.yaml b/istio-1.5.0/samples/kubernetes-blog/bookinfo-reviews-v2.yaml new file mode 100644 index 0000000..8ae3489 --- /dev/null +++ b/istio-1.5.0/samples/kubernetes-blog/bookinfo-reviews-v2.yaml @@ -0,0 +1,40 @@ +# Copyright 2017 Istio Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +################################################################################################## +# Reviews service v2 +################################################################################################## +apiVersion: apps/v1 +kind: Deployment +metadata: + name: reviews-v2 +spec: + replicas: 1 + selector: + matchLabels: + app: reviews + version: v2 + template: + metadata: + labels: + app: reviews + version: v2 + spec: + containers: + - name: reviews + image: docker.io/istio/examples-bookinfo-reviews-v2:0.2.3 + imagePullPolicy: IfNotPresent + ports: + - containerPort: 9080 +--- diff --git a/istio-1.5.0/samples/kubernetes-blog/bookinfo-v1.yaml b/istio-1.5.0/samples/kubernetes-blog/bookinfo-v1.yaml new file mode 100644 index 0000000..d675374 --- /dev/null +++ b/istio-1.5.0/samples/kubernetes-blog/bookinfo-v1.yaml @@ -0,0 +1,131 @@ +# Copyright 2017 Istio Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +################################################################################################## +# Details service +################################################################################################## +apiVersion: v1 +kind: Service +metadata: + name: details + labels: + app: details +spec: + ports: + - port: 9080 + name: http + selector: + app: details +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: details-v1 +spec: + replicas: 1 + selector: + matchLabels: + app: details + version: v1 + template: + metadata: + labels: + app: details + version: v1 + spec: + containers: + - name: details + image: istio/examples-bookinfo-details-v1:0.2.3 + imagePullPolicy: IfNotPresent + ports: + - containerPort: 9080 +--- +################################################################################################## +# Reviews service +################################################################################################## +apiVersion: v1 +kind: Service +metadata: + name: reviews + labels: + app: reviews +spec: + ports: + - port: 9080 + name: http + selector: + app: reviews +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: reviews-v1 +spec: + replicas: 1 + selector: + matchLabels: + app: reviews + version: v1 + template: + metadata: + labels: + app: reviews + version: v1 + spec: + containers: + - name: reviews + image: docker.io/istio/examples-bookinfo-reviews-v1:0.2.3 + imagePullPolicy: IfNotPresent + ports: + - containerPort: 9080 +--- +################################################################################################## +# Productpage services +################################################################################################## +apiVersion: v1 +kind: Service +metadata: + name: productpage + labels: + app: productpage +spec: + ports: + - port: 9080 + name: http + selector: + app: productpage +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: productpage-v1 +spec: + replicas: 1 + selector: + matchLabels: + app: productpage + version: v1 + template: + metadata: + labels: + app: productpage + version: v1 + spec: + containers: + - name: productpage + image: docker.io/istio/examples-bookinfo-productpage-v1:0.2.3 + imagePullPolicy: IfNotPresent + ports: + - containerPort: 9080 +--- diff --git a/istio-1.5.0/samples/multicluster/README.md b/istio-1.5.0/samples/multicluster/README.md new file mode 100644 index 0000000..bb01427 --- /dev/null +++ b/istio-1.5.0/samples/multicluster/README.md @@ -0,0 +1,77 @@ +# Instructions for building a multi-cluster multi-network mesh + +These instructions assume a kubeconfig file already exists with the clusters to +be added to the mesh. + +Pick the mesh specific parameters. + +```bash +# Organization name for root and intermediate certs. +export ORG_NAME=jason.example.com + +# Pick a unique ID for the mesh.b +export MESH_ID=MyMesh +``` + +Create a working directory for generated certs and configuration. + +```bash +export WORKDIR=mesh-workspace +[ ! -d "${WORKDIR}" ] && mkdir ${WORKDIR} +``` + +Prepare the initial configuration for the mesh. This creates a root key and cert +that will sign intermediate certs for each cluster. + +```bash +./setup-mesh.sh prep +``` + +Add clusters to mesh and apply the configuration to build the multicluster + +```bash +# add clusters to the mesh following the example in the topology file. +# Clusters are identified by the context name as defined by the kubeconfig +# file. +${EDITOR} ${WORKDIR}/topology.yaml + +# apply topology changes +./setup-mesh.sh apply +``` + +Install the sample bookinfo application in each cluster. + +```bash +./setup-bookinfo.sh install +``` + +Scale the bookinfo services in each cluster to simulate partial service +availability. The application should continue to function when accessed through +cluster's gateway. + +```bash +# only serve review-v1 and ratings-v1 +for DEPLOYMENT in details-v1 productpage-v1 reviews-v2 reviews-v3; do + kubectl --kubeconfig=${CLUSTER0_KUBECONFIG} --context=${CLUSTER0_CONTEXT} \ + scale deployment ${DEPLOYMENT} --replicas=0 +done + +# only serve review-v2 and productpage-v1 +for DEPLOYMENT in details-v1 reviews-v2 reviews-v3 ratings-v1; do + kubectl --kubeconfig=${CLUSTER1_KUBECONFIG} --context=${CLUSTER1_CONTEXT} \ + scale deployment ${DEPLOYMENT} --replicas=0 +done + +# only serve review-v3 and details-v1 +for DEPLOYMENT in productpage-v1 reviews-v2 reviews-v1 ratings-v1; do + kubectl --kubeconfig=${CLUSTER2_KUBECONFIG} --context=${CLUSTER2_CONTEXT} \ + scale deployment ${DEPLOYMENT} --replicas=0 +done +``` + +Teardown the mesh and remove the sample bookinfo application. + +```bash +./setup-mesh.sh teardown +./setup-bookinfo.sh uninstall +``` diff --git a/istio-1.5.0/samples/operator/default-install.yaml b/istio-1.5.0/samples/operator/default-install.yaml new file mode 100644 index 0000000..65a4d9b --- /dev/null +++ b/istio-1.5.0/samples/operator/default-install.yaml @@ -0,0 +1,8 @@ +apiVersion: install.istio.io/v1alpha1 +kind: IstioOperator +metadata: + namespace: istio-system + name: istio-operator +spec: + profile: default + diff --git a/istio-1.5.0/samples/operator/pilot-advanced-override.yaml b/istio-1.5.0/samples/operator/pilot-advanced-override.yaml new file mode 100644 index 0000000..d2f2c66 --- /dev/null +++ b/istio-1.5.0/samples/operator/pilot-advanced-override.yaml @@ -0,0 +1,23 @@ +apiVersion: install.istio.io/v1alpha1 +kind: IstioOperator +spec: + trafficManagement: + enabled: true + components: + proxy: + enabled: false + pilot: + k8s: + overlays: + - kind: Deployment + name: istio-pilot + patches: + - path: spec.template.spec.containers.[name:discovery].args.[30m] + value: "60m" # OVERRIDDEN + - path: spec.template.spec.containers.[name:discovery].ports.[containerPort:8080].containerPort + value: 8090 # OVERRIDDEN + - kind: Service + name: istio-pilot + patches: + - path: spec.ports.[name:grpc-xds].port + value: 15099 # OVERRIDDEN diff --git a/istio-1.5.0/samples/operator/pilot-k8s.yaml b/istio-1.5.0/samples/operator/pilot-k8s.yaml new file mode 100644 index 0000000..4a7051c --- /dev/null +++ b/istio-1.5.0/samples/operator/pilot-k8s.yaml @@ -0,0 +1,22 @@ +apiVersion: install.istio.io/v1alpha1 +kind: IstioOperator +spec: + trafficManagement: + components: + pilot: + k8s: + resources: + requests: + cpu: 1000m # override from default 500m + memory: 4096Mi # ... default 2048Mi + hpaSpec: + maxReplicas: 10 # ... default 5 + minReplicas: 2 # ... default 1 + nodeSelector: + master: "true" + tolerations: + - key: dedicated + operator: Exists + effect: NoSchedule + - key: CriticalAddonsOnly + operator: Exists diff --git a/istio-1.5.0/samples/operator/sds-policy-off.yaml b/istio-1.5.0/samples/operator/sds-policy-off.yaml new file mode 100644 index 0000000..c055b8c --- /dev/null +++ b/istio-1.5.0/samples/operator/sds-policy-off.yaml @@ -0,0 +1,6 @@ +apiVersion: install.istio.io/v1alpha1 +kind: IstioOperator +spec: + profile: sds + policy: + enabled: false diff --git a/istio-1.5.0/samples/operator/sds.yaml b/istio-1.5.0/samples/operator/sds.yaml new file mode 100644 index 0000000..7e00e59 --- /dev/null +++ b/istio-1.5.0/samples/operator/sds.yaml @@ -0,0 +1,4 @@ +apiVersion: install.istio.io/v1alpha1 +kind: IstioOperator +spec: + profile: sds diff --git a/istio-1.5.0/samples/operator/trafficManagement-namespace.yaml b/istio-1.5.0/samples/operator/trafficManagement-namespace.yaml new file mode 100644 index 0000000..7df197a --- /dev/null +++ b/istio-1.5.0/samples/operator/trafficManagement-namespace.yaml @@ -0,0 +1,6 @@ +apiVersion: install.istio.io/v1alpha1 +kind: IstioOperator +spec: + trafficManagement: + components: + namespace: istio-control-custom diff --git a/istio-1.5.0/samples/operator/values-global.yaml b/istio-1.5.0/samples/operator/values-global.yaml new file mode 100644 index 0000000..8726f27 --- /dev/null +++ b/istio-1.5.0/samples/operator/values-global.yaml @@ -0,0 +1,7 @@ +apiVersion: install.istio.io/v1alpha1 +kind: IstioOperator +spec: + values: + global: + logging: + level: "default:warning" # override from info diff --git a/istio-1.5.0/samples/operator/values-pilot.yaml b/istio-1.5.0/samples/operator/values-pilot.yaml new file mode 100644 index 0000000..bca6c2e --- /dev/null +++ b/istio-1.5.0/samples/operator/values-pilot.yaml @@ -0,0 +1,6 @@ +apiVersion: install.istio.io/v1alpha1 +kind: IstioOperator +spec: + values: + pilot: + traceSampling: 0.1 # override from 1.0 diff --git a/istio-1.5.0/samples/rawvm/README.md b/istio-1.5.0/samples/rawvm/README.md new file mode 100644 index 0000000..208af23 --- /dev/null +++ b/istio-1.5.0/samples/rawvm/README.md @@ -0,0 +1,167 @@ +# RawVM in Istio 0.2 demo notes + +## MySQL Installation + +### Official oracle version + +```shell +wget https://dev.mysql.com/get/mysql-apt-config_0.8.7-1_all.deb +sudo dpkg -i mysql-apt-config_0.8.7-1_all.deb +# Select server 5.7 (default), tools and previews not needed/disabled +sudo apt-get update +sudo apt-get install mysql-server +# Clearly this is insecure, don't do that for prod ! +sudo mysql + ALTER USER 'root'@'localhost' IDENTIFIED WITH mysql_native_password BY 'password'; + # Remote 'root' can read test.*, to avoid + # ERROR 1130 (HY000): Host '...' is not allowed to connect to this MySQL server + create user 'root'@'%' IDENTIFIED WITH mysql_native_password BY 'password'; + GRANT SELECT ON test.* TO 'root'@'%'; +# Create tables : +mysql -u root -h 127.0.0.1 --password=password < ~/github/istio/samples/bookinfo/src/mysql/mysqldb-init.sql +# And to be able to connect remotely (only needed to test before injection) +sudo vi /etc/mysql/mysql.conf.d/mysqld.cnf +# comment out: +#bind-address = 127.0.0.1 +sudo service mysql restart +# check it's now binding on * +$ sudo lsof -i :3306 +COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME +mysqld 29145 mysql 31u IPv6 168376 0t0 TCP *:mysql (LISTEN) +# from another host, verify it works: +ldemailly@benchmark-2:~$ mysql -u root -h instance-1 --password=password test -e "select * from ratings" +mysql: [Warning] Using a password on the command line interface can be insecure. ++----------+--------+ +| ReviewID | Rating | ++----------+--------+ +| 1 | 5 | +| 2 | 6 | ++----------+--------+ +# for low volume troubleshooting: +mysql -u root -h instance-1 --password=password + SET global general_log_file='/tmp/mysqlquery.log'; + SET global general_log = 1; +# then +tail -f /tmp/mysqlquery.log +``` + +### Or + +sudo apt-get mariadb-server + +TODO: figure out equivalent of above for mariadb + + + +## Sidecar + +See + +## Bookinfo with MySql in k8s + +You need 5 nodes in your cluster to add mysql (until we tune the requests) + +```bash +# source istio.VERSION +wget https://storage.googleapis.com/istio-artifacts/pilot/$PILOT_TAG/artifacts/istioctl/istioctl-osx +chmod 755 istioctl-osx +./istioctl-osx kube-inject --hub $PILOT_HUB --tag $PILOT_TAG -f samples/bookinfo/kube/bookinfo.yaml > bookinfo-istio.yaml +kubectl apply -f bookinfo-istio.yaml +./istioctl-osx kube-inject --hub $PILOT_HUB --tag $PILOT_TAG -f samples/bookinfo/kube/bookinfo-mysql.yaml > bookinfo-mysql-istio.yaml +kubectl apply -f bookinfo-mysql-istio.yaml +./istioctl-osx kube-inject --hub $PILOT_HUB --tag $PILOT_TAG -f samples/bookinfo/kube/bookinfo-ratings-v2.yaml > bookinfo-ratings-v2-istio.yaml +kubectl apply -f bookinfo-ratings-v2-istio.yaml +# use it (ratings v2 and mysql) +kubectl apply -f samples/bookinfo/networking/virtual-service-ratings-mysql.yaml +# wait a bit / reload product page +# see mysql in grafana and 5,6 stars +kubectl port-forward mysqldb-v1-325529163-9x1r0 3306:3306 # use actual mysql pod +mysql -u root -h 127.0.0.1 --password=password test + select * from ratings; + update ratings set rating=3 where reviewid=1; +# see first rating change to 3 stars + +# for metrics: +fortio load -t 1m http://$INGRESS_IP/productpage +``` + +## Move MySQL to VM + +1. remove the k8s based service + + ```bash + kubectl delete svc mysqldb + ``` + +1. observe `product ratings not available` when re-loading the page + +1. register the VM instead: + + ```bash + ./istioctl-osx register mysqldb 10.138.0.13 3306 + I0904 11:12:56.785430 34562 register.go:44] Registering for service 'mysqldb' ip '10.138.0.13', ports list [{3306 mysql}] + I0904 11:12:56.785536 34562 register.go:49] 0 labels ([]) and 1 annotations ([alpha.istio.io/kubernetes-serviceaccounts=default]) + W0904 11:12:56.887017 34562 register.go:123] Got 'services "mysqldb" not found' looking up svc 'mysqldb' in namespace 'default', attempting to create it + W0904 11:12:56.938721 34562 register.go:139] Got 'endpoints "mysqldb" not found' looking up endpoints for 'mysqldb' in namespace 'default', attempting to create them + I0904 11:12:57.055643 34562 register.go:180] No pre existing exact matching ports list found, created new subset {[{10.138.0.13 nil}] [] [{mysql 3306 }]} + I0904 11:12:57.090739 34562 register.go:191] Successfully updated mysqldb, now with 1 endpoints + ``` + +1. check the registration: + + ``` + kubectl get svc mysqldb -o yaml + apiVersion: v1 + kind: Service + metadata: + annotations: + alpha.istio.io/kubernetes-serviceaccounts: default + creationTimestamp: 2017-09-04T18:12:56Z + name: mysqldb + namespace: default + resourceVersion: "464459" + selfLink: /api/v1/namespaces/default/services/mysqldb + uid: ad746e4c-919c-11e7-9a62-42010a8a004e + spec: + clusterIP: 10.31.253.143 + ports: + - name: mysql + port: 3306 + protocol: TCP + targetPort: 3306 + sessionAffinity: None + type: ClusterIP + status: + loadBalancer: {} + ``` + +## Build debian packages + +Prereq: + +ps: for docker - remember to "docker ps" and it should work/not error out and not require sudo, if it doesn't work add your username to /etc/group docker + +For gcloud (): + +```shell +export CLOUD_SDK_REPO="cloud-sdk-$(lsb_release -c -s)" +echo "deb http://packages.cloud.google.com/apt $CLOUD_SDK_REPO main" | sudo tee -a /etc/apt/sources.list.d/google-cloud-sdk.list +curl https://packages.cloud.google.com/apt/doc/apt-key.gpg | sudo apt-key add - +sudo apt-get update && sudo apt-get install google-cloud-sdk +gcloud init +sudo apt-get install kubectl +gcloud container clusters get-credentials demo-1 --zone us-west1-b --project istio-demo-0-2 +``` + +Note to install rbac yaml you need: + +```bash +kubectl create clusterrolebinding my-admin-access --clusterrole cluster-admin --user USERNAME +``` + +Then: + +```bash +git clone https://github.com/istio/proxy.git -b rawvm-demo-0-2-2 +tools/deb/test/build_all.sh +``` diff --git a/istio-1.5.0/samples/security/psp/all-pods-psp.yaml b/istio-1.5.0/samples/security/psp/all-pods-psp.yaml new file mode 100644 index 0000000..a52d56a --- /dev/null +++ b/istio-1.5.0/samples/security/psp/all-pods-psp.yaml @@ -0,0 +1,51 @@ +# For details about using this yaml file, please refer to: +# https://istio.io/docs/tasks/security/auth-sds/#increasing-security-with-pod-security-policies +apiVersion: extensions/v1beta1 +kind: PodSecurityPolicy +metadata: + name: istio-sds-uds +spec: + # Protect the unix domain socket from unauthorized modification + allowedHostPaths: + - pathPrefix: "/var/run/sds" + readOnly: true + # Allow the istio sidecar injector to work + allowedCapabilities: + - NET_ADMIN + seLinux: + rule: RunAsAny + supplementalGroups: + rule: RunAsAny + runAsUser: + rule: RunAsAny + fsGroup: + rule: RunAsAny + volumes: + - '*' +--- +kind: ClusterRole +apiVersion: rbac.authorization.k8s.io/v1 +metadata: + name: istio-sds-uds-psp +rules: + - apiGroups: + - extensions + resources: + - podsecuritypolicies + resourceNames: + - istio-sds-uds + verbs: + - use +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: istio-sds-uds-psp +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: istio-sds-uds-psp +subjects: + - apiGroup: rbac.authorization.k8s.io + kind: Group + name: system:serviceaccounts diff --git a/istio-1.5.0/samples/security/psp/citadel-agent-psp.yaml b/istio-1.5.0/samples/security/psp/citadel-agent-psp.yaml new file mode 100644 index 0000000..c141ee5 --- /dev/null +++ b/istio-1.5.0/samples/security/psp/citadel-agent-psp.yaml @@ -0,0 +1,48 @@ +# For details about using this yaml file, please refer to: +# https://istio.io/docs/tasks/security/auth-sds/#increasing-security-with-pod-security-policies +apiVersion: extensions/v1beta1 +kind: PodSecurityPolicy +metadata: + name: istio-nodeagent +spec: + allowedHostPaths: + - pathPrefix: "/var/run/sds" + seLinux: + rule: RunAsAny + supplementalGroups: + rule: RunAsAny + runAsUser: + rule: RunAsAny + fsGroup: + rule: RunAsAny + volumes: + - '*' +--- +kind: Role +apiVersion: rbac.authorization.k8s.io/v1 +metadata: + name: istio-nodeagent-istio-system-psp + namespace: istio-system +rules: + - apiGroups: + - extensions + resources: + - podsecuritypolicies + resourceNames: + - istio-nodeagent + verbs: + - use +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: RoleBinding +metadata: + name: istio-nodeagent-istio-system-psp + namespace: istio-system +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: Role + name: istio-nodeagent-istio-system-psp +subjects: + - kind: ServiceAccount + name: istio-nodeagent-service-account + namespace: istio-system diff --git a/istio-1.5.0/samples/sleep/README.md b/istio-1.5.0/samples/sleep/README.md new file mode 100644 index 0000000..3fe8215 --- /dev/null +++ b/istio-1.5.0/samples/sleep/README.md @@ -0,0 +1,37 @@ +# Simple sleep service + +This sample consists of a simple service that does nothing but sleep. +It's a ubuntu container with curl installed that can be used as a request source for invoking other services +to experiment with Istio networking. + +To use it: + +1. Install Istio by following the [istio install instructions](https://istio.io/docs/setup/). + +1. Start the sleep service: + + If you have [automatic sidecar injection](https://istio.io/docs/setup/additional-setup/sidecar-injection/#automatic-sidecar-injection) enabled: + + ```bash + kubectl apply -f sleep.yaml + ``` + + Otherwise manually inject the sidecars before applying: + + ```bash + kubectl apply -f <(istioctl kube-inject -f sleep.yaml) + ``` + +1. Start some other services, for example, the [Bookinfo sample](https://istio.io/docs/examples/bookinfo/). + + Now you can `kubectl exec` into the sleep service to experiment with Istio networking. + For example, the following commands can be used to call the Bookinfo `ratings` service: + + ```bash + export SLEEP_POD=$(kubectl get pod -l app=sleep -o jsonpath={.items..metadata.name}) + kubectl exec -it $SLEEP_POD -c sleep curl http://ratings.default.svc.cluster.local:9080/ratings/1 + {"id":1,"ratings":{"Reviewer1":5,"Reviewer2":4}} + ``` + +You can also use the sleep service to test accessing services outside of the mesh. +See [configuring egress](https://istio.io/docs/tasks/traffic-management/egress/) for details. diff --git a/istio-1.5.0/samples/sleep/policy/sni-serviceaccount.yaml b/istio-1.5.0/samples/sleep/policy/sni-serviceaccount.yaml new file mode 100644 index 0000000..7e77f49 --- /dev/null +++ b/istio-1.5.0/samples/sleep/policy/sni-serviceaccount.yaml @@ -0,0 +1,55 @@ +apiVersion: config.istio.io/v1alpha2 +kind: instance +metadata: + name: requested-server-name + namespace: istio-system +spec: + compiledTemplate: listentry + params: + value: connection.requested_server_name +--- +apiVersion: config.istio.io/v1alpha2 +kind: handler +metadata: + name: us-wikipedia-checker + namespace: istio-system +spec: + compiledAdapter: listchecker + params: + overrides: ["en.wikipedia.org", "es.wikipedia.org"] + blacklist: false +--- +# Rule to check access to *.wikipedia.org +apiVersion: config.istio.io/v1alpha2 +kind: rule +metadata: + name: check-us-wikipedia-access + namespace: istio-system +spec: + match: source.labels["app"] == "istio-egressgateway-with-sni-proxy" && destination.labels["app"] == "" && source.principal == "cluster.local/ns/default/sa/sleep-us" + actions: + - handler: us-wikipedia-checker + instances: [ requested-server-name ] +--- +apiVersion: config.istio.io/v1alpha2 +kind: handler +metadata: + name: canada-wikipedia-checker + namespace: istio-system +spec: + compiledAdapter: listchecker + params: + overrides: ["en.wikipedia.org", "fr.wikipedia.org"] + blacklist: false +--- +# Rule to check access to *.wikipedia.org +apiVersion: "config.istio.io/v1alpha2" +kind: rule +metadata: + name: check-canada-wikipedia-access + namespace: istio-system +spec: + match: source.labels["app"] == "istio-egressgateway-with-sni-proxy" && destination.labels["app"] == "" && source.principal == "cluster.local/ns/default/sa/sleep-canada" + actions: + - handler: canada-wikipedia-checker + instances: [ requested-server-name ] diff --git a/istio-1.5.0/samples/sleep/policy/sni-wikipedia.yaml b/istio-1.5.0/samples/sleep/policy/sni-wikipedia.yaml new file mode 100644 index 0000000..43fe491 --- /dev/null +++ b/istio-1.5.0/samples/sleep/policy/sni-wikipedia.yaml @@ -0,0 +1,32 @@ +apiVersion: config.istio.io/v1alpha2 +kind: handler +metadata: + name: wikipedia-checker + namespace: istio-system +spec: + compiledAdapter: listchecker + params: + overrides: ["en.wikipedia.org"] # overrides provide a static list + blacklist: true +--- +apiVersion: config.istio.io/v1alpha2 +kind: instance +metadata: + name: requested-server-name + namespace: istio-system +spec: + compiledTemplate: listentry + params: + value: connection.requested_server_name +--- +# Rule to check access to *.wikipedia.org +apiVersion: config.istio.io/v1alpha2 +kind: rule +metadata: + name: check-wikipedia-access + namespace: istio-system +spec: + match: source.labels["app"] == "istio-egressgateway-with-sni-proxy" && destination.labels["app"] == "" + actions: + - handler: wikipedia-checker + instances: [ requested-server-name ] diff --git a/istio-1.5.0/samples/sleep/sleep-vault.yaml b/istio-1.5.0/samples/sleep/sleep-vault.yaml new file mode 100644 index 0000000..b82fb14 --- /dev/null +++ b/istio-1.5.0/samples/sleep/sleep-vault.yaml @@ -0,0 +1,56 @@ +# Copyright 2019 Istio Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +################################################################################################## +# Sleep service +################################################################################################## +apiVersion: v1 +kind: ServiceAccount +metadata: + name: sleep +--- +apiVersion: v1 +kind: Service +metadata: + name: sleep + labels: + app: sleep +spec: + ports: + - port: 80 + name: http + selector: + app: sleep +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: sleep +spec: + replicas: 1 + selector: + matchLabels: + app: sleep + template: + metadata: + labels: + app: sleep + spec: + serviceAccountName: vault-citadel-sa + containers: + - name: sleep + image: pstauffer/curl + command: ["/bin/sleep", "3650d"] + imagePullPolicy: IfNotPresent +--- diff --git a/istio-1.5.0/samples/sleep/sleep.yaml b/istio-1.5.0/samples/sleep/sleep.yaml new file mode 100644 index 0000000..f072861 --- /dev/null +++ b/istio-1.5.0/samples/sleep/sleep.yaml @@ -0,0 +1,64 @@ +# Copyright 2017 Istio Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +################################################################################################## +# Sleep service +################################################################################################## +apiVersion: v1 +kind: ServiceAccount +metadata: + name: sleep +--- +apiVersion: v1 +kind: Service +metadata: + name: sleep + labels: + app: sleep +spec: + ports: + - port: 80 + name: http + selector: + app: sleep +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: sleep +spec: + replicas: 1 + selector: + matchLabels: + app: sleep + template: + metadata: + labels: + app: sleep + spec: + serviceAccountName: sleep + containers: + - name: sleep + image: governmentpaas/curl-ssl + command: ["/bin/sleep", "3650d"] + imagePullPolicy: IfNotPresent + volumeMounts: + - mountPath: /etc/sleep/tls + name: secret-volume + volumes: + - name: secret-volume + secret: + secretName: sleep-secret + optional: true +--- diff --git a/istio-1.5.0/samples/sleep/telemetry/sni-logging.yaml b/istio-1.5.0/samples/sleep/telemetry/sni-logging.yaml new file mode 100644 index 0000000..cf1c89a --- /dev/null +++ b/istio-1.5.0/samples/sleep/telemetry/sni-logging.yaml @@ -0,0 +1,45 @@ +# Log entry for egress access +apiVersion: config.istio.io/v1alpha2 +kind: instance +metadata: + name: egress-access + namespace: istio-system +spec: + compiledTemplate: logentry + params: + severity: '"info"' + timestamp: context.time | timestamp("2017-01-01T00:00:00Z") + variables: + connectionEvent: connection.event | "" + source: source.labels["app"] | "unknown" + sourceNamespace: source.namespace | "unknown" + sourceWorkload: source.workload.name | "" + sourcePrincipal: source.principal | "unknown" + requestedServerName: connection.requested_server_name | "unknown" + destinationApp: destination.labels["app"] | "" + monitored_resource_type: '"UNSPECIFIED"' +--- +# Handler for info egress access entries +apiVersion: config.istio.io/v1alpha2 +kind: handler +metadata: + name: egress-access-logger + namespace: istio-system +spec: + compiledAdapter: stdio + params: + severity_levels: + info: 0 # output log level as info + outputAsJson: true +--- +# Rule to handle access to *.wikipedia.org +apiVersion: config.istio.io/v1alpha2 +kind: rule +metadata: + name: handle-wikipedia-access + namespace: istio-system +spec: + match: source.labels["app"] == "istio-egressgateway-with-sni-proxy" && destination.labels["app"] == "" && connection.event == "open" + actions: + - handler: egress-access-logger + instances: [ egress-access ] diff --git a/istio-1.5.0/samples/tcp-echo/README.md b/istio-1.5.0/samples/tcp-echo/README.md new file mode 100644 index 0000000..5705658 --- /dev/null +++ b/istio-1.5.0/samples/tcp-echo/README.md @@ -0,0 +1,38 @@ +# TCP Echo Service + +This sample runs [TCP Echo Server](src/) as an Istio service. TCP Echo Server +allows you to connect to it over TCP and echoes back data sent to it along with +a preconfigured prefix. + +## Usage + +To run the TCP Echo Service sample: + +1. Install Istio by following the [istio install instructions](https://istio.io/docs/setup/kubernetes/quick-start.html). + +1. Start the `tcp-echo-server` service inside the Istio service mesh: + + ```console + $ kubectl apply -f <(istioctl kube-inject -f tcp-echo.yaml) + service/tcp-echo created + deployment.extensions/tcp-echo created + ``` + +1. Test by running the `nc` command from a `busybox` container from within the cluster. + + ```console + $ kubectl run -i --rm --restart=Never dummy --image=busybox -- sh -c "echo world | nc tcp-echo 9000" + hello world + pod "dummy" deleted + ``` + + As you observe, sending _world_ on a TCP connection to the server results in + the server prepending _hello_ and echoing back with _hello world_. + +1. To clean up, execute the following command: + + ```console + $ kubectl delete -f tcp-echo.yaml + service "tcp-echo" deleted + deployment.extensions "tcp-echo" deleted + ``` diff --git a/istio-1.5.0/samples/tcp-echo/tcp-echo-20-v2.yaml b/istio-1.5.0/samples/tcp-echo/tcp-echo-20-v2.yaml new file mode 100644 index 0000000..f69ab11 --- /dev/null +++ b/istio-1.5.0/samples/tcp-echo/tcp-echo-20-v2.yaml @@ -0,0 +1,39 @@ +# Copyright 2018 Istio Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +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 diff --git a/istio-1.5.0/samples/tcp-echo/tcp-echo-all-v1.yaml b/istio-1.5.0/samples/tcp-echo/tcp-echo-all-v1.yaml new file mode 100644 index 0000000..3c302c5 --- /dev/null +++ b/istio-1.5.0/samples/tcp-echo/tcp-echo-all-v1.yaml @@ -0,0 +1,61 @@ +# Copyright 2018 Istio Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +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 diff --git a/istio-1.5.0/samples/tcp-echo/tcp-echo-services.yaml b/istio-1.5.0/samples/tcp-echo/tcp-echo-services.yaml new file mode 100644 index 0000000..6316809 --- /dev/null +++ b/istio-1.5.0/samples/tcp-echo/tcp-echo-services.yaml @@ -0,0 +1,79 @@ +# Copyright 2018 Istio Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +apiVersion: v1 +kind: Service +metadata: + name: tcp-echo + labels: + app: tcp-echo +spec: + ports: + - name: tcp + port: 9000 + - name: tcp-other + port: 9001 + # Port 9002 is omitted intentionally for testing the pass through filter chain. + selector: + app: tcp-echo +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: tcp-echo-v1 +spec: + replicas: 1 + selector: + matchLabels: + app: tcp-echo + version: v1 + template: + metadata: + labels: + app: tcp-echo + version: v1 + spec: + containers: + - name: tcp-echo + image: docker.io/istio/tcp-echo-server:1.2 + imagePullPolicy: IfNotPresent + args: [ "9000,9001,9002", "one" ] + ports: + - containerPort: 9000 + - containerPort: 9001 +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: tcp-echo-v2 +spec: + replicas: 1 + selector: + matchLabels: + app: tcp-echo + version: v2 + template: + metadata: + labels: + app: tcp-echo + version: v2 + spec: + containers: + - name: tcp-echo + image: docker.io/istio/tcp-echo-server:1.2 + imagePullPolicy: IfNotPresent + args: [ "9000,9001,9002", "two" ] + ports: + - containerPort: 9000 + - containerPort: 9001 diff --git a/istio-1.5.0/samples/tcp-echo/tcp-echo.yaml b/istio-1.5.0/samples/tcp-echo/tcp-echo.yaml new file mode 100644 index 0000000..fc0e8ca --- /dev/null +++ b/istio-1.5.0/samples/tcp-echo/tcp-echo.yaml @@ -0,0 +1,57 @@ +# Copyright 2018 Istio Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +################################################################################ +# tcp-echo service +################################################################################ +apiVersion: v1 +kind: Service +metadata: + name: tcp-echo + labels: + app: tcp-echo +spec: + ports: + - name: tcp + port: 9000 + - name: tcp-other + port: 9001 + # Port 9002 is omitted intentionally for testing the pass through filter chain. + selector: + app: tcp-echo +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: tcp-echo +spec: + replicas: 1 + selector: + matchLabels: + app: tcp-echo + version: v1 + template: + metadata: + labels: + app: tcp-echo + version: v1 + spec: + containers: + - name: tcp-echo + image: docker.io/istio/tcp-echo-server:1.2 + imagePullPolicy: IfNotPresent + args: [ "9000,9001,9002", "hello" ] + ports: + - containerPort: 9000 + - containerPort: 9001 diff --git a/istio-1.5.0/samples/websockets/README.md b/istio-1.5.0/samples/websockets/README.md new file mode 100644 index 0000000..26a1f38 --- /dev/null +++ b/istio-1.5.0/samples/websockets/README.md @@ -0,0 +1,48 @@ +# Tornado - Demo Websockets App + +This is a sample application that demonstrates the use of an upgraded websockets connection on an ingress traffic when using Istio `VirtualService`. +The `app.yaml` creates a Kubernetes `Service` and a `Deployment` that is based on an existing Docker image for [Hiroakis's Tornado Websocket Example](https://github.com/hiroakis/tornado-websocket-example). + +__Notice:__ The addition of websockets upgrade support in v1alpha3 routing rules has only been added after the release of `Istio v0.8.0`. + +## Prerequisites + +Install Istio by following the [Istio Quick Start](https://istio.io/docs/setup/kubernetes/quick-start.html). + +## Installation + +1. First install the application service: + + - With manual sidecar injection: + + ```command + kubectl create -f <(istioctl kube-inject -f samples/websockets/app.yaml) + ``` + + - With automatic sidecar injection + + ```command + kubectl create -f samples/websockets/app.yaml + ``` + +1. Create the Ingress `Gateway` and `VirtualService` that enables the upgrade to Websocket for incoming traffic: + + ```command + kubectl create -f samples/websockets/route.yaml + ``` + +## Test + +- [Find your ingress gateway IP](https://istio.io/docs/tasks/traffic-management/ingress/#determining-the-ingress-ip-and-ports) + +- Access with your browser + +- The `WebSocket status` should show a green `open` status which means that a websocket connection to the server has been established. +To see the websocket in action see the instructions in the _REST API examples_ section of the demo app webpage for updating the server-side data and getting the updated data through the open websocket to the table in the webpage (without refreshing). + +## Cleanup + +```command +kubectl delete -f samples/websockets/route.yaml +kubectl delete -f samples/websockets/app.yaml +``` diff --git a/istio-1.5.0/samples/websockets/app.yaml b/istio-1.5.0/samples/websockets/app.yaml new file mode 100644 index 0000000..f307f64 --- /dev/null +++ b/istio-1.5.0/samples/websockets/app.yaml @@ -0,0 +1,36 @@ +apiVersion: v1 +kind: Service +metadata: + name: tornado + labels: + app: tornado +spec: + ports: + - port: 8888 + name: http + selector: + app: tornado +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: tornado +spec: + replicas: 1 + selector: + matchLabels: + app: tornado + version: v1 + template: + metadata: + labels: + app: tornado + version: v1 + spec: + containers: + - name: tornado + image: hiroakis/tornado-websocket-example + imagePullPolicy: IfNotPresent + ports: + - containerPort: 8888 +--- diff --git a/istio-1.5.0/samples/websockets/route.yaml b/istio-1.5.0/samples/websockets/route.yaml new file mode 100644 index 0000000..ef580b2 --- /dev/null +++ b/istio-1.5.0/samples/websockets/route.yaml @@ -0,0 +1,32 @@ +apiVersion: networking.istio.io/v1alpha3 +kind: Gateway +metadata: + name: tornado-gateway +spec: + selector: + istio: ingressgateway + servers: + - port: + number: 80 + name: http + protocol: HTTP + hosts: + - "*" +--- +apiVersion: networking.istio.io/v1alpha3 +kind: VirtualService +metadata: + name: tornado +spec: + hosts: + - "*" + gateways: + - tornado-gateway + http: + - match: + - uri: + prefix: / + route: + - destination: + host: tornado + weight: 100 diff --git a/istio-1.5.0/tools/_istioctl b/istio-1.5.0/tools/_istioctl new file mode 100644 index 0000000..2ba9cbf --- /dev/null +++ b/istio-1.5.0/tools/_istioctl @@ -0,0 +1,3520 @@ +#compdef istioctl + +__istio_bash_source() { + alias shopt=':' + alias _expand=_bash_expand + alias _complete=_bash_comp + emulate -L sh + setopt kshglob noshglob braceexpand + source "$@" +} +__istio_type() { + # -t is not supported by zsh + if [ "$1" == "-t" ]; then + shift + # fake Bash 4 to disable "complete -o nospace". Instead + # "compopt +-o nospace" is used in the code to toggle trailing + # spaces. We don't support that, but leave trailing spaces on + # all the time + if [ "$1" = "__istio_compopt" ]; then + echo builtin + return 0 + fi + fi + type "$@" +} +__istio_compgen() { + local completions w + completions=( $(compgen "$@") ) || return $? + # filter by given word as prefix + while [[ "$1" = -* && "$1" != -- ]]; do + shift + shift + done + if [[ "$1" == -- ]]; then + shift + fi + for w in "${completions[@]}"; do + if [[ "${w}" = "$1"* ]]; then + echo "${w}" + fi + done +} +__istio_compopt() { + true # don't do anything. Not supported by bashcompinit in zsh +} +__istio_ltrim_colon_completions() +{ + if [[ "$1" == *:* && "$COMP_WORDBREAKS" == *:* ]]; then + # Remove colon-word prefix from COMPREPLY items + local colon_word=${1%${1##*:}} + local i=${#COMPREPLY[*]} + while [[ $((--i)) -ge 0 ]]; do + COMPREPLY[$i]=${COMPREPLY[$i]#"$colon_word"} + done + fi +} +__istio_get_comp_words_by_ref() { + cur="${COMP_WORDS[COMP_CWORD]}" + prev="${COMP_WORDS[${COMP_CWORD}-1]}" + words=("${COMP_WORDS[@]}") + cword=("${COMP_CWORD[@]}") +} +__istio_filedir() { + local RET OLD_IFS w qw + __istio_debug "_filedir $@ cur=$cur" + if [[ "$1" = \~* ]]; then + # somehow does not work. Maybe, zsh does not call this at all + eval echo "$1" + return 0 + fi + OLD_IFS="$IFS" + IFS=$'\n' + if [ "$1" = "-d" ]; then + shift + RET=( $(compgen -d) ) + else + RET=( $(compgen -f) ) + fi + IFS="$OLD_IFS" + IFS="," __istio_debug "RET=${RET[@]} len=${#RET[@]}" + for w in ${RET[@]}; do + if [[ ! "${w}" = "${cur}"* ]]; then + continue + fi + if eval "[[ \"\${w}\" = *.$1 || -d \"\${w}\" ]]"; then + qw="$(__istio_quote "${w}")" + if [ -d "${w}" ]; then + COMPREPLY+=("${qw}/") + else + COMPREPLY+=("${qw}") + fi + fi + done +} +__istio_quote() { + if [[ $1 == \'* || $1 == \"* ]]; then + # Leave out first character + printf %q "${1:1}" + else + printf %q "$1" + fi +} +autoload -U +X bashcompinit && bashcompinit +# use word boundary patterns for BSD or GNU sed +LWORD='[[:<:]]' +RWORD='[[:>:]]' +if sed --help 2>&1 | grep -q GNU; then + LWORD='\<' + RWORD='\>' +fi +__istio_convert_bash_to_zsh() { + sed \ + -e 's/declare -F/whence -w/' \ + -e 's/_get_comp_words_by_ref "\$@"/_get_comp_words_by_ref "\$*"/' \ + -e 's/local \([a-zA-Z0-9_]*\)=/local \1; \1=/' \ + -e 's/flags+=("\(--.*\)=")/flags+=("\1"); two_word_flags+=("\1")/' \ + -e 's/must_have_one_flag+=("\(--.*\)=")/must_have_one_flag+=("\1")/' \ + -e "s/${LWORD}_filedir${RWORD}/__istio_filedir/g" \ + -e "s/${LWORD}_get_comp_words_by_ref${RWORD}/__istio_get_comp_words_by_ref/g" \ + -e "s/${LWORD}__ltrim_colon_completions${RWORD}/__istio_ltrim_colon_completions/g" \ + -e "s/${LWORD}compgen${RWORD}/__istio_compgen/g" \ + -e "s/${LWORD}compopt${RWORD}/__istio_compopt/g" \ + -e "s/${LWORD}declare${RWORD}/builtin declare/g" \ + -e "s/\\\$(type${RWORD}/\$(__istio_type/g" \ + <<'BASH_COMPLETION_EOF' +# bash completion for istioctl -*- shell-script -*- + +__istioctl_debug() +{ + if [[ -n ${BASH_COMP_DEBUG_FILE} ]]; then + echo "$*" >> "${BASH_COMP_DEBUG_FILE}" + fi +} + +# Homebrew on Macs have version 1.3 of bash-completion which doesn't include +# _init_completion. This is a very minimal version of that function. +__istioctl_init_completion() +{ + COMPREPLY=() + _get_comp_words_by_ref "$@" cur prev words cword +} + +__istioctl_index_of_word() +{ + local w word=$1 + shift + index=0 + for w in "$@"; do + [[ $w = "$word" ]] && return + index=$((index+1)) + done + index=-1 +} + +__istioctl_contains_word() +{ + local w word=$1; shift + for w in "$@"; do + [[ $w = "$word" ]] && return + done + return 1 +} + +__istioctl_handle_reply() +{ + __istioctl_debug "${FUNCNAME[0]}" + case $cur in + -*) + if [[ $(type -t compopt) = "builtin" ]]; then + compopt -o nospace + fi + local allflags + if [ ${#must_have_one_flag[@]} -ne 0 ]; then + allflags=("${must_have_one_flag[@]}") + else + allflags=("${flags[*]} ${two_word_flags[*]}") + fi + COMPREPLY=( $(compgen -W "${allflags[*]}" -- "$cur") ) + if [[ $(type -t compopt) = "builtin" ]]; then + [[ "${COMPREPLY[0]}" == *= ]] || compopt +o nospace + fi + + # complete after --flag=abc + if [[ $cur == *=* ]]; then + if [[ $(type -t compopt) = "builtin" ]]; then + compopt +o nospace + fi + + local index flag + flag="${cur%=*}" + __istioctl_index_of_word "${flag}" "${flags_with_completion[@]}" + COMPREPLY=() + if [[ ${index} -ge 0 ]]; then + PREFIX="" + cur="${cur#*=}" + ${flags_completion[${index}]} + if [ -n "${ZSH_VERSION}" ]; then + # zsh completion needs --flag= prefix + eval "COMPREPLY=( \"\${COMPREPLY[@]/#/${flag}=}\" )" + fi + fi + fi + return 0; + ;; + esac + + # check if we are handling a flag with special work handling + local index + __istioctl_index_of_word "${prev}" "${flags_with_completion[@]}" + if [[ ${index} -ge 0 ]]; then + ${flags_completion[${index}]} + return + fi + + # we are parsing a flag and don't have a special handler, no completion + if [[ ${cur} != "${words[cword]}" ]]; then + return + fi + + local completions + completions=("${commands[@]}") + if [[ ${#must_have_one_noun[@]} -ne 0 ]]; then + completions=("${must_have_one_noun[@]}") + fi + if [[ ${#must_have_one_flag[@]} -ne 0 ]]; then + completions+=("${must_have_one_flag[@]}") + fi + COMPREPLY=( $(compgen -W "${completions[*]}" -- "$cur") ) + + if [[ ${#COMPREPLY[@]} -eq 0 && ${#noun_aliases[@]} -gt 0 && ${#must_have_one_noun[@]} -ne 0 ]]; then + COMPREPLY=( $(compgen -W "${noun_aliases[*]}" -- "$cur") ) + fi + + if [[ ${#COMPREPLY[@]} -eq 0 ]]; then + if declare -F __istioctl_custom_func >/dev/null; then + # try command name qualified custom func + __istioctl_custom_func + else + # otherwise fall back to unqualified for compatibility + declare -F __custom_func >/dev/null && __custom_func + fi + fi + + # available in bash-completion >= 2, not always present on macOS + if declare -F __ltrim_colon_completions >/dev/null; then + __ltrim_colon_completions "$cur" + fi + + # If there is only 1 completion and it is a flag with an = it will be completed + # but we don't want a space after the = + if [[ "${#COMPREPLY[@]}" -eq "1" ]] && [[ $(type -t compopt) = "builtin" ]] && [[ "${COMPREPLY[0]}" == --*= ]]; then + compopt -o nospace + fi +} + +# The arguments should be in the form "ext1|ext2|extn" +__istioctl_handle_filename_extension_flag() +{ + local ext="$1" + _filedir "@(${ext})" +} + +__istioctl_handle_subdirs_in_dir_flag() +{ + local dir="$1" + pushd "${dir}" >/dev/null 2>&1 && _filedir -d && popd >/dev/null 2>&1 +} + +__istioctl_handle_flag() +{ + __istioctl_debug "${FUNCNAME[0]}: c is $c words[c] is ${words[c]}" + + # if a command required a flag, and we found it, unset must_have_one_flag() + local flagname=${words[c]} + local flagvalue + # if the word contained an = + if [[ ${words[c]} == *"="* ]]; then + flagvalue=${flagname#*=} # take in as flagvalue after the = + flagname=${flagname%=*} # strip everything after the = + flagname="${flagname}=" # but put the = back + fi + __istioctl_debug "${FUNCNAME[0]}: looking for ${flagname}" + if __istioctl_contains_word "${flagname}" "${must_have_one_flag[@]}"; then + must_have_one_flag=() + fi + + # if you set a flag which only applies to this command, don't show subcommands + if __istioctl_contains_word "${flagname}" "${local_nonpersistent_flags[@]}"; then + commands=() + fi + + # keep flag value with flagname as flaghash + # flaghash variable is an associative array which is only supported in bash > 3. + if [[ -z "${BASH_VERSION}" || "${BASH_VERSINFO[0]}" -gt 3 ]]; then + if [ -n "${flagvalue}" ] ; then + flaghash[${flagname}]=${flagvalue} + elif [ -n "${words[ $((c+1)) ]}" ] ; then + flaghash[${flagname}]=${words[ $((c+1)) ]} + else + flaghash[${flagname}]="true" # pad "true" for bool flag + fi + fi + + # skip the argument to a two word flag + if [[ ${words[c]} != *"="* ]] && __istioctl_contains_word "${words[c]}" "${two_word_flags[@]}"; then + __istioctl_debug "${FUNCNAME[0]}: found a flag ${words[c]}, skip the next argument" + c=$((c+1)) + # if we are looking for a flags value, don't show commands + if [[ $c -eq $cword ]]; then + commands=() + fi + fi + + c=$((c+1)) + +} + +__istioctl_handle_noun() +{ + __istioctl_debug "${FUNCNAME[0]}: c is $c words[c] is ${words[c]}" + + if __istioctl_contains_word "${words[c]}" "${must_have_one_noun[@]}"; then + must_have_one_noun=() + elif __istioctl_contains_word "${words[c]}" "${noun_aliases[@]}"; then + must_have_one_noun=() + fi + + nouns+=("${words[c]}") + c=$((c+1)) +} + +__istioctl_handle_command() +{ + __istioctl_debug "${FUNCNAME[0]}: c is $c words[c] is ${words[c]}" + + local next_command + if [[ -n ${last_command} ]]; then + next_command="_${last_command}_${words[c]//:/__}" + else + if [[ $c -eq 0 ]]; then + next_command="_istioctl_root_command" + else + next_command="_${words[c]//:/__}" + fi + fi + c=$((c+1)) + __istioctl_debug "${FUNCNAME[0]}: looking for ${next_command}" + declare -F "$next_command" >/dev/null && $next_command +} + +__istioctl_handle_word() +{ + if [[ $c -ge $cword ]]; then + __istioctl_handle_reply + return + fi + __istioctl_debug "${FUNCNAME[0]}: c is $c words[c] is ${words[c]}" + if [[ "${words[c]}" == -* ]]; then + __istioctl_handle_flag + elif __istioctl_contains_word "${words[c]}" "${commands[@]}"; then + __istioctl_handle_command + elif [[ $c -eq 0 ]]; then + __istioctl_handle_command + elif __istioctl_contains_word "${words[c]}" "${command_aliases[@]}"; then + # aliashash variable is an associative array which is only supported in bash > 3. + if [[ -z "${BASH_VERSION}" || "${BASH_VERSINFO[0]}" -gt 3 ]]; then + words[c]=${aliashash[${words[c]}]} + __istioctl_handle_command + else + __istioctl_handle_noun + fi + else + __istioctl_handle_noun + fi + __istioctl_handle_word +} + +_istioctl_analyze() +{ + last_command="istioctl_analyze" + + command_aliases=() + + commands=() + + flags=() + two_word_flags=() + local_nonpersistent_flags=() + flags_with_completion=() + flags_completion=() + + flags+=("--all-namespaces") + flags+=("-A") + flags+=("--color") + flags+=("--failure-threshold=") + two_word_flags+=("--failure-threshold") + flags+=("--list-analyzers") + flags+=("-L") + flags+=("--meshConfigFile=") + two_word_flags+=("--meshConfigFile") + flags+=("--output=") + two_word_flags+=("--output") + two_word_flags+=("-o") + flags+=("--output-threshold=") + two_word_flags+=("--output-threshold") + flags+=("--recursive") + flags+=("-R") + flags+=("--suppress=") + two_word_flags+=("--suppress") + two_word_flags+=("-S") + flags+=("--timeout=") + two_word_flags+=("--timeout") + flags+=("--use-kube") + flags+=("-k") + flags+=("--verbose") + flags+=("-v") + flags+=("--context=") + two_word_flags+=("--context") + flags+=("--istioNamespace=") + two_word_flags+=("--istioNamespace") + two_word_flags+=("-i") + flags+=("--kubeconfig=") + two_word_flags+=("--kubeconfig") + two_word_flags+=("-c") + flags+=("--log_output_level=") + two_word_flags+=("--log_output_level") + flags+=("--namespace=") + two_word_flags+=("--namespace") + two_word_flags+=("-n") + + must_have_one_flag=() + must_have_one_noun=() + noun_aliases=() +} + +_istioctl_authn_tls-check() +{ + last_command="istioctl_authn_tls-check" + + command_aliases=() + + commands=() + + flags=() + two_word_flags=() + local_nonpersistent_flags=() + flags_with_completion=() + flags_completion=() + + flags+=("--context=") + two_word_flags+=("--context") + flags+=("--istioNamespace=") + two_word_flags+=("--istioNamespace") + two_word_flags+=("-i") + flags+=("--kubeconfig=") + two_word_flags+=("--kubeconfig") + two_word_flags+=("-c") + flags+=("--log_output_level=") + two_word_flags+=("--log_output_level") + flags+=("--namespace=") + two_word_flags+=("--namespace") + two_word_flags+=("-n") + + must_have_one_flag=() + must_have_one_noun=() + noun_aliases=() +} + +_istioctl_authn() +{ + last_command="istioctl_authn" + + command_aliases=() + + commands=() + commands+=("tls-check") + + flags=() + two_word_flags=() + local_nonpersistent_flags=() + flags_with_completion=() + flags_completion=() + + flags+=("--context=") + two_word_flags+=("--context") + flags+=("--istioNamespace=") + two_word_flags+=("--istioNamespace") + two_word_flags+=("-i") + flags+=("--kubeconfig=") + two_word_flags+=("--kubeconfig") + two_word_flags+=("-c") + flags+=("--log_output_level=") + two_word_flags+=("--log_output_level") + flags+=("--namespace=") + two_word_flags+=("--namespace") + two_word_flags+=("-n") + + must_have_one_flag=() + must_have_one_noun=() + noun_aliases=() +} + +_istioctl_authz() +{ + last_command="istioctl_authz" + + command_aliases=() + + commands=() + + flags=() + two_word_flags=() + local_nonpersistent_flags=() + flags_with_completion=() + flags_completion=() + + flags+=("--context=") + two_word_flags+=("--context") + flags+=("--istioNamespace=") + two_word_flags+=("--istioNamespace") + two_word_flags+=("-i") + flags+=("--kubeconfig=") + two_word_flags+=("--kubeconfig") + two_word_flags+=("-c") + flags+=("--log_output_level=") + two_word_flags+=("--log_output_level") + flags+=("--namespace=") + two_word_flags+=("--namespace") + two_word_flags+=("-n") + + must_have_one_flag=() + must_have_one_noun=() + noun_aliases=() +} + +_istioctl_convert-ingress() +{ + last_command="istioctl_convert-ingress" + + command_aliases=() + + commands=() + + flags=() + two_word_flags=() + local_nonpersistent_flags=() + flags_with_completion=() + flags_completion=() + + flags+=("--filenames=") + two_word_flags+=("--filenames") + two_word_flags+=("-f") + flags+=("--output=") + two_word_flags+=("--output") + two_word_flags+=("-o") + flags+=("--context=") + two_word_flags+=("--context") + flags+=("--istioNamespace=") + two_word_flags+=("--istioNamespace") + two_word_flags+=("-i") + flags+=("--kubeconfig=") + two_word_flags+=("--kubeconfig") + two_word_flags+=("-c") + flags+=("--log_output_level=") + two_word_flags+=("--log_output_level") + flags+=("--namespace=") + two_word_flags+=("--namespace") + two_word_flags+=("-n") + + must_have_one_flag=() + must_have_one_noun=() + noun_aliases=() +} + +_istioctl_dashboard_controlz() +{ + last_command="istioctl_dashboard_controlz" + + command_aliases=() + + commands=() + + flags=() + two_word_flags=() + local_nonpersistent_flags=() + flags_with_completion=() + flags_completion=() + + flags+=("--ctrlz_port=") + two_word_flags+=("--ctrlz_port") + flags+=("--selector=") + two_word_flags+=("--selector") + two_word_flags+=("-l") + flags+=("--context=") + two_word_flags+=("--context") + flags+=("--istioNamespace=") + two_word_flags+=("--istioNamespace") + two_word_flags+=("-i") + flags+=("--kubeconfig=") + two_word_flags+=("--kubeconfig") + two_word_flags+=("-c") + flags+=("--log_output_level=") + two_word_flags+=("--log_output_level") + flags+=("--namespace=") + two_word_flags+=("--namespace") + two_word_flags+=("-n") + + must_have_one_flag=() + must_have_one_noun=() + noun_aliases=() +} + +_istioctl_dashboard_envoy() +{ + last_command="istioctl_dashboard_envoy" + + command_aliases=() + + commands=() + + flags=() + two_word_flags=() + local_nonpersistent_flags=() + flags_with_completion=() + flags_completion=() + + flags+=("--selector=") + two_word_flags+=("--selector") + two_word_flags+=("-l") + flags+=("--context=") + two_word_flags+=("--context") + flags+=("--istioNamespace=") + two_word_flags+=("--istioNamespace") + two_word_flags+=("-i") + flags+=("--kubeconfig=") + two_word_flags+=("--kubeconfig") + two_word_flags+=("-c") + flags+=("--log_output_level=") + two_word_flags+=("--log_output_level") + flags+=("--namespace=") + two_word_flags+=("--namespace") + two_word_flags+=("-n") + + must_have_one_flag=() + must_have_one_noun=() + noun_aliases=() +} + +_istioctl_dashboard_grafana() +{ + last_command="istioctl_dashboard_grafana" + + command_aliases=() + + commands=() + + flags=() + two_word_flags=() + local_nonpersistent_flags=() + flags_with_completion=() + flags_completion=() + + flags+=("--context=") + two_word_flags+=("--context") + flags+=("--istioNamespace=") + two_word_flags+=("--istioNamespace") + two_word_flags+=("-i") + flags+=("--kubeconfig=") + two_word_flags+=("--kubeconfig") + two_word_flags+=("-c") + flags+=("--log_output_level=") + two_word_flags+=("--log_output_level") + flags+=("--namespace=") + two_word_flags+=("--namespace") + two_word_flags+=("-n") + + must_have_one_flag=() + must_have_one_noun=() + noun_aliases=() +} + +_istioctl_dashboard_jaeger() +{ + last_command="istioctl_dashboard_jaeger" + + command_aliases=() + + commands=() + + flags=() + two_word_flags=() + local_nonpersistent_flags=() + flags_with_completion=() + flags_completion=() + + flags+=("--context=") + two_word_flags+=("--context") + flags+=("--istioNamespace=") + two_word_flags+=("--istioNamespace") + two_word_flags+=("-i") + flags+=("--kubeconfig=") + two_word_flags+=("--kubeconfig") + two_word_flags+=("-c") + flags+=("--log_output_level=") + two_word_flags+=("--log_output_level") + flags+=("--namespace=") + two_word_flags+=("--namespace") + two_word_flags+=("-n") + + must_have_one_flag=() + must_have_one_noun=() + noun_aliases=() +} + +_istioctl_dashboard_kiali() +{ + last_command="istioctl_dashboard_kiali" + + command_aliases=() + + commands=() + + flags=() + two_word_flags=() + local_nonpersistent_flags=() + flags_with_completion=() + flags_completion=() + + flags+=("--context=") + two_word_flags+=("--context") + flags+=("--istioNamespace=") + two_word_flags+=("--istioNamespace") + two_word_flags+=("-i") + flags+=("--kubeconfig=") + two_word_flags+=("--kubeconfig") + two_word_flags+=("-c") + flags+=("--log_output_level=") + two_word_flags+=("--log_output_level") + flags+=("--namespace=") + two_word_flags+=("--namespace") + two_word_flags+=("-n") + + must_have_one_flag=() + must_have_one_noun=() + noun_aliases=() +} + +_istioctl_dashboard_prometheus() +{ + last_command="istioctl_dashboard_prometheus" + + command_aliases=() + + commands=() + + flags=() + two_word_flags=() + local_nonpersistent_flags=() + flags_with_completion=() + flags_completion=() + + flags+=("--context=") + two_word_flags+=("--context") + flags+=("--istioNamespace=") + two_word_flags+=("--istioNamespace") + two_word_flags+=("-i") + flags+=("--kubeconfig=") + two_word_flags+=("--kubeconfig") + two_word_flags+=("-c") + flags+=("--log_output_level=") + two_word_flags+=("--log_output_level") + flags+=("--namespace=") + two_word_flags+=("--namespace") + two_word_flags+=("-n") + + must_have_one_flag=() + must_have_one_noun=() + noun_aliases=() +} + +_istioctl_dashboard_zipkin() +{ + last_command="istioctl_dashboard_zipkin" + + command_aliases=() + + commands=() + + flags=() + two_word_flags=() + local_nonpersistent_flags=() + flags_with_completion=() + flags_completion=() + + flags+=("--context=") + two_word_flags+=("--context") + flags+=("--istioNamespace=") + two_word_flags+=("--istioNamespace") + two_word_flags+=("-i") + flags+=("--kubeconfig=") + two_word_flags+=("--kubeconfig") + two_word_flags+=("-c") + flags+=("--log_output_level=") + two_word_flags+=("--log_output_level") + flags+=("--namespace=") + two_word_flags+=("--namespace") + two_word_flags+=("-n") + + must_have_one_flag=() + must_have_one_noun=() + noun_aliases=() +} + +_istioctl_dashboard() +{ + last_command="istioctl_dashboard" + + command_aliases=() + + commands=() + commands+=("controlz") + commands+=("envoy") + commands+=("grafana") + commands+=("jaeger") + commands+=("kiali") + commands+=("prometheus") + commands+=("zipkin") + + flags=() + two_word_flags=() + local_nonpersistent_flags=() + flags_with_completion=() + flags_completion=() + + flags+=("--context=") + two_word_flags+=("--context") + flags+=("--istioNamespace=") + two_word_flags+=("--istioNamespace") + two_word_flags+=("-i") + flags+=("--kubeconfig=") + two_word_flags+=("--kubeconfig") + two_word_flags+=("-c") + flags+=("--log_output_level=") + two_word_flags+=("--log_output_level") + flags+=("--namespace=") + two_word_flags+=("--namespace") + two_word_flags+=("-n") + + must_have_one_flag=() + must_have_one_noun=() + noun_aliases=() +} + +_istioctl_deregister() +{ + last_command="istioctl_deregister" + + command_aliases=() + + commands=() + + flags=() + two_word_flags=() + local_nonpersistent_flags=() + flags_with_completion=() + flags_completion=() + + flags+=("--context=") + two_word_flags+=("--context") + flags+=("--istioNamespace=") + two_word_flags+=("--istioNamespace") + two_word_flags+=("-i") + flags+=("--kubeconfig=") + two_word_flags+=("--kubeconfig") + two_word_flags+=("-c") + flags+=("--log_output_level=") + two_word_flags+=("--log_output_level") + flags+=("--namespace=") + two_word_flags+=("--namespace") + two_word_flags+=("-n") + + must_have_one_flag=() + must_have_one_noun=() + noun_aliases=() +} + +_istioctl_experimental_add-to-mesh_deployment() +{ + last_command="istioctl_experimental_add-to-mesh_deployment" + + command_aliases=() + + commands=() + + flags=() + two_word_flags=() + local_nonpersistent_flags=() + flags_with_completion=() + flags_completion=() + + flags+=("--context=") + two_word_flags+=("--context") + flags+=("--injectConfigFile=") + two_word_flags+=("--injectConfigFile") + flags+=("--injectConfigMapName=") + two_word_flags+=("--injectConfigMapName") + flags+=("--istioNamespace=") + two_word_flags+=("--istioNamespace") + two_word_flags+=("-i") + flags+=("--kubeconfig=") + two_word_flags+=("--kubeconfig") + two_word_flags+=("-c") + flags+=("--log_output_level=") + two_word_flags+=("--log_output_level") + flags+=("--meshConfigFile=") + two_word_flags+=("--meshConfigFile") + flags+=("--meshConfigMapName=") + two_word_flags+=("--meshConfigMapName") + flags+=("--namespace=") + two_word_flags+=("--namespace") + two_word_flags+=("-n") + flags+=("--valuesFile=") + two_word_flags+=("--valuesFile") + + must_have_one_flag=() + must_have_one_noun=() + noun_aliases=() +} + +_istioctl_experimental_add-to-mesh_external-service() +{ + last_command="istioctl_experimental_add-to-mesh_external-service" + + command_aliases=() + + commands=() + + flags=() + two_word_flags=() + local_nonpersistent_flags=() + flags_with_completion=() + flags_completion=() + + flags+=("--annotations=") + two_word_flags+=("--annotations") + two_word_flags+=("-a") + flags+=("--labels=") + two_word_flags+=("--labels") + two_word_flags+=("-l") + flags+=("--serviceaccount=") + two_word_flags+=("--serviceaccount") + two_word_flags+=("-s") + flags+=("--context=") + two_word_flags+=("--context") + flags+=("--injectConfigFile=") + two_word_flags+=("--injectConfigFile") + flags+=("--injectConfigMapName=") + two_word_flags+=("--injectConfigMapName") + flags+=("--istioNamespace=") + two_word_flags+=("--istioNamespace") + two_word_flags+=("-i") + flags+=("--kubeconfig=") + two_word_flags+=("--kubeconfig") + two_word_flags+=("-c") + flags+=("--log_output_level=") + two_word_flags+=("--log_output_level") + flags+=("--meshConfigFile=") + two_word_flags+=("--meshConfigFile") + flags+=("--meshConfigMapName=") + two_word_flags+=("--meshConfigMapName") + flags+=("--namespace=") + two_word_flags+=("--namespace") + two_word_flags+=("-n") + flags+=("--valuesFile=") + two_word_flags+=("--valuesFile") + + must_have_one_flag=() + must_have_one_noun=() + noun_aliases=() +} + +_istioctl_experimental_add-to-mesh_service() +{ + last_command="istioctl_experimental_add-to-mesh_service" + + command_aliases=() + + commands=() + + flags=() + two_word_flags=() + local_nonpersistent_flags=() + flags_with_completion=() + flags_completion=() + + flags+=("--context=") + two_word_flags+=("--context") + flags+=("--injectConfigFile=") + two_word_flags+=("--injectConfigFile") + flags+=("--injectConfigMapName=") + two_word_flags+=("--injectConfigMapName") + flags+=("--istioNamespace=") + two_word_flags+=("--istioNamespace") + two_word_flags+=("-i") + flags+=("--kubeconfig=") + two_word_flags+=("--kubeconfig") + two_word_flags+=("-c") + flags+=("--log_output_level=") + two_word_flags+=("--log_output_level") + flags+=("--meshConfigFile=") + two_word_flags+=("--meshConfigFile") + flags+=("--meshConfigMapName=") + two_word_flags+=("--meshConfigMapName") + flags+=("--namespace=") + two_word_flags+=("--namespace") + two_word_flags+=("-n") + flags+=("--valuesFile=") + two_word_flags+=("--valuesFile") + + must_have_one_flag=() + must_have_one_noun=() + noun_aliases=() +} + +_istioctl_experimental_add-to-mesh() +{ + last_command="istioctl_experimental_add-to-mesh" + + command_aliases=() + + commands=() + commands+=("deployment") + commands+=("external-service") + commands+=("service") + + flags=() + two_word_flags=() + local_nonpersistent_flags=() + flags_with_completion=() + flags_completion=() + + flags+=("--injectConfigFile=") + two_word_flags+=("--injectConfigFile") + flags+=("--injectConfigMapName=") + two_word_flags+=("--injectConfigMapName") + flags+=("--meshConfigFile=") + two_word_flags+=("--meshConfigFile") + flags+=("--meshConfigMapName=") + two_word_flags+=("--meshConfigMapName") + flags+=("--valuesFile=") + two_word_flags+=("--valuesFile") + flags+=("--context=") + two_word_flags+=("--context") + flags+=("--istioNamespace=") + two_word_flags+=("--istioNamespace") + two_word_flags+=("-i") + flags+=("--kubeconfig=") + two_word_flags+=("--kubeconfig") + two_word_flags+=("-c") + flags+=("--log_output_level=") + two_word_flags+=("--log_output_level") + flags+=("--namespace=") + two_word_flags+=("--namespace") + two_word_flags+=("-n") + + must_have_one_flag=() + must_have_one_noun=() + noun_aliases=() +} + +_istioctl_experimental_analyze() +{ + last_command="istioctl_experimental_analyze" + + command_aliases=() + + commands=() + + flags=() + two_word_flags=() + local_nonpersistent_flags=() + flags_with_completion=() + flags_completion=() + + flags+=("--all-namespaces") + flags+=("-A") + flags+=("--color") + flags+=("--failure-threshold=") + two_word_flags+=("--failure-threshold") + flags+=("--list-analyzers") + flags+=("-L") + flags+=("--meshConfigFile=") + two_word_flags+=("--meshConfigFile") + flags+=("--output=") + two_word_flags+=("--output") + two_word_flags+=("-o") + flags+=("--output-threshold=") + two_word_flags+=("--output-threshold") + flags+=("--recursive") + flags+=("-R") + flags+=("--suppress=") + two_word_flags+=("--suppress") + two_word_flags+=("-S") + flags+=("--timeout=") + two_word_flags+=("--timeout") + flags+=("--use-kube") + flags+=("-k") + flags+=("--verbose") + flags+=("-v") + flags+=("--context=") + two_word_flags+=("--context") + flags+=("--istioNamespace=") + two_word_flags+=("--istioNamespace") + two_word_flags+=("-i") + flags+=("--kubeconfig=") + two_word_flags+=("--kubeconfig") + two_word_flags+=("-c") + flags+=("--log_output_level=") + two_word_flags+=("--log_output_level") + flags+=("--namespace=") + two_word_flags+=("--namespace") + two_word_flags+=("-n") + + must_have_one_flag=() + must_have_one_noun=() + noun_aliases=() +} + +_istioctl_experimental_authz_check() +{ + last_command="istioctl_experimental_authz_check" + + command_aliases=() + + commands=() + + flags=() + two_word_flags=() + local_nonpersistent_flags=() + flags_with_completion=() + flags_completion=() + + flags+=("--all") + flags+=("-a") + flags+=("--file=") + two_word_flags+=("--file") + two_word_flags+=("-f") + flags+=("--context=") + two_word_flags+=("--context") + flags+=("--istioNamespace=") + two_word_flags+=("--istioNamespace") + two_word_flags+=("-i") + flags+=("--kubeconfig=") + two_word_flags+=("--kubeconfig") + two_word_flags+=("-c") + flags+=("--log_output_level=") + two_word_flags+=("--log_output_level") + flags+=("--namespace=") + two_word_flags+=("--namespace") + two_word_flags+=("-n") + + must_have_one_flag=() + must_have_one_noun=() + noun_aliases=() +} + +_istioctl_experimental_authz_convert() +{ + last_command="istioctl_experimental_authz_convert" + + command_aliases=() + + commands=() + + flags=() + two_word_flags=() + local_nonpersistent_flags=() + flags_with_completion=() + flags_completion=() + + flags+=("--allowNoClusterRbacConfig") + flags+=("--file=") + two_word_flags+=("--file") + two_word_flags+=("-f") + flags+=("--rootNamespace=") + two_word_flags+=("--rootNamespace") + two_word_flags+=("-r") + flags+=("--service=") + two_word_flags+=("--service") + two_word_flags+=("-s") + flags+=("--context=") + two_word_flags+=("--context") + flags+=("--istioNamespace=") + two_word_flags+=("--istioNamespace") + two_word_flags+=("-i") + flags+=("--kubeconfig=") + two_word_flags+=("--kubeconfig") + two_word_flags+=("-c") + flags+=("--log_output_level=") + two_word_flags+=("--log_output_level") + flags+=("--namespace=") + two_word_flags+=("--namespace") + two_word_flags+=("-n") + + must_have_one_flag=() + must_have_one_noun=() + noun_aliases=() +} + +_istioctl_experimental_authz() +{ + last_command="istioctl_experimental_authz" + + command_aliases=() + + commands=() + commands+=("check") + commands+=("convert") + + flags=() + two_word_flags=() + local_nonpersistent_flags=() + flags_with_completion=() + flags_completion=() + + flags+=("--context=") + two_word_flags+=("--context") + flags+=("--istioNamespace=") + two_word_flags+=("--istioNamespace") + two_word_flags+=("-i") + flags+=("--kubeconfig=") + two_word_flags+=("--kubeconfig") + two_word_flags+=("-c") + flags+=("--log_output_level=") + two_word_flags+=("--log_output_level") + flags+=("--namespace=") + two_word_flags+=("--namespace") + two_word_flags+=("-n") + + must_have_one_flag=() + must_have_one_noun=() + noun_aliases=() +} + +_istioctl_experimental_convert-ingress() +{ + last_command="istioctl_experimental_convert-ingress" + + command_aliases=() + + commands=() + + flags=() + two_word_flags=() + local_nonpersistent_flags=() + flags_with_completion=() + flags_completion=() + + flags+=("--context=") + two_word_flags+=("--context") + flags+=("--istioNamespace=") + two_word_flags+=("--istioNamespace") + two_word_flags+=("-i") + flags+=("--kubeconfig=") + two_word_flags+=("--kubeconfig") + two_word_flags+=("-c") + flags+=("--log_output_level=") + two_word_flags+=("--log_output_level") + flags+=("--namespace=") + two_word_flags+=("--namespace") + two_word_flags+=("-n") + + must_have_one_flag=() + must_have_one_noun=() + noun_aliases=() +} + +_istioctl_experimental_create-remote-secret() +{ + last_command="istioctl_experimental_create-remote-secret" + + command_aliases=() + + commands=() + + flags=() + two_word_flags=() + local_nonpersistent_flags=() + flags_with_completion=() + flags_completion=() + + flags+=("--auth-plugin-config=") + two_word_flags+=("--auth-plugin-config") + flags+=("--auth-plugin-name=") + two_word_flags+=("--auth-plugin-name") + flags+=("--auth-type=") + two_word_flags+=("--auth-type") + flags+=("--name=") + two_word_flags+=("--name") + flags+=("--service-account=") + two_word_flags+=("--service-account") + flags+=("--context=") + two_word_flags+=("--context") + flags+=("--istioNamespace=") + two_word_flags+=("--istioNamespace") + two_word_flags+=("-i") + flags+=("--kubeconfig=") + two_word_flags+=("--kubeconfig") + two_word_flags+=("-c") + flags+=("--log_output_level=") + two_word_flags+=("--log_output_level") + flags+=("--namespace=") + two_word_flags+=("--namespace") + two_word_flags+=("-n") + + must_have_one_flag=() + must_have_one_noun=() + noun_aliases=() +} + +_istioctl_experimental_dashboard() +{ + last_command="istioctl_experimental_dashboard" + + command_aliases=() + + commands=() + + flags=() + two_word_flags=() + local_nonpersistent_flags=() + flags_with_completion=() + flags_completion=() + + flags+=("--context=") + two_word_flags+=("--context") + flags+=("--istioNamespace=") + two_word_flags+=("--istioNamespace") + two_word_flags+=("-i") + flags+=("--kubeconfig=") + two_word_flags+=("--kubeconfig") + two_word_flags+=("-c") + flags+=("--log_output_level=") + two_word_flags+=("--log_output_level") + flags+=("--namespace=") + two_word_flags+=("--namespace") + two_word_flags+=("-n") + + must_have_one_flag=() + must_have_one_noun=() + noun_aliases=() +} + +_istioctl_experimental_describe_pod() +{ + last_command="istioctl_experimental_describe_pod" + + command_aliases=() + + commands=() + + flags=() + two_word_flags=() + local_nonpersistent_flags=() + flags_with_completion=() + flags_completion=() + + flags+=("--ignoreUnmeshed") + flags+=("--context=") + two_word_flags+=("--context") + flags+=("--istioNamespace=") + two_word_flags+=("--istioNamespace") + two_word_flags+=("-i") + flags+=("--kubeconfig=") + two_word_flags+=("--kubeconfig") + two_word_flags+=("-c") + flags+=("--log_output_level=") + two_word_flags+=("--log_output_level") + flags+=("--namespace=") + two_word_flags+=("--namespace") + two_word_flags+=("-n") + + must_have_one_flag=() + must_have_one_noun=() + noun_aliases=() +} + +_istioctl_experimental_describe_service() +{ + last_command="istioctl_experimental_describe_service" + + command_aliases=() + + commands=() + + flags=() + two_word_flags=() + local_nonpersistent_flags=() + flags_with_completion=() + flags_completion=() + + flags+=("--ignoreUnmeshed") + flags+=("--context=") + two_word_flags+=("--context") + flags+=("--istioNamespace=") + two_word_flags+=("--istioNamespace") + two_word_flags+=("-i") + flags+=("--kubeconfig=") + two_word_flags+=("--kubeconfig") + two_word_flags+=("-c") + flags+=("--log_output_level=") + two_word_flags+=("--log_output_level") + flags+=("--namespace=") + two_word_flags+=("--namespace") + two_word_flags+=("-n") + + must_have_one_flag=() + must_have_one_noun=() + noun_aliases=() +} + +_istioctl_experimental_describe() +{ + last_command="istioctl_experimental_describe" + + command_aliases=() + + commands=() + commands+=("pod") + commands+=("service") + if [[ -z "${BASH_VERSION}" || "${BASH_VERSINFO[0]}" -gt 3 ]]; then + command_aliases+=("svc") + aliashash["svc"]="service" + fi + + flags=() + two_word_flags=() + local_nonpersistent_flags=() + flags_with_completion=() + flags_completion=() + + flags+=("--context=") + two_word_flags+=("--context") + flags+=("--istioNamespace=") + two_word_flags+=("--istioNamespace") + two_word_flags+=("-i") + flags+=("--kubeconfig=") + two_word_flags+=("--kubeconfig") + two_word_flags+=("-c") + flags+=("--log_output_level=") + two_word_flags+=("--log_output_level") + flags+=("--namespace=") + two_word_flags+=("--namespace") + two_word_flags+=("-n") + + must_have_one_flag=() + must_have_one_noun=() + noun_aliases=() +} + +_istioctl_experimental_kube-uninject() +{ + last_command="istioctl_experimental_kube-uninject" + + command_aliases=() + + commands=() + + flags=() + two_word_flags=() + local_nonpersistent_flags=() + flags_with_completion=() + flags_completion=() + + flags+=("--filename=") + two_word_flags+=("--filename") + two_word_flags+=("-f") + flags+=("--output=") + two_word_flags+=("--output") + two_word_flags+=("-o") + flags+=("--context=") + two_word_flags+=("--context") + flags+=("--istioNamespace=") + two_word_flags+=("--istioNamespace") + two_word_flags+=("-i") + flags+=("--kubeconfig=") + two_word_flags+=("--kubeconfig") + two_word_flags+=("-c") + flags+=("--log_output_level=") + two_word_flags+=("--log_output_level") + flags+=("--namespace=") + two_word_flags+=("--namespace") + two_word_flags+=("-n") + + must_have_one_flag=() + must_have_one_noun=() + noun_aliases=() +} + +_istioctl_experimental_metrics() +{ + last_command="istioctl_experimental_metrics" + + command_aliases=() + + commands=() + + flags=() + two_word_flags=() + local_nonpersistent_flags=() + flags_with_completion=() + flags_completion=() + + flags+=("--context=") + two_word_flags+=("--context") + flags+=("--istioNamespace=") + two_word_flags+=("--istioNamespace") + two_word_flags+=("-i") + flags+=("--kubeconfig=") + two_word_flags+=("--kubeconfig") + two_word_flags+=("-c") + flags+=("--log_output_level=") + two_word_flags+=("--log_output_level") + flags+=("--namespace=") + two_word_flags+=("--namespace") + two_word_flags+=("-n") + + must_have_one_flag=() + must_have_one_noun=() + noun_aliases=() +} + +_istioctl_experimental_multicluster_apply() +{ + last_command="istioctl_experimental_multicluster_apply" + + command_aliases=() + + commands=() + + flags=() + two_word_flags=() + local_nonpersistent_flags=() + flags_with_completion=() + flags_completion=() + + flags+=("--filename=") + two_word_flags+=("--filename") + two_word_flags+=("-f") + flags+=("--context=") + two_word_flags+=("--context") + flags+=("--istioNamespace=") + two_word_flags+=("--istioNamespace") + two_word_flags+=("-i") + flags+=("--kubeconfig=") + two_word_flags+=("--kubeconfig") + two_word_flags+=("-c") + flags+=("--log_output_level=") + two_word_flags+=("--log_output_level") + flags+=("--namespace=") + two_word_flags+=("--namespace") + two_word_flags+=("-n") + + must_have_one_flag=() + must_have_one_noun=() + noun_aliases=() +} + +_istioctl_experimental_multicluster_describe() +{ + last_command="istioctl_experimental_multicluster_describe" + + command_aliases=() + + commands=() + + flags=() + two_word_flags=() + local_nonpersistent_flags=() + flags_with_completion=() + flags_completion=() + + flags+=("--all") + flags+=("--filename=") + two_word_flags+=("--filename") + two_word_flags+=("-f") + flags+=("--context=") + two_word_flags+=("--context") + flags+=("--istioNamespace=") + two_word_flags+=("--istioNamespace") + two_word_flags+=("-i") + flags+=("--kubeconfig=") + two_word_flags+=("--kubeconfig") + two_word_flags+=("-c") + flags+=("--log_output_level=") + two_word_flags+=("--log_output_level") + flags+=("--namespace=") + two_word_flags+=("--namespace") + two_word_flags+=("-n") + + must_have_one_flag=() + must_have_one_noun=() + noun_aliases=() +} + +_istioctl_experimental_multicluster_generate() +{ + last_command="istioctl_experimental_multicluster_generate" + + command_aliases=() + + commands=() + + flags=() + two_word_flags=() + local_nonpersistent_flags=() + flags_with_completion=() + flags_completion=() + + flags+=("--filename=") + two_word_flags+=("--filename") + two_word_flags+=("-f") + flags+=("--from=") + two_word_flags+=("--from") + flags+=("--wait-for-gateways") + flags+=("--context=") + two_word_flags+=("--context") + flags+=("--istioNamespace=") + two_word_flags+=("--istioNamespace") + two_word_flags+=("-i") + flags+=("--kubeconfig=") + two_word_flags+=("--kubeconfig") + two_word_flags+=("-c") + flags+=("--log_output_level=") + two_word_flags+=("--log_output_level") + flags+=("--namespace=") + two_word_flags+=("--namespace") + two_word_flags+=("-n") + + must_have_one_flag=() + must_have_one_noun=() + noun_aliases=() +} + +_istioctl_experimental_multicluster() +{ + last_command="istioctl_experimental_multicluster" + + command_aliases=() + + commands=() + commands+=("apply") + commands+=("describe") + commands+=("generate") + + flags=() + two_word_flags=() + local_nonpersistent_flags=() + flags_with_completion=() + flags_completion=() + + flags+=("--context=") + two_word_flags+=("--context") + flags+=("--istioNamespace=") + two_word_flags+=("--istioNamespace") + two_word_flags+=("-i") + flags+=("--kubeconfig=") + two_word_flags+=("--kubeconfig") + two_word_flags+=("-c") + flags+=("--log_output_level=") + two_word_flags+=("--log_output_level") + flags+=("--namespace=") + two_word_flags+=("--namespace") + two_word_flags+=("-n") + + must_have_one_flag=() + must_have_one_noun=() + noun_aliases=() +} + +_istioctl_experimental_post-install_webhook_disable() +{ + last_command="istioctl_experimental_post-install_webhook_disable" + + command_aliases=() + + commands=() + + flags=() + two_word_flags=() + local_nonpersistent_flags=() + flags_with_completion=() + flags_completion=() + + flags+=("--injection") + local_nonpersistent_flags+=("--injection") + flags+=("--injection-config=") + two_word_flags+=("--injection-config") + local_nonpersistent_flags+=("--injection-config=") + flags+=("--validation") + local_nonpersistent_flags+=("--validation") + flags+=("--validation-config=") + two_word_flags+=("--validation-config") + local_nonpersistent_flags+=("--validation-config=") + flags+=("--context=") + two_word_flags+=("--context") + flags+=("--istioNamespace=") + two_word_flags+=("--istioNamespace") + two_word_flags+=("-i") + flags+=("--kubeconfig=") + two_word_flags+=("--kubeconfig") + two_word_flags+=("-c") + flags+=("--log_output_level=") + two_word_flags+=("--log_output_level") + flags+=("--namespace=") + two_word_flags+=("--namespace") + two_word_flags+=("-n") + + must_have_one_flag=() + must_have_one_noun=() + noun_aliases=() +} + +_istioctl_experimental_post-install_webhook_enable() +{ + last_command="istioctl_experimental_post-install_webhook_enable" + + command_aliases=() + + commands=() + + flags=() + two_word_flags=() + local_nonpersistent_flags=() + flags_with_completion=() + flags_completion=() + + flags+=("--ca-bundle-file=") + two_word_flags+=("--ca-bundle-file") + local_nonpersistent_flags+=("--ca-bundle-file=") + flags+=("--injection") + local_nonpersistent_flags+=("--injection") + flags+=("--injection-path=") + two_word_flags+=("--injection-path") + local_nonpersistent_flags+=("--injection-path=") + flags+=("--injection-service=") + two_word_flags+=("--injection-service") + local_nonpersistent_flags+=("--injection-service=") + flags+=("--read-cert-timeout=") + two_word_flags+=("--read-cert-timeout") + local_nonpersistent_flags+=("--read-cert-timeout=") + flags+=("--timeout=") + two_word_flags+=("--timeout") + local_nonpersistent_flags+=("--timeout=") + flags+=("--validation") + local_nonpersistent_flags+=("--validation") + flags+=("--validation-path=") + two_word_flags+=("--validation-path") + local_nonpersistent_flags+=("--validation-path=") + flags+=("--validation-service=") + two_word_flags+=("--validation-service") + local_nonpersistent_flags+=("--validation-service=") + flags+=("--webhook-secret=") + two_word_flags+=("--webhook-secret") + local_nonpersistent_flags+=("--webhook-secret=") + flags+=("--context=") + two_word_flags+=("--context") + flags+=("--istioNamespace=") + two_word_flags+=("--istioNamespace") + two_word_flags+=("-i") + flags+=("--kubeconfig=") + two_word_flags+=("--kubeconfig") + two_word_flags+=("-c") + flags+=("--log_output_level=") + two_word_flags+=("--log_output_level") + flags+=("--namespace=") + two_word_flags+=("--namespace") + two_word_flags+=("-n") + + must_have_one_flag=() + must_have_one_noun=() + noun_aliases=() +} + +_istioctl_experimental_post-install_webhook_status() +{ + last_command="istioctl_experimental_post-install_webhook_status" + + command_aliases=() + + commands=() + + flags=() + two_word_flags=() + local_nonpersistent_flags=() + flags_with_completion=() + flags_completion=() + + flags+=("--injection") + local_nonpersistent_flags+=("--injection") + flags+=("--injection-config=") + two_word_flags+=("--injection-config") + local_nonpersistent_flags+=("--injection-config=") + flags+=("--validation") + local_nonpersistent_flags+=("--validation") + flags+=("--validation-config=") + two_word_flags+=("--validation-config") + local_nonpersistent_flags+=("--validation-config=") + flags+=("--context=") + two_word_flags+=("--context") + flags+=("--istioNamespace=") + two_word_flags+=("--istioNamespace") + two_word_flags+=("-i") + flags+=("--kubeconfig=") + two_word_flags+=("--kubeconfig") + two_word_flags+=("-c") + flags+=("--log_output_level=") + two_word_flags+=("--log_output_level") + flags+=("--namespace=") + two_word_flags+=("--namespace") + two_word_flags+=("-n") + + must_have_one_flag=() + must_have_one_noun=() + noun_aliases=() +} + +_istioctl_experimental_post-install_webhook() +{ + last_command="istioctl_experimental_post-install_webhook" + + command_aliases=() + + commands=() + commands+=("disable") + commands+=("enable") + commands+=("status") + + flags=() + two_word_flags=() + local_nonpersistent_flags=() + flags_with_completion=() + flags_completion=() + + flags+=("--context=") + two_word_flags+=("--context") + flags+=("--istioNamespace=") + two_word_flags+=("--istioNamespace") + two_word_flags+=("-i") + flags+=("--kubeconfig=") + two_word_flags+=("--kubeconfig") + two_word_flags+=("-c") + flags+=("--log_output_level=") + two_word_flags+=("--log_output_level") + flags+=("--namespace=") + two_word_flags+=("--namespace") + two_word_flags+=("-n") + + must_have_one_flag=() + must_have_one_noun=() + noun_aliases=() +} + +_istioctl_experimental_post-install() +{ + last_command="istioctl_experimental_post-install" + + command_aliases=() + + commands=() + commands+=("webhook") + + flags=() + two_word_flags=() + local_nonpersistent_flags=() + flags_with_completion=() + flags_completion=() + + flags+=("--context=") + two_word_flags+=("--context") + flags+=("--istioNamespace=") + two_word_flags+=("--istioNamespace") + two_word_flags+=("-i") + flags+=("--kubeconfig=") + two_word_flags+=("--kubeconfig") + two_word_flags+=("-c") + flags+=("--log_output_level=") + two_word_flags+=("--log_output_level") + flags+=("--namespace=") + two_word_flags+=("--namespace") + two_word_flags+=("-n") + + must_have_one_flag=() + must_have_one_noun=() + noun_aliases=() +} + +_istioctl_experimental_remove-from-mesh_deployment() +{ + last_command="istioctl_experimental_remove-from-mesh_deployment" + + command_aliases=() + + commands=() + + flags=() + two_word_flags=() + local_nonpersistent_flags=() + flags_with_completion=() + flags_completion=() + + flags+=("--context=") + two_word_flags+=("--context") + flags+=("--istioNamespace=") + two_word_flags+=("--istioNamespace") + two_word_flags+=("-i") + flags+=("--kubeconfig=") + two_word_flags+=("--kubeconfig") + two_word_flags+=("-c") + flags+=("--log_output_level=") + two_word_flags+=("--log_output_level") + flags+=("--namespace=") + two_word_flags+=("--namespace") + two_word_flags+=("-n") + + must_have_one_flag=() + must_have_one_noun=() + noun_aliases=() +} + +_istioctl_experimental_remove-from-mesh_external-service() +{ + last_command="istioctl_experimental_remove-from-mesh_external-service" + + command_aliases=() + + commands=() + + flags=() + two_word_flags=() + local_nonpersistent_flags=() + flags_with_completion=() + flags_completion=() + + flags+=("--context=") + two_word_flags+=("--context") + flags+=("--istioNamespace=") + two_word_flags+=("--istioNamespace") + two_word_flags+=("-i") + flags+=("--kubeconfig=") + two_word_flags+=("--kubeconfig") + two_word_flags+=("-c") + flags+=("--log_output_level=") + two_word_flags+=("--log_output_level") + flags+=("--namespace=") + two_word_flags+=("--namespace") + two_word_flags+=("-n") + + must_have_one_flag=() + must_have_one_noun=() + noun_aliases=() +} + +_istioctl_experimental_remove-from-mesh_service() +{ + last_command="istioctl_experimental_remove-from-mesh_service" + + command_aliases=() + + commands=() + + flags=() + two_word_flags=() + local_nonpersistent_flags=() + flags_with_completion=() + flags_completion=() + + flags+=("--context=") + two_word_flags+=("--context") + flags+=("--istioNamespace=") + two_word_flags+=("--istioNamespace") + two_word_flags+=("-i") + flags+=("--kubeconfig=") + two_word_flags+=("--kubeconfig") + two_word_flags+=("-c") + flags+=("--log_output_level=") + two_word_flags+=("--log_output_level") + flags+=("--namespace=") + two_word_flags+=("--namespace") + two_word_flags+=("-n") + + must_have_one_flag=() + must_have_one_noun=() + noun_aliases=() +} + +_istioctl_experimental_remove-from-mesh() +{ + last_command="istioctl_experimental_remove-from-mesh" + + command_aliases=() + + commands=() + commands+=("deployment") + commands+=("external-service") + commands+=("service") + + flags=() + two_word_flags=() + local_nonpersistent_flags=() + flags_with_completion=() + flags_completion=() + + flags+=("--context=") + two_word_flags+=("--context") + flags+=("--istioNamespace=") + two_word_flags+=("--istioNamespace") + two_word_flags+=("-i") + flags+=("--kubeconfig=") + two_word_flags+=("--kubeconfig") + two_word_flags+=("-c") + flags+=("--log_output_level=") + two_word_flags+=("--log_output_level") + flags+=("--namespace=") + two_word_flags+=("--namespace") + two_word_flags+=("-n") + + must_have_one_flag=() + must_have_one_noun=() + noun_aliases=() +} + +_istioctl_experimental_upgrade() +{ + last_command="istioctl_experimental_upgrade" + + command_aliases=() + + commands=() + + flags=() + two_word_flags=() + local_nonpersistent_flags=() + flags_with_completion=() + flags_completion=() + + flags+=("--dry-run") + flags+=("--filename=") + two_word_flags+=("--filename") + two_word_flags+=("-f") + flags+=("--force") + flags+=("--logtostderr") + flags+=("--skip-confirmation") + flags+=("-y") + flags+=("--verbose") + flags+=("--versionsURI=") + two_word_flags+=("--versionsURI") + two_word_flags+=("-u") + flags+=("--wait") + flags+=("-w") + flags+=("--context=") + two_word_flags+=("--context") + flags+=("--istioNamespace=") + two_word_flags+=("--istioNamespace") + two_word_flags+=("-i") + flags+=("--kubeconfig=") + two_word_flags+=("--kubeconfig") + two_word_flags+=("-c") + flags+=("--log_output_level=") + two_word_flags+=("--log_output_level") + flags+=("--namespace=") + two_word_flags+=("--namespace") + two_word_flags+=("-n") + + must_have_one_flag=() + must_have_one_noun=() + noun_aliases=() +} + +_istioctl_experimental_wait() +{ + last_command="istioctl_experimental_wait" + + command_aliases=() + + commands=() + + flags=() + two_word_flags=() + local_nonpersistent_flags=() + flags_with_completion=() + flags_completion=() + + flags+=("--for=") + two_word_flags+=("--for") + flags+=("--resource-version=") + two_word_flags+=("--resource-version") + flags+=("--threshold=") + two_word_flags+=("--threshold") + flags+=("--timeout=") + two_word_flags+=("--timeout") + flags+=("--context=") + two_word_flags+=("--context") + flags+=("--istioNamespace=") + two_word_flags+=("--istioNamespace") + two_word_flags+=("-i") + flags+=("--kubeconfig=") + two_word_flags+=("--kubeconfig") + two_word_flags+=("-c") + flags+=("--log_output_level=") + two_word_flags+=("--log_output_level") + flags+=("--namespace=") + two_word_flags+=("--namespace") + two_word_flags+=("-n") + + must_have_one_flag=() + must_have_one_noun=() + noun_aliases=() +} + +_istioctl_experimental() +{ + last_command="istioctl_experimental" + + command_aliases=() + + commands=() + commands+=("add-to-mesh") + if [[ -z "${BASH_VERSION}" || "${BASH_VERSINFO[0]}" -gt 3 ]]; then + command_aliases+=("add") + aliashash["add"]="add-to-mesh" + fi + commands+=("analyze") + commands+=("authz") + commands+=("convert-ingress") + commands+=("create-remote-secret") + commands+=("dashboard") + commands+=("describe") + if [[ -z "${BASH_VERSION}" || "${BASH_VERSINFO[0]}" -gt 3 ]]; then + command_aliases+=("des") + aliashash["des"]="describe" + fi + commands+=("kube-uninject") + commands+=("metrics") + if [[ -z "${BASH_VERSION}" || "${BASH_VERSINFO[0]}" -gt 3 ]]; then + command_aliases+=("m") + aliashash["m"]="metrics" + fi + commands+=("multicluster") + if [[ -z "${BASH_VERSION}" || "${BASH_VERSINFO[0]}" -gt 3 ]]; then + command_aliases+=("mc") + aliashash["mc"]="multicluster" + fi + commands+=("post-install") + commands+=("remove-from-mesh") + if [[ -z "${BASH_VERSION}" || "${BASH_VERSINFO[0]}" -gt 3 ]]; then + command_aliases+=("rm") + aliashash["rm"]="remove-from-mesh" + fi + commands+=("upgrade") + commands+=("wait") + + flags=() + two_word_flags=() + local_nonpersistent_flags=() + flags_with_completion=() + flags_completion=() + + flags+=("--context=") + two_word_flags+=("--context") + flags+=("--istioNamespace=") + two_word_flags+=("--istioNamespace") + two_word_flags+=("-i") + flags+=("--kubeconfig=") + two_word_flags+=("--kubeconfig") + two_word_flags+=("-c") + flags+=("--log_output_level=") + two_word_flags+=("--log_output_level") + flags+=("--namespace=") + two_word_flags+=("--namespace") + two_word_flags+=("-n") + + must_have_one_flag=() + must_have_one_noun=() + noun_aliases=() +} + +_istioctl_kube-inject() +{ + last_command="istioctl_kube-inject" + + command_aliases=() + + commands=() + + flags=() + two_word_flags=() + local_nonpersistent_flags=() + flags_with_completion=() + flags_completion=() + + flags+=("--filename=") + two_word_flags+=("--filename") + two_word_flags+=("-f") + flags+=("--injectConfigFile=") + two_word_flags+=("--injectConfigFile") + flags+=("--injectConfigMapName=") + two_word_flags+=("--injectConfigMapName") + flags+=("--meshConfigFile=") + two_word_flags+=("--meshConfigFile") + flags+=("--meshConfigMapName=") + two_word_flags+=("--meshConfigMapName") + flags+=("--output=") + two_word_flags+=("--output") + two_word_flags+=("-o") + flags+=("--valuesFile=") + two_word_flags+=("--valuesFile") + flags+=("--context=") + two_word_flags+=("--context") + flags+=("--istioNamespace=") + two_word_flags+=("--istioNamespace") + two_word_flags+=("-i") + flags+=("--kubeconfig=") + two_word_flags+=("--kubeconfig") + two_word_flags+=("-c") + flags+=("--log_output_level=") + two_word_flags+=("--log_output_level") + flags+=("--namespace=") + two_word_flags+=("--namespace") + two_word_flags+=("-n") + + must_have_one_flag=() + must_have_one_noun=() + noun_aliases=() +} + +_istioctl_manifest_apply() +{ + last_command="istioctl_manifest_apply" + + command_aliases=() + + commands=() + + flags=() + two_word_flags=() + local_nonpersistent_flags=() + flags_with_completion=() + flags_completion=() + + flags+=("--filename=") + two_word_flags+=("--filename") + two_word_flags+=("-f") + flags+=("--force") + flags+=("--readiness-timeout=") + two_word_flags+=("--readiness-timeout") + flags+=("--set=") + two_word_flags+=("--set") + two_word_flags+=("-s") + flags+=("--skip-confirmation") + flags+=("-y") + flags+=("--wait") + flags+=("-w") + flags+=("--context=") + two_word_flags+=("--context") + flags+=("--dry-run") + flags+=("--istioNamespace=") + two_word_flags+=("--istioNamespace") + two_word_flags+=("-i") + flags+=("--kubeconfig=") + two_word_flags+=("--kubeconfig") + two_word_flags+=("-c") + flags+=("--log_output_level=") + two_word_flags+=("--log_output_level") + flags+=("--logtostderr") + flags+=("--namespace=") + two_word_flags+=("--namespace") + two_word_flags+=("-n") + flags+=("--verbose") + + must_have_one_flag=() + must_have_one_noun=() + noun_aliases=() +} + +_istioctl_manifest_diff() +{ + last_command="istioctl_manifest_diff" + + command_aliases=() + + commands=() + + flags=() + two_word_flags=() + local_nonpersistent_flags=() + flags_with_completion=() + flags_completion=() + + flags+=("--directory") + flags+=("-r") + flags+=("--ignore=") + two_word_flags+=("--ignore") + flags+=("--rename=") + two_word_flags+=("--rename") + flags+=("--select=") + two_word_flags+=("--select") + flags+=("--context=") + two_word_flags+=("--context") + flags+=("--dry-run") + flags+=("--istioNamespace=") + two_word_flags+=("--istioNamespace") + two_word_flags+=("-i") + flags+=("--kubeconfig=") + two_word_flags+=("--kubeconfig") + two_word_flags+=("-c") + flags+=("--log_output_level=") + two_word_flags+=("--log_output_level") + flags+=("--logtostderr") + flags+=("--namespace=") + two_word_flags+=("--namespace") + two_word_flags+=("-n") + flags+=("--verbose") + + must_have_one_flag=() + must_have_one_noun=() + noun_aliases=() +} + +_istioctl_manifest_generate() +{ + last_command="istioctl_manifest_generate" + + command_aliases=() + + commands=() + + flags=() + two_word_flags=() + local_nonpersistent_flags=() + flags_with_completion=() + flags_completion=() + + flags+=("--filename=") + two_word_flags+=("--filename") + two_word_flags+=("-f") + flags+=("--force") + flags+=("--output=") + two_word_flags+=("--output") + two_word_flags+=("-o") + flags+=("--set=") + two_word_flags+=("--set") + two_word_flags+=("-s") + flags+=("--context=") + two_word_flags+=("--context") + flags+=("--dry-run") + flags+=("--istioNamespace=") + two_word_flags+=("--istioNamespace") + two_word_flags+=("-i") + flags+=("--kubeconfig=") + two_word_flags+=("--kubeconfig") + two_word_flags+=("-c") + flags+=("--log_output_level=") + two_word_flags+=("--log_output_level") + flags+=("--logtostderr") + flags+=("--namespace=") + two_word_flags+=("--namespace") + two_word_flags+=("-n") + flags+=("--verbose") + + must_have_one_flag=() + must_have_one_noun=() + noun_aliases=() +} + +_istioctl_manifest_migrate() +{ + last_command="istioctl_manifest_migrate" + + command_aliases=() + + commands=() + + flags=() + two_word_flags=() + local_nonpersistent_flags=() + flags_with_completion=() + flags_completion=() + + flags+=("--force") + flags+=("--context=") + two_word_flags+=("--context") + flags+=("--dry-run") + flags+=("--istioNamespace=") + two_word_flags+=("--istioNamespace") + two_word_flags+=("-i") + flags+=("--kubeconfig=") + two_word_flags+=("--kubeconfig") + two_word_flags+=("-c") + flags+=("--log_output_level=") + two_word_flags+=("--log_output_level") + flags+=("--logtostderr") + flags+=("--namespace=") + two_word_flags+=("--namespace") + two_word_flags+=("-n") + flags+=("--verbose") + + must_have_one_flag=() + must_have_one_noun=() + noun_aliases=() +} + +_istioctl_manifest_versions() +{ + last_command="istioctl_manifest_versions" + + command_aliases=() + + commands=() + + flags=() + two_word_flags=() + local_nonpersistent_flags=() + flags_with_completion=() + flags_completion=() + + flags+=("--versionsURI=") + two_word_flags+=("--versionsURI") + two_word_flags+=("-u") + flags+=("--context=") + two_word_flags+=("--context") + flags+=("--dry-run") + flags+=("--istioNamespace=") + two_word_flags+=("--istioNamespace") + two_word_flags+=("-i") + flags+=("--kubeconfig=") + two_word_flags+=("--kubeconfig") + two_word_flags+=("-c") + flags+=("--log_output_level=") + two_word_flags+=("--log_output_level") + flags+=("--logtostderr") + flags+=("--namespace=") + two_word_flags+=("--namespace") + two_word_flags+=("-n") + flags+=("--verbose") + + must_have_one_flag=() + must_have_one_noun=() + noun_aliases=() +} + +_istioctl_manifest() +{ + last_command="istioctl_manifest" + + command_aliases=() + + commands=() + commands+=("apply") + commands+=("diff") + commands+=("generate") + commands+=("migrate") + commands+=("versions") + + flags=() + two_word_flags=() + local_nonpersistent_flags=() + flags_with_completion=() + flags_completion=() + + flags+=("--dry-run") + flags+=("--logtostderr") + flags+=("--verbose") + flags+=("--context=") + two_word_flags+=("--context") + flags+=("--istioNamespace=") + two_word_flags+=("--istioNamespace") + two_word_flags+=("-i") + flags+=("--kubeconfig=") + two_word_flags+=("--kubeconfig") + two_word_flags+=("-c") + flags+=("--log_output_level=") + two_word_flags+=("--log_output_level") + flags+=("--namespace=") + two_word_flags+=("--namespace") + two_word_flags+=("-n") + + must_have_one_flag=() + must_have_one_noun=() + noun_aliases=() +} + +_istioctl_operator_init() +{ + last_command="istioctl_operator_init" + + command_aliases=() + + commands=() + + flags=() + two_word_flags=() + local_nonpersistent_flags=() + flags_with_completion=() + flags_completion=() + + flags+=("--dry-run") + flags+=("--filename=") + two_word_flags+=("--filename") + two_word_flags+=("-f") + flags+=("--hub=") + two_word_flags+=("--hub") + flags+=("--logtostderr") + flags+=("--operatorNamespace=") + two_word_flags+=("--operatorNamespace") + flags+=("--readiness-timeout=") + two_word_flags+=("--readiness-timeout") + flags+=("--tag=") + two_word_flags+=("--tag") + flags+=("--verbose") + flags+=("--wait") + flags+=("-w") + flags+=("--context=") + two_word_flags+=("--context") + flags+=("--istioNamespace=") + two_word_flags+=("--istioNamespace") + two_word_flags+=("-i") + flags+=("--kubeconfig=") + two_word_flags+=("--kubeconfig") + two_word_flags+=("-c") + flags+=("--log_output_level=") + two_word_flags+=("--log_output_level") + flags+=("--namespace=") + two_word_flags+=("--namespace") + two_word_flags+=("-n") + + must_have_one_flag=() + must_have_one_noun=() + noun_aliases=() +} + +_istioctl_operator_remove() +{ + last_command="istioctl_operator_remove" + + command_aliases=() + + commands=() + + flags=() + two_word_flags=() + local_nonpersistent_flags=() + flags_with_completion=() + flags_completion=() + + flags+=("--dry-run") + flags+=("--filename=") + two_word_flags+=("--filename") + two_word_flags+=("-f") + flags+=("--force") + flags+=("--hub=") + two_word_flags+=("--hub") + flags+=("--logtostderr") + flags+=("--operatorNamespace=") + two_word_flags+=("--operatorNamespace") + flags+=("--readiness-timeout=") + two_word_flags+=("--readiness-timeout") + flags+=("--tag=") + two_word_flags+=("--tag") + flags+=("--verbose") + flags+=("--wait") + flags+=("-w") + flags+=("--context=") + two_word_flags+=("--context") + flags+=("--istioNamespace=") + two_word_flags+=("--istioNamespace") + two_word_flags+=("-i") + flags+=("--kubeconfig=") + two_word_flags+=("--kubeconfig") + two_word_flags+=("-c") + flags+=("--log_output_level=") + two_word_flags+=("--log_output_level") + flags+=("--namespace=") + two_word_flags+=("--namespace") + two_word_flags+=("-n") + + must_have_one_flag=() + must_have_one_noun=() + noun_aliases=() +} + +_istioctl_operator() +{ + last_command="istioctl_operator" + + command_aliases=() + + commands=() + commands+=("init") + commands+=("remove") + + flags=() + two_word_flags=() + local_nonpersistent_flags=() + flags_with_completion=() + flags_completion=() + + flags+=("--context=") + two_word_flags+=("--context") + flags+=("--istioNamespace=") + two_word_flags+=("--istioNamespace") + two_word_flags+=("-i") + flags+=("--kubeconfig=") + two_word_flags+=("--kubeconfig") + two_word_flags+=("-c") + flags+=("--log_output_level=") + two_word_flags+=("--log_output_level") + flags+=("--namespace=") + two_word_flags+=("--namespace") + two_word_flags+=("-n") + + must_have_one_flag=() + must_have_one_noun=() + noun_aliases=() +} + +_istioctl_profile_diff() +{ + last_command="istioctl_profile_diff" + + command_aliases=() + + commands=() + + flags=() + two_word_flags=() + local_nonpersistent_flags=() + flags_with_completion=() + flags_completion=() + + flags+=("--context=") + two_word_flags+=("--context") + flags+=("--dry-run") + flags+=("--istioNamespace=") + two_word_flags+=("--istioNamespace") + two_word_flags+=("-i") + flags+=("--kubeconfig=") + two_word_flags+=("--kubeconfig") + two_word_flags+=("-c") + flags+=("--log_output_level=") + two_word_flags+=("--log_output_level") + flags+=("--logtostderr") + flags+=("--namespace=") + two_word_flags+=("--namespace") + two_word_flags+=("-n") + flags+=("--verbose") + + must_have_one_flag=() + must_have_one_noun=() + noun_aliases=() +} + +_istioctl_profile_dump() +{ + last_command="istioctl_profile_dump" + + command_aliases=() + + commands=() + + flags=() + two_word_flags=() + local_nonpersistent_flags=() + flags_with_completion=() + flags_completion=() + + flags+=("--config-path=") + two_word_flags+=("--config-path") + two_word_flags+=("-p") + flags+=("--filename=") + two_word_flags+=("--filename") + two_word_flags+=("-f") + flags+=("--output=") + two_word_flags+=("--output") + two_word_flags+=("-o") + flags+=("--context=") + two_word_flags+=("--context") + flags+=("--dry-run") + flags+=("--istioNamespace=") + two_word_flags+=("--istioNamespace") + two_word_flags+=("-i") + flags+=("--kubeconfig=") + two_word_flags+=("--kubeconfig") + two_word_flags+=("-c") + flags+=("--log_output_level=") + two_word_flags+=("--log_output_level") + flags+=("--logtostderr") + flags+=("--namespace=") + two_word_flags+=("--namespace") + two_word_flags+=("-n") + flags+=("--verbose") + + must_have_one_flag=() + must_have_one_noun=() + noun_aliases=() +} + +_istioctl_profile_list() +{ + last_command="istioctl_profile_list" + + command_aliases=() + + commands=() + + flags=() + two_word_flags=() + local_nonpersistent_flags=() + flags_with_completion=() + flags_completion=() + + flags+=("--context=") + two_word_flags+=("--context") + flags+=("--dry-run") + flags+=("--istioNamespace=") + two_word_flags+=("--istioNamespace") + two_word_flags+=("-i") + flags+=("--kubeconfig=") + two_word_flags+=("--kubeconfig") + two_word_flags+=("-c") + flags+=("--log_output_level=") + two_word_flags+=("--log_output_level") + flags+=("--logtostderr") + flags+=("--namespace=") + two_word_flags+=("--namespace") + two_word_flags+=("-n") + flags+=("--verbose") + + must_have_one_flag=() + must_have_one_noun=() + noun_aliases=() +} + +_istioctl_profile() +{ + last_command="istioctl_profile" + + command_aliases=() + + commands=() + commands+=("diff") + commands+=("dump") + commands+=("list") + + flags=() + two_word_flags=() + local_nonpersistent_flags=() + flags_with_completion=() + flags_completion=() + + flags+=("--dry-run") + flags+=("--logtostderr") + flags+=("--verbose") + flags+=("--context=") + two_word_flags+=("--context") + flags+=("--istioNamespace=") + two_word_flags+=("--istioNamespace") + two_word_flags+=("-i") + flags+=("--kubeconfig=") + two_word_flags+=("--kubeconfig") + two_word_flags+=("-c") + flags+=("--log_output_level=") + two_word_flags+=("--log_output_level") + flags+=("--namespace=") + two_word_flags+=("--namespace") + two_word_flags+=("-n") + + must_have_one_flag=() + must_have_one_noun=() + noun_aliases=() +} + +_istioctl_proxy-config_bootstrap() +{ + last_command="istioctl_proxy-config_bootstrap" + + command_aliases=() + + commands=() + + flags=() + two_word_flags=() + local_nonpersistent_flags=() + flags_with_completion=() + flags_completion=() + + flags+=("--file=") + two_word_flags+=("--file") + two_word_flags+=("-f") + flags+=("--context=") + two_word_flags+=("--context") + flags+=("--istioNamespace=") + two_word_flags+=("--istioNamespace") + two_word_flags+=("-i") + flags+=("--kubeconfig=") + two_word_flags+=("--kubeconfig") + two_word_flags+=("-c") + flags+=("--log_output_level=") + two_word_flags+=("--log_output_level") + flags+=("--namespace=") + two_word_flags+=("--namespace") + two_word_flags+=("-n") + flags+=("--output=") + two_word_flags+=("--output") + two_word_flags+=("-o") + + must_have_one_flag=() + must_have_one_noun=() + noun_aliases=() +} + +_istioctl_proxy-config_cluster() +{ + last_command="istioctl_proxy-config_cluster" + + command_aliases=() + + commands=() + + flags=() + two_word_flags=() + local_nonpersistent_flags=() + flags_with_completion=() + flags_completion=() + + flags+=("--direction=") + two_word_flags+=("--direction") + flags+=("--file=") + two_word_flags+=("--file") + two_word_flags+=("-f") + flags+=("--fqdn=") + two_word_flags+=("--fqdn") + flags+=("--port=") + two_word_flags+=("--port") + flags+=("--subset=") + two_word_flags+=("--subset") + flags+=("--context=") + two_word_flags+=("--context") + flags+=("--istioNamespace=") + two_word_flags+=("--istioNamespace") + two_word_flags+=("-i") + flags+=("--kubeconfig=") + two_word_flags+=("--kubeconfig") + two_word_flags+=("-c") + flags+=("--log_output_level=") + two_word_flags+=("--log_output_level") + flags+=("--namespace=") + two_word_flags+=("--namespace") + two_word_flags+=("-n") + flags+=("--output=") + two_word_flags+=("--output") + two_word_flags+=("-o") + + must_have_one_flag=() + must_have_one_noun=() + noun_aliases=() +} + +_istioctl_proxy-config_endpoint() +{ + last_command="istioctl_proxy-config_endpoint" + + command_aliases=() + + commands=() + + flags=() + two_word_flags=() + local_nonpersistent_flags=() + flags_with_completion=() + flags_completion=() + + flags+=("--address=") + two_word_flags+=("--address") + flags+=("--cluster=") + two_word_flags+=("--cluster") + flags+=("--file=") + two_word_flags+=("--file") + two_word_flags+=("-f") + flags+=("--port=") + two_word_flags+=("--port") + flags+=("--status=") + two_word_flags+=("--status") + flags+=("--context=") + two_word_flags+=("--context") + flags+=("--istioNamespace=") + two_word_flags+=("--istioNamespace") + two_word_flags+=("-i") + flags+=("--kubeconfig=") + two_word_flags+=("--kubeconfig") + two_word_flags+=("-c") + flags+=("--log_output_level=") + two_word_flags+=("--log_output_level") + flags+=("--namespace=") + two_word_flags+=("--namespace") + two_word_flags+=("-n") + flags+=("--output=") + two_word_flags+=("--output") + two_word_flags+=("-o") + + must_have_one_flag=() + must_have_one_noun=() + noun_aliases=() +} + +_istioctl_proxy-config_listener() +{ + last_command="istioctl_proxy-config_listener" + + command_aliases=() + + commands=() + + flags=() + two_word_flags=() + local_nonpersistent_flags=() + flags_with_completion=() + flags_completion=() + + flags+=("--address=") + two_word_flags+=("--address") + flags+=("--file=") + two_word_flags+=("--file") + two_word_flags+=("-f") + flags+=("--port=") + two_word_flags+=("--port") + flags+=("--type=") + two_word_flags+=("--type") + flags+=("--context=") + two_word_flags+=("--context") + flags+=("--istioNamespace=") + two_word_flags+=("--istioNamespace") + two_word_flags+=("-i") + flags+=("--kubeconfig=") + two_word_flags+=("--kubeconfig") + two_word_flags+=("-c") + flags+=("--log_output_level=") + two_word_flags+=("--log_output_level") + flags+=("--namespace=") + two_word_flags+=("--namespace") + two_word_flags+=("-n") + flags+=("--output=") + two_word_flags+=("--output") + two_word_flags+=("-o") + + must_have_one_flag=() + must_have_one_noun=() + noun_aliases=() +} + +_istioctl_proxy-config_log() +{ + last_command="istioctl_proxy-config_log" + + command_aliases=() + + commands=() + + flags=() + two_word_flags=() + local_nonpersistent_flags=() + flags_with_completion=() + flags_completion=() + + flags+=("--level=") + two_word_flags+=("--level") + flags+=("--reset") + flags+=("-r") + flags+=("--context=") + two_word_flags+=("--context") + flags+=("--istioNamespace=") + two_word_flags+=("--istioNamespace") + two_word_flags+=("-i") + flags+=("--kubeconfig=") + two_word_flags+=("--kubeconfig") + two_word_flags+=("-c") + flags+=("--log_output_level=") + two_word_flags+=("--log_output_level") + flags+=("--namespace=") + two_word_flags+=("--namespace") + two_word_flags+=("-n") + flags+=("--output=") + two_word_flags+=("--output") + two_word_flags+=("-o") + + must_have_one_flag=() + must_have_one_noun=() + noun_aliases=() +} + +_istioctl_proxy-config_route() +{ + last_command="istioctl_proxy-config_route" + + command_aliases=() + + commands=() + + flags=() + two_word_flags=() + local_nonpersistent_flags=() + flags_with_completion=() + flags_completion=() + + flags+=("--file=") + two_word_flags+=("--file") + two_word_flags+=("-f") + flags+=("--name=") + two_word_flags+=("--name") + flags+=("--context=") + two_word_flags+=("--context") + flags+=("--istioNamespace=") + two_word_flags+=("--istioNamespace") + two_word_flags+=("-i") + flags+=("--kubeconfig=") + two_word_flags+=("--kubeconfig") + two_word_flags+=("-c") + flags+=("--log_output_level=") + two_word_flags+=("--log_output_level") + flags+=("--namespace=") + two_word_flags+=("--namespace") + two_word_flags+=("-n") + flags+=("--output=") + two_word_flags+=("--output") + two_word_flags+=("-o") + + must_have_one_flag=() + must_have_one_noun=() + noun_aliases=() +} + +_istioctl_proxy-config_secret() +{ + last_command="istioctl_proxy-config_secret" + + command_aliases=() + + commands=() + + flags=() + two_word_flags=() + local_nonpersistent_flags=() + flags_with_completion=() + flags_completion=() + + flags+=("--file=") + two_word_flags+=("--file") + two_word_flags+=("-f") + flags+=("--context=") + two_word_flags+=("--context") + flags+=("--istioNamespace=") + two_word_flags+=("--istioNamespace") + two_word_flags+=("-i") + flags+=("--kubeconfig=") + two_word_flags+=("--kubeconfig") + two_word_flags+=("-c") + flags+=("--log_output_level=") + two_word_flags+=("--log_output_level") + flags+=("--namespace=") + two_word_flags+=("--namespace") + two_word_flags+=("-n") + flags+=("--output=") + two_word_flags+=("--output") + two_word_flags+=("-o") + + must_have_one_flag=() + must_have_one_noun=() + noun_aliases=() +} + +_istioctl_proxy-config() +{ + last_command="istioctl_proxy-config" + + command_aliases=() + + commands=() + commands+=("bootstrap") + if [[ -z "${BASH_VERSION}" || "${BASH_VERSINFO[0]}" -gt 3 ]]; then + command_aliases+=("b") + aliashash["b"]="bootstrap" + fi + commands+=("cluster") + if [[ -z "${BASH_VERSION}" || "${BASH_VERSINFO[0]}" -gt 3 ]]; then + command_aliases+=("c") + aliashash["c"]="cluster" + command_aliases+=("clusters") + aliashash["clusters"]="cluster" + fi + commands+=("endpoint") + if [[ -z "${BASH_VERSION}" || "${BASH_VERSINFO[0]}" -gt 3 ]]; then + command_aliases+=("endpoints") + aliashash["endpoints"]="endpoint" + command_aliases+=("ep") + aliashash["ep"]="endpoint" + fi + commands+=("listener") + if [[ -z "${BASH_VERSION}" || "${BASH_VERSINFO[0]}" -gt 3 ]]; then + command_aliases+=("l") + aliashash["l"]="listener" + command_aliases+=("listeners") + aliashash["listeners"]="listener" + fi + commands+=("log") + if [[ -z "${BASH_VERSION}" || "${BASH_VERSINFO[0]}" -gt 3 ]]; then + command_aliases+=("o") + aliashash["o"]="log" + fi + commands+=("route") + if [[ -z "${BASH_VERSION}" || "${BASH_VERSINFO[0]}" -gt 3 ]]; then + command_aliases+=("r") + aliashash["r"]="route" + command_aliases+=("routes") + aliashash["routes"]="route" + fi + commands+=("secret") + if [[ -z "${BASH_VERSION}" || "${BASH_VERSINFO[0]}" -gt 3 ]]; then + command_aliases+=("s") + aliashash["s"]="secret" + fi + + flags=() + two_word_flags=() + local_nonpersistent_flags=() + flags_with_completion=() + flags_completion=() + + flags+=("--output=") + two_word_flags+=("--output") + two_word_flags+=("-o") + flags+=("--context=") + two_word_flags+=("--context") + flags+=("--istioNamespace=") + two_word_flags+=("--istioNamespace") + two_word_flags+=("-i") + flags+=("--kubeconfig=") + two_word_flags+=("--kubeconfig") + two_word_flags+=("-c") + flags+=("--log_output_level=") + two_word_flags+=("--log_output_level") + flags+=("--namespace=") + two_word_flags+=("--namespace") + two_word_flags+=("-n") + + must_have_one_flag=() + must_have_one_noun=() + noun_aliases=() +} + +_istioctl_proxy-status() +{ + last_command="istioctl_proxy-status" + + command_aliases=() + + commands=() + + flags=() + two_word_flags=() + local_nonpersistent_flags=() + flags_with_completion=() + flags_completion=() + + flags+=("--sds") + flags+=("-s") + local_nonpersistent_flags+=("--sds") + flags+=("--sds-json") + local_nonpersistent_flags+=("--sds-json") + flags+=("--context=") + two_word_flags+=("--context") + flags+=("--istioNamespace=") + two_word_flags+=("--istioNamespace") + two_word_flags+=("-i") + flags+=("--kubeconfig=") + two_word_flags+=("--kubeconfig") + two_word_flags+=("-c") + flags+=("--log_output_level=") + two_word_flags+=("--log_output_level") + flags+=("--namespace=") + two_word_flags+=("--namespace") + two_word_flags+=("-n") + + must_have_one_flag=() + must_have_one_noun=() + noun_aliases=() +} + +_istioctl_register() +{ + last_command="istioctl_register" + + command_aliases=() + + commands=() + + flags=() + two_word_flags=() + local_nonpersistent_flags=() + flags_with_completion=() + flags_completion=() + + flags+=("--annotations=") + two_word_flags+=("--annotations") + two_word_flags+=("-a") + flags+=("--labels=") + two_word_flags+=("--labels") + two_word_flags+=("-l") + flags+=("--serviceaccount=") + two_word_flags+=("--serviceaccount") + two_word_flags+=("-s") + flags+=("--context=") + two_word_flags+=("--context") + flags+=("--istioNamespace=") + two_word_flags+=("--istioNamespace") + two_word_flags+=("-i") + flags+=("--kubeconfig=") + two_word_flags+=("--kubeconfig") + two_word_flags+=("-c") + flags+=("--log_output_level=") + two_word_flags+=("--log_output_level") + flags+=("--namespace=") + two_word_flags+=("--namespace") + two_word_flags+=("-n") + + must_have_one_flag=() + must_have_one_noun=() + noun_aliases=() +} + +_istioctl_upgrade() +{ + last_command="istioctl_upgrade" + + command_aliases=() + + commands=() + + flags=() + two_word_flags=() + local_nonpersistent_flags=() + flags_with_completion=() + flags_completion=() + + flags+=("--dry-run") + flags+=("--filename=") + two_word_flags+=("--filename") + two_word_flags+=("-f") + flags+=("--force") + flags+=("--logtostderr") + flags+=("--skip-confirmation") + flags+=("-y") + flags+=("--verbose") + flags+=("--versionsURI=") + two_word_flags+=("--versionsURI") + two_word_flags+=("-u") + flags+=("--wait") + flags+=("-w") + flags+=("--context=") + two_word_flags+=("--context") + flags+=("--istioNamespace=") + two_word_flags+=("--istioNamespace") + two_word_flags+=("-i") + flags+=("--kubeconfig=") + two_word_flags+=("--kubeconfig") + two_word_flags+=("-c") + flags+=("--log_output_level=") + two_word_flags+=("--log_output_level") + flags+=("--namespace=") + two_word_flags+=("--namespace") + two_word_flags+=("-n") + + must_have_one_flag=() + must_have_one_noun=() + noun_aliases=() +} + +_istioctl_validate() +{ + last_command="istioctl_validate" + + command_aliases=() + + commands=() + + flags=() + two_word_flags=() + local_nonpersistent_flags=() + flags_with_completion=() + flags_completion=() + + flags+=("--filename=") + two_word_flags+=("--filename") + two_word_flags+=("-f") + flags+=("--referential") + flags+=("-x") + flags+=("--context=") + two_word_flags+=("--context") + flags+=("--istioNamespace=") + two_word_flags+=("--istioNamespace") + two_word_flags+=("-i") + flags+=("--kubeconfig=") + two_word_flags+=("--kubeconfig") + two_word_flags+=("-c") + flags+=("--log_output_level=") + two_word_flags+=("--log_output_level") + flags+=("--namespace=") + two_word_flags+=("--namespace") + two_word_flags+=("-n") + + must_have_one_flag=() + must_have_one_noun=() + noun_aliases=() +} + +_istioctl_verify-install() +{ + last_command="istioctl_verify-install" + + command_aliases=() + + commands=() + + flags=() + two_word_flags=() + local_nonpersistent_flags=() + flags_with_completion=() + flags_completion=() + + flags+=("--enableVerbose") + local_nonpersistent_flags+=("--enableVerbose") + flags+=("--filename=") + two_word_flags+=("--filename") + flags_with_completion+=("--filename") + flags_completion+=("__istioctl_handle_filename_extension_flag json|yaml|yml") + two_word_flags+=("-f") + flags_with_completion+=("-f") + flags_completion+=("__istioctl_handle_filename_extension_flag json|yaml|yml") + flags+=("--recursive") + flags+=("-R") + flags+=("--context=") + two_word_flags+=("--context") + flags+=("--istioNamespace=") + two_word_flags+=("--istioNamespace") + two_word_flags+=("-i") + flags+=("--kubeconfig=") + two_word_flags+=("--kubeconfig") + two_word_flags+=("-c") + flags+=("--log_output_level=") + two_word_flags+=("--log_output_level") + flags+=("--namespace=") + two_word_flags+=("--namespace") + two_word_flags+=("-n") + + must_have_one_flag=() + must_have_one_noun=() + noun_aliases=() +} + +_istioctl_version() +{ + last_command="istioctl_version" + + command_aliases=() + + commands=() + + flags=() + two_word_flags=() + local_nonpersistent_flags=() + flags_with_completion=() + flags_completion=() + + flags+=("--output=") + two_word_flags+=("--output") + two_word_flags+=("-o") + local_nonpersistent_flags+=("--output=") + flags+=("--remote") + local_nonpersistent_flags+=("--remote") + flags+=("--short") + flags+=("-s") + local_nonpersistent_flags+=("--short") + flags+=("--context=") + two_word_flags+=("--context") + flags+=("--istioNamespace=") + two_word_flags+=("--istioNamespace") + two_word_flags+=("-i") + flags+=("--kubeconfig=") + two_word_flags+=("--kubeconfig") + two_word_flags+=("-c") + flags+=("--log_output_level=") + two_word_flags+=("--log_output_level") + flags+=("--namespace=") + two_word_flags+=("--namespace") + two_word_flags+=("-n") + + must_have_one_flag=() + must_have_one_noun=() + noun_aliases=() +} + +_istioctl_root_command() +{ + last_command="istioctl" + + command_aliases=() + + commands=() + commands+=("analyze") + commands+=("authn") + commands+=("authz") + commands+=("convert-ingress") + commands+=("dashboard") + if [[ -z "${BASH_VERSION}" || "${BASH_VERSINFO[0]}" -gt 3 ]]; then + command_aliases+=("d") + aliashash["d"]="dashboard" + command_aliases+=("dash") + aliashash["dash"]="dashboard" + fi + commands+=("deregister") + commands+=("experimental") + if [[ -z "${BASH_VERSION}" || "${BASH_VERSINFO[0]}" -gt 3 ]]; then + command_aliases+=("exp") + aliashash["exp"]="experimental" + command_aliases+=("x") + aliashash["x"]="experimental" + fi + commands+=("kube-inject") + commands+=("manifest") + commands+=("operator") + commands+=("profile") + commands+=("proxy-config") + if [[ -z "${BASH_VERSION}" || "${BASH_VERSINFO[0]}" -gt 3 ]]; then + command_aliases+=("pc") + aliashash["pc"]="proxy-config" + fi + commands+=("proxy-status") + if [[ -z "${BASH_VERSION}" || "${BASH_VERSINFO[0]}" -gt 3 ]]; then + command_aliases+=("ps") + aliashash["ps"]="proxy-status" + fi + commands+=("register") + commands+=("upgrade") + commands+=("validate") + commands+=("verify-install") + commands+=("version") + + flags=() + two_word_flags=() + local_nonpersistent_flags=() + flags_with_completion=() + flags_completion=() + + flags+=("--context=") + two_word_flags+=("--context") + flags+=("--istioNamespace=") + two_word_flags+=("--istioNamespace") + two_word_flags+=("-i") + flags+=("--kubeconfig=") + two_word_flags+=("--kubeconfig") + two_word_flags+=("-c") + flags+=("--log_output_level=") + two_word_flags+=("--log_output_level") + flags+=("--namespace=") + two_word_flags+=("--namespace") + two_word_flags+=("-n") + + must_have_one_flag=() + must_have_one_noun=() + noun_aliases=() +} + +__start_istioctl() +{ + local cur prev words cword + declare -A flaghash 2>/dev/null || : + declare -A aliashash 2>/dev/null || : + if declare -F _init_completion >/dev/null 2>&1; then + _init_completion -s || return + else + __istioctl_init_completion -n "=" || return + fi + + local c=0 + local flags=() + local two_word_flags=() + local local_nonpersistent_flags=() + local flags_with_completion=() + local flags_completion=() + local commands=("istioctl") + local must_have_one_flag=() + local must_have_one_noun=() + local last_command + local nouns=() + + __istioctl_handle_word +} + +if [[ $(type -t compopt) = "builtin" ]]; then + complete -o default -F __start_istioctl istioctl +else + complete -o default -o nospace -F __start_istioctl istioctl +fi + +# ex: ts=4 sw=4 et filetype=sh + +BASH_COMPLETION_EOF +} + +__istio_bash_source <(__istio_convert_bash_to_zsh) +_complete istio 2>/dev/null diff --git a/istio-1.5.0/tools/convert_RbacConfig_to_ClusterRbacConfig.sh b/istio-1.5.0/tools/convert_RbacConfig_to_ClusterRbacConfig.sh new file mode 100644 index 0000000..4a0f691 --- /dev/null +++ b/istio-1.5.0/tools/convert_RbacConfig_to_ClusterRbacConfig.sh @@ -0,0 +1,63 @@ +#!/bin/bash + +# Copyright Istio Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +set -e +set -u + +# This script is provided to help converting RbacConfig to ClusterRbacConfig automatically. The RbacConfig +# will be deleted after the corresponding ClusterRbacConfig is successfully applied. +# The RbacConfig is deprecated by ClusterRbacConfig due to an implementation bug that could cause the +# RbacConfig to be namespace scoped in some cases. The ClusterRbacConfig has exactly same specification +# as the RbacConfig, but with correctly implemented cluster scope. + +RBAC_CONFIGS=$(kubectl get RbacConfig --all-namespaces --no-headers --ignore-not-found) +if [ "${RBAC_CONFIGS}" == "" ] +then + echo "RbacConfig not found" + exit 0 +fi + +RBAC_CONFIG_COUNT=$(echo "${RBAC_CONFIGS}" | wc -l) +if [ "${RBAC_CONFIG_COUNT}" -ne 1 ] +then + echo "${RBAC_CONFIGS}" + echo "found ${RBAC_CONFIG_COUNT} RbacConfigs, expecting only 1. Please delete extra RbacConfigs and execute again." + exit 1 +fi + +NS=$(echo "${RBAC_CONFIGS}" | cut -f 1 -d ' ') +echo "converting RbacConfig in namespace $NS to ClusterRbacConfig" + +SPEC=$(kubectl get RbacConfig default -n "${NS}" -o yaml | sed -n -e '/spec:/,$p') + +cat <&2 +} + +usage() { + error 'Collect all possible data from a Kubernetes cluster using kubectl.' + error '' + error 'Usage:' + error ' dump_kubernetes.sh [options]' + error '' + error 'Options:' + error ' -d, --output-directory directory to output files; defaults to' + error ' "istio-dump"' + error ' -z, --archive if present, archives and removes the output' + error ' directory' + error ' -q, --quiet if present, do not log' + error ' -m, --max-bytes max total bytes, 0=no limit, default='${DEFAULT_MAX_LOG_BYTES} + error ' -l, --label if set, dump logs only for pods with given labels e.g. "-l app=pilot -l istio=galley"' + error ' -n, --namespace if set, dump logs only for pods in the given namespaces e.g. "-n default -n istio-system"' + error ' --error-if-nasty-logs if present, exit with 255 if any logs' + error ' contain errors' + exit 1 +} + +log() { + local msg="${1}" + if [ "${QUIET}" = false ]; then + printf '%s\n' "${msg}" + fi +} + +parse_args() { + local max_bytes="${DEFAULT_MAX_LOG_BYTES}" + while [ "$#" -gt 0 ]; do + case "${1}" in + -d|--output-directory) + local out_dir="${2}" + shift 2 # Shift past option and value. + ;; + -z|--archive) + local should_archive=true + shift # Shift past flag. + ;; + -q|--quiet) + local quiet=true + shift # Shift past flag. + ;; + --error-if-nasty-logs) + local should_check_logs_for_errors=true + shift # Shift past flag. + ;; + -m|--max-bytes) + max_bytes="${2}" + shift 2 + ;; + -l|--label) + pod_labels+="${2} " + shift 2 + ;; + -n|--namespace) + namespaces+="${2} " + shift 2 + ;; + *) + usage + ;; + esac + done + + readonly OUT_DIR="${out_dir:-istio-dump}" + readonly SHOULD_ARCHIVE="${should_archive:-false}" + readonly QUIET="${quiet:-false}" + readonly SHOULD_CHECK_LOGS_FOR_ERRORS="${should_check_logs_for_errors:-false}" + readonly LOG_DIR="${OUT_DIR}/logs" + readonly RESOURCES_FILE="${OUT_DIR}/resources.yaml" + readonly ISTIO_RESOURCES_FILE="${OUT_DIR}/istio-resources.yaml" + readonly MAX_LOG_BYTES="${max_bytes}" +} + +check_prerequisites() { + local prerequisites=$* + for prerequisite in ${prerequisites}; do + if ! command -v "${prerequisite}" > /dev/null; then + error "\"${prerequisite}\" is required. Please install it." + return 1 + fi + done +} + +dump_time() { + mkdir -p "${OUT_DIR}" + date -u > "${OUT_DIR}/DUMP_TIME" +} + +# mv_unless_max_exceeded src_file dest_file performs mv src_file dest_file unless the global variable stored_log_bytes +# would exceed max_log_bytes. +# If total not exceeded, file is moved and max_log_bytes updated, otherwise an error is logged. +# src_file is always deleted when calling this function. +mv_unless_max_exceeded() { + local src_file="${1}" + local dst_file="${2}" + + file_size=$(wc -c "${src_file}" | awk '{print $1}') + local nsb=$((stored_log_bytes + file_size)) + + if (("${nsb}" > "${MAX_LOG_BYTES}")); then + log "Not storing ${log_file} because appending its ${file_size} bytes would exceed max logged bytes ${MAX_LOG_BYTES}" + rm "${src_file}" + else + dirn=$(dirname "${dst_file}") + mkdir -p "${dirn}" + mv "${src_file}" "${dst_file}" + stored_log_bytes="${nsb}" + fi +} + +dump_logs_for_container() { + local namespace="${1}" + local pod="${2}" + local container="${3}" + + log "Retrieving logs for ${namespace}/${pod}/${container}" + + mkdir -p "${LOG_DIR}/${namespace}/${pod}" + local log_file_head="${LOG_DIR}/${namespace}/${pod}/${container}" + local temp_log_file="${LOG_DIR}/temp_log_file.log" + + local log_file="${log_file_head}.log" + kubectl logs --namespace="${namespace}" "${pod}" "${container}" \ + > "${temp_log_file}" + mv_unless_max_exceeded "${temp_log_file}" "${log_file}" + + local filter="?(@.name == \"${container}\")" + local json_path='{.status.containerStatuses['${filter}'].restartCount}' + local restart_count + restart_count=$(kubectl get --namespace="${namespace}" \ + pod "${pod}" -o=jsonpath="${json_path}") + # (There will be no restart_count if the pod status is for example "Pending") + if [ -n "${restart_count}" ] && [ "${restart_count}" -gt 0 ]; then + log "Retrieving previous logs for ${namespace}/${pod}/${container}" + + local log_previous_file + log_previous_file="${log_file_head}_previous.log" + kubectl logs --namespace="${namespace}" \ + --previous "${pod}" "${container}" \ + > "${temp_log_file}" + mv_unless_max_exceeded "${temp_log_file}" "${log_previous_file}" + fi +} + +copy_core_dumps_if_istio_proxy() { + local namespace="${1}" + local pod="${2}" + local container="${3}" + local got_core_dump=false + + if [ "istio-proxy" = "${container}" ]; then + local out_dir="${LOG_DIR}/${namespace}/${pod}" + mkdir -p "${out_dir}" + local core_dumps + core_dumps=$(kubectl exec -n "${namespace}" "${pod}" -c "${container}" -- \ + find ${COREDUMP_DIR} -name 'core.*') + for f in ${core_dumps}; do + local out_file + out_file="${out_dir}/$(basename "${f}")" + + kubectl exec -n "${namespace}" "${pod}" -c "${container}" -- \ + cat "${f}" > "${out_file}" + + log "Copied ${namespace}/${pod}/${container}:${f} to ${out_file}" + got_core_dump=true + done + fi + if [ "${got_core_dump}" = true ]; then + return 254 + fi +} + +# Run functions on each container. Each argument should be a function which +# takes 3 args: ${namespace} ${pod} ${container}. +# If any of the called functions returns error, tap_containers returns +# immediately with that error. +tap_containers() { + local functions=("$@") + if [ -z "${namespaces}" ]; then + namespaces=$(kubectl get \ + namespaces -o=jsonpath="{.items[*].metadata.name}") + fi + for namespace in ${namespaces}; do + local pods="" + if [ -n "${pod_labels}" ]; then + for label in $pod_labels; do + pods+=$(kubectl get --namespace="${namespace}" -l"${label}" \ + pods -o=jsonpath='{.items[*].metadata.name}')" " + done + else + pods=$(kubectl get --namespace="${namespace}" \ + pods -o=jsonpath='{.items[*].metadata.name}') + fi + for pod in ${pods}; do + local containers + containers=$(kubectl get --namespace="${namespace}" \ + pod "${pod}" -o=jsonpath='{.spec.containers[*].name}') + for container in ${containers}; do + for f in "${functions[@]}"; do + "${f}" "${namespace}" "${pod}" "${container}" || return $? + done + done + done + done + + return 0 +} + +dump_kubernetes_resources() { + log "Retrieving Kubernetes resource configurations" + + mkdir -p "${OUT_DIR}" + # Only works in Kubernetes 1.8.0 and above. + kubectl get --all-namespaces --export \ + all,jobs,ingresses,endpoints,customresourcedefinitions,configmaps,secrets,events \ + -o yaml > "${RESOURCES_FILE}" +} + +dump_istio_custom_resource_definitions() { + log "Retrieving Istio resource configurations" + + local istio_resources + # Trim to only first field; join by comma; remove last comma. + istio_resources=$(kubectl get customresourcedefinitions \ + --no-headers 2> /dev/null \ + | cut -d ' ' -f 1 \ + | tr '\n' ',' \ + | sed 's/,$//') + + if [ -n "${istio_resources}" ]; then + kubectl get "${istio_resources}" --all-namespaces -o yaml \ + > "${ISTIO_RESOURCES_FILE}" + fi +} + +dump_resources() { + dump_kubernetes_resources + dump_istio_custom_resource_definitions + + mkdir -p "${OUT_DIR}" + kubectl cluster-info dump > "${OUT_DIR}/cluster-info.dump.txt" + kubectl describe pods -n istio-system > "${OUT_DIR}/istio-system-pods.txt" + kubectl get events --all-namespaces -o wide > "${OUT_DIR}/events.txt" +} + +dump_pilot_url(){ + local pilot_pod=$1 + local url=$2 + local dname=$3 + local outfile + + outfile="${dname}/$(basename "${url}")-${pilot_pod}" + + log "Fetching ${url} from pilot" + kubectl -n istio-system exec -i -t "${pilot_pod}" -c istio-proxy -- \ + curl "http://localhost:8080/${url}" > "${outfile}" +} + +dump_pilot() { + local pilot_pods + pilot_pods=$(kubectl -n istio-system get pods -l istio=pilot \ + -o jsonpath='{.items[*].metadata.name}') + + if [ -n "${pilot_pods}" ]; then + local pilot_dir="${OUT_DIR}/pilot" + mkdir -p "${pilot_dir}" + for pilot_pod in ${pilot_pods} + do + dump_pilot_url "${pilot_pod}" debug/configz "${pilot_dir}" + dump_pilot_url "${pilot_pod}" debug/endpointz "${pilot_dir}" + dump_pilot_url "${pilot_pod}" debug/adsz "${pilot_dir}" + dump_pilot_url "${pilot_pod}" debug/authenticationz "${pilot_dir}" + dump_pilot_url "${pilot_pod}" metrics "${pilot_dir}" + done + fi +} + +archive() { + local parent_dir + parent_dir=$(dirname "${OUT_DIR}") + local dir + dir=$(basename "${OUT_DIR}") + + pushd "${parent_dir}" > /dev/null || exit + tar -czf "${dir}.tar.gz" "${dir}" + popd > /dev/null || exit + + log "Wrote ${parent_dir}/${dir}.tar.gz" +} + +check_logs_for_errors() { + log "Searching logs for errors." + grep -R --include "${LOG_DIR}/*.log" --ignore-case -e 'segmentation fault' +} + +main() { + local exit_code=0 + parse_args "$@" + check_prerequisites kubectl + dump_time + dump_pilot + dump_resources + tap_containers "dump_logs_for_container" "copy_core_dumps_if_istio_proxy" + exit_code=$? + + if [ "${SHOULD_CHECK_LOGS_FOR_ERRORS}" = true ]; then + if ! check_logs_for_errors; then + exit_code=255 + fi + fi + + if [ "${SHOULD_ARCHIVE}" = true ] ; then + archive + rm -r "${OUT_DIR}" + fi + log "Wrote to ${OUT_DIR}" + + return ${exit_code} +} + +stored_log_bytes=0 + +main "$@" diff --git a/istio-1.5.0/tools/istioctl.bash b/istio-1.5.0/tools/istioctl.bash new file mode 100644 index 0000000..af55867 --- /dev/null +++ b/istio-1.5.0/tools/istioctl.bash @@ -0,0 +1,3389 @@ +# bash completion for istioctl -*- shell-script -*- + +__istioctl_debug() +{ + if [[ -n ${BASH_COMP_DEBUG_FILE} ]]; then + echo "$*" >> "${BASH_COMP_DEBUG_FILE}" + fi +} + +# Homebrew on Macs have version 1.3 of bash-completion which doesn't include +# _init_completion. This is a very minimal version of that function. +__istioctl_init_completion() +{ + COMPREPLY=() + _get_comp_words_by_ref "$@" cur prev words cword +} + +__istioctl_index_of_word() +{ + local w word=$1 + shift + index=0 + for w in "$@"; do + [[ $w = "$word" ]] && return + index=$((index+1)) + done + index=-1 +} + +__istioctl_contains_word() +{ + local w word=$1; shift + for w in "$@"; do + [[ $w = "$word" ]] && return + done + return 1 +} + +__istioctl_handle_reply() +{ + __istioctl_debug "${FUNCNAME[0]}" + case $cur in + -*) + if [[ $(type -t compopt) = "builtin" ]]; then + compopt -o nospace + fi + local allflags + if [ ${#must_have_one_flag[@]} -ne 0 ]; then + allflags=("${must_have_one_flag[@]}") + else + allflags=("${flags[*]} ${two_word_flags[*]}") + fi + COMPREPLY=( $(compgen -W "${allflags[*]}" -- "$cur") ) + if [[ $(type -t compopt) = "builtin" ]]; then + [[ "${COMPREPLY[0]}" == *= ]] || compopt +o nospace + fi + + # complete after --flag=abc + if [[ $cur == *=* ]]; then + if [[ $(type -t compopt) = "builtin" ]]; then + compopt +o nospace + fi + + local index flag + flag="${cur%=*}" + __istioctl_index_of_word "${flag}" "${flags_with_completion[@]}" + COMPREPLY=() + if [[ ${index} -ge 0 ]]; then + PREFIX="" + cur="${cur#*=}" + ${flags_completion[${index}]} + if [ -n "${ZSH_VERSION}" ]; then + # zsh completion needs --flag= prefix + eval "COMPREPLY=( \"\${COMPREPLY[@]/#/${flag}=}\" )" + fi + fi + fi + return 0; + ;; + esac + + # check if we are handling a flag with special work handling + local index + __istioctl_index_of_word "${prev}" "${flags_with_completion[@]}" + if [[ ${index} -ge 0 ]]; then + ${flags_completion[${index}]} + return + fi + + # we are parsing a flag and don't have a special handler, no completion + if [[ ${cur} != "${words[cword]}" ]]; then + return + fi + + local completions + completions=("${commands[@]}") + if [[ ${#must_have_one_noun[@]} -ne 0 ]]; then + completions=("${must_have_one_noun[@]}") + fi + if [[ ${#must_have_one_flag[@]} -ne 0 ]]; then + completions+=("${must_have_one_flag[@]}") + fi + COMPREPLY=( $(compgen -W "${completions[*]}" -- "$cur") ) + + if [[ ${#COMPREPLY[@]} -eq 0 && ${#noun_aliases[@]} -gt 0 && ${#must_have_one_noun[@]} -ne 0 ]]; then + COMPREPLY=( $(compgen -W "${noun_aliases[*]}" -- "$cur") ) + fi + + if [[ ${#COMPREPLY[@]} -eq 0 ]]; then + if declare -F __istioctl_custom_func >/dev/null; then + # try command name qualified custom func + __istioctl_custom_func + else + # otherwise fall back to unqualified for compatibility + declare -F __custom_func >/dev/null && __custom_func + fi + fi + + # available in bash-completion >= 2, not always present on macOS + if declare -F __ltrim_colon_completions >/dev/null; then + __ltrim_colon_completions "$cur" + fi + + # If there is only 1 completion and it is a flag with an = it will be completed + # but we don't want a space after the = + if [[ "${#COMPREPLY[@]}" -eq "1" ]] && [[ $(type -t compopt) = "builtin" ]] && [[ "${COMPREPLY[0]}" == --*= ]]; then + compopt -o nospace + fi +} + +# The arguments should be in the form "ext1|ext2|extn" +__istioctl_handle_filename_extension_flag() +{ + local ext="$1" + _filedir "@(${ext})" +} + +__istioctl_handle_subdirs_in_dir_flag() +{ + local dir="$1" + pushd "${dir}" >/dev/null 2>&1 && _filedir -d && popd >/dev/null 2>&1 +} + +__istioctl_handle_flag() +{ + __istioctl_debug "${FUNCNAME[0]}: c is $c words[c] is ${words[c]}" + + # if a command required a flag, and we found it, unset must_have_one_flag() + local flagname=${words[c]} + local flagvalue + # if the word contained an = + if [[ ${words[c]} == *"="* ]]; then + flagvalue=${flagname#*=} # take in as flagvalue after the = + flagname=${flagname%=*} # strip everything after the = + flagname="${flagname}=" # but put the = back + fi + __istioctl_debug "${FUNCNAME[0]}: looking for ${flagname}" + if __istioctl_contains_word "${flagname}" "${must_have_one_flag[@]}"; then + must_have_one_flag=() + fi + + # if you set a flag which only applies to this command, don't show subcommands + if __istioctl_contains_word "${flagname}" "${local_nonpersistent_flags[@]}"; then + commands=() + fi + + # keep flag value with flagname as flaghash + # flaghash variable is an associative array which is only supported in bash > 3. + if [[ -z "${BASH_VERSION}" || "${BASH_VERSINFO[0]}" -gt 3 ]]; then + if [ -n "${flagvalue}" ] ; then + flaghash[${flagname}]=${flagvalue} + elif [ -n "${words[ $((c+1)) ]}" ] ; then + flaghash[${flagname}]=${words[ $((c+1)) ]} + else + flaghash[${flagname}]="true" # pad "true" for bool flag + fi + fi + + # skip the argument to a two word flag + if [[ ${words[c]} != *"="* ]] && __istioctl_contains_word "${words[c]}" "${two_word_flags[@]}"; then + __istioctl_debug "${FUNCNAME[0]}: found a flag ${words[c]}, skip the next argument" + c=$((c+1)) + # if we are looking for a flags value, don't show commands + if [[ $c -eq $cword ]]; then + commands=() + fi + fi + + c=$((c+1)) + +} + +__istioctl_handle_noun() +{ + __istioctl_debug "${FUNCNAME[0]}: c is $c words[c] is ${words[c]}" + + if __istioctl_contains_word "${words[c]}" "${must_have_one_noun[@]}"; then + must_have_one_noun=() + elif __istioctl_contains_word "${words[c]}" "${noun_aliases[@]}"; then + must_have_one_noun=() + fi + + nouns+=("${words[c]}") + c=$((c+1)) +} + +__istioctl_handle_command() +{ + __istioctl_debug "${FUNCNAME[0]}: c is $c words[c] is ${words[c]}" + + local next_command + if [[ -n ${last_command} ]]; then + next_command="_${last_command}_${words[c]//:/__}" + else + if [[ $c -eq 0 ]]; then + next_command="_istioctl_root_command" + else + next_command="_${words[c]//:/__}" + fi + fi + c=$((c+1)) + __istioctl_debug "${FUNCNAME[0]}: looking for ${next_command}" + declare -F "$next_command" >/dev/null && $next_command +} + +__istioctl_handle_word() +{ + if [[ $c -ge $cword ]]; then + __istioctl_handle_reply + return + fi + __istioctl_debug "${FUNCNAME[0]}: c is $c words[c] is ${words[c]}" + if [[ "${words[c]}" == -* ]]; then + __istioctl_handle_flag + elif __istioctl_contains_word "${words[c]}" "${commands[@]}"; then + __istioctl_handle_command + elif [[ $c -eq 0 ]]; then + __istioctl_handle_command + elif __istioctl_contains_word "${words[c]}" "${command_aliases[@]}"; then + # aliashash variable is an associative array which is only supported in bash > 3. + if [[ -z "${BASH_VERSION}" || "${BASH_VERSINFO[0]}" -gt 3 ]]; then + words[c]=${aliashash[${words[c]}]} + __istioctl_handle_command + else + __istioctl_handle_noun + fi + else + __istioctl_handle_noun + fi + __istioctl_handle_word +} + +_istioctl_analyze() +{ + last_command="istioctl_analyze" + + command_aliases=() + + commands=() + + flags=() + two_word_flags=() + local_nonpersistent_flags=() + flags_with_completion=() + flags_completion=() + + flags+=("--all-namespaces") + flags+=("-A") + flags+=("--color") + flags+=("--failure-threshold=") + two_word_flags+=("--failure-threshold") + flags+=("--list-analyzers") + flags+=("-L") + flags+=("--meshConfigFile=") + two_word_flags+=("--meshConfigFile") + flags+=("--output=") + two_word_flags+=("--output") + two_word_flags+=("-o") + flags+=("--output-threshold=") + two_word_flags+=("--output-threshold") + flags+=("--recursive") + flags+=("-R") + flags+=("--suppress=") + two_word_flags+=("--suppress") + two_word_flags+=("-S") + flags+=("--timeout=") + two_word_flags+=("--timeout") + flags+=("--use-kube") + flags+=("-k") + flags+=("--verbose") + flags+=("-v") + flags+=("--context=") + two_word_flags+=("--context") + flags+=("--istioNamespace=") + two_word_flags+=("--istioNamespace") + two_word_flags+=("-i") + flags+=("--kubeconfig=") + two_word_flags+=("--kubeconfig") + two_word_flags+=("-c") + flags+=("--log_output_level=") + two_word_flags+=("--log_output_level") + flags+=("--namespace=") + two_word_flags+=("--namespace") + two_word_flags+=("-n") + + must_have_one_flag=() + must_have_one_noun=() + noun_aliases=() +} + +_istioctl_authn_tls-check() +{ + last_command="istioctl_authn_tls-check" + + command_aliases=() + + commands=() + + flags=() + two_word_flags=() + local_nonpersistent_flags=() + flags_with_completion=() + flags_completion=() + + flags+=("--context=") + two_word_flags+=("--context") + flags+=("--istioNamespace=") + two_word_flags+=("--istioNamespace") + two_word_flags+=("-i") + flags+=("--kubeconfig=") + two_word_flags+=("--kubeconfig") + two_word_flags+=("-c") + flags+=("--log_output_level=") + two_word_flags+=("--log_output_level") + flags+=("--namespace=") + two_word_flags+=("--namespace") + two_word_flags+=("-n") + + must_have_one_flag=() + must_have_one_noun=() + noun_aliases=() +} + +_istioctl_authn() +{ + last_command="istioctl_authn" + + command_aliases=() + + commands=() + commands+=("tls-check") + + flags=() + two_word_flags=() + local_nonpersistent_flags=() + flags_with_completion=() + flags_completion=() + + flags+=("--context=") + two_word_flags+=("--context") + flags+=("--istioNamespace=") + two_word_flags+=("--istioNamespace") + two_word_flags+=("-i") + flags+=("--kubeconfig=") + two_word_flags+=("--kubeconfig") + two_word_flags+=("-c") + flags+=("--log_output_level=") + two_word_flags+=("--log_output_level") + flags+=("--namespace=") + two_word_flags+=("--namespace") + two_word_flags+=("-n") + + must_have_one_flag=() + must_have_one_noun=() + noun_aliases=() +} + +_istioctl_authz() +{ + last_command="istioctl_authz" + + command_aliases=() + + commands=() + + flags=() + two_word_flags=() + local_nonpersistent_flags=() + flags_with_completion=() + flags_completion=() + + flags+=("--context=") + two_word_flags+=("--context") + flags+=("--istioNamespace=") + two_word_flags+=("--istioNamespace") + two_word_flags+=("-i") + flags+=("--kubeconfig=") + two_word_flags+=("--kubeconfig") + two_word_flags+=("-c") + flags+=("--log_output_level=") + two_word_flags+=("--log_output_level") + flags+=("--namespace=") + two_word_flags+=("--namespace") + two_word_flags+=("-n") + + must_have_one_flag=() + must_have_one_noun=() + noun_aliases=() +} + +_istioctl_convert-ingress() +{ + last_command="istioctl_convert-ingress" + + command_aliases=() + + commands=() + + flags=() + two_word_flags=() + local_nonpersistent_flags=() + flags_with_completion=() + flags_completion=() + + flags+=("--filenames=") + two_word_flags+=("--filenames") + two_word_flags+=("-f") + flags+=("--output=") + two_word_flags+=("--output") + two_word_flags+=("-o") + flags+=("--context=") + two_word_flags+=("--context") + flags+=("--istioNamespace=") + two_word_flags+=("--istioNamespace") + two_word_flags+=("-i") + flags+=("--kubeconfig=") + two_word_flags+=("--kubeconfig") + two_word_flags+=("-c") + flags+=("--log_output_level=") + two_word_flags+=("--log_output_level") + flags+=("--namespace=") + two_word_flags+=("--namespace") + two_word_flags+=("-n") + + must_have_one_flag=() + must_have_one_noun=() + noun_aliases=() +} + +_istioctl_dashboard_controlz() +{ + last_command="istioctl_dashboard_controlz" + + command_aliases=() + + commands=() + + flags=() + two_word_flags=() + local_nonpersistent_flags=() + flags_with_completion=() + flags_completion=() + + flags+=("--ctrlz_port=") + two_word_flags+=("--ctrlz_port") + flags+=("--selector=") + two_word_flags+=("--selector") + two_word_flags+=("-l") + flags+=("--context=") + two_word_flags+=("--context") + flags+=("--istioNamespace=") + two_word_flags+=("--istioNamespace") + two_word_flags+=("-i") + flags+=("--kubeconfig=") + two_word_flags+=("--kubeconfig") + two_word_flags+=("-c") + flags+=("--log_output_level=") + two_word_flags+=("--log_output_level") + flags+=("--namespace=") + two_word_flags+=("--namespace") + two_word_flags+=("-n") + + must_have_one_flag=() + must_have_one_noun=() + noun_aliases=() +} + +_istioctl_dashboard_envoy() +{ + last_command="istioctl_dashboard_envoy" + + command_aliases=() + + commands=() + + flags=() + two_word_flags=() + local_nonpersistent_flags=() + flags_with_completion=() + flags_completion=() + + flags+=("--selector=") + two_word_flags+=("--selector") + two_word_flags+=("-l") + flags+=("--context=") + two_word_flags+=("--context") + flags+=("--istioNamespace=") + two_word_flags+=("--istioNamespace") + two_word_flags+=("-i") + flags+=("--kubeconfig=") + two_word_flags+=("--kubeconfig") + two_word_flags+=("-c") + flags+=("--log_output_level=") + two_word_flags+=("--log_output_level") + flags+=("--namespace=") + two_word_flags+=("--namespace") + two_word_flags+=("-n") + + must_have_one_flag=() + must_have_one_noun=() + noun_aliases=() +} + +_istioctl_dashboard_grafana() +{ + last_command="istioctl_dashboard_grafana" + + command_aliases=() + + commands=() + + flags=() + two_word_flags=() + local_nonpersistent_flags=() + flags_with_completion=() + flags_completion=() + + flags+=("--context=") + two_word_flags+=("--context") + flags+=("--istioNamespace=") + two_word_flags+=("--istioNamespace") + two_word_flags+=("-i") + flags+=("--kubeconfig=") + two_word_flags+=("--kubeconfig") + two_word_flags+=("-c") + flags+=("--log_output_level=") + two_word_flags+=("--log_output_level") + flags+=("--namespace=") + two_word_flags+=("--namespace") + two_word_flags+=("-n") + + must_have_one_flag=() + must_have_one_noun=() + noun_aliases=() +} + +_istioctl_dashboard_jaeger() +{ + last_command="istioctl_dashboard_jaeger" + + command_aliases=() + + commands=() + + flags=() + two_word_flags=() + local_nonpersistent_flags=() + flags_with_completion=() + flags_completion=() + + flags+=("--context=") + two_word_flags+=("--context") + flags+=("--istioNamespace=") + two_word_flags+=("--istioNamespace") + two_word_flags+=("-i") + flags+=("--kubeconfig=") + two_word_flags+=("--kubeconfig") + two_word_flags+=("-c") + flags+=("--log_output_level=") + two_word_flags+=("--log_output_level") + flags+=("--namespace=") + two_word_flags+=("--namespace") + two_word_flags+=("-n") + + must_have_one_flag=() + must_have_one_noun=() + noun_aliases=() +} + +_istioctl_dashboard_kiali() +{ + last_command="istioctl_dashboard_kiali" + + command_aliases=() + + commands=() + + flags=() + two_word_flags=() + local_nonpersistent_flags=() + flags_with_completion=() + flags_completion=() + + flags+=("--context=") + two_word_flags+=("--context") + flags+=("--istioNamespace=") + two_word_flags+=("--istioNamespace") + two_word_flags+=("-i") + flags+=("--kubeconfig=") + two_word_flags+=("--kubeconfig") + two_word_flags+=("-c") + flags+=("--log_output_level=") + two_word_flags+=("--log_output_level") + flags+=("--namespace=") + two_word_flags+=("--namespace") + two_word_flags+=("-n") + + must_have_one_flag=() + must_have_one_noun=() + noun_aliases=() +} + +_istioctl_dashboard_prometheus() +{ + last_command="istioctl_dashboard_prometheus" + + command_aliases=() + + commands=() + + flags=() + two_word_flags=() + local_nonpersistent_flags=() + flags_with_completion=() + flags_completion=() + + flags+=("--context=") + two_word_flags+=("--context") + flags+=("--istioNamespace=") + two_word_flags+=("--istioNamespace") + two_word_flags+=("-i") + flags+=("--kubeconfig=") + two_word_flags+=("--kubeconfig") + two_word_flags+=("-c") + flags+=("--log_output_level=") + two_word_flags+=("--log_output_level") + flags+=("--namespace=") + two_word_flags+=("--namespace") + two_word_flags+=("-n") + + must_have_one_flag=() + must_have_one_noun=() + noun_aliases=() +} + +_istioctl_dashboard_zipkin() +{ + last_command="istioctl_dashboard_zipkin" + + command_aliases=() + + commands=() + + flags=() + two_word_flags=() + local_nonpersistent_flags=() + flags_with_completion=() + flags_completion=() + + flags+=("--context=") + two_word_flags+=("--context") + flags+=("--istioNamespace=") + two_word_flags+=("--istioNamespace") + two_word_flags+=("-i") + flags+=("--kubeconfig=") + two_word_flags+=("--kubeconfig") + two_word_flags+=("-c") + flags+=("--log_output_level=") + two_word_flags+=("--log_output_level") + flags+=("--namespace=") + two_word_flags+=("--namespace") + two_word_flags+=("-n") + + must_have_one_flag=() + must_have_one_noun=() + noun_aliases=() +} + +_istioctl_dashboard() +{ + last_command="istioctl_dashboard" + + command_aliases=() + + commands=() + commands+=("controlz") + commands+=("envoy") + commands+=("grafana") + commands+=("jaeger") + commands+=("kiali") + commands+=("prometheus") + commands+=("zipkin") + + flags=() + two_word_flags=() + local_nonpersistent_flags=() + flags_with_completion=() + flags_completion=() + + flags+=("--context=") + two_word_flags+=("--context") + flags+=("--istioNamespace=") + two_word_flags+=("--istioNamespace") + two_word_flags+=("-i") + flags+=("--kubeconfig=") + two_word_flags+=("--kubeconfig") + two_word_flags+=("-c") + flags+=("--log_output_level=") + two_word_flags+=("--log_output_level") + flags+=("--namespace=") + two_word_flags+=("--namespace") + two_word_flags+=("-n") + + must_have_one_flag=() + must_have_one_noun=() + noun_aliases=() +} + +_istioctl_deregister() +{ + last_command="istioctl_deregister" + + command_aliases=() + + commands=() + + flags=() + two_word_flags=() + local_nonpersistent_flags=() + flags_with_completion=() + flags_completion=() + + flags+=("--context=") + two_word_flags+=("--context") + flags+=("--istioNamespace=") + two_word_flags+=("--istioNamespace") + two_word_flags+=("-i") + flags+=("--kubeconfig=") + two_word_flags+=("--kubeconfig") + two_word_flags+=("-c") + flags+=("--log_output_level=") + two_word_flags+=("--log_output_level") + flags+=("--namespace=") + two_word_flags+=("--namespace") + two_word_flags+=("-n") + + must_have_one_flag=() + must_have_one_noun=() + noun_aliases=() +} + +_istioctl_experimental_add-to-mesh_deployment() +{ + last_command="istioctl_experimental_add-to-mesh_deployment" + + command_aliases=() + + commands=() + + flags=() + two_word_flags=() + local_nonpersistent_flags=() + flags_with_completion=() + flags_completion=() + + flags+=("--context=") + two_word_flags+=("--context") + flags+=("--injectConfigFile=") + two_word_flags+=("--injectConfigFile") + flags+=("--injectConfigMapName=") + two_word_flags+=("--injectConfigMapName") + flags+=("--istioNamespace=") + two_word_flags+=("--istioNamespace") + two_word_flags+=("-i") + flags+=("--kubeconfig=") + two_word_flags+=("--kubeconfig") + two_word_flags+=("-c") + flags+=("--log_output_level=") + two_word_flags+=("--log_output_level") + flags+=("--meshConfigFile=") + two_word_flags+=("--meshConfigFile") + flags+=("--meshConfigMapName=") + two_word_flags+=("--meshConfigMapName") + flags+=("--namespace=") + two_word_flags+=("--namespace") + two_word_flags+=("-n") + flags+=("--valuesFile=") + two_word_flags+=("--valuesFile") + + must_have_one_flag=() + must_have_one_noun=() + noun_aliases=() +} + +_istioctl_experimental_add-to-mesh_external-service() +{ + last_command="istioctl_experimental_add-to-mesh_external-service" + + command_aliases=() + + commands=() + + flags=() + two_word_flags=() + local_nonpersistent_flags=() + flags_with_completion=() + flags_completion=() + + flags+=("--annotations=") + two_word_flags+=("--annotations") + two_word_flags+=("-a") + flags+=("--labels=") + two_word_flags+=("--labels") + two_word_flags+=("-l") + flags+=("--serviceaccount=") + two_word_flags+=("--serviceaccount") + two_word_flags+=("-s") + flags+=("--context=") + two_word_flags+=("--context") + flags+=("--injectConfigFile=") + two_word_flags+=("--injectConfigFile") + flags+=("--injectConfigMapName=") + two_word_flags+=("--injectConfigMapName") + flags+=("--istioNamespace=") + two_word_flags+=("--istioNamespace") + two_word_flags+=("-i") + flags+=("--kubeconfig=") + two_word_flags+=("--kubeconfig") + two_word_flags+=("-c") + flags+=("--log_output_level=") + two_word_flags+=("--log_output_level") + flags+=("--meshConfigFile=") + two_word_flags+=("--meshConfigFile") + flags+=("--meshConfigMapName=") + two_word_flags+=("--meshConfigMapName") + flags+=("--namespace=") + two_word_flags+=("--namespace") + two_word_flags+=("-n") + flags+=("--valuesFile=") + two_word_flags+=("--valuesFile") + + must_have_one_flag=() + must_have_one_noun=() + noun_aliases=() +} + +_istioctl_experimental_add-to-mesh_service() +{ + last_command="istioctl_experimental_add-to-mesh_service" + + command_aliases=() + + commands=() + + flags=() + two_word_flags=() + local_nonpersistent_flags=() + flags_with_completion=() + flags_completion=() + + flags+=("--context=") + two_word_flags+=("--context") + flags+=("--injectConfigFile=") + two_word_flags+=("--injectConfigFile") + flags+=("--injectConfigMapName=") + two_word_flags+=("--injectConfigMapName") + flags+=("--istioNamespace=") + two_word_flags+=("--istioNamespace") + two_word_flags+=("-i") + flags+=("--kubeconfig=") + two_word_flags+=("--kubeconfig") + two_word_flags+=("-c") + flags+=("--log_output_level=") + two_word_flags+=("--log_output_level") + flags+=("--meshConfigFile=") + two_word_flags+=("--meshConfigFile") + flags+=("--meshConfigMapName=") + two_word_flags+=("--meshConfigMapName") + flags+=("--namespace=") + two_word_flags+=("--namespace") + two_word_flags+=("-n") + flags+=("--valuesFile=") + two_word_flags+=("--valuesFile") + + must_have_one_flag=() + must_have_one_noun=() + noun_aliases=() +} + +_istioctl_experimental_add-to-mesh() +{ + last_command="istioctl_experimental_add-to-mesh" + + command_aliases=() + + commands=() + commands+=("deployment") + commands+=("external-service") + commands+=("service") + + flags=() + two_word_flags=() + local_nonpersistent_flags=() + flags_with_completion=() + flags_completion=() + + flags+=("--injectConfigFile=") + two_word_flags+=("--injectConfigFile") + flags+=("--injectConfigMapName=") + two_word_flags+=("--injectConfigMapName") + flags+=("--meshConfigFile=") + two_word_flags+=("--meshConfigFile") + flags+=("--meshConfigMapName=") + two_word_flags+=("--meshConfigMapName") + flags+=("--valuesFile=") + two_word_flags+=("--valuesFile") + flags+=("--context=") + two_word_flags+=("--context") + flags+=("--istioNamespace=") + two_word_flags+=("--istioNamespace") + two_word_flags+=("-i") + flags+=("--kubeconfig=") + two_word_flags+=("--kubeconfig") + two_word_flags+=("-c") + flags+=("--log_output_level=") + two_word_flags+=("--log_output_level") + flags+=("--namespace=") + two_word_flags+=("--namespace") + two_word_flags+=("-n") + + must_have_one_flag=() + must_have_one_noun=() + noun_aliases=() +} + +_istioctl_experimental_analyze() +{ + last_command="istioctl_experimental_analyze" + + command_aliases=() + + commands=() + + flags=() + two_word_flags=() + local_nonpersistent_flags=() + flags_with_completion=() + flags_completion=() + + flags+=("--all-namespaces") + flags+=("-A") + flags+=("--color") + flags+=("--failure-threshold=") + two_word_flags+=("--failure-threshold") + flags+=("--list-analyzers") + flags+=("-L") + flags+=("--meshConfigFile=") + two_word_flags+=("--meshConfigFile") + flags+=("--output=") + two_word_flags+=("--output") + two_word_flags+=("-o") + flags+=("--output-threshold=") + two_word_flags+=("--output-threshold") + flags+=("--recursive") + flags+=("-R") + flags+=("--suppress=") + two_word_flags+=("--suppress") + two_word_flags+=("-S") + flags+=("--timeout=") + two_word_flags+=("--timeout") + flags+=("--use-kube") + flags+=("-k") + flags+=("--verbose") + flags+=("-v") + flags+=("--context=") + two_word_flags+=("--context") + flags+=("--istioNamespace=") + two_word_flags+=("--istioNamespace") + two_word_flags+=("-i") + flags+=("--kubeconfig=") + two_word_flags+=("--kubeconfig") + two_word_flags+=("-c") + flags+=("--log_output_level=") + two_word_flags+=("--log_output_level") + flags+=("--namespace=") + two_word_flags+=("--namespace") + two_word_flags+=("-n") + + must_have_one_flag=() + must_have_one_noun=() + noun_aliases=() +} + +_istioctl_experimental_authz_check() +{ + last_command="istioctl_experimental_authz_check" + + command_aliases=() + + commands=() + + flags=() + two_word_flags=() + local_nonpersistent_flags=() + flags_with_completion=() + flags_completion=() + + flags+=("--all") + flags+=("-a") + flags+=("--file=") + two_word_flags+=("--file") + two_word_flags+=("-f") + flags+=("--context=") + two_word_flags+=("--context") + flags+=("--istioNamespace=") + two_word_flags+=("--istioNamespace") + two_word_flags+=("-i") + flags+=("--kubeconfig=") + two_word_flags+=("--kubeconfig") + two_word_flags+=("-c") + flags+=("--log_output_level=") + two_word_flags+=("--log_output_level") + flags+=("--namespace=") + two_word_flags+=("--namespace") + two_word_flags+=("-n") + + must_have_one_flag=() + must_have_one_noun=() + noun_aliases=() +} + +_istioctl_experimental_authz_convert() +{ + last_command="istioctl_experimental_authz_convert" + + command_aliases=() + + commands=() + + flags=() + two_word_flags=() + local_nonpersistent_flags=() + flags_with_completion=() + flags_completion=() + + flags+=("--allowNoClusterRbacConfig") + flags+=("--file=") + two_word_flags+=("--file") + two_word_flags+=("-f") + flags+=("--rootNamespace=") + two_word_flags+=("--rootNamespace") + two_word_flags+=("-r") + flags+=("--service=") + two_word_flags+=("--service") + two_word_flags+=("-s") + flags+=("--context=") + two_word_flags+=("--context") + flags+=("--istioNamespace=") + two_word_flags+=("--istioNamespace") + two_word_flags+=("-i") + flags+=("--kubeconfig=") + two_word_flags+=("--kubeconfig") + two_word_flags+=("-c") + flags+=("--log_output_level=") + two_word_flags+=("--log_output_level") + flags+=("--namespace=") + two_word_flags+=("--namespace") + two_word_flags+=("-n") + + must_have_one_flag=() + must_have_one_noun=() + noun_aliases=() +} + +_istioctl_experimental_authz() +{ + last_command="istioctl_experimental_authz" + + command_aliases=() + + commands=() + commands+=("check") + commands+=("convert") + + flags=() + two_word_flags=() + local_nonpersistent_flags=() + flags_with_completion=() + flags_completion=() + + flags+=("--context=") + two_word_flags+=("--context") + flags+=("--istioNamespace=") + two_word_flags+=("--istioNamespace") + two_word_flags+=("-i") + flags+=("--kubeconfig=") + two_word_flags+=("--kubeconfig") + two_word_flags+=("-c") + flags+=("--log_output_level=") + two_word_flags+=("--log_output_level") + flags+=("--namespace=") + two_word_flags+=("--namespace") + two_word_flags+=("-n") + + must_have_one_flag=() + must_have_one_noun=() + noun_aliases=() +} + +_istioctl_experimental_convert-ingress() +{ + last_command="istioctl_experimental_convert-ingress" + + command_aliases=() + + commands=() + + flags=() + two_word_flags=() + local_nonpersistent_flags=() + flags_with_completion=() + flags_completion=() + + flags+=("--context=") + two_word_flags+=("--context") + flags+=("--istioNamespace=") + two_word_flags+=("--istioNamespace") + two_word_flags+=("-i") + flags+=("--kubeconfig=") + two_word_flags+=("--kubeconfig") + two_word_flags+=("-c") + flags+=("--log_output_level=") + two_word_flags+=("--log_output_level") + flags+=("--namespace=") + two_word_flags+=("--namespace") + two_word_flags+=("-n") + + must_have_one_flag=() + must_have_one_noun=() + noun_aliases=() +} + +_istioctl_experimental_create-remote-secret() +{ + last_command="istioctl_experimental_create-remote-secret" + + command_aliases=() + + commands=() + + flags=() + two_word_flags=() + local_nonpersistent_flags=() + flags_with_completion=() + flags_completion=() + + flags+=("--auth-plugin-config=") + two_word_flags+=("--auth-plugin-config") + flags+=("--auth-plugin-name=") + two_word_flags+=("--auth-plugin-name") + flags+=("--auth-type=") + two_word_flags+=("--auth-type") + flags+=("--name=") + two_word_flags+=("--name") + flags+=("--service-account=") + two_word_flags+=("--service-account") + flags+=("--context=") + two_word_flags+=("--context") + flags+=("--istioNamespace=") + two_word_flags+=("--istioNamespace") + two_word_flags+=("-i") + flags+=("--kubeconfig=") + two_word_flags+=("--kubeconfig") + two_word_flags+=("-c") + flags+=("--log_output_level=") + two_word_flags+=("--log_output_level") + flags+=("--namespace=") + two_word_flags+=("--namespace") + two_word_flags+=("-n") + + must_have_one_flag=() + must_have_one_noun=() + noun_aliases=() +} + +_istioctl_experimental_dashboard() +{ + last_command="istioctl_experimental_dashboard" + + command_aliases=() + + commands=() + + flags=() + two_word_flags=() + local_nonpersistent_flags=() + flags_with_completion=() + flags_completion=() + + flags+=("--context=") + two_word_flags+=("--context") + flags+=("--istioNamespace=") + two_word_flags+=("--istioNamespace") + two_word_flags+=("-i") + flags+=("--kubeconfig=") + two_word_flags+=("--kubeconfig") + two_word_flags+=("-c") + flags+=("--log_output_level=") + two_word_flags+=("--log_output_level") + flags+=("--namespace=") + two_word_flags+=("--namespace") + two_word_flags+=("-n") + + must_have_one_flag=() + must_have_one_noun=() + noun_aliases=() +} + +_istioctl_experimental_describe_pod() +{ + last_command="istioctl_experimental_describe_pod" + + command_aliases=() + + commands=() + + flags=() + two_word_flags=() + local_nonpersistent_flags=() + flags_with_completion=() + flags_completion=() + + flags+=("--ignoreUnmeshed") + flags+=("--context=") + two_word_flags+=("--context") + flags+=("--istioNamespace=") + two_word_flags+=("--istioNamespace") + two_word_flags+=("-i") + flags+=("--kubeconfig=") + two_word_flags+=("--kubeconfig") + two_word_flags+=("-c") + flags+=("--log_output_level=") + two_word_flags+=("--log_output_level") + flags+=("--namespace=") + two_word_flags+=("--namespace") + two_word_flags+=("-n") + + must_have_one_flag=() + must_have_one_noun=() + noun_aliases=() +} + +_istioctl_experimental_describe_service() +{ + last_command="istioctl_experimental_describe_service" + + command_aliases=() + + commands=() + + flags=() + two_word_flags=() + local_nonpersistent_flags=() + flags_with_completion=() + flags_completion=() + + flags+=("--ignoreUnmeshed") + flags+=("--context=") + two_word_flags+=("--context") + flags+=("--istioNamespace=") + two_word_flags+=("--istioNamespace") + two_word_flags+=("-i") + flags+=("--kubeconfig=") + two_word_flags+=("--kubeconfig") + two_word_flags+=("-c") + flags+=("--log_output_level=") + two_word_flags+=("--log_output_level") + flags+=("--namespace=") + two_word_flags+=("--namespace") + two_word_flags+=("-n") + + must_have_one_flag=() + must_have_one_noun=() + noun_aliases=() +} + +_istioctl_experimental_describe() +{ + last_command="istioctl_experimental_describe" + + command_aliases=() + + commands=() + commands+=("pod") + commands+=("service") + if [[ -z "${BASH_VERSION}" || "${BASH_VERSINFO[0]}" -gt 3 ]]; then + command_aliases+=("svc") + aliashash["svc"]="service" + fi + + flags=() + two_word_flags=() + local_nonpersistent_flags=() + flags_with_completion=() + flags_completion=() + + flags+=("--context=") + two_word_flags+=("--context") + flags+=("--istioNamespace=") + two_word_flags+=("--istioNamespace") + two_word_flags+=("-i") + flags+=("--kubeconfig=") + two_word_flags+=("--kubeconfig") + two_word_flags+=("-c") + flags+=("--log_output_level=") + two_word_flags+=("--log_output_level") + flags+=("--namespace=") + two_word_flags+=("--namespace") + two_word_flags+=("-n") + + must_have_one_flag=() + must_have_one_noun=() + noun_aliases=() +} + +_istioctl_experimental_kube-uninject() +{ + last_command="istioctl_experimental_kube-uninject" + + command_aliases=() + + commands=() + + flags=() + two_word_flags=() + local_nonpersistent_flags=() + flags_with_completion=() + flags_completion=() + + flags+=("--filename=") + two_word_flags+=("--filename") + two_word_flags+=("-f") + flags+=("--output=") + two_word_flags+=("--output") + two_word_flags+=("-o") + flags+=("--context=") + two_word_flags+=("--context") + flags+=("--istioNamespace=") + two_word_flags+=("--istioNamespace") + two_word_flags+=("-i") + flags+=("--kubeconfig=") + two_word_flags+=("--kubeconfig") + two_word_flags+=("-c") + flags+=("--log_output_level=") + two_word_flags+=("--log_output_level") + flags+=("--namespace=") + two_word_flags+=("--namespace") + two_word_flags+=("-n") + + must_have_one_flag=() + must_have_one_noun=() + noun_aliases=() +} + +_istioctl_experimental_metrics() +{ + last_command="istioctl_experimental_metrics" + + command_aliases=() + + commands=() + + flags=() + two_word_flags=() + local_nonpersistent_flags=() + flags_with_completion=() + flags_completion=() + + flags+=("--context=") + two_word_flags+=("--context") + flags+=("--istioNamespace=") + two_word_flags+=("--istioNamespace") + two_word_flags+=("-i") + flags+=("--kubeconfig=") + two_word_flags+=("--kubeconfig") + two_word_flags+=("-c") + flags+=("--log_output_level=") + two_word_flags+=("--log_output_level") + flags+=("--namespace=") + two_word_flags+=("--namespace") + two_word_flags+=("-n") + + must_have_one_flag=() + must_have_one_noun=() + noun_aliases=() +} + +_istioctl_experimental_multicluster_apply() +{ + last_command="istioctl_experimental_multicluster_apply" + + command_aliases=() + + commands=() + + flags=() + two_word_flags=() + local_nonpersistent_flags=() + flags_with_completion=() + flags_completion=() + + flags+=("--filename=") + two_word_flags+=("--filename") + two_word_flags+=("-f") + flags+=("--context=") + two_word_flags+=("--context") + flags+=("--istioNamespace=") + two_word_flags+=("--istioNamespace") + two_word_flags+=("-i") + flags+=("--kubeconfig=") + two_word_flags+=("--kubeconfig") + two_word_flags+=("-c") + flags+=("--log_output_level=") + two_word_flags+=("--log_output_level") + flags+=("--namespace=") + two_word_flags+=("--namespace") + two_word_flags+=("-n") + + must_have_one_flag=() + must_have_one_noun=() + noun_aliases=() +} + +_istioctl_experimental_multicluster_describe() +{ + last_command="istioctl_experimental_multicluster_describe" + + command_aliases=() + + commands=() + + flags=() + two_word_flags=() + local_nonpersistent_flags=() + flags_with_completion=() + flags_completion=() + + flags+=("--all") + flags+=("--filename=") + two_word_flags+=("--filename") + two_word_flags+=("-f") + flags+=("--context=") + two_word_flags+=("--context") + flags+=("--istioNamespace=") + two_word_flags+=("--istioNamespace") + two_word_flags+=("-i") + flags+=("--kubeconfig=") + two_word_flags+=("--kubeconfig") + two_word_flags+=("-c") + flags+=("--log_output_level=") + two_word_flags+=("--log_output_level") + flags+=("--namespace=") + two_word_flags+=("--namespace") + two_word_flags+=("-n") + + must_have_one_flag=() + must_have_one_noun=() + noun_aliases=() +} + +_istioctl_experimental_multicluster_generate() +{ + last_command="istioctl_experimental_multicluster_generate" + + command_aliases=() + + commands=() + + flags=() + two_word_flags=() + local_nonpersistent_flags=() + flags_with_completion=() + flags_completion=() + + flags+=("--filename=") + two_word_flags+=("--filename") + two_word_flags+=("-f") + flags+=("--from=") + two_word_flags+=("--from") + flags+=("--wait-for-gateways") + flags+=("--context=") + two_word_flags+=("--context") + flags+=("--istioNamespace=") + two_word_flags+=("--istioNamespace") + two_word_flags+=("-i") + flags+=("--kubeconfig=") + two_word_flags+=("--kubeconfig") + two_word_flags+=("-c") + flags+=("--log_output_level=") + two_word_flags+=("--log_output_level") + flags+=("--namespace=") + two_word_flags+=("--namespace") + two_word_flags+=("-n") + + must_have_one_flag=() + must_have_one_noun=() + noun_aliases=() +} + +_istioctl_experimental_multicluster() +{ + last_command="istioctl_experimental_multicluster" + + command_aliases=() + + commands=() + commands+=("apply") + commands+=("describe") + commands+=("generate") + + flags=() + two_word_flags=() + local_nonpersistent_flags=() + flags_with_completion=() + flags_completion=() + + flags+=("--context=") + two_word_flags+=("--context") + flags+=("--istioNamespace=") + two_word_flags+=("--istioNamespace") + two_word_flags+=("-i") + flags+=("--kubeconfig=") + two_word_flags+=("--kubeconfig") + two_word_flags+=("-c") + flags+=("--log_output_level=") + two_word_flags+=("--log_output_level") + flags+=("--namespace=") + two_word_flags+=("--namespace") + two_word_flags+=("-n") + + must_have_one_flag=() + must_have_one_noun=() + noun_aliases=() +} + +_istioctl_experimental_post-install_webhook_disable() +{ + last_command="istioctl_experimental_post-install_webhook_disable" + + command_aliases=() + + commands=() + + flags=() + two_word_flags=() + local_nonpersistent_flags=() + flags_with_completion=() + flags_completion=() + + flags+=("--injection") + local_nonpersistent_flags+=("--injection") + flags+=("--injection-config=") + two_word_flags+=("--injection-config") + local_nonpersistent_flags+=("--injection-config=") + flags+=("--validation") + local_nonpersistent_flags+=("--validation") + flags+=("--validation-config=") + two_word_flags+=("--validation-config") + local_nonpersistent_flags+=("--validation-config=") + flags+=("--context=") + two_word_flags+=("--context") + flags+=("--istioNamespace=") + two_word_flags+=("--istioNamespace") + two_word_flags+=("-i") + flags+=("--kubeconfig=") + two_word_flags+=("--kubeconfig") + two_word_flags+=("-c") + flags+=("--log_output_level=") + two_word_flags+=("--log_output_level") + flags+=("--namespace=") + two_word_flags+=("--namespace") + two_word_flags+=("-n") + + must_have_one_flag=() + must_have_one_noun=() + noun_aliases=() +} + +_istioctl_experimental_post-install_webhook_enable() +{ + last_command="istioctl_experimental_post-install_webhook_enable" + + command_aliases=() + + commands=() + + flags=() + two_word_flags=() + local_nonpersistent_flags=() + flags_with_completion=() + flags_completion=() + + flags+=("--ca-bundle-file=") + two_word_flags+=("--ca-bundle-file") + local_nonpersistent_flags+=("--ca-bundle-file=") + flags+=("--injection") + local_nonpersistent_flags+=("--injection") + flags+=("--injection-path=") + two_word_flags+=("--injection-path") + local_nonpersistent_flags+=("--injection-path=") + flags+=("--injection-service=") + two_word_flags+=("--injection-service") + local_nonpersistent_flags+=("--injection-service=") + flags+=("--read-cert-timeout=") + two_word_flags+=("--read-cert-timeout") + local_nonpersistent_flags+=("--read-cert-timeout=") + flags+=("--timeout=") + two_word_flags+=("--timeout") + local_nonpersistent_flags+=("--timeout=") + flags+=("--validation") + local_nonpersistent_flags+=("--validation") + flags+=("--validation-path=") + two_word_flags+=("--validation-path") + local_nonpersistent_flags+=("--validation-path=") + flags+=("--validation-service=") + two_word_flags+=("--validation-service") + local_nonpersistent_flags+=("--validation-service=") + flags+=("--webhook-secret=") + two_word_flags+=("--webhook-secret") + local_nonpersistent_flags+=("--webhook-secret=") + flags+=("--context=") + two_word_flags+=("--context") + flags+=("--istioNamespace=") + two_word_flags+=("--istioNamespace") + two_word_flags+=("-i") + flags+=("--kubeconfig=") + two_word_flags+=("--kubeconfig") + two_word_flags+=("-c") + flags+=("--log_output_level=") + two_word_flags+=("--log_output_level") + flags+=("--namespace=") + two_word_flags+=("--namespace") + two_word_flags+=("-n") + + must_have_one_flag=() + must_have_one_noun=() + noun_aliases=() +} + +_istioctl_experimental_post-install_webhook_status() +{ + last_command="istioctl_experimental_post-install_webhook_status" + + command_aliases=() + + commands=() + + flags=() + two_word_flags=() + local_nonpersistent_flags=() + flags_with_completion=() + flags_completion=() + + flags+=("--injection") + local_nonpersistent_flags+=("--injection") + flags+=("--injection-config=") + two_word_flags+=("--injection-config") + local_nonpersistent_flags+=("--injection-config=") + flags+=("--validation") + local_nonpersistent_flags+=("--validation") + flags+=("--validation-config=") + two_word_flags+=("--validation-config") + local_nonpersistent_flags+=("--validation-config=") + flags+=("--context=") + two_word_flags+=("--context") + flags+=("--istioNamespace=") + two_word_flags+=("--istioNamespace") + two_word_flags+=("-i") + flags+=("--kubeconfig=") + two_word_flags+=("--kubeconfig") + two_word_flags+=("-c") + flags+=("--log_output_level=") + two_word_flags+=("--log_output_level") + flags+=("--namespace=") + two_word_flags+=("--namespace") + two_word_flags+=("-n") + + must_have_one_flag=() + must_have_one_noun=() + noun_aliases=() +} + +_istioctl_experimental_post-install_webhook() +{ + last_command="istioctl_experimental_post-install_webhook" + + command_aliases=() + + commands=() + commands+=("disable") + commands+=("enable") + commands+=("status") + + flags=() + two_word_flags=() + local_nonpersistent_flags=() + flags_with_completion=() + flags_completion=() + + flags+=("--context=") + two_word_flags+=("--context") + flags+=("--istioNamespace=") + two_word_flags+=("--istioNamespace") + two_word_flags+=("-i") + flags+=("--kubeconfig=") + two_word_flags+=("--kubeconfig") + two_word_flags+=("-c") + flags+=("--log_output_level=") + two_word_flags+=("--log_output_level") + flags+=("--namespace=") + two_word_flags+=("--namespace") + two_word_flags+=("-n") + + must_have_one_flag=() + must_have_one_noun=() + noun_aliases=() +} + +_istioctl_experimental_post-install() +{ + last_command="istioctl_experimental_post-install" + + command_aliases=() + + commands=() + commands+=("webhook") + + flags=() + two_word_flags=() + local_nonpersistent_flags=() + flags_with_completion=() + flags_completion=() + + flags+=("--context=") + two_word_flags+=("--context") + flags+=("--istioNamespace=") + two_word_flags+=("--istioNamespace") + two_word_flags+=("-i") + flags+=("--kubeconfig=") + two_word_flags+=("--kubeconfig") + two_word_flags+=("-c") + flags+=("--log_output_level=") + two_word_flags+=("--log_output_level") + flags+=("--namespace=") + two_word_flags+=("--namespace") + two_word_flags+=("-n") + + must_have_one_flag=() + must_have_one_noun=() + noun_aliases=() +} + +_istioctl_experimental_remove-from-mesh_deployment() +{ + last_command="istioctl_experimental_remove-from-mesh_deployment" + + command_aliases=() + + commands=() + + flags=() + two_word_flags=() + local_nonpersistent_flags=() + flags_with_completion=() + flags_completion=() + + flags+=("--context=") + two_word_flags+=("--context") + flags+=("--istioNamespace=") + two_word_flags+=("--istioNamespace") + two_word_flags+=("-i") + flags+=("--kubeconfig=") + two_word_flags+=("--kubeconfig") + two_word_flags+=("-c") + flags+=("--log_output_level=") + two_word_flags+=("--log_output_level") + flags+=("--namespace=") + two_word_flags+=("--namespace") + two_word_flags+=("-n") + + must_have_one_flag=() + must_have_one_noun=() + noun_aliases=() +} + +_istioctl_experimental_remove-from-mesh_external-service() +{ + last_command="istioctl_experimental_remove-from-mesh_external-service" + + command_aliases=() + + commands=() + + flags=() + two_word_flags=() + local_nonpersistent_flags=() + flags_with_completion=() + flags_completion=() + + flags+=("--context=") + two_word_flags+=("--context") + flags+=("--istioNamespace=") + two_word_flags+=("--istioNamespace") + two_word_flags+=("-i") + flags+=("--kubeconfig=") + two_word_flags+=("--kubeconfig") + two_word_flags+=("-c") + flags+=("--log_output_level=") + two_word_flags+=("--log_output_level") + flags+=("--namespace=") + two_word_flags+=("--namespace") + two_word_flags+=("-n") + + must_have_one_flag=() + must_have_one_noun=() + noun_aliases=() +} + +_istioctl_experimental_remove-from-mesh_service() +{ + last_command="istioctl_experimental_remove-from-mesh_service" + + command_aliases=() + + commands=() + + flags=() + two_word_flags=() + local_nonpersistent_flags=() + flags_with_completion=() + flags_completion=() + + flags+=("--context=") + two_word_flags+=("--context") + flags+=("--istioNamespace=") + two_word_flags+=("--istioNamespace") + two_word_flags+=("-i") + flags+=("--kubeconfig=") + two_word_flags+=("--kubeconfig") + two_word_flags+=("-c") + flags+=("--log_output_level=") + two_word_flags+=("--log_output_level") + flags+=("--namespace=") + two_word_flags+=("--namespace") + two_word_flags+=("-n") + + must_have_one_flag=() + must_have_one_noun=() + noun_aliases=() +} + +_istioctl_experimental_remove-from-mesh() +{ + last_command="istioctl_experimental_remove-from-mesh" + + command_aliases=() + + commands=() + commands+=("deployment") + commands+=("external-service") + commands+=("service") + + flags=() + two_word_flags=() + local_nonpersistent_flags=() + flags_with_completion=() + flags_completion=() + + flags+=("--context=") + two_word_flags+=("--context") + flags+=("--istioNamespace=") + two_word_flags+=("--istioNamespace") + two_word_flags+=("-i") + flags+=("--kubeconfig=") + two_word_flags+=("--kubeconfig") + two_word_flags+=("-c") + flags+=("--log_output_level=") + two_word_flags+=("--log_output_level") + flags+=("--namespace=") + two_word_flags+=("--namespace") + two_word_flags+=("-n") + + must_have_one_flag=() + must_have_one_noun=() + noun_aliases=() +} + +_istioctl_experimental_upgrade() +{ + last_command="istioctl_experimental_upgrade" + + command_aliases=() + + commands=() + + flags=() + two_word_flags=() + local_nonpersistent_flags=() + flags_with_completion=() + flags_completion=() + + flags+=("--dry-run") + flags+=("--filename=") + two_word_flags+=("--filename") + two_word_flags+=("-f") + flags+=("--force") + flags+=("--logtostderr") + flags+=("--skip-confirmation") + flags+=("-y") + flags+=("--verbose") + flags+=("--versionsURI=") + two_word_flags+=("--versionsURI") + two_word_flags+=("-u") + flags+=("--wait") + flags+=("-w") + flags+=("--context=") + two_word_flags+=("--context") + flags+=("--istioNamespace=") + two_word_flags+=("--istioNamespace") + two_word_flags+=("-i") + flags+=("--kubeconfig=") + two_word_flags+=("--kubeconfig") + two_word_flags+=("-c") + flags+=("--log_output_level=") + two_word_flags+=("--log_output_level") + flags+=("--namespace=") + two_word_flags+=("--namespace") + two_word_flags+=("-n") + + must_have_one_flag=() + must_have_one_noun=() + noun_aliases=() +} + +_istioctl_experimental_wait() +{ + last_command="istioctl_experimental_wait" + + command_aliases=() + + commands=() + + flags=() + two_word_flags=() + local_nonpersistent_flags=() + flags_with_completion=() + flags_completion=() + + flags+=("--for=") + two_word_flags+=("--for") + flags+=("--resource-version=") + two_word_flags+=("--resource-version") + flags+=("--threshold=") + two_word_flags+=("--threshold") + flags+=("--timeout=") + two_word_flags+=("--timeout") + flags+=("--context=") + two_word_flags+=("--context") + flags+=("--istioNamespace=") + two_word_flags+=("--istioNamespace") + two_word_flags+=("-i") + flags+=("--kubeconfig=") + two_word_flags+=("--kubeconfig") + two_word_flags+=("-c") + flags+=("--log_output_level=") + two_word_flags+=("--log_output_level") + flags+=("--namespace=") + two_word_flags+=("--namespace") + two_word_flags+=("-n") + + must_have_one_flag=() + must_have_one_noun=() + noun_aliases=() +} + +_istioctl_experimental() +{ + last_command="istioctl_experimental" + + command_aliases=() + + commands=() + commands+=("add-to-mesh") + if [[ -z "${BASH_VERSION}" || "${BASH_VERSINFO[0]}" -gt 3 ]]; then + command_aliases+=("add") + aliashash["add"]="add-to-mesh" + fi + commands+=("analyze") + commands+=("authz") + commands+=("convert-ingress") + commands+=("create-remote-secret") + commands+=("dashboard") + commands+=("describe") + if [[ -z "${BASH_VERSION}" || "${BASH_VERSINFO[0]}" -gt 3 ]]; then + command_aliases+=("des") + aliashash["des"]="describe" + fi + commands+=("kube-uninject") + commands+=("metrics") + if [[ -z "${BASH_VERSION}" || "${BASH_VERSINFO[0]}" -gt 3 ]]; then + command_aliases+=("m") + aliashash["m"]="metrics" + fi + commands+=("multicluster") + if [[ -z "${BASH_VERSION}" || "${BASH_VERSINFO[0]}" -gt 3 ]]; then + command_aliases+=("mc") + aliashash["mc"]="multicluster" + fi + commands+=("post-install") + commands+=("remove-from-mesh") + if [[ -z "${BASH_VERSION}" || "${BASH_VERSINFO[0]}" -gt 3 ]]; then + command_aliases+=("rm") + aliashash["rm"]="remove-from-mesh" + fi + commands+=("upgrade") + commands+=("wait") + + flags=() + two_word_flags=() + local_nonpersistent_flags=() + flags_with_completion=() + flags_completion=() + + flags+=("--context=") + two_word_flags+=("--context") + flags+=("--istioNamespace=") + two_word_flags+=("--istioNamespace") + two_word_flags+=("-i") + flags+=("--kubeconfig=") + two_word_flags+=("--kubeconfig") + two_word_flags+=("-c") + flags+=("--log_output_level=") + two_word_flags+=("--log_output_level") + flags+=("--namespace=") + two_word_flags+=("--namespace") + two_word_flags+=("-n") + + must_have_one_flag=() + must_have_one_noun=() + noun_aliases=() +} + +_istioctl_kube-inject() +{ + last_command="istioctl_kube-inject" + + command_aliases=() + + commands=() + + flags=() + two_word_flags=() + local_nonpersistent_flags=() + flags_with_completion=() + flags_completion=() + + flags+=("--filename=") + two_word_flags+=("--filename") + two_word_flags+=("-f") + flags+=("--injectConfigFile=") + two_word_flags+=("--injectConfigFile") + flags+=("--injectConfigMapName=") + two_word_flags+=("--injectConfigMapName") + flags+=("--meshConfigFile=") + two_word_flags+=("--meshConfigFile") + flags+=("--meshConfigMapName=") + two_word_flags+=("--meshConfigMapName") + flags+=("--output=") + two_word_flags+=("--output") + two_word_flags+=("-o") + flags+=("--valuesFile=") + two_word_flags+=("--valuesFile") + flags+=("--context=") + two_word_flags+=("--context") + flags+=("--istioNamespace=") + two_word_flags+=("--istioNamespace") + two_word_flags+=("-i") + flags+=("--kubeconfig=") + two_word_flags+=("--kubeconfig") + two_word_flags+=("-c") + flags+=("--log_output_level=") + two_word_flags+=("--log_output_level") + flags+=("--namespace=") + two_word_flags+=("--namespace") + two_word_flags+=("-n") + + must_have_one_flag=() + must_have_one_noun=() + noun_aliases=() +} + +_istioctl_manifest_apply() +{ + last_command="istioctl_manifest_apply" + + command_aliases=() + + commands=() + + flags=() + two_word_flags=() + local_nonpersistent_flags=() + flags_with_completion=() + flags_completion=() + + flags+=("--filename=") + two_word_flags+=("--filename") + two_word_flags+=("-f") + flags+=("--force") + flags+=("--readiness-timeout=") + two_word_flags+=("--readiness-timeout") + flags+=("--set=") + two_word_flags+=("--set") + two_word_flags+=("-s") + flags+=("--skip-confirmation") + flags+=("-y") + flags+=("--wait") + flags+=("-w") + flags+=("--context=") + two_word_flags+=("--context") + flags+=("--dry-run") + flags+=("--istioNamespace=") + two_word_flags+=("--istioNamespace") + two_word_flags+=("-i") + flags+=("--kubeconfig=") + two_word_flags+=("--kubeconfig") + two_word_flags+=("-c") + flags+=("--log_output_level=") + two_word_flags+=("--log_output_level") + flags+=("--logtostderr") + flags+=("--namespace=") + two_word_flags+=("--namespace") + two_word_flags+=("-n") + flags+=("--verbose") + + must_have_one_flag=() + must_have_one_noun=() + noun_aliases=() +} + +_istioctl_manifest_diff() +{ + last_command="istioctl_manifest_diff" + + command_aliases=() + + commands=() + + flags=() + two_word_flags=() + local_nonpersistent_flags=() + flags_with_completion=() + flags_completion=() + + flags+=("--directory") + flags+=("-r") + flags+=("--ignore=") + two_word_flags+=("--ignore") + flags+=("--rename=") + two_word_flags+=("--rename") + flags+=("--select=") + two_word_flags+=("--select") + flags+=("--context=") + two_word_flags+=("--context") + flags+=("--dry-run") + flags+=("--istioNamespace=") + two_word_flags+=("--istioNamespace") + two_word_flags+=("-i") + flags+=("--kubeconfig=") + two_word_flags+=("--kubeconfig") + two_word_flags+=("-c") + flags+=("--log_output_level=") + two_word_flags+=("--log_output_level") + flags+=("--logtostderr") + flags+=("--namespace=") + two_word_flags+=("--namespace") + two_word_flags+=("-n") + flags+=("--verbose") + + must_have_one_flag=() + must_have_one_noun=() + noun_aliases=() +} + +_istioctl_manifest_generate() +{ + last_command="istioctl_manifest_generate" + + command_aliases=() + + commands=() + + flags=() + two_word_flags=() + local_nonpersistent_flags=() + flags_with_completion=() + flags_completion=() + + flags+=("--filename=") + two_word_flags+=("--filename") + two_word_flags+=("-f") + flags+=("--force") + flags+=("--output=") + two_word_flags+=("--output") + two_word_flags+=("-o") + flags+=("--set=") + two_word_flags+=("--set") + two_word_flags+=("-s") + flags+=("--context=") + two_word_flags+=("--context") + flags+=("--dry-run") + flags+=("--istioNamespace=") + two_word_flags+=("--istioNamespace") + two_word_flags+=("-i") + flags+=("--kubeconfig=") + two_word_flags+=("--kubeconfig") + two_word_flags+=("-c") + flags+=("--log_output_level=") + two_word_flags+=("--log_output_level") + flags+=("--logtostderr") + flags+=("--namespace=") + two_word_flags+=("--namespace") + two_word_flags+=("-n") + flags+=("--verbose") + + must_have_one_flag=() + must_have_one_noun=() + noun_aliases=() +} + +_istioctl_manifest_migrate() +{ + last_command="istioctl_manifest_migrate" + + command_aliases=() + + commands=() + + flags=() + two_word_flags=() + local_nonpersistent_flags=() + flags_with_completion=() + flags_completion=() + + flags+=("--force") + flags+=("--context=") + two_word_flags+=("--context") + flags+=("--dry-run") + flags+=("--istioNamespace=") + two_word_flags+=("--istioNamespace") + two_word_flags+=("-i") + flags+=("--kubeconfig=") + two_word_flags+=("--kubeconfig") + two_word_flags+=("-c") + flags+=("--log_output_level=") + two_word_flags+=("--log_output_level") + flags+=("--logtostderr") + flags+=("--namespace=") + two_word_flags+=("--namespace") + two_word_flags+=("-n") + flags+=("--verbose") + + must_have_one_flag=() + must_have_one_noun=() + noun_aliases=() +} + +_istioctl_manifest_versions() +{ + last_command="istioctl_manifest_versions" + + command_aliases=() + + commands=() + + flags=() + two_word_flags=() + local_nonpersistent_flags=() + flags_with_completion=() + flags_completion=() + + flags+=("--versionsURI=") + two_word_flags+=("--versionsURI") + two_word_flags+=("-u") + flags+=("--context=") + two_word_flags+=("--context") + flags+=("--dry-run") + flags+=("--istioNamespace=") + two_word_flags+=("--istioNamespace") + two_word_flags+=("-i") + flags+=("--kubeconfig=") + two_word_flags+=("--kubeconfig") + two_word_flags+=("-c") + flags+=("--log_output_level=") + two_word_flags+=("--log_output_level") + flags+=("--logtostderr") + flags+=("--namespace=") + two_word_flags+=("--namespace") + two_word_flags+=("-n") + flags+=("--verbose") + + must_have_one_flag=() + must_have_one_noun=() + noun_aliases=() +} + +_istioctl_manifest() +{ + last_command="istioctl_manifest" + + command_aliases=() + + commands=() + commands+=("apply") + commands+=("diff") + commands+=("generate") + commands+=("migrate") + commands+=("versions") + + flags=() + two_word_flags=() + local_nonpersistent_flags=() + flags_with_completion=() + flags_completion=() + + flags+=("--dry-run") + flags+=("--logtostderr") + flags+=("--verbose") + flags+=("--context=") + two_word_flags+=("--context") + flags+=("--istioNamespace=") + two_word_flags+=("--istioNamespace") + two_word_flags+=("-i") + flags+=("--kubeconfig=") + two_word_flags+=("--kubeconfig") + two_word_flags+=("-c") + flags+=("--log_output_level=") + two_word_flags+=("--log_output_level") + flags+=("--namespace=") + two_word_flags+=("--namespace") + two_word_flags+=("-n") + + must_have_one_flag=() + must_have_one_noun=() + noun_aliases=() +} + +_istioctl_operator_init() +{ + last_command="istioctl_operator_init" + + command_aliases=() + + commands=() + + flags=() + two_word_flags=() + local_nonpersistent_flags=() + flags_with_completion=() + flags_completion=() + + flags+=("--dry-run") + flags+=("--filename=") + two_word_flags+=("--filename") + two_word_flags+=("-f") + flags+=("--hub=") + two_word_flags+=("--hub") + flags+=("--logtostderr") + flags+=("--operatorNamespace=") + two_word_flags+=("--operatorNamespace") + flags+=("--readiness-timeout=") + two_word_flags+=("--readiness-timeout") + flags+=("--tag=") + two_word_flags+=("--tag") + flags+=("--verbose") + flags+=("--wait") + flags+=("-w") + flags+=("--context=") + two_word_flags+=("--context") + flags+=("--istioNamespace=") + two_word_flags+=("--istioNamespace") + two_word_flags+=("-i") + flags+=("--kubeconfig=") + two_word_flags+=("--kubeconfig") + two_word_flags+=("-c") + flags+=("--log_output_level=") + two_word_flags+=("--log_output_level") + flags+=("--namespace=") + two_word_flags+=("--namespace") + two_word_flags+=("-n") + + must_have_one_flag=() + must_have_one_noun=() + noun_aliases=() +} + +_istioctl_operator_remove() +{ + last_command="istioctl_operator_remove" + + command_aliases=() + + commands=() + + flags=() + two_word_flags=() + local_nonpersistent_flags=() + flags_with_completion=() + flags_completion=() + + flags+=("--dry-run") + flags+=("--filename=") + two_word_flags+=("--filename") + two_word_flags+=("-f") + flags+=("--force") + flags+=("--hub=") + two_word_flags+=("--hub") + flags+=("--logtostderr") + flags+=("--operatorNamespace=") + two_word_flags+=("--operatorNamespace") + flags+=("--readiness-timeout=") + two_word_flags+=("--readiness-timeout") + flags+=("--tag=") + two_word_flags+=("--tag") + flags+=("--verbose") + flags+=("--wait") + flags+=("-w") + flags+=("--context=") + two_word_flags+=("--context") + flags+=("--istioNamespace=") + two_word_flags+=("--istioNamespace") + two_word_flags+=("-i") + flags+=("--kubeconfig=") + two_word_flags+=("--kubeconfig") + two_word_flags+=("-c") + flags+=("--log_output_level=") + two_word_flags+=("--log_output_level") + flags+=("--namespace=") + two_word_flags+=("--namespace") + two_word_flags+=("-n") + + must_have_one_flag=() + must_have_one_noun=() + noun_aliases=() +} + +_istioctl_operator() +{ + last_command="istioctl_operator" + + command_aliases=() + + commands=() + commands+=("init") + commands+=("remove") + + flags=() + two_word_flags=() + local_nonpersistent_flags=() + flags_with_completion=() + flags_completion=() + + flags+=("--context=") + two_word_flags+=("--context") + flags+=("--istioNamespace=") + two_word_flags+=("--istioNamespace") + two_word_flags+=("-i") + flags+=("--kubeconfig=") + two_word_flags+=("--kubeconfig") + two_word_flags+=("-c") + flags+=("--log_output_level=") + two_word_flags+=("--log_output_level") + flags+=("--namespace=") + two_word_flags+=("--namespace") + two_word_flags+=("-n") + + must_have_one_flag=() + must_have_one_noun=() + noun_aliases=() +} + +_istioctl_profile_diff() +{ + last_command="istioctl_profile_diff" + + command_aliases=() + + commands=() + + flags=() + two_word_flags=() + local_nonpersistent_flags=() + flags_with_completion=() + flags_completion=() + + flags+=("--context=") + two_word_flags+=("--context") + flags+=("--dry-run") + flags+=("--istioNamespace=") + two_word_flags+=("--istioNamespace") + two_word_flags+=("-i") + flags+=("--kubeconfig=") + two_word_flags+=("--kubeconfig") + two_word_flags+=("-c") + flags+=("--log_output_level=") + two_word_flags+=("--log_output_level") + flags+=("--logtostderr") + flags+=("--namespace=") + two_word_flags+=("--namespace") + two_word_flags+=("-n") + flags+=("--verbose") + + must_have_one_flag=() + must_have_one_noun=() + noun_aliases=() +} + +_istioctl_profile_dump() +{ + last_command="istioctl_profile_dump" + + command_aliases=() + + commands=() + + flags=() + two_word_flags=() + local_nonpersistent_flags=() + flags_with_completion=() + flags_completion=() + + flags+=("--config-path=") + two_word_flags+=("--config-path") + two_word_flags+=("-p") + flags+=("--filename=") + two_word_flags+=("--filename") + two_word_flags+=("-f") + flags+=("--output=") + two_word_flags+=("--output") + two_word_flags+=("-o") + flags+=("--context=") + two_word_flags+=("--context") + flags+=("--dry-run") + flags+=("--istioNamespace=") + two_word_flags+=("--istioNamespace") + two_word_flags+=("-i") + flags+=("--kubeconfig=") + two_word_flags+=("--kubeconfig") + two_word_flags+=("-c") + flags+=("--log_output_level=") + two_word_flags+=("--log_output_level") + flags+=("--logtostderr") + flags+=("--namespace=") + two_word_flags+=("--namespace") + two_word_flags+=("-n") + flags+=("--verbose") + + must_have_one_flag=() + must_have_one_noun=() + noun_aliases=() +} + +_istioctl_profile_list() +{ + last_command="istioctl_profile_list" + + command_aliases=() + + commands=() + + flags=() + two_word_flags=() + local_nonpersistent_flags=() + flags_with_completion=() + flags_completion=() + + flags+=("--context=") + two_word_flags+=("--context") + flags+=("--dry-run") + flags+=("--istioNamespace=") + two_word_flags+=("--istioNamespace") + two_word_flags+=("-i") + flags+=("--kubeconfig=") + two_word_flags+=("--kubeconfig") + two_word_flags+=("-c") + flags+=("--log_output_level=") + two_word_flags+=("--log_output_level") + flags+=("--logtostderr") + flags+=("--namespace=") + two_word_flags+=("--namespace") + two_word_flags+=("-n") + flags+=("--verbose") + + must_have_one_flag=() + must_have_one_noun=() + noun_aliases=() +} + +_istioctl_profile() +{ + last_command="istioctl_profile" + + command_aliases=() + + commands=() + commands+=("diff") + commands+=("dump") + commands+=("list") + + flags=() + two_word_flags=() + local_nonpersistent_flags=() + flags_with_completion=() + flags_completion=() + + flags+=("--dry-run") + flags+=("--logtostderr") + flags+=("--verbose") + flags+=("--context=") + two_word_flags+=("--context") + flags+=("--istioNamespace=") + two_word_flags+=("--istioNamespace") + two_word_flags+=("-i") + flags+=("--kubeconfig=") + two_word_flags+=("--kubeconfig") + two_word_flags+=("-c") + flags+=("--log_output_level=") + two_word_flags+=("--log_output_level") + flags+=("--namespace=") + two_word_flags+=("--namespace") + two_word_flags+=("-n") + + must_have_one_flag=() + must_have_one_noun=() + noun_aliases=() +} + +_istioctl_proxy-config_bootstrap() +{ + last_command="istioctl_proxy-config_bootstrap" + + command_aliases=() + + commands=() + + flags=() + two_word_flags=() + local_nonpersistent_flags=() + flags_with_completion=() + flags_completion=() + + flags+=("--file=") + two_word_flags+=("--file") + two_word_flags+=("-f") + flags+=("--context=") + two_word_flags+=("--context") + flags+=("--istioNamespace=") + two_word_flags+=("--istioNamespace") + two_word_flags+=("-i") + flags+=("--kubeconfig=") + two_word_flags+=("--kubeconfig") + two_word_flags+=("-c") + flags+=("--log_output_level=") + two_word_flags+=("--log_output_level") + flags+=("--namespace=") + two_word_flags+=("--namespace") + two_word_flags+=("-n") + flags+=("--output=") + two_word_flags+=("--output") + two_word_flags+=("-o") + + must_have_one_flag=() + must_have_one_noun=() + noun_aliases=() +} + +_istioctl_proxy-config_cluster() +{ + last_command="istioctl_proxy-config_cluster" + + command_aliases=() + + commands=() + + flags=() + two_word_flags=() + local_nonpersistent_flags=() + flags_with_completion=() + flags_completion=() + + flags+=("--direction=") + two_word_flags+=("--direction") + flags+=("--file=") + two_word_flags+=("--file") + two_word_flags+=("-f") + flags+=("--fqdn=") + two_word_flags+=("--fqdn") + flags+=("--port=") + two_word_flags+=("--port") + flags+=("--subset=") + two_word_flags+=("--subset") + flags+=("--context=") + two_word_flags+=("--context") + flags+=("--istioNamespace=") + two_word_flags+=("--istioNamespace") + two_word_flags+=("-i") + flags+=("--kubeconfig=") + two_word_flags+=("--kubeconfig") + two_word_flags+=("-c") + flags+=("--log_output_level=") + two_word_flags+=("--log_output_level") + flags+=("--namespace=") + two_word_flags+=("--namespace") + two_word_flags+=("-n") + flags+=("--output=") + two_word_flags+=("--output") + two_word_flags+=("-o") + + must_have_one_flag=() + must_have_one_noun=() + noun_aliases=() +} + +_istioctl_proxy-config_endpoint() +{ + last_command="istioctl_proxy-config_endpoint" + + command_aliases=() + + commands=() + + flags=() + two_word_flags=() + local_nonpersistent_flags=() + flags_with_completion=() + flags_completion=() + + flags+=("--address=") + two_word_flags+=("--address") + flags+=("--cluster=") + two_word_flags+=("--cluster") + flags+=("--file=") + two_word_flags+=("--file") + two_word_flags+=("-f") + flags+=("--port=") + two_word_flags+=("--port") + flags+=("--status=") + two_word_flags+=("--status") + flags+=("--context=") + two_word_flags+=("--context") + flags+=("--istioNamespace=") + two_word_flags+=("--istioNamespace") + two_word_flags+=("-i") + flags+=("--kubeconfig=") + two_word_flags+=("--kubeconfig") + two_word_flags+=("-c") + flags+=("--log_output_level=") + two_word_flags+=("--log_output_level") + flags+=("--namespace=") + two_word_flags+=("--namespace") + two_word_flags+=("-n") + flags+=("--output=") + two_word_flags+=("--output") + two_word_flags+=("-o") + + must_have_one_flag=() + must_have_one_noun=() + noun_aliases=() +} + +_istioctl_proxy-config_listener() +{ + last_command="istioctl_proxy-config_listener" + + command_aliases=() + + commands=() + + flags=() + two_word_flags=() + local_nonpersistent_flags=() + flags_with_completion=() + flags_completion=() + + flags+=("--address=") + two_word_flags+=("--address") + flags+=("--file=") + two_word_flags+=("--file") + two_word_flags+=("-f") + flags+=("--port=") + two_word_flags+=("--port") + flags+=("--type=") + two_word_flags+=("--type") + flags+=("--context=") + two_word_flags+=("--context") + flags+=("--istioNamespace=") + two_word_flags+=("--istioNamespace") + two_word_flags+=("-i") + flags+=("--kubeconfig=") + two_word_flags+=("--kubeconfig") + two_word_flags+=("-c") + flags+=("--log_output_level=") + two_word_flags+=("--log_output_level") + flags+=("--namespace=") + two_word_flags+=("--namespace") + two_word_flags+=("-n") + flags+=("--output=") + two_word_flags+=("--output") + two_word_flags+=("-o") + + must_have_one_flag=() + must_have_one_noun=() + noun_aliases=() +} + +_istioctl_proxy-config_log() +{ + last_command="istioctl_proxy-config_log" + + command_aliases=() + + commands=() + + flags=() + two_word_flags=() + local_nonpersistent_flags=() + flags_with_completion=() + flags_completion=() + + flags+=("--level=") + two_word_flags+=("--level") + flags+=("--reset") + flags+=("-r") + flags+=("--context=") + two_word_flags+=("--context") + flags+=("--istioNamespace=") + two_word_flags+=("--istioNamespace") + two_word_flags+=("-i") + flags+=("--kubeconfig=") + two_word_flags+=("--kubeconfig") + two_word_flags+=("-c") + flags+=("--log_output_level=") + two_word_flags+=("--log_output_level") + flags+=("--namespace=") + two_word_flags+=("--namespace") + two_word_flags+=("-n") + flags+=("--output=") + two_word_flags+=("--output") + two_word_flags+=("-o") + + must_have_one_flag=() + must_have_one_noun=() + noun_aliases=() +} + +_istioctl_proxy-config_route() +{ + last_command="istioctl_proxy-config_route" + + command_aliases=() + + commands=() + + flags=() + two_word_flags=() + local_nonpersistent_flags=() + flags_with_completion=() + flags_completion=() + + flags+=("--file=") + two_word_flags+=("--file") + two_word_flags+=("-f") + flags+=("--name=") + two_word_flags+=("--name") + flags+=("--context=") + two_word_flags+=("--context") + flags+=("--istioNamespace=") + two_word_flags+=("--istioNamespace") + two_word_flags+=("-i") + flags+=("--kubeconfig=") + two_word_flags+=("--kubeconfig") + two_word_flags+=("-c") + flags+=("--log_output_level=") + two_word_flags+=("--log_output_level") + flags+=("--namespace=") + two_word_flags+=("--namespace") + two_word_flags+=("-n") + flags+=("--output=") + two_word_flags+=("--output") + two_word_flags+=("-o") + + must_have_one_flag=() + must_have_one_noun=() + noun_aliases=() +} + +_istioctl_proxy-config_secret() +{ + last_command="istioctl_proxy-config_secret" + + command_aliases=() + + commands=() + + flags=() + two_word_flags=() + local_nonpersistent_flags=() + flags_with_completion=() + flags_completion=() + + flags+=("--file=") + two_word_flags+=("--file") + two_word_flags+=("-f") + flags+=("--context=") + two_word_flags+=("--context") + flags+=("--istioNamespace=") + two_word_flags+=("--istioNamespace") + two_word_flags+=("-i") + flags+=("--kubeconfig=") + two_word_flags+=("--kubeconfig") + two_word_flags+=("-c") + flags+=("--log_output_level=") + two_word_flags+=("--log_output_level") + flags+=("--namespace=") + two_word_flags+=("--namespace") + two_word_flags+=("-n") + flags+=("--output=") + two_word_flags+=("--output") + two_word_flags+=("-o") + + must_have_one_flag=() + must_have_one_noun=() + noun_aliases=() +} + +_istioctl_proxy-config() +{ + last_command="istioctl_proxy-config" + + command_aliases=() + + commands=() + commands+=("bootstrap") + if [[ -z "${BASH_VERSION}" || "${BASH_VERSINFO[0]}" -gt 3 ]]; then + command_aliases+=("b") + aliashash["b"]="bootstrap" + fi + commands+=("cluster") + if [[ -z "${BASH_VERSION}" || "${BASH_VERSINFO[0]}" -gt 3 ]]; then + command_aliases+=("c") + aliashash["c"]="cluster" + command_aliases+=("clusters") + aliashash["clusters"]="cluster" + fi + commands+=("endpoint") + if [[ -z "${BASH_VERSION}" || "${BASH_VERSINFO[0]}" -gt 3 ]]; then + command_aliases+=("endpoints") + aliashash["endpoints"]="endpoint" + command_aliases+=("ep") + aliashash["ep"]="endpoint" + fi + commands+=("listener") + if [[ -z "${BASH_VERSION}" || "${BASH_VERSINFO[0]}" -gt 3 ]]; then + command_aliases+=("l") + aliashash["l"]="listener" + command_aliases+=("listeners") + aliashash["listeners"]="listener" + fi + commands+=("log") + if [[ -z "${BASH_VERSION}" || "${BASH_VERSINFO[0]}" -gt 3 ]]; then + command_aliases+=("o") + aliashash["o"]="log" + fi + commands+=("route") + if [[ -z "${BASH_VERSION}" || "${BASH_VERSINFO[0]}" -gt 3 ]]; then + command_aliases+=("r") + aliashash["r"]="route" + command_aliases+=("routes") + aliashash["routes"]="route" + fi + commands+=("secret") + if [[ -z "${BASH_VERSION}" || "${BASH_VERSINFO[0]}" -gt 3 ]]; then + command_aliases+=("s") + aliashash["s"]="secret" + fi + + flags=() + two_word_flags=() + local_nonpersistent_flags=() + flags_with_completion=() + flags_completion=() + + flags+=("--output=") + two_word_flags+=("--output") + two_word_flags+=("-o") + flags+=("--context=") + two_word_flags+=("--context") + flags+=("--istioNamespace=") + two_word_flags+=("--istioNamespace") + two_word_flags+=("-i") + flags+=("--kubeconfig=") + two_word_flags+=("--kubeconfig") + two_word_flags+=("-c") + flags+=("--log_output_level=") + two_word_flags+=("--log_output_level") + flags+=("--namespace=") + two_word_flags+=("--namespace") + two_word_flags+=("-n") + + must_have_one_flag=() + must_have_one_noun=() + noun_aliases=() +} + +_istioctl_proxy-status() +{ + last_command="istioctl_proxy-status" + + command_aliases=() + + commands=() + + flags=() + two_word_flags=() + local_nonpersistent_flags=() + flags_with_completion=() + flags_completion=() + + flags+=("--sds") + flags+=("-s") + local_nonpersistent_flags+=("--sds") + flags+=("--sds-json") + local_nonpersistent_flags+=("--sds-json") + flags+=("--context=") + two_word_flags+=("--context") + flags+=("--istioNamespace=") + two_word_flags+=("--istioNamespace") + two_word_flags+=("-i") + flags+=("--kubeconfig=") + two_word_flags+=("--kubeconfig") + two_word_flags+=("-c") + flags+=("--log_output_level=") + two_word_flags+=("--log_output_level") + flags+=("--namespace=") + two_word_flags+=("--namespace") + two_word_flags+=("-n") + + must_have_one_flag=() + must_have_one_noun=() + noun_aliases=() +} + +_istioctl_register() +{ + last_command="istioctl_register" + + command_aliases=() + + commands=() + + flags=() + two_word_flags=() + local_nonpersistent_flags=() + flags_with_completion=() + flags_completion=() + + flags+=("--annotations=") + two_word_flags+=("--annotations") + two_word_flags+=("-a") + flags+=("--labels=") + two_word_flags+=("--labels") + two_word_flags+=("-l") + flags+=("--serviceaccount=") + two_word_flags+=("--serviceaccount") + two_word_flags+=("-s") + flags+=("--context=") + two_word_flags+=("--context") + flags+=("--istioNamespace=") + two_word_flags+=("--istioNamespace") + two_word_flags+=("-i") + flags+=("--kubeconfig=") + two_word_flags+=("--kubeconfig") + two_word_flags+=("-c") + flags+=("--log_output_level=") + two_word_flags+=("--log_output_level") + flags+=("--namespace=") + two_word_flags+=("--namespace") + two_word_flags+=("-n") + + must_have_one_flag=() + must_have_one_noun=() + noun_aliases=() +} + +_istioctl_upgrade() +{ + last_command="istioctl_upgrade" + + command_aliases=() + + commands=() + + flags=() + two_word_flags=() + local_nonpersistent_flags=() + flags_with_completion=() + flags_completion=() + + flags+=("--dry-run") + flags+=("--filename=") + two_word_flags+=("--filename") + two_word_flags+=("-f") + flags+=("--force") + flags+=("--logtostderr") + flags+=("--skip-confirmation") + flags+=("-y") + flags+=("--verbose") + flags+=("--versionsURI=") + two_word_flags+=("--versionsURI") + two_word_flags+=("-u") + flags+=("--wait") + flags+=("-w") + flags+=("--context=") + two_word_flags+=("--context") + flags+=("--istioNamespace=") + two_word_flags+=("--istioNamespace") + two_word_flags+=("-i") + flags+=("--kubeconfig=") + two_word_flags+=("--kubeconfig") + two_word_flags+=("-c") + flags+=("--log_output_level=") + two_word_flags+=("--log_output_level") + flags+=("--namespace=") + two_word_flags+=("--namespace") + two_word_flags+=("-n") + + must_have_one_flag=() + must_have_one_noun=() + noun_aliases=() +} + +_istioctl_validate() +{ + last_command="istioctl_validate" + + command_aliases=() + + commands=() + + flags=() + two_word_flags=() + local_nonpersistent_flags=() + flags_with_completion=() + flags_completion=() + + flags+=("--filename=") + two_word_flags+=("--filename") + two_word_flags+=("-f") + flags+=("--referential") + flags+=("-x") + flags+=("--context=") + two_word_flags+=("--context") + flags+=("--istioNamespace=") + two_word_flags+=("--istioNamespace") + two_word_flags+=("-i") + flags+=("--kubeconfig=") + two_word_flags+=("--kubeconfig") + two_word_flags+=("-c") + flags+=("--log_output_level=") + two_word_flags+=("--log_output_level") + flags+=("--namespace=") + two_word_flags+=("--namespace") + two_word_flags+=("-n") + + must_have_one_flag=() + must_have_one_noun=() + noun_aliases=() +} + +_istioctl_verify-install() +{ + last_command="istioctl_verify-install" + + command_aliases=() + + commands=() + + flags=() + two_word_flags=() + local_nonpersistent_flags=() + flags_with_completion=() + flags_completion=() + + flags+=("--enableVerbose") + local_nonpersistent_flags+=("--enableVerbose") + flags+=("--filename=") + two_word_flags+=("--filename") + flags_with_completion+=("--filename") + flags_completion+=("__istioctl_handle_filename_extension_flag json|yaml|yml") + two_word_flags+=("-f") + flags_with_completion+=("-f") + flags_completion+=("__istioctl_handle_filename_extension_flag json|yaml|yml") + flags+=("--recursive") + flags+=("-R") + flags+=("--context=") + two_word_flags+=("--context") + flags+=("--istioNamespace=") + two_word_flags+=("--istioNamespace") + two_word_flags+=("-i") + flags+=("--kubeconfig=") + two_word_flags+=("--kubeconfig") + two_word_flags+=("-c") + flags+=("--log_output_level=") + two_word_flags+=("--log_output_level") + flags+=("--namespace=") + two_word_flags+=("--namespace") + two_word_flags+=("-n") + + must_have_one_flag=() + must_have_one_noun=() + noun_aliases=() +} + +_istioctl_version() +{ + last_command="istioctl_version" + + command_aliases=() + + commands=() + + flags=() + two_word_flags=() + local_nonpersistent_flags=() + flags_with_completion=() + flags_completion=() + + flags+=("--output=") + two_word_flags+=("--output") + two_word_flags+=("-o") + local_nonpersistent_flags+=("--output=") + flags+=("--remote") + local_nonpersistent_flags+=("--remote") + flags+=("--short") + flags+=("-s") + local_nonpersistent_flags+=("--short") + flags+=("--context=") + two_word_flags+=("--context") + flags+=("--istioNamespace=") + two_word_flags+=("--istioNamespace") + two_word_flags+=("-i") + flags+=("--kubeconfig=") + two_word_flags+=("--kubeconfig") + two_word_flags+=("-c") + flags+=("--log_output_level=") + two_word_flags+=("--log_output_level") + flags+=("--namespace=") + two_word_flags+=("--namespace") + two_word_flags+=("-n") + + must_have_one_flag=() + must_have_one_noun=() + noun_aliases=() +} + +_istioctl_root_command() +{ + last_command="istioctl" + + command_aliases=() + + commands=() + commands+=("analyze") + commands+=("authn") + commands+=("authz") + commands+=("convert-ingress") + commands+=("dashboard") + if [[ -z "${BASH_VERSION}" || "${BASH_VERSINFO[0]}" -gt 3 ]]; then + command_aliases+=("d") + aliashash["d"]="dashboard" + command_aliases+=("dash") + aliashash["dash"]="dashboard" + fi + commands+=("deregister") + commands+=("experimental") + if [[ -z "${BASH_VERSION}" || "${BASH_VERSINFO[0]}" -gt 3 ]]; then + command_aliases+=("exp") + aliashash["exp"]="experimental" + command_aliases+=("x") + aliashash["x"]="experimental" + fi + commands+=("kube-inject") + commands+=("manifest") + commands+=("operator") + commands+=("profile") + commands+=("proxy-config") + if [[ -z "${BASH_VERSION}" || "${BASH_VERSINFO[0]}" -gt 3 ]]; then + command_aliases+=("pc") + aliashash["pc"]="proxy-config" + fi + commands+=("proxy-status") + if [[ -z "${BASH_VERSION}" || "${BASH_VERSINFO[0]}" -gt 3 ]]; then + command_aliases+=("ps") + aliashash["ps"]="proxy-status" + fi + commands+=("register") + commands+=("upgrade") + commands+=("validate") + commands+=("verify-install") + commands+=("version") + + flags=() + two_word_flags=() + local_nonpersistent_flags=() + flags_with_completion=() + flags_completion=() + + flags+=("--context=") + two_word_flags+=("--context") + flags+=("--istioNamespace=") + two_word_flags+=("--istioNamespace") + two_word_flags+=("-i") + flags+=("--kubeconfig=") + two_word_flags+=("--kubeconfig") + two_word_flags+=("-c") + flags+=("--log_output_level=") + two_word_flags+=("--log_output_level") + flags+=("--namespace=") + two_word_flags+=("--namespace") + two_word_flags+=("-n") + + must_have_one_flag=() + must_have_one_noun=() + noun_aliases=() +} + +__start_istioctl() +{ + local cur prev words cword + declare -A flaghash 2>/dev/null || : + declare -A aliashash 2>/dev/null || : + if declare -F _init_completion >/dev/null 2>&1; then + _init_completion -s || return + else + __istioctl_init_completion -n "=" || return + fi + + local c=0 + local flags=() + local two_word_flags=() + local local_nonpersistent_flags=() + local flags_with_completion=() + local flags_completion=() + local commands=("istioctl") + local must_have_one_flag=() + local must_have_one_noun=() + local last_command + local nouns=() + + __istioctl_handle_word +} + +if [[ $(type -t compopt) = "builtin" ]]; then + complete -o default -F __start_istioctl istioctl +else + complete -o default -o nospace -F __start_istioctl istioctl +fi + +# ex: ts=4 sw=4 et filetype=sh diff --git a/istio-manifests/istio-demo.yaml b/istio-manifests/istio-demo.yaml new file mode 100644 index 0000000..7e176e5 --- /dev/null +++ b/istio-manifests/istio-demo.yaml @@ -0,0 +1,20257 @@ +--- +# Source: istio/charts/galley/templates/poddisruptionbudget.yaml + +apiVersion: policy/v1beta1 +kind: PodDisruptionBudget +metadata: + name: istio-galley + namespace: istio-system + labels: + app: galley + chart: galley + heritage: Tiller + release: istio + istio: galley +spec: + + minAvailable: 1 + selector: + matchLabels: + app: galley + release: istio + istio: galley + +--- +# Source: istio/charts/gateways/templates/poddisruptionbudget.yaml + +apiVersion: policy/v1beta1 +kind: PodDisruptionBudget +metadata: + name: istio-egressgateway + namespace: istio-system + labels: + chart: gateways + heritage: Tiller + release: istio + app: istio-egressgateway + istio: egressgateway +spec: + + minAvailable: 1 + selector: + matchLabels: + release: istio + app: istio-egressgateway + istio: egressgateway +--- +apiVersion: policy/v1beta1 +kind: PodDisruptionBudget +metadata: + name: istio-ingressgateway + namespace: istio-system + labels: + chart: gateways + heritage: Tiller + release: istio + app: istio-ingressgateway + istio: ingressgateway +spec: + + minAvailable: 1 + selector: + matchLabels: + release: istio + app: istio-ingressgateway + istio: ingressgateway +--- + +--- +# Source: istio/charts/mixer/templates/poddisruptionbudget.yaml + +apiVersion: policy/v1beta1 +kind: PodDisruptionBudget +metadata: + name: istio-policy + namespace: istio-system + labels: + app: policy + chart: mixer + heritage: Tiller + release: istio + version: 1.5.0 + istio: mixer + istio-mixer-type: policy +spec: + + minAvailable: 1 + selector: + matchLabels: + app: policy + release: istio + istio: mixer + istio-mixer-type: policy +--- +apiVersion: policy/v1beta1 +kind: PodDisruptionBudget +metadata: + name: istio-telemetry + namespace: istio-system + labels: + app: telemetry + chart: mixer + heritage: Tiller + release: istio + version: 1.5.0 + istio: mixer + istio-mixer-type: telemetry +spec: + + minAvailable: 1 + selector: + matchLabels: + app: telemetry + release: istio + istio: mixer + istio-mixer-type: telemetry +--- + +--- +# Source: istio/charts/pilot/templates/poddisruptionbudget.yaml + +apiVersion: policy/v1beta1 +kind: PodDisruptionBudget +metadata: + name: istio-pilot + namespace: istio-system + labels: + app: pilot + chart: pilot + heritage: Tiller + release: istio + istio: pilot +spec: + + minAvailable: 1 + selector: + matchLabels: + app: pilot + release: istio + istio: pilot + +--- +# Source: istio/charts/security/templates/poddisruptionbudget.yaml + +apiVersion: policy/v1beta1 +kind: PodDisruptionBudget +metadata: + name: istio-citadel + namespace: istio-system + labels: + app: security + chart: security + heritage: Tiller + release: istio + istio: citadel +spec: + + minAvailable: 1 + selector: + matchLabels: + app: security + release: istio + istio: citadel + +--- +# Source: istio/charts/sidecarInjectorWebhook/templates/poddisruptionbudget.yaml + +apiVersion: policy/v1beta1 +kind: PodDisruptionBudget +metadata: + name: istio-sidecar-injector + namespace: istio-system + labels: + app: sidecarInjectorWebhook + release: istio + istio: sidecar-injector +spec: + + minAvailable: 1 + selector: + matchLabels: + app: sidecarInjectorWebhook + release: istio + istio: sidecar-injector + +--- +# Source: istio/charts/kiali/templates/demosecret.yaml + +apiVersion: v1 +kind: Secret +metadata: + name: kiali + namespace: istio-system + labels: + app: kiali + chart: kiali + heritage: Tiller + release: istio +type: Opaque +data: + username: YWRtaW4= # admin + passphrase: YWRtaW4= # admin + +--- +# Source: istio/charts/galley/templates/configmap.yaml +apiVersion: v1 +kind: ConfigMap +metadata: + name: istio-galley-configuration + namespace: istio-system + labels: + app: galley + chart: galley + heritage: Tiller + release: istio + istio: galley +data: + validatingwebhookconfiguration.yaml: |- + apiVersion: admissionregistration.k8s.io/v1beta1 + kind: ValidatingWebhookConfiguration + metadata: + name: istio-galley + labels: + app: galley + chart: galley + heritage: Tiller + release: istio + istio: galley + webhooks: + - name: pilot.validation.istio.io + clientConfig: + service: + name: istio-galley + namespace: istio-system + path: "/admitpilot" + caBundle: "" + rules: + - operations: + - CREATE + - UPDATE + apiGroups: + - config.istio.io + apiVersions: + - v1alpha2 + resources: + - httpapispecs + - httpapispecbindings + - quotaspecs + - quotaspecbindings + - operations: + - CREATE + - UPDATE + apiGroups: + - rbac.istio.io + apiVersions: + - "*" + resources: + - "*" + - operations: + - CREATE + - UPDATE + apiGroups: + - security.istio.io + apiVersions: + - "*" + resources: + - "*" + - operations: + - CREATE + - UPDATE + apiGroups: + - authentication.istio.io + apiVersions: + - "*" + resources: + - "*" + - operations: + - CREATE + - UPDATE + apiGroups: + - networking.istio.io + apiVersions: + - "*" + resources: + - destinationrules + - envoyfilters + - gateways + - serviceentries + - sidecars + - virtualservices + # Fail open until the validation webhook is ready. The webhook controller + # will update this to `Fail` and patch in the `caBundle` when the webhook + # endpoint is ready. + failurePolicy: Ignore + sideEffects: None + - name: mixer.validation.istio.io + clientConfig: + service: + name: istio-galley + namespace: istio-system + path: "/admitmixer" + caBundle: "" + rules: + - operations: + - CREATE + - UPDATE + apiGroups: + - config.istio.io + apiVersions: + - v1alpha2 + resources: + - rules + - attributemanifests + - adapters + - handlers + - instances + - templates + # Fail open until the validation webhook is ready. The webhook controller + # will update this to `Fail` and patch in the `caBundle` when the webhook + # endpoint is ready. + failurePolicy: Ignore + sideEffects: None + +--- +# Source: istio/charts/grafana/templates/configmap-custom-resources.yaml +apiVersion: v1 +kind: ConfigMap +metadata: + name: istio-grafana-custom-resources + namespace: istio-system + labels: + app: grafana + chart: grafana + heritage: Tiller + release: istio + istio: grafana +data: + custom-resources.yaml: |- + apiVersion: authentication.istio.io/v1alpha1 + kind: Policy + metadata: + name: grafana-ports-mtls-disabled + namespace: istio-system + labels: + app: grafana + chart: grafana + heritage: Tiller + release: istio + spec: + targets: + - name: grafana + ports: + - number: 3000 + run.sh: |- + #!/bin/sh + + set -x + + if [ "$#" -ne "1" ]; then + echo "first argument should be path to custom resource yaml" + exit 1 + fi + + pathToResourceYAML=${1} + + kubectl get validatingwebhookconfiguration istio-galley 2>/dev/null + if [ "$?" -eq 0 ]; then + echo "istio-galley validatingwebhookconfiguration found - waiting for istio-galley deployment to be ready" + while true; do + kubectl -n istio-system get deployment istio-galley 2>/dev/null + if [ "$?" -eq 0 ]; then + break + fi + sleep 1 + done + kubectl -n istio-system rollout status deployment istio-galley + if [ "$?" -ne 0 ]; then + echo "istio-galley deployment rollout status check failed" + exit 1 + fi + echo "istio-galley deployment ready for configuration validation" + fi + sleep 5 + kubectl apply -f ${pathToResourceYAML} + + +--- +# Source: istio/charts/grafana/templates/configmap-dashboards.yaml + +apiVersion: v1 +kind: ConfigMap +metadata: + name: istio-grafana-configuration-dashboards-citadel-dashboard + namespace: istio-system + labels: + app: grafana + chart: grafana + heritage: Tiller + release: istio + istio: grafana +data: + citadel-dashboard.json: '{ + "annotations": { + "list": [ + { + "builtIn": 1, + "datasource": "-- Grafana --", + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations & Alerts", + "type": "dashboard" + } + ] + }, + "description": "", + "editable": true, + "gnetId": null, + "graphTooltip": 0, + "links": [], + "panels": [ + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 0 + }, + "id": 8, + "panels": [], + "title": "Performance", + "type": "row" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "description": "CPU usage across Citadel instances.", + "fill": 1, + "gridPos": { + "h": 6, + "w": 8, + "x": 0, + "y": 1 + }, + "id": 10, + "legend": { + "alignAsTable": false, + "avg": false, + "current": false, + "max": false, + "min": false, + "rightSide": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(rate(container_cpu_usage_seconds_total{job=\"kubernetes-cadvisor\",container=~\"citadel\", pod=~\"istio-citadel-.*\"}[1m]))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Citadel CPU usage rate", + "refId": "A" + }, + { + "expr": "irate(process_cpu_seconds_total{job=\"citadel\"}[1m])", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Citadel CPU usage irate", + "refId": "C" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "CPU", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": "", + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "description": "Citadel process memory statistics.", + "fill": 1, + "gridPos": { + "h": 6, + "w": 8, + "x": 8, + "y": 1 + }, + "id": 12, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "process_virtual_memory_bytes{job=\"citadel\"}", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Virtual Memory", + "refId": "A" + }, + { + "expr": "process_resident_memory_bytes{job=\"citadel\"}", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Resident Memory", + "refId": "B" + }, + { + "expr": "go_memstats_heap_sys_bytes{job=\"citadel\"}", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Heap Memory Total", + "refId": "C" + }, + { + "expr": "go_memstats_alloc_bytes{job=\"citadel\"}", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Heap Memory Allocated", + "refId": "E" + }, + { + "expr": "go_memstats_heap_inuse_bytes{job=\"citadel\"}", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Heap Inuse", + "refId": "F" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Memory", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "fill": 1, + "gridPos": { + "h": 6, + "w": 8, + "x": 16, + "y": 1 + }, + "id": 14, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "go_goroutines{job=\"citadel\"}", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Goroutines", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Goroutines", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 7 + }, + "id": 28, + "panels": [], + "title": "General", + "type": "row" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "description": "Total number of CSR requests made to Citadel.", + "fill": 1, + "gridPos": { + "h": 5, + "w": 12, + "x": 0, + "y": 8 + }, + "id": 30, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "citadel_server_csr_count{job=\"citadel\"}", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "CSR Request Count", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "CSR Requests", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "description": "The number of certificates issuances that have succeeded.", + "fill": 1, + "gridPos": { + "h": 5, + "w": 12, + "x": 12, + "y": 8 + }, + "id": 32, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "citadel_server_success_cert_issuance_count{job=\"citadel\"}", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Certificates Issued", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Certificates Issued", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 13 + }, + "id": 23, + "panels": [], + "title": "Errors", + "type": "row" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "description": "The number of errors occurred when creating the CSR.", + "fill": 1, + "gridPos": { + "h": 5, + "w": 8, + "x": 0, + "y": 14 + }, + "id": 20, + "legend": { + "alignAsTable": false, + "avg": false, + "current": false, + "max": false, + "min": false, + "rightSide": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "citadel_secret_controller_csr_err_count{job=\"citadel\"}", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "CSR Creation Error Count", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "CSR Creation Errors", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": "", + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "fill": 1, + "gridPos": { + "h": 5, + "w": 8, + "x": 8, + "y": 14 + }, + "id": 24, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "citadel_server_csr_parsing_err_count{job=\"citadel\"}", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "CSR Parse Error Count", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "CSR Parse Errors", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "description": "The number of authentication failures.", + "fill": 1, + "gridPos": { + "h": 5, + "w": 8, + "x": 16, + "y": 14 + }, + "id": 26, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "citadel_server_authentication_failure_count{job=\"citadel\"}", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Authentication Failure Count", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Authentication Failures", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 19 + }, + "id": 4, + "panels": [], + "title": "Secret Controller", + "type": "row" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "description": "The number of certificates created due to service account creation.", + "fill": 1, + "gridPos": { + "h": 5, + "w": 8, + "x": 0, + "y": 20 + }, + "id": 2, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": true, + "targets": [ + { + "expr": "citadel_secret_controller_svc_acc_created_cert_count{job=\"citadel\"}", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "SA Secrets Created", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Service Account Secrets Created (due to SA creation)", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "decimals": null, + "format": "short", + "label": "Certs Created", + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "description": "The number of certificates deleted due to service account deletion.", + "fill": 1, + "gridPos": { + "h": 5, + "w": 8, + "x": 8, + "y": 20 + }, + "id": 16, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": true, + "targets": [ + { + "expr": "citadel_secret_controller_svc_acc_deleted_cert_count{job=\"citadel\"}", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "SA Secrets Deleted", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Service Account Secrets Deleted (due to SA deletion)", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "decimals": null, + "format": "short", + "label": "Certs Created", + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "description": "The number of certificates recreated due to secret deletion (service account still exists).", + "fill": 1, + "gridPos": { + "h": 5, + "w": 8, + "x": 16, + "y": 20 + }, + "id": 6, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": true, + "targets": [ + { + "expr": "citadel_secret_controller_secret_deleted_cert_count{job=\"citadel\"}", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "SA Secrets Recreated", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Service Account Secrets Recreated (due to errant deletion)", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "decimals": null, + "format": "short", + "label": "Certs Created", + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + } + ], + "refresh": "5s", + "schemaVersion": 18, + "style": "dark", + "tags": [], + "templating": { + "list": [] + }, + "time": { + "from": "now-5m", + "to": "now" + }, + "timepicker": { + "refresh_intervals": [ + "5s", + "10s", + "30s", + "1m", + "5m", + "15m", + "30m", + "1h", + "2h", + "1d" + ], + "time_options": [ + "5m", + "15m", + "1h", + "6h", + "12h", + "24h", + "2d", + "7d", + "30d" + ] + }, + "timezone": "", + "title": "Istio Citadel Dashboard", + "uid": "OOyOqb4Wz", + "version": 1 +}' +--- +apiVersion: v1 +kind: ConfigMap +metadata: + name: istio-grafana-configuration-dashboards-galley-dashboard + namespace: istio-system + labels: + app: grafana + chart: grafana + heritage: Tiller + release: istio + istio: grafana +data: + galley-dashboard.json: '{ + "__inputs": [ + { + "name": "DS_PROMETHEUS", + "label": "Prometheus", + "description": "", + "type": "datasource", + "pluginId": "prometheus", + "pluginName": "Prometheus" + } + ], + "annotations": { + "list": [ + { + "builtIn": 1, + "datasource": "-- Grafana --", + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations & Alerts", + "type": "dashboard" + } + ] + }, + "editable": false, + "gnetId": null, + "graphTooltip": 0, + "links": [], + "panels": [ + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 5, + "w": 24, + "x": 0, + "y": 0 + }, + "id": 46, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(istio_build{component=\"galley\"}) by (tag)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{ tag }}", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Galley Versions", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 5 + }, + "id": 40, + "panels": [], + "title": "Resource Usage", + "type": "row" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 8, + "w": 6, + "x": 0, + "y": 6 + }, + "id": 36, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "process_virtual_memory_bytes{job=\"galley\"}", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "Virtual Memory", + "refId": "A" + }, + { + "expr": "process_resident_memory_bytes{job=\"galley\"}", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "Resident Memory", + "refId": "B" + }, + { + "expr": "go_memstats_heap_sys_bytes{job=\"galley\"}", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "heap sys", + "refId": "C" + }, + { + "expr": "go_memstats_heap_alloc_bytes{job=\"galley\"}", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "heap alloc", + "refId": "D" + }, + { + "expr": "go_memstats_alloc_bytes{job=\"galley\"}", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "Alloc", + "refId": "F" + }, + { + "expr": "go_memstats_heap_inuse_bytes{job=\"galley\"}", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "Heap in-use", + "refId": "G" + }, + { + "expr": "go_memstats_stack_inuse_bytes{job=\"galley\"}", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "Stack in-use", + "refId": "H" + }, + { + "expr": "sum(container_memory_usage_bytes{job=\"kubernetes-cadvisor\",container=~\"galley\", pod=~\"istio-galley-.*\"})", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Total (kis)", + "refId": "E" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Memory", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 8, + "w": 6, + "x": 6, + "y": 6 + }, + "id": 38, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(rate(container_cpu_usage_seconds_total{job=\"kubernetes-cadvisor\",container=~\"galley\", pod=~\"istio-galley-.*\"}[1m]))", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "Total (k8s)", + "refId": "A" + }, + { + "expr": "sum(rate(container_cpu_usage_seconds_total{job=\"kubernetes-cadvisor\",container=~\"galley\", pod=~\"istio-galley-.*\"}[1m])) by (container)", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "{{ container }} (k8s)", + "refId": "B" + }, + { + "expr": "irate(process_cpu_seconds_total{job=\"galley\"}[1m])", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "galley (self-reported)", + "refId": "C" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "CPU", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 8, + "w": 6, + "x": 12, + "y": 6 + }, + "id": 42, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "process_open_fds{job=\"galley\"}", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "Open FDs (galley)", + "refId": "A" + }, + { + "expr": "container_fs_usage_bytes{job=\"kubernetes-cadvisor\",container=~\"galley\", pod=~\"istio-galley-.*\"}", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "{{ container }} ", + "refId": "B" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Disk", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 8, + "w": 6, + "x": 18, + "y": 6 + }, + "id": 44, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "go_goroutines{job=\"galley\"}", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "goroutines_total", + "refId": "A" + }, + { + "expr": "istio_mcp_clients_total{component=\"galley\"}", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "clients_total", + "refId": "B" + }, + { + "expr": "go_goroutines{job=\"galley\"}/sum(istio_mcp_clients_total{component=\"galley\"}) without (component)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "avg_goroutines_per_client", + "refId": "C" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Goroutines", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 14 + }, + "id": 10, + "panels": [], + "title": "Runtime", + "type": "row" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 6, + "w": 8, + "x": 0, + "y": 15 + }, + "id": 2, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(rate(galley_runtime_strategy_on_change_total[1m])) * 60", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Strategy Change Events", + "refId": "A" + }, + { + "expr": "sum(rate(galley_runtime_processor_events_processed_total[1m])) * 60", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Processed Events", + "refId": "B" + }, + { + "expr": "sum(rate(galley_runtime_processor_snapshots_published_total[1m])) * 60", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Snapshot Published", + "refId": "C" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Event Rates", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": "Events/min", + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": "", + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 6, + "w": 8, + "x": 8, + "y": 15 + }, + "id": 4, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(rate(galley_runtime_strategy_timer_max_time_reached_total[1m])) * 60", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Max Time Reached", + "refId": "A" + }, + { + "expr": "sum(rate(galley_runtime_strategy_timer_quiesce_reached_total[1m])) * 60", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Quiesce Reached", + "refId": "B" + }, + { + "expr": "sum(rate(galley_runtime_strategy_timer_resets_total[1m])) * 60", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Timer Resets", + "refId": "C" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Timer Rates", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": "Events/min", + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 6, + "w": 8, + "x": 16, + "y": 15 + }, + "id": 8, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 3, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": true, + "steppedLine": false, + "targets": [ + { + "expr": "histogram_quantile(0.50, sum by (le) (galley_runtime_processor_snapshot_events_total_bucket))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "P50", + "refId": "A" + }, + { + "expr": "histogram_quantile(0.90, sum by (le) (galley_runtime_processor_snapshot_events_total_bucket))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "P90", + "refId": "B" + }, + { + "expr": "histogram_quantile(0.95, sum by (le) (galley_runtime_processor_snapshot_events_total_bucket))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "P95", + "refId": "C" + }, + { + "expr": "histogram_quantile(0.99, sum by (le) (galley_runtime_processor_snapshot_events_total_bucket))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "P99", + "refId": "D" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Events Per Snapshot", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 6, + "w": 8, + "x": 8, + "y": 21 + }, + "id": 6, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum by (collection) (galley_runtime_state_type_instances_total)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{ collection }}", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "State Type Instances", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": "Count", + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 27 + }, + "id": 34, + "panels": [], + "title": "Validation", + "type": "row" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 6, + "w": 8, + "x": 0, + "y": 28 + }, + "id": 28, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "galley_validation_cert_key_updates{job=\"galley\"}", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Key Updates", + "refId": "A" + }, + { + "expr": "galley_validation_cert_key_update_errors{job=\"galley\"}", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Key Update Errors: {{ error }}", + "refId": "B" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Validation Webhook Certificate", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 6, + "w": 8, + "x": 8, + "y": 28 + }, + "id": 30, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(galley_validation_passed{job=\"galley\"}) by (group, version, resource)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Passed: {{ group }}/{{ version }}/{{resource}}", + "refId": "A" + }, + { + "expr": "sum(galley_validation_failed{job=\"galley\"}) by (group, version, resource, reason)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Failed: {{ group }}/{{ version }}/{{resource}} ({{ reason}})", + "refId": "B" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Resource Validation", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 6, + "w": 8, + "x": 16, + "y": 28 + }, + "id": 32, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(galley_validation_http_error{job=\"galley\"}) by (status)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{ status }}", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Validation HTTP Errors", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 34 + }, + "id": 12, + "panels": [], + "title": "Kubernetes Source", + "type": "row" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 6, + "w": 8, + "x": 0, + "y": 35 + }, + "id": 14, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "rate(galley_source_kube_event_success_total[1m]) * 60", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Success", + "refId": "A" + }, + { + "expr": "rate(galley_source_kube_event_error_total[1m]) * 60", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Error", + "refId": "B" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Source Event Rate", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": "Events/min", + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 6, + "w": 8, + "x": 16, + "y": 35 + }, + "id": 24, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "rate(galley_source_kube_dynamic_converter_failure_total[1m]) * 60", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Error", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Kubernetes Object Conversion Failures", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": "Failures/min", + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 41 + }, + "id": 18, + "panels": [], + "title": "Mesh Configuration Protocol", + "type": "row" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 6, + "w": 8, + "x": 0, + "y": 42 + }, + "id": 20, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(istio_mcp_clients_total{component=\"galley\"})", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Clients", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Connected Clients", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 6, + "w": 8, + "x": 8, + "y": 42 + }, + "id": 22, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum by(collection)(irate(istio_mcp_request_acks_total{component=\"galley\"}[1m]) * 60)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Request ACKs", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": "ACKs/min", + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 6, + "w": 8, + "x": 16, + "y": 42 + }, + "id": 26, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "rate(istio_mcp_request_nacks_total{component=\"galley\"}[1m]) * 60", + "format": "time_series", + "intervalFactor": 1, + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Request NACKs", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": "NACKs/min", + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + } + ], + "refresh": "5s", + "schemaVersion": 16, + "style": "dark", + "tags": [], + "templating": { + "list": [] + }, + "time": { + "from": "now-5m", + "to": "now" + }, + "timepicker": { + "refresh_intervals": [ + "5s", + "10s", + "30s", + "1m", + "5m", + "15m", + "30m", + "1h", + "2h", + "1d" + ], + "time_options": [ + "5m", + "15m", + "1h", + "6h", + "12h", + "24h", + "2d", + "7d", + "30d" + ] + }, + "timezone": "", + "title": "Istio Galley Dashboard", + "uid": "TSEY6jLmk", + "version": 1 +} +' +--- +apiVersion: v1 +kind: ConfigMap +metadata: + name: istio-grafana-configuration-dashboards-istio-mesh-dashboard + namespace: istio-system + labels: + app: grafana + chart: grafana + heritage: Tiller + release: istio + istio: grafana +data: + istio-mesh-dashboard.json: '{ + "annotations": { + "list": [ + { + "builtIn": 1, + "datasource": "-- Grafana --", + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations & Alerts", + "type": "dashboard" + } + ] + }, + "editable": false, + "gnetId": null, + "graphTooltip": 0, + "id": null, + "links": [], + "panels": [ + { + "content": "
\n
\n Istio\n
\n
\n Istio is an open platform that provides a uniform way to connect,\n manage, and \n secure microservices.\n
\n Need help? Join the Istio community.\n
\n
", + "gridPos": { + "h": 3, + "w": 24, + "x": 0, + "y": 0 + }, + "height": "50px", + "id": 13, + "links": [], + "mode": "html", + "style": { + "font-size": "18pt" + }, + "title": "", + "transparent": true, + "type": "text" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "datasource": "Prometheus", + "format": "ops", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "gridPos": { + "h": 3, + "w": 6, + "x": 0, + "y": 3 + }, + "id": 20, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": true, + "lineColor": "rgb(31, 120, 193)", + "show": true + }, + "tableColumn": "", + "targets": [ + { + "expr": "round(sum(irate(istio_requests_total{reporter=\"destination\"}[1m])), 0.001)", + "intervalFactor": 1, + "refId": "A", + "step": 4 + } + ], + "thresholds": "", + "title": "Global Request Volume", + "type": "singlestat", + "valueFontSize": "80%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "avg" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "datasource": "Prometheus", + "format": "percentunit", + "gauge": { + "maxValue": 100, + "minValue": 80, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": false + }, + "gridPos": { + "h": 3, + "w": 6, + "x": 6, + "y": 3 + }, + "id": 21, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": true, + "lineColor": "rgb(31, 120, 193)", + "show": true + }, + "tableColumn": "", + "targets": [ + { + "expr": "sum(rate(istio_requests_total{reporter=\"destination\", response_code!~\"5.*\"}[1m])) / sum(rate(istio_requests_total{reporter=\"destination\"}[1m]))", + "format": "time_series", + "intervalFactor": 1, + "refId": "A", + "step": 4 + } + ], + "thresholds": "95, 99, 99.5", + "title": "Global Success Rate (non-5xx responses)", + "type": "singlestat", + "valueFontSize": "80%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "avg" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "datasource": "Prometheus", + "format": "ops", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "gridPos": { + "h": 3, + "w": 6, + "x": 12, + "y": 3 + }, + "id": 22, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": true, + "lineColor": "rgb(31, 120, 193)", + "show": true + }, + "tableColumn": "", + "targets": [ + { + "expr": "sum(irate(istio_requests_total{reporter=\"destination\", response_code=~\"4.*\"}[1m])) ", + "format": "time_series", + "intervalFactor": 1, + "refId": "A", + "step": 4 + } + ], + "thresholds": "", + "title": "4xxs", + "type": "singlestat", + "valueFontSize": "80%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "avg" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "datasource": "Prometheus", + "format": "ops", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "gridPos": { + "h": 3, + "w": 6, + "x": 18, + "y": 3 + }, + "id": 23, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": true, + "lineColor": "rgb(31, 120, 193)", + "show": true + }, + "tableColumn": "", + "targets": [ + { + "expr": "sum(irate(istio_requests_total{reporter=\"destination\", response_code=~\"5.*\"}[1m])) ", + "format": "time_series", + "intervalFactor": 1, + "refId": "A", + "step": 4 + } + ], + "thresholds": "", + "title": "5xxs", + "type": "singlestat", + "valueFontSize": "80%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "avg" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "#299c46", + "rgba(237, 129, 40, 0.89)", + "#d44a3a" + ], + "format": "none", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "gridPos": { + "h": 3, + "w": 6, + "x": 0, + "y": 6 + }, + "id": 113, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": false, + "lineColor": "rgb(31, 120, 193)", + "show": true + }, + "tableColumn": "", + "targets": [ + { + "expr": "sum(galley_istio_networking_virtualservices) / count(up{job=\"galley\"})", + "format": "time_series", + "intervalFactor": 1, + "refId": "A" + } + ], + "thresholds": "", + "timeFrom": null, + "timeShift": null, + "title": "Virtual Services", + "type": "singlestat", + "valueFontSize": "80%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "current" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "#299c46", + "rgba(237, 129, 40, 0.89)", + "#d44a3a" + ], + "format": "none", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "gridPos": { + "h": 3, + "w": 6, + "x": 6, + "y": 6 + }, + "id": 114, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": false, + "lineColor": "rgb(31, 120, 193)", + "show": true + }, + "tableColumn": "", + "targets": [ + { + "expr": "sum(galley_istio_networking_destinationrules) / count(up{job=\"galley\"})", + "format": "time_series", + "intervalFactor": 1, + "refId": "A" + } + ], + "thresholds": "", + "timeFrom": null, + "timeShift": null, + "title": "Destination Rules", + "type": "singlestat", + "valueFontSize": "80%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "current" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "#299c46", + "rgba(237, 129, 40, 0.89)", + "#d44a3a" + ], + "format": "none", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "gridPos": { + "h": 3, + "w": 6, + "x": 12, + "y": 6 + }, + "id": 115, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": false, + "lineColor": "rgb(31, 120, 193)", + "show": true + }, + "tableColumn": "", + "targets": [ + { + "expr": "sum(galley_istio_networking_gateways) / count(up{job=\"galley\"})", + "format": "time_series", + "intervalFactor": 1, + "refId": "A" + } + ], + "thresholds": "", + "timeFrom": null, + "timeShift": null, + "title": "Gateways", + "type": "singlestat", + "valueFontSize": "80%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "current" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "#299c46", + "rgba(237, 129, 40, 0.89)", + "#d44a3a" + ], + "format": "none", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "gridPos": { + "h": 3, + "w": 6, + "x": 18, + "y": 6 + }, + "id": 116, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": false, + "lineColor": "rgb(31, 120, 193)", + "show": true + }, + "tableColumn": "", + "targets": [ + { + "expr": "sum(galley_istio_authentication_meshpolicies) / count(up{job=\"galley\"})", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "refId": "A" + } + ], + "thresholds": "", + "timeFrom": null, + "timeShift": null, + "title": "Authentication Mesh Policies", + "type": "singlestat", + "valueFontSize": "80%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "current" + }, + { + "columns": [], + "datasource": "Prometheus", + "fontSize": "100%", + "gridPos": { + "h": 21, + "w": 24, + "x": 0, + "y": 9 + }, + "hideTimeOverride": false, + "id": 73, + "links": [], + "pageSize": null, + "repeat": null, + "repeatDirection": "v", + "scroll": true, + "showHeader": true, + "sort": { + "col": 4, + "desc": true + }, + "styles": [ + { + "alias": "Workload", + "colorMode": null, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "link": false, + "linkTargetBlank": false, + "linkTooltip": "Workload dashboard", + "linkUrl": "/dashboard/db/istio-workload-dashboard?var-namespace=$__cell_2&var-workload=$__cell_", + "pattern": "destination_workload", + "preserveFormat": false, + "sanitize": false, + "thresholds": [], + "type": "hidden", + "unit": "short" + }, + { + "alias": "", + "colorMode": null, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "pattern": "Time", + "thresholds": [], + "type": "hidden", + "unit": "short" + }, + { + "alias": "Requests", + "colorMode": null, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "pattern": "Value #A", + "thresholds": [], + "type": "number", + "unit": "ops" + }, + { + "alias": "P50 Latency", + "colorMode": null, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "pattern": "Value #B", + "thresholds": [], + "type": "number", + "unit": "s" + }, + { + "alias": "P90 Latency", + "colorMode": null, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "pattern": "Value #D", + "thresholds": [], + "type": "number", + "unit": "s" + }, + { + "alias": "P99 Latency", + "colorMode": null, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "pattern": "Value #E", + "thresholds": [], + "type": "number", + "unit": "s" + }, + { + "alias": "Success Rate", + "colorMode": "cell", + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "pattern": "Value #F", + "thresholds": [ + ".95", + " 1.00" + ], + "type": "number", + "unit": "percentunit" + }, + { + "alias": "Workload", + "colorMode": null, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "link": true, + "linkTooltip": "$__cell dashboard", + "linkUrl": "/dashboard/db/istio-workload-dashboard?var-workload=$__cell_2&var-namespace=$__cell_3", + "pattern": "destination_workload_var", + "thresholds": [], + "type": "number", + "unit": "short" + }, + { + "alias": "Service", + "colorMode": null, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "link": true, + "linkTooltip": "$__cell dashboard", + "linkUrl": "/dashboard/db/istio-service-dashboard?var-service=$__cell", + "pattern": "destination_service", + "thresholds": [], + "type": "string", + "unit": "short" + }, + { + "alias": "", + "colorMode": null, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "pattern": "destination_workload_namespace", + "thresholds": [], + "type": "hidden", + "unit": "short" + } + ], + "targets": [ + { + "expr": "label_join(sum(rate(istio_requests_total{reporter=\"destination\", response_code=\"200\"}[1m])) by (destination_workload, destination_workload_namespace, destination_service), \"destination_workload_var\", \".\", \"destination_workload\", \"destination_workload_namespace\")", + "format": "table", + "hide": false, + "instant": true, + "intervalFactor": 1, + "legendFormat": "{{ destination_workload}}.{{ destination_workload_namespace }}", + "refId": "A" + }, + { + "expr": "label_join((histogram_quantile(0.50, sum(rate(istio_request_duration_milliseconds_bucket{reporter=\"destination\"}[1m])) by (le, destination_workload, destination_workload_namespace)) / 1000) or histogram_quantile(0.50, sum(rate(istio_request_duration_seconds_bucket{reporter=\"destination\"}[1m])) by (le, destination_workload, destination_workload_namespace)), \"destination_workload_var\", \".\", \"destination_workload\", \"destination_workload_namespace\")", + "format": "table", + "hide": false, + "instant": true, + "intervalFactor": 1, + "legendFormat": "{{ destination_workload}}.{{ destination_workload_namespace }}", + "refId": "B" + }, + { + "expr": "label_join((histogram_quantile(0.90, sum(rate(istio_request_duration_milliseconds_bucket{reporter=\"destination\"}[1m])) by (le, destination_workload, destination_workload_namespace)) / 1000) or histogram_quantile(0.90, sum(rate(istio_request_duration_seconds_bucket{reporter=\"destination\"}[1m])) by (le, destination_workload, destination_workload_namespace)), \"destination_workload_var\", \".\", \"destination_workload\", \"destination_workload_namespace\")", + "format": "table", + "hide": false, + "instant": true, + "intervalFactor": 1, + "legendFormat": "{{ destination_workload }}.{{ destination_workload_namespace }}", + "refId": "D" + }, + { + "expr": "label_join((histogram_quantile(0.99, sum(rate(istio_request_duration_milliseconds_bucket{reporter=\"destination\"}[1m])) by (le, destination_workload, destination_workload_namespace)) / 1000) or histogram_quantile(0.99, sum(rate(istio_request_duration_seconds_bucket{reporter=\"destination\"}[1m])) by (le, destination_workload, destination_workload_namespace)), \"destination_workload_var\", \".\", \"destination_workload\", \"destination_workload_namespace\")", + "format": "table", + "hide": false, + "instant": true, + "intervalFactor": 1, + "legendFormat": "{{ destination_workload }}.{{ destination_workload_namespace }}", + "refId": "E" + }, + { + "expr": "label_join((sum(rate(istio_requests_total{reporter=\"destination\", response_code!~\"5.*\"}[1m])) by (destination_workload, destination_workload_namespace) / sum(rate(istio_requests_total{reporter=\"destination\"}[1m])) by (destination_workload, destination_workload_namespace)), \"destination_workload_var\", \".\", \"destination_workload\", \"destination_workload_namespace\")", + "format": "table", + "hide": false, + "instant": true, + "interval": "", + "intervalFactor": 1, + "legendFormat": "{{ destination_workload }}.{{ destination_workload_namespace }}", + "refId": "F" + } + ], + "timeFrom": null, + "title": "HTTP/GRPC Workloads", + "transform": "table", + "type": "table" + }, + { + "columns": [], + "datasource": "Prometheus", + "fontSize": "100%", + "gridPos": { + "h": 18, + "w": 24, + "x": 0, + "y": 30 + }, + "hideTimeOverride": false, + "id": 109, + "links": [], + "pageSize": null, + "repeatDirection": "v", + "scroll": true, + "showHeader": true, + "sort": { + "col": 2, + "desc": true + }, + "styles": [ + { + "alias": "Workload", + "colorMode": null, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "link": false, + "linkTargetBlank": false, + "linkTooltip": "$__cell dashboard", + "linkUrl": "/dashboard/db/istio-tcp-workload-dashboard?var-namespace=$__cell_2&&var-workload=$__cell", + "pattern": "destination_workload", + "preserveFormat": false, + "sanitize": false, + "thresholds": [], + "type": "hidden", + "unit": "short" + }, + { + "alias": "Bytes Sent", + "colorMode": null, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "pattern": "Value #A", + "thresholds": [ + "" + ], + "type": "number", + "unit": "Bps" + }, + { + "alias": "Bytes Received", + "colorMode": null, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "pattern": "Value #C", + "thresholds": [], + "type": "number", + "unit": "Bps" + }, + { + "alias": "", + "colorMode": null, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "pattern": "Time", + "thresholds": [], + "type": "hidden", + "unit": "short" + }, + { + "alias": "Workload", + "colorMode": null, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "link": true, + "linkTooltip": "$__cell dashboard", + "linkUrl": "/dashboard/db/istio-workload-dashboard?var-namespace=$__cell_3&var-workload=$__cell_2", + "pattern": "destination_workload_var", + "thresholds": [], + "type": "string", + "unit": "short" + }, + { + "alias": "", + "colorMode": null, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "pattern": "destination_workload_namespace", + "thresholds": [], + "type": "hidden", + "unit": "short" + }, + { + "alias": "Service", + "colorMode": null, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "link": true, + "linkTooltip": "$__cell dashboard", + "linkUrl": "/dashboard/db/istio-service-dashboard?var-service=$__cell", + "pattern": "destination_service", + "thresholds": [], + "type": "number", + "unit": "short" + } + ], + "targets": [ + { + "expr": "label_join(sum(rate(istio_tcp_received_bytes_total{reporter=\"source\"}[1m])) by (destination_workload, destination_workload_namespace, destination_service), \"destination_workload_var\", \".\", \"destination_workload\", \"destination_workload_namespace\")", + "format": "table", + "hide": false, + "instant": true, + "intervalFactor": 1, + "legendFormat": "{{ destination_workload }}", + "refId": "C" + }, + { + "expr": "label_join(sum(rate(istio_tcp_sent_bytes_total{reporter=\"source\"}[1m])) by (destination_workload, destination_workload_namespace, destination_service), \"destination_workload_var\", \".\", \"destination_workload\", \"destination_workload_namespace\")", + "format": "table", + "hide": false, + "instant": true, + "intervalFactor": 1, + "legendFormat": "{{ destination_workload }}", + "refId": "A" + } + ], + "timeFrom": null, + "title": "TCP Workloads", + "transform": "table", + "type": "table" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 9, + "w": 24, + "x": 0, + "y": 48 + }, + "id": 111, + "legend": { + "alignAsTable": false, + "avg": false, + "current": false, + "max": false, + "min": false, + "rightSide": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(istio_build) by (component, tag)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{ component }}: {{ tag }}", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Istio Components by Version", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + } + ], + "refresh": "5s", + "schemaVersion": 18, + "style": "dark", + "tags": [], + "templating": { + "list": [] + }, + "time": { + "from": "now-5m", + "to": "now" + }, + "timepicker": { + "refresh_intervals": [ + "5s", + "10s", + "30s", + "1m", + "5m", + "15m", + "30m", + "1h", + "2h", + "1d" + ], + "time_options": [ + "5m", + "15m", + "1h", + "6h", + "12h", + "24h", + "2d", + "7d", + "30d" + ] + }, + "timezone": "browser", + "title": "Istio Mesh Dashboard", + "uid": "G8wLrJIZk", + "version": 5 +} +' +--- +apiVersion: v1 +kind: ConfigMap +metadata: + name: istio-grafana-configuration-dashboards-istio-performance-dashboard + namespace: istio-system + labels: + app: grafana + chart: grafana + heritage: Tiller + release: istio + istio: grafana +data: + istio-performance-dashboard.json: '{ + "annotations": { + "list": [ + { + "builtIn": 1, + "datasource": "-- Grafana --", + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations & Alerts", + "type": "dashboard" + } + ] + }, + "editable": false, + "gnetId": null, + "graphTooltip": 0, + "id": 9, + "links": [], + "panels": [ + { + "collapsed": true, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 0 + }, + "id": 21, + "panels": [ + { + "content": "The charts on this dashboard are intended to show Istio main components cost in terms resources utilization under steady load.\n\n- **vCPU/1k rps:** shows vCPU utilization by the main Istio components normalized by 1000 requests/second. When idle or low traffic, this chart will be blank. The curve for istio-proxy refers to the services sidecars only.\n- **vCPU:** vCPU utilization by Istio components, not normalized.\n- **Memory:** memory footprint for the components. Telemetry and policy are normalized by 1k rps, and no data is shown when there is no traffic. For ingress and istio-proxy, the data is per instance.\n- **Bytes transferred/ sec:** shows the number of bytes flowing through each Istio component.\n\n\n", + "gridPos": { + "h": 6, + "w": 24, + "x": 0, + "y": 1 + }, + "id": 19, + "links": [], + "mode": "markdown", + "timeFrom": null, + "timeShift": null, + "title": "Performance Dashboard README", + "transparent": true, + "type": "text" + } + ], + "title": "Performance Dashboard Notes", + "type": "row" + }, + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 1 + }, + "id": 6, + "panels": [], + "title": "vCPU Usage", + "type": "row" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "fill": 1, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 2 + }, + "id": 4, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "(sum(irate(container_cpu_usage_seconds_total{job=\"kubernetes-cadvisor\",pod=~\"istio-telemetry-.*\",container=~\"mixer|istio-proxy\"}[1m]))/ (round(sum(irate(istio_requests_total[1m])), 0.001)/1000))/ (sum(irate(istio_requests_total{source_workload=\"istio-ingressgateway\"}[1m])) >bool 10)", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "istio-telemetry", + "refId": "A" + }, + { + "expr": "(sum(irate(container_cpu_usage_seconds_total{job=\"kubernetes-cadvisor\",pod=~\"istio-ingressgateway-.*\",container=\"istio-proxy\"}[1m])) / (round(sum(irate(istio_requests_total{source_workload=\"istio-ingressgateway\", reporter=\"source\"}[1m])), 0.001)/1000))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "istio-ingressgateway", + "refId": "B" + }, + { + "expr": "(sum(irate(container_cpu_usage_seconds_total{job=\"kubernetes-cadvisor\",namespace!=\"istio-system\",container=\"istio-proxy\"}[1m]))/ (round(sum(irate(istio_requests_total[1m])), 0.001)/1000))/ (sum(irate(istio_requests_total{source_workload=\"istio-ingressgateway\"}[1m])) >bool 10)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "istio-proxy", + "refId": "C" + }, + { + "expr": "(sum(irate(container_cpu_usage_seconds_total{job=\"kubernetes-cadvisor\",pod=~\"istio-policy-.*\",container=~\"mixer|istio-proxy\"}[1m]))/ (round(sum(irate(istio_requests_total[1m])), 0.001)/1000))/ (sum(irate(istio_requests_total{source_workload=\"istio-ingressgateway\"}[1m])) >bool 10)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "istio-policy", + "refId": "D" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "vCPU / 1k rps", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "fill": 1, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 2 + }, + "id": 7, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(rate(container_cpu_usage_seconds_total{job=\"kubernetes-cadvisor\",pod=~\"istio-telemetry-.*\",container=~\"mixer|istio-proxy\"}[1m]))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "istio-telemetry", + "refId": "A" + }, + { + "expr": "sum(rate(container_cpu_usage_seconds_total{job=\"kubernetes-cadvisor\",pod=~\"istio-ingressgateway-.*\",container=\"istio-proxy\"}[1m]))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "istio-ingressgateway", + "refId": "B" + }, + { + "expr": "sum(rate(container_cpu_usage_seconds_total{job=\"kubernetes-cadvisor\",namespace!=\"istio-system\",container=\"istio-proxy\"}[1m]))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "istio-proxy", + "refId": "C" + }, + { + "expr": "sum(rate(container_cpu_usage_seconds_total{job=\"kubernetes-cadvisor\",pod=~\"istio-policy-.*\",container=~\"mixer|istio-proxy\"}[1m]))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "istio-policy", + "refId": "D" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "vCPU", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 10 + }, + "id": 13, + "panels": [], + "title": "Memory and Data Rates", + "type": "row" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "fill": 1, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 11 + }, + "id": 902, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "(sum(container_memory_usage_bytes{job=\"kubernetes-cadvisor\",pod=~\"istio-telemetry-.*\"}) / (sum(irate(istio_requests_total[1m])) / 1000)) / (sum(irate(istio_requests_total{source_workload=\"istio-ingressgateway\"}[1m])) >bool 10)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "istio-telemetry / 1k rps", + "refId": "A" + }, + { + "expr": "sum(container_memory_usage_bytes{job=\"kubernetes-cadvisor\",pod=~\"istio-ingressgateway-.*\"}) / count(container_memory_usage_bytes{job=\"kubernetes-cadvisor\",pod=~\"istio-ingressgateway-.*\",container!=\"POD\"})", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "per istio-ingressgateway", + "refId": "B" + }, + { + "expr": "sum(container_memory_usage_bytes{job=\"kubernetes-cadvisor\",namespace!=\"istio-system\",container=\"istio-proxy\"}) / count(container_memory_usage_bytes{job=\"kubernetes-cadvisor\",namespace!=\"istio-system\",container=\"istio-proxy\"})", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "per istio proxy", + "refId": "C" + }, + { + "expr": "(sum(container_memory_usage_bytes{job=\"kubernetes-cadvisor\",pod=~\"istio-policy-.*\"}) / (sum(irate(istio_requests_total[1m])) / 1000))/ (sum(irate(istio_requests_total{source_workload=\"istio-ingressgateway\"}[1m])) >bool 10)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "istio-policy / 1k rps", + "refId": "D" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Memory Usage", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "bytes", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "fill": 1, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 11 + }, + "id": 11, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(irate(istio_response_bytes_sum{destination_workload=\"istio-telemetry\"}[1m])) + sum(irate(istio_request_bytes_sum{destination_workload=\"istio-telemetry\"}[1m]))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "istio-telemetry", + "refId": "A" + }, + { + "expr": "sum(irate(istio_response_bytes_sum{source_workload=\"istio-ingressgateway\", reporter=\"source\"}[1m]))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "istio-ingressgateway", + "refId": "B" + }, + { + "expr": "sum(irate(istio_response_bytes_sum{source_workload_namespace!=\"istio-system\", reporter=\"source\"}[1m])) + sum(irate(istio_response_bytes_sum{destination_workload_namespace!=\"istio-system\", reporter=\"destination\"}[1m])) + sum(irate(istio_request_bytes_sum{source_workload_namespace!=\"istio-system\", reporter=\"source\"}[1m])) + sum(irate(istio_request_bytes_sum{destination_workload_namespace!=\"istio-system\", reporter=\"destination\"}[1m]))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "istio-proxy", + "refId": "C" + }, + { + "expr": "sum(irate(istio_response_bytes_sum{destination_workload=\"istio-policy\"}[1m])) + sum(irate(istio_request_bytes_sum{destination_workload=\"istio-policy\"}[1m]))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "istio_policy", + "refId": "D" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Bytes transferred / sec", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "Bps", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 19 + }, + "id": 17, + "panels": [], + "title": "Istio Component Versions", + "type": "row" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "fill": 1, + "gridPos": { + "h": 8, + "w": 24, + "x": 0, + "y": 20 + }, + "id": 15, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(istio_build) by (component, tag)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{ component }}: {{ tag }}", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Istio Components by Version", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 31 + }, + "id": 71, + "panels": [], + "title": "Proxy Resource Usage", + "type": "row" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 7, + "w": 6, + "x": 0, + "y": 32 + }, + "id": 72, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(container_memory_usage_bytes{job=\"kubernetes-cadvisor\",container=\"istio-proxy\"})", + "format": "time_series", + "hide": false, + "intervalFactor": 2, + "legendFormat": "{{ container }} (k8s)", + "refId": "B", + "step": 2 + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Memory", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "bytes", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 7, + "w": 6, + "x": 6, + "y": 32 + }, + "id": 73, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(rate(container_cpu_usage_seconds_total{job=\"kubernetes-cadvisor\",container=\"istio-proxy\"}[1m]))", + "format": "time_series", + "hide": false, + "intervalFactor": 2, + "legendFormat": "Total (k8s)", + "refId": "A", + "step": 2 + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "vCPU", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 7, + "w": 6, + "x": 12, + "y": 32 + }, + "id": 702, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(container_fs_usage_bytes{job=\"kubernetes-cadvisor\", container=\"istio-proxy\"})", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "{{ container }}", + "refId": "B", + "step": 2 + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Disk", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "bytes", + "label": "", + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "decimals": null, + "format": "none", + "label": "", + "logBase": 1024, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 39 + }, + "id": 69, + "panels": [], + "title": "Pilot Resource Usage", + "type": "row" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 7, + "w": 6, + "x": 0, + "y": 40 + }, + "id": 5, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "process_virtual_memory_bytes{job=\"pilot\"}", + "format": "time_series", + "instant": false, + "intervalFactor": 2, + "legendFormat": "Virtual Memory", + "refId": "I", + "step": 2 + }, + { + "expr": "process_resident_memory_bytes{job=\"pilot\"}", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "Resident Memory", + "refId": "H", + "step": 2 + }, + { + "expr": "go_memstats_heap_sys_bytes{job=\"pilot\"}", + "format": "time_series", + "hide": true, + "intervalFactor": 2, + "legendFormat": "heap sys", + "refId": "A" + }, + { + "expr": "go_memstats_heap_alloc_bytes{job=\"pilot\"}", + "format": "time_series", + "hide": true, + "intervalFactor": 2, + "legendFormat": "heap alloc", + "refId": "D" + }, + { + "expr": "go_memstats_alloc_bytes{job=\"pilot\"}", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "Alloc", + "refId": "F", + "step": 2 + }, + { + "expr": "go_memstats_heap_inuse_bytes{job=\"pilot\"}", + "format": "time_series", + "hide": false, + "intervalFactor": 2, + "legendFormat": "Heap in-use", + "refId": "E", + "step": 2 + }, + { + "expr": "go_memstats_stack_inuse_bytes{job=\"pilot\"}", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "Stack in-use", + "refId": "G", + "step": 2 + }, + { + "expr": "sum(container_memory_usage_bytes{job=\"kubernetes-cadvisor\",container=~\"discovery|istio-proxy\", pod=~\"istio-pilot-.*\"})", + "format": "time_series", + "hide": false, + "intervalFactor": 2, + "legendFormat": "Total (k8s)", + "refId": "C", + "step": 2 + }, + { + "expr": "container_memory_usage_bytes{job=\"kubernetes-cadvisor\",container=~\"discovery|istio-proxy\", pod=~\"istio-pilot-.*\"}", + "format": "time_series", + "hide": false, + "intervalFactor": 2, + "legendFormat": "{{ container }} (k8s)", + "refId": "B", + "step": 2 + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Memory", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "bytes", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 7, + "w": 6, + "x": 6, + "y": 40 + }, + "id": 602, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(rate(container_cpu_usage_seconds_total{job=\"kubernetes-cadvisor\",container=~\"discovery|istio-proxy\", pod=~\"istio-pilot-.*\"}[1m]))", + "format": "time_series", + "hide": false, + "intervalFactor": 2, + "legendFormat": "Total (k8s)", + "refId": "A", + "step": 2 + }, + { + "expr": "sum(rate(container_cpu_usage_seconds_total{job=\"kubernetes-cadvisor\",container=~\"discovery|istio-proxy\", pod=~\"istio-pilot-.*\"}[1m])) by (container)", + "format": "time_series", + "hide": false, + "intervalFactor": 2, + "legendFormat": "{{ container }} (k8s)", + "refId": "B", + "step": 2 + }, + { + "expr": "irate(process_cpu_seconds_total{job=\"pilot\"}[1m])", + "format": "time_series", + "hide": false, + "intervalFactor": 2, + "legendFormat": "pilot (self-reported)", + "refId": "C", + "step": 2 + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "vCPU", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 7, + "w": 6, + "x": 12, + "y": 40 + }, + "id": 74, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "process_open_fds{job=\"pilot\"}", + "format": "time_series", + "hide": true, + "instant": false, + "interval": "", + "intervalFactor": 2, + "legendFormat": "Open FDs (pilot)", + "refId": "A" + }, + { + "expr": "container_fs_usage_bytes{job=\"kubernetes-cadvisor\", container=~\"discovery|istio-proxy\", pod=~\"istio-pilot-.*\"}", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "{{ container }}", + "refId": "B", + "step": 2 + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Disk", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "bytes", + "label": "", + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "decimals": null, + "format": "none", + "label": "", + "logBase": 1024, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 7, + "w": 6, + "x": 18, + "y": 40 + }, + "id": 402, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": false, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "go_goroutines{job=\"pilot\"}", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "Number of Goroutines", + "refId": "A", + "step": 2 + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Goroutines", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": "", + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 47 + }, + "id": 93, + "panels": [], + "title": "Mixer Resource Usage", + "type": "row" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 7, + "w": 6, + "x": 0, + "y": 48 + }, + "id": 94, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "process_virtual_memory_bytes{job=~\"istio-telemetry|istio-policy\"}", + "format": "time_series", + "instant": false, + "intervalFactor": 2, + "legendFormat": "Virtual Memory", + "refId": "I", + "step": 2 + }, + { + "expr": "process_resident_memory_bytes{job=~\"istio-telemetry|istio-policy\"}", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "Resident Memory", + "refId": "H", + "step": 2 + }, + { + "expr": "go_memstats_heap_sys_bytes{job=~\"istio-telemetry|istio-policy\"}", + "format": "time_series", + "hide": true, + "intervalFactor": 2, + "legendFormat": "heap sys", + "refId": "A" + }, + { + "expr": "go_memstats_heap_alloc_bytes{job=~\"istio-telemetry|istio-policy\"}", + "format": "time_series", + "hide": true, + "intervalFactor": 2, + "legendFormat": "heap alloc", + "refId": "D" + }, + { + "expr": "go_memstats_alloc_bytes{job=~\"istio-telemetry|istio-policy\"}", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "Alloc", + "refId": "F", + "step": 2 + }, + { + "expr": "go_memstats_heap_inuse_bytes{job=~\"istio-telemetry|istio-policy\"}", + "format": "time_series", + "hide": false, + "intervalFactor": 2, + "legendFormat": "Heap in-use", + "refId": "E", + "step": 2 + }, + { + "expr": "go_memstats_stack_inuse_bytes{job=~\"istio-policy|istio-telemetry\"}", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "Stack in-use", + "refId": "G", + "step": 2 + }, + { + "expr": "sum(container_memory_usage_bytes{job=\"kubernetes-cadvisor\",container=~\"mixer|istio-proxy\", pod=~\"istio-telemetry-.*\"})", + "format": "time_series", + "hide": false, + "intervalFactor": 2, + "legendFormat": "Total (k8s)", + "refId": "C", + "step": 2 + }, + { + "expr": "container_memory_usage_bytes{job=\"kubernetes-cadvisor\",container=~\"mixer|istio-proxy\", pod=~\"istio-telemetry-.*\"}", + "format": "time_series", + "hide": false, + "intervalFactor": 2, + "legendFormat": "{{ container }} (k8s)", + "refId": "B", + "step": 2 + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Memory", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "bytes", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 7, + "w": 6, + "x": 6, + "y": 48 + }, + "id": 95, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(rate(container_cpu_usage_seconds_total{job=\"kubernetes-cadvisor\",container=~\"mixer|istio-proxy\", pod=~\"istio-telemetry-.*\"}[1m]))", + "format": "time_series", + "hide": false, + "intervalFactor": 2, + "legendFormat": "Total (k8s)", + "refId": "A", + "step": 2 + }, + { + "expr": "sum(rate(container_cpu_usage_seconds_total{job=\"kubernetes-cadvisor\",container=~\"mixer|istio-proxy\", pod=~\"istio-telemetry-.*\"}[1m])) by (container)", + "format": "time_series", + "hide": false, + "intervalFactor": 2, + "legendFormat": "{{ container }} (k8s)", + "refId": "B", + "step": 2 + }, + { + "expr": "irate(process_cpu_seconds_total{job=~\"istio-policy|istio-telemetry\"}[1m])", + "format": "time_series", + "hide": false, + "intervalFactor": 2, + "legendFormat": "mixer (self-reported)", + "refId": "C", + "step": 2 + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "vCPU", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 7, + "w": 6, + "x": 12, + "y": 48 + }, + "id": 96, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "process_open_fds{job=~\"istio-policy|istio-telemetry\"}", + "format": "time_series", + "hide": true, + "instant": false, + "interval": "", + "intervalFactor": 2, + "legendFormat": "Open FDs (pilot)", + "refId": "A" + }, + { + "expr": "container_fs_usage_bytes{job=\"kubernetes-cadvisor\", container=~\"mixer|istio-proxy\", pod=~\"istio-telemetry-.*\"}", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "{{ container }}", + "refId": "B", + "step": 2 + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Disk", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "bytes", + "label": "", + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "decimals": null, + "format": "none", + "label": "", + "logBase": 1024, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 7, + "w": 6, + "x": 18, + "y": 48 + }, + "id": 97, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": false, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "go_goroutines{job=\"istio-telemetry\"}", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "Number of Goroutines", + "refId": "A", + "step": 2 + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Goroutines", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": "", + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + } + ], + "refresh": "10s", + "schemaVersion": 18, + "style": "dark", + "tags": [], + "templating": { + "list": [] + }, + "time": { + "from": "now-5m", + "to": "now" + }, + "timepicker": { + "refresh_intervals": [ + "5s", + "10s", + "30s", + "1m", + "5m", + "15m", + "30m", + "1h", + "2h", + "1d" + ], + "time_options": [ + "5m", + "15m", + "1h", + "6h", + "12h", + "24h", + "2d", + "7d", + "30d" + ] + }, + "timezone": "", + "title": "Istio Performance Dashboard", + "uid": "vu8e0VWZk", + "version": 22 +} +' +--- +apiVersion: v1 +kind: ConfigMap +metadata: + name: istio-grafana-configuration-dashboards-istio-service-dashboard + namespace: istio-system + labels: + app: grafana + chart: grafana + heritage: Tiller + release: istio + istio: grafana +data: + istio-service-dashboard.json: '{ + "annotations": { + "list": [ + { + "builtIn": 1, + "datasource": "-- Grafana --", + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations & Alerts", + "type": "dashboard" + } + ] + }, + "editable": false, + "gnetId": null, + "graphTooltip": 0, + "iteration": 1536442501501, + "links": [], + "panels": [ + { + "content": "
\nSERVICE: $service\n
", + "gridPos": { + "h": 3, + "w": 24, + "x": 0, + "y": 0 + }, + "id": 89, + "links": [], + "mode": "html", + "title": "", + "transparent": true, + "type": "text" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "datasource": "Prometheus", + "format": "ops", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "gridPos": { + "h": 4, + "w": 6, + "x": 0, + "y": 3 + }, + "id": 12, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": true, + "lineColor": "rgb(31, 120, 193)", + "show": true + }, + "tableColumn": "", + "targets": [ + { + "expr": "round(sum(irate(istio_requests_total{reporter=\"source\",destination_service=~\"$service\"}[5m])), 0.001)", + "format": "time_series", + "intervalFactor": 1, + "refId": "A", + "step": 4 + } + ], + "thresholds": "", + "title": "Client Request Volume", + "transparent": false, + "type": "singlestat", + "valueFontSize": "80%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "current" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "rgba(50, 172, 45, 0.97)", + "rgba(237, 129, 40, 0.89)", + "rgba(245, 54, 54, 0.9)" + ], + "datasource": "Prometheus", + "decimals": null, + "format": "percentunit", + "gauge": { + "maxValue": 100, + "minValue": 80, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": false + }, + "gridPos": { + "h": 4, + "w": 6, + "x": 6, + "y": 3 + }, + "id": 14, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": true, + "lineColor": "rgb(31, 120, 193)", + "show": true + }, + "tableColumn": "", + "targets": [ + { + "expr": "sum(irate(istio_requests_total{reporter=\"source\",destination_service=~\"$service\",response_code!~\"5.*\"}[5m])) / sum(irate(istio_requests_total{reporter=\"source\",destination_service=~\"$service\"}[5m]))", + "format": "time_series", + "intervalFactor": 1, + "refId": "B" + } + ], + "thresholds": "95, 99, 99.5", + "title": "Client Success Rate (non-5xx responses)", + "transparent": false, + "type": "singlestat", + "valueFontSize": "80%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "avg" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 4, + "w": 6, + "x": 12, + "y": 3 + }, + "id": 87, + "legend": { + "alignAsTable": false, + "avg": false, + "current": false, + "hideEmpty": false, + "hideZero": false, + "max": false, + "min": false, + "rightSide": true, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "(histogram_quantile(0.50, sum(irate(istio_request_duration_milliseconds_bucket{reporter=\"source\",destination_service=~\"$service\"}[1m])) by (le)) / 1000) or histogram_quantile(0.50, sum(irate(istio_request_duration_seconds_bucket{reporter=\"source\",destination_service=~\"$service\"}[1m])) by (le))", + "format": "time_series", + "interval": "", + "intervalFactor": 1, + "legendFormat": "P50", + "refId": "A" + }, + { + "expr": "(histogram_quantile(0.90, sum(irate(istio_request_duration_milliseconds_bucket{reporter=\"source\",destination_service=~\"$service\"}[1m])) by (le)) / 1000) or histogram_quantile(0.90, sum(irate(istio_request_duration_seconds_bucket{reporter=\"source\",destination_service=~\"$service\"}[1m])) by (le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "P90", + "refId": "B" + }, + { + "expr": "(histogram_quantile(0.99, sum(irate(istio_request_duration_milliseconds_bucket{reporter=\"source\",destination_service=~\"$service\"}[1m])) by (le)) / 1000) or histogram_quantile(0.99, sum(irate(istio_request_duration_seconds_bucket{reporter=\"source\",destination_service=~\"$service\"}[1m])) by (le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "P99", + "refId": "C" + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Client Request Duration", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "s", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "#299c46", + "rgba(237, 129, 40, 0.89)", + "#d44a3a" + ], + "datasource": "Prometheus", + "format": "Bps", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "gridPos": { + "h": 4, + "w": 6, + "x": 18, + "y": 3 + }, + "id": 84, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": true, + "lineColor": "rgb(31, 120, 193)", + "show": true + }, + "tableColumn": "", + "targets": [ + { + "expr": "sum(irate(istio_tcp_received_bytes_total{reporter=\"source\", destination_service=~\"$service\"}[1m]))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "", + "refId": "A" + } + ], + "thresholds": "", + "title": "TCP Received Bytes", + "transparent": false, + "type": "singlestat", + "valueFontSize": "80%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "avg" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "datasource": "Prometheus", + "format": "ops", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "gridPos": { + "h": 4, + "w": 6, + "x": 0, + "y": 7 + }, + "id": 97, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": true, + "lineColor": "rgb(31, 120, 193)", + "show": true + }, + "tableColumn": "", + "targets": [ + { + "expr": "round(sum(irate(istio_requests_total{reporter=\"destination\",destination_service=~\"$service\"}[5m])), 0.001)", + "format": "time_series", + "intervalFactor": 1, + "refId": "A", + "step": 4 + } + ], + "thresholds": "", + "title": "Server Request Volume", + "transparent": false, + "type": "singlestat", + "valueFontSize": "80%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "current" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "rgba(50, 172, 45, 0.97)", + "rgba(237, 129, 40, 0.89)", + "rgba(245, 54, 54, 0.9)" + ], + "datasource": "Prometheus", + "decimals": null, + "format": "percentunit", + "gauge": { + "maxValue": 100, + "minValue": 80, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": false + }, + "gridPos": { + "h": 4, + "w": 6, + "x": 6, + "y": 7 + }, + "id": 98, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": true, + "lineColor": "rgb(31, 120, 193)", + "show": true + }, + "tableColumn": "", + "targets": [ + { + "expr": "sum(irate(istio_requests_total{reporter=\"destination\",destination_service=~\"$service\",response_code!~\"5.*\"}[5m])) / sum(irate(istio_requests_total{reporter=\"destination\",destination_service=~\"$service\"}[5m]))", + "format": "time_series", + "intervalFactor": 1, + "refId": "B" + } + ], + "thresholds": "95, 99, 99.5", + "title": "Server Success Rate (non-5xx responses)", + "transparent": false, + "type": "singlestat", + "valueFontSize": "80%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "avg" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 4, + "w": 6, + "x": 12, + "y": 7 + }, + "id": 99, + "legend": { + "alignAsTable": false, + "avg": false, + "current": false, + "hideEmpty": false, + "hideZero": false, + "max": false, + "min": false, + "rightSide": true, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "(histogram_quantile(0.50, sum(irate(istio_request_duration_milliseconds_bucket{reporter=\"destination\",destination_service=~\"$service\"}[1m])) by (le)) / 1000) or histogram_quantile(0.50, sum(irate(istio_request_duration_seconds_bucket{reporter=\"destination\",destination_service=~\"$service\"}[1m])) by (le))", + "format": "time_series", + "interval": "", + "intervalFactor": 1, + "legendFormat": "P50", + "refId": "A" + }, + { + "expr": "(histogram_quantile(0.90, sum(irate(istio_request_duration_milliseconds_bucket{reporter=\"destination\",destination_service=~\"$service\"}[1m])) by (le)) / 1000) or histogram_quantile(0.90, sum(irate(istio_request_duration_seconds_bucket{reporter=\"destination\",destination_service=~\"$service\"}[1m])) by (le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "P90", + "refId": "B" + }, + { + "expr": "(histogram_quantile(0.99, sum(irate(istio_request_duration_milliseconds_bucket{reporter=\"destination\",destination_service=~\"$service\"}[1m])) by (le)) / 1000) or histogram_quantile(0.99, sum(irate(istio_request_duration_seconds_bucket{reporter=\"destination\",destination_service=~\"$service\"}[1m])) by (le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "P99", + "refId": "C" + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Server Request Duration", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "s", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "#299c46", + "rgba(237, 129, 40, 0.89)", + "#d44a3a" + ], + "datasource": "Prometheus", + "format": "Bps", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "gridPos": { + "h": 4, + "w": 6, + "x": 18, + "y": 7 + }, + "id": 100, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": true, + "lineColor": "rgb(31, 120, 193)", + "show": true + }, + "tableColumn": "", + "targets": [ + { + "expr": "sum(irate(istio_tcp_sent_bytes_total{reporter=\"source\", destination_service=~\"$service\"}[1m])) ", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "", + "refId": "A" + } + ], + "thresholds": "", + "title": "TCP Sent Bytes", + "transparent": false, + "type": "singlestat", + "valueFontSize": "80%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "avg" + }, + { + "content": "
\nCLIENT WORKLOADS\n
", + "gridPos": { + "h": 3, + "w": 24, + "x": 0, + "y": 11 + }, + "id": 45, + "links": [], + "mode": "html", + "title": "", + "transparent": true, + "type": "text" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 0, + "gridPos": { + "h": 6, + "w": 12, + "x": 0, + "y": 14 + }, + "id": 25, + "legend": { + "avg": false, + "current": false, + "hideEmpty": true, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null as zero", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "round(sum(irate(istio_requests_total{connection_security_policy=\"mutual_tls\",destination_service=~\"$service\",reporter=\"source\",source_workload=~\"$srcwl\",source_workload_namespace=~\"$srcns\"}[5m])) by (source_workload, source_workload_namespace, response_code), 0.001)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{ source_workload }}.{{ source_workload_namespace }} : {{ response_code }} (🔐mTLS)", + "refId": "B", + "step": 2 + }, + { + "expr": "round(sum(irate(istio_requests_total{connection_security_policy!=\"mutual_tls\", destination_service=~\"$service\", reporter=\"source\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[5m])) by (source_workload, source_workload_namespace, response_code), 0.001)", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ source_workload }}.{{ source_workload_namespace }} : {{ response_code }}", + "refId": "A", + "step": 2 + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Incoming Requests by Source And Response Code", + "tooltip": { + "shared": false, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [ + "total" + ] + }, + "yaxes": [ + { + "format": "ops", + "label": null, + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 6, + "w": 12, + "x": 12, + "y": 14 + }, + "id": 26, + "legend": { + "avg": false, + "current": false, + "hideEmpty": true, + "hideZero": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(irate(istio_requests_total{reporter=\"source\", connection_security_policy=\"mutual_tls\", destination_service=~\"$service\",response_code!~\"5.*\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[5m])) by (source_workload, source_workload_namespace) / sum(irate(istio_requests_total{reporter=\"source\", connection_security_policy=\"mutual_tls\", destination_service=~\"$service\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[5m])) by (source_workload, source_workload_namespace)", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ source_workload }}.{{ source_workload_namespace }} (🔐mTLS)", + "refId": "A", + "step": 2 + }, + { + "expr": "sum(irate(istio_requests_total{reporter=\"source\", connection_security_policy!=\"mutual_tls\", destination_service=~\"$service\",response_code!~\"5.*\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[5m])) by (source_workload, source_workload_namespace) / sum(irate(istio_requests_total{reporter=\"source\", connection_security_policy!=\"mutual_tls\", destination_service=~\"$service\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[5m])) by (source_workload, source_workload_namespace)", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ source_workload }}.{{ source_workload_namespace }}", + "refId": "B", + "step": 2 + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Incoming Success Rate (non-5xx responses) By Source", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "percentunit", + "label": null, + "logBase": 1, + "max": "1.01", + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "description": "", + "fill": 1, + "gridPos": { + "h": 6, + "w": 8, + "x": 0, + "y": 20 + }, + "id": 27, + "legend": { + "alignAsTable": false, + "avg": false, + "current": false, + "hideEmpty": true, + "hideZero": false, + "max": false, + "min": false, + "rightSide": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "(histogram_quantile(0.50, sum(irate(istio_request_duration_milliseconds_bucket{reporter=\"source\", connection_security_policy=\"mutual_tls\", destination_service=~\"$service\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le)) / 1000) or histogram_quantile(0.50, sum(irate(istio_request_duration_seconds_bucket{reporter=\"source\", connection_security_policy=\"mutual_tls\", destination_service=~\"$service\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{source_workload}}.{{source_workload_namespace}} P50 (🔐mTLS)", + "refId": "D", + "step": 2 + }, + { + "expr": "(histogram_quantile(0.90, sum(irate(istio_request_duration_milliseconds_bucket{reporter=\"source\", connection_security_policy=\"mutual_tls\", destination_service=~\"$service\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le)) / 1000) or histogram_quantile(0.90, sum(irate(istio_request_duration_seconds_bucket{reporter=\"source\", connection_security_policy=\"mutual_tls\", destination_service=~\"$service\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{source_workload}}.{{source_workload_namespace}} P90 (🔐mTLS)", + "refId": "A", + "step": 2 + }, + { + "expr": "(histogram_quantile(0.95, sum(irate(istio_request_duration_milliseconds_bucket{reporter=\"source\", connection_security_policy=\"mutual_tls\", destination_service=~\"$service\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le)) / 1000) or histogram_quantile(0.95, sum(irate(istio_request_duration_seconds_bucket{reporter=\"source\", connection_security_policy=\"mutual_tls\", destination_service=~\"$service\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{source_workload}}.{{source_workload_namespace}} P95 (🔐mTLS)", + "refId": "B", + "step": 2 + }, + { + "expr": "(histogram_quantile(0.99, sum(irate(istio_request_duration_milliseconds_bucket{reporter=\"source\", connection_security_policy=\"mutual_tls\", destination_service=~\"$service\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le)) / 1000) or histogram_quantile(0.99, sum(irate(istio_request_duration_seconds_bucket{reporter=\"source\", connection_security_policy=\"mutual_tls\", destination_service=~\"$service\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{source_workload}}.{{source_workload_namespace}} P99 (🔐mTLS)", + "refId": "C", + "step": 2 + }, + { + "expr": "(histogram_quantile(0.50, sum(irate(istio_request_duration_milliseconds_bucket{reporter=\"source\", connection_security_policy!=\"mutual_tls\", destination_service=~\"$service\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le)) / 1000) or histogram_quantile(0.50, sum(irate(istio_request_duration_seconds_bucket{reporter=\"source\", connection_security_policy!=\"mutual_tls\", destination_service=~\"$service\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{source_workload}}.{{source_workload_namespace}} P50", + "refId": "E", + "step": 2 + }, + { + "expr": "(histogram_quantile(0.90, sum(irate(istio_request_duration_milliseconds_bucket{reporter=\"source\", connection_security_policy!=\"mutual_tls\", destination_service=~\"$service\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le)) / 1000) or histogram_quantile(0.90, sum(irate(istio_request_duration_seconds_bucket{reporter=\"source\", connection_security_policy!=\"mutual_tls\", destination_service=~\"$service\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{source_workload}}.{{source_workload_namespace}} P90", + "refId": "F", + "step": 2 + }, + { + "expr": "(histogram_quantile(0.95, sum(irate(istio_request_duration_milliseconds_bucket{reporter=\"source\", connection_security_policy!=\"mutual_tls\", destination_service=~\"$service\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le)) / 1000) or histogram_quantile(0.95, sum(irate(istio_request_duration_seconds_bucket{reporter=\"source\", connection_security_policy!=\"mutual_tls\", destination_service=~\"$service\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{source_workload}}.{{source_workload_namespace}} P95", + "refId": "G", + "step": 2 + }, + { + "expr": "(histogram_quantile(0.99, sum(irate(istio_request_duration_milliseconds_bucket{reporter=\"source\", connection_security_policy!=\"mutual_tls\", destination_service=~\"$service\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le)) / 1000) or histogram_quantile(0.99, sum(irate(istio_request_duration_seconds_bucket{reporter=\"source\", connection_security_policy!=\"mutual_tls\", destination_service=~\"$service\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{source_workload}}.{{source_workload_namespace}} P99", + "refId": "H", + "step": 2 + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Incoming Request Duration by Source", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "s", + "label": null, + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 6, + "w": 8, + "x": 8, + "y": 20 + }, + "id": 28, + "legend": { + "alignAsTable": false, + "avg": false, + "current": false, + "hideEmpty": true, + "max": false, + "min": false, + "rightSide": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "histogram_quantile(0.50, sum(irate(istio_request_bytes_bucket{reporter=\"source\", connection_security_policy=\"mutual_tls\", destination_service=~\"$service\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{source_workload}}.{{source_workload_namespace}} P50 (🔐mTLS)", + "refId": "D", + "step": 2 + }, + { + "expr": "histogram_quantile(0.90, sum(irate(istio_request_bytes_bucket{reporter=\"source\", connection_security_policy=\"mutual_tls\", destination_service=~\"$service\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{source_workload}}.{{source_workload_namespace}} P90 (🔐mTLS)", + "refId": "A", + "step": 2 + }, + { + "expr": "histogram_quantile(0.95, sum(irate(istio_request_bytes_bucket{reporter=\"source\", connection_security_policy=\"mutual_tls\", destination_service=~\"$service\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{source_workload}}.{{source_workload_namespace}} P95 (🔐mTLS)", + "refId": "B", + "step": 2 + }, + { + "expr": "histogram_quantile(0.99, sum(irate(istio_request_bytes_bucket{reporter=\"source\", connection_security_policy=\"mutual_tls\", destination_service=~\"$service\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{source_workload}}.{{source_workload_namespace}} P99 (🔐mTLS)", + "refId": "C", + "step": 2 + }, + { + "expr": "histogram_quantile(0.50, sum(irate(istio_request_bytes_bucket{reporter=\"source\", connection_security_policy!=\"mutual_tls\", destination_service=~\"$service\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{source_workload}}.{{source_workload_namespace}} P50", + "refId": "E", + "step": 2 + }, + { + "expr": "histogram_quantile(0.90, sum(irate(istio_request_bytes_bucket{reporter=\"source\", connection_security_policy!=\"mutual_tls\", destination_service=~\"$service\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{source_workload}}.{{source_workload_namespace}} P90", + "refId": "F", + "step": 2 + }, + { + "expr": "histogram_quantile(0.95, sum(irate(istio_request_bytes_bucket{reporter=\"source\", connection_security_policy!=\"mutual_tls\", destination_service=~\"$service\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{source_workload}}.{{source_workload_namespace}} P95", + "refId": "G", + "step": 2 + }, + { + "expr": "histogram_quantile(0.99, sum(irate(istio_request_bytes_bucket{reporter=\"source\", connection_security_policy!=\"mutual_tls\", destination_service=~\"$service\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{source_workload}}.{{source_workload_namespace}} P99", + "refId": "H", + "step": 2 + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Incoming Request Size By Source", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "decbytes", + "label": null, + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 6, + "w": 8, + "x": 16, + "y": 20 + }, + "id": 68, + "legend": { + "alignAsTable": false, + "avg": false, + "current": false, + "hideEmpty": true, + "max": false, + "min": false, + "rightSide": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "histogram_quantile(0.50, sum(irate(istio_response_bytes_bucket{reporter=\"source\", connection_security_policy=\"mutual_tls\", destination_service=~\"$service\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{source_workload}}.{{source_workload_namespace}} P50 (🔐mTLS)", + "refId": "D", + "step": 2 + }, + { + "expr": "histogram_quantile(0.90, sum(irate(istio_response_bytes_bucket{reporter=\"source\", connection_security_policy=\"mutual_tls\", destination_service=~\"$service\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{source_workload}}.{{source_workload_namespace}} P90 (🔐mTLS)", + "refId": "A", + "step": 2 + }, + { + "expr": "histogram_quantile(0.95, sum(irate(istio_response_bytes_bucket{reporter=\"source\", connection_security_policy=\"mutual_tls\", destination_service=~\"$service\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{source_workload}}.{{source_workload_namespace}} P95 (🔐mTLS)", + "refId": "B", + "step": 2 + }, + { + "expr": "histogram_quantile(0.99, sum(irate(istio_response_bytes_bucket{reporter=\"source\", connection_security_policy=\"mutual_tls\", destination_service=~\"$service\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{source_workload}}.{{source_workload_namespace}} P99 (🔐mTLS)", + "refId": "C", + "step": 2 + }, + { + "expr": "histogram_quantile(0.50, sum(irate(istio_response_bytes_bucket{reporter=\"source\", connection_security_policy!=\"mutual_tls\", destination_service=~\"$service\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{source_workload}}.{{source_workload_namespace}} P50", + "refId": "E", + "step": 2 + }, + { + "expr": "histogram_quantile(0.90, sum(irate(istio_response_bytes_bucket{reporter=\"source\", connection_security_policy!=\"mutual_tls\", destination_service=~\"$service\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{source_workload}}.{{source_workload_namespace}} P90", + "refId": "F", + "step": 2 + }, + { + "expr": "histogram_quantile(0.95, sum(irate(istio_response_bytes_bucket{reporter=\"source\", connection_security_policy!=\"mutual_tls\", destination_service=~\"$service\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{source_workload}}.{{source_workload_namespace}} P95", + "refId": "G", + "step": 2 + }, + { + "expr": "histogram_quantile(0.99, sum(irate(istio_response_bytes_bucket{reporter=\"source\", connection_security_policy!=\"mutual_tls\", destination_service=~\"$service\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{source_workload}}.{{source_workload_namespace}} P99", + "refId": "H", + "step": 2 + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Response Size By Source", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "decbytes", + "label": null, + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 6, + "w": 12, + "x": 0, + "y": 26 + }, + "id": 80, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "round(sum(irate(istio_tcp_received_bytes_total{reporter=\"source\", connection_security_policy=\"mutual_tls\", destination_service=~\"$service\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace), 0.001)", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ source_workload }}.{{ source_workload_namespace}} (🔐mTLS)", + "refId": "A", + "step": 2 + }, + { + "expr": "round(sum(irate(istio_tcp_received_bytes_total{reporter=\"source\", connection_security_policy!=\"mutual_tls\", destination_service=~\"$service\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace), 0.001)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{ source_workload }}.{{ source_workload_namespace}}", + "refId": "B", + "step": 2 + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Bytes Received from Incoming TCP Connection", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "Bps", + "label": null, + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 6, + "w": 12, + "x": 12, + "y": 26 + }, + "id": 82, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "round(sum(irate(istio_tcp_sent_bytes_total{connection_security_policy=\"mutual_tls\", reporter=\"source\", destination_service=~\"$service\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace), 0.001)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{ source_workload }}.{{ source_workload_namespace}} (🔐mTLS)", + "refId": "A", + "step": 2 + }, + { + "expr": "round(sum(irate(istio_tcp_sent_bytes_total{connection_security_policy!=\"mutual_tls\", reporter=\"source\", destination_service=~\"$service\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace), 0.001)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{ source_workload }}.{{ source_workload_namespace}}", + "refId": "B", + "step": 2 + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Bytes Sent to Incoming TCP Connection", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "Bps", + "label": null, + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "content": "
\nSERVICE WORKLOADS\n
", + "gridPos": { + "h": 3, + "w": 24, + "x": 0, + "y": 32 + }, + "id": 69, + "links": [], + "mode": "html", + "title": "", + "transparent": true, + "type": "text" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 0, + "gridPos": { + "h": 6, + "w": 12, + "x": 0, + "y": 35 + }, + "id": 90, + "legend": { + "avg": false, + "current": false, + "hideEmpty": true, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null as zero", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "round(sum(irate(istio_requests_total{connection_security_policy=\"mutual_tls\",destination_service=~\"$service\",reporter=\"destination\",destination_workload=~\"$dstwl\",destination_workload_namespace=~\"$dstns\"}[5m])) by (destination_workload, destination_workload_namespace, response_code), 0.001)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{ destination_workload }}.{{ destination_workload_namespace }} : {{ response_code }} (🔐mTLS)", + "refId": "B", + "step": 2 + }, + { + "expr": "round(sum(irate(istio_requests_total{connection_security_policy!=\"mutual_tls\", destination_service=~\"$service\", reporter=\"destination\", destination_workload=~\"$dstwl\", destination_workload_namespace=~\"$dstns\"}[5m])) by (destination_workload, destination_workload_namespace, response_code), 0.001)", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_workload }}.{{ destination_workload_namespace }} : {{ response_code }}", + "refId": "A", + "step": 2 + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Incoming Requests by Destination And Response Code", + "tooltip": { + "shared": false, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [ + "total" + ] + }, + "yaxes": [ + { + "format": "ops", + "label": null, + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 6, + "w": 12, + "x": 12, + "y": 35 + }, + "id": 91, + "legend": { + "avg": false, + "current": false, + "hideEmpty": true, + "hideZero": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(irate(istio_requests_total{reporter=\"destination\", connection_security_policy=\"mutual_tls\", destination_service=~\"$service\",response_code!~\"5.*\", destination_workload=~\"$dstwl\", destination_workload_namespace=~\"$dstns\"}[5m])) by (destination_workload, destination_workload_namespace) / sum(irate(istio_requests_total{reporter=\"destination\", connection_security_policy=\"mutual_tls\", destination_service=~\"$service\", destination_workload=~\"$dstwl\", destination_workload_namespace=~\"$dstns\"}[5m])) by (destination_workload, destination_workload_namespace)", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_workload }}.{{ destination_workload_namespace }} (🔐mTLS)", + "refId": "A", + "step": 2 + }, + { + "expr": "sum(irate(istio_requests_total{reporter=\"destination\", connection_security_policy!=\"mutual_tls\", destination_service=~\"$service\",response_code!~\"5.*\", destination_workload=~\"$dstwl\", destination_workload_namespace=~\"$dstns\"}[5m])) by (destination_workload, destination_workload_namespace) / sum(irate(istio_requests_total{reporter=\"destination\", connection_security_policy!=\"mutual_tls\", destination_service=~\"$service\", destination_workload=~\"$dstwl\", destination_workload_namespace=~\"$dstns\"}[5m])) by (destination_workload, destination_workload_namespace)", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_workload }}.{{ destination_workload_namespace }}", + "refId": "B", + "step": 2 + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Incoming Success Rate (non-5xx responses) By Source", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "percentunit", + "label": null, + "logBase": 1, + "max": "1.01", + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "description": "", + "fill": 1, + "gridPos": { + "h": 6, + "w": 8, + "x": 0, + "y": 41 + }, + "id": 94, + "legend": { + "alignAsTable": false, + "avg": false, + "current": false, + "hideEmpty": true, + "hideZero": false, + "max": false, + "min": false, + "rightSide": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "(histogram_quantile(0.50, sum(irate(istio_request_duration_milliseconds_bucket{reporter=\"destination\", connection_security_policy=\"mutual_tls\", destination_service=~\"$service\", destination_workload=~\"$dstwl\", destination_workload_namespace=~\"$dstns\"}[1m])) by (destination_workload, destination_workload_namespace, le)) / 1000) or histogram_quantile(0.50, sum(irate(istio_request_duration_seconds_bucket{reporter=\"destination\", connection_security_policy=\"mutual_tls\", destination_service=~\"$service\", destination_workload=~\"$dstwl\", destination_workload_namespace=~\"$dstns\"}[1m])) by (destination_workload, destination_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_workload }}.{{ destination_workload_namespace }} P50 (🔐mTLS)", + "refId": "D", + "step": 2 + }, + { + "expr": "(histogram_quantile(0.90, sum(irate(istio_request_duration_milliseconds_bucket{reporter=\"destination\", connection_security_policy=\"mutual_tls\", destination_service=~\"$service\", destination_workload=~\"$dstwl\", destination_workload_namespace=~\"$dstns\"}[1m])) by (destination_workload, destination_workload_namespace, le)) / 1000) or histogram_quantile(0.90, sum(irate(istio_request_duration_seconds_bucket{reporter=\"destination\", connection_security_policy=\"mutual_tls\", destination_service=~\"$service\", destination_workload=~\"$dstwl\", destination_workload_namespace=~\"$dstns\"}[1m])) by (destination_workload, destination_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_workload }}.{{ destination_workload_namespace }} P90 (🔐mTLS)", + "refId": "A", + "step": 2 + }, + { + "expr": "(histogram_quantile(0.95, sum(irate(istio_request_duration_milliseconds_bucket{reporter=\"destination\", connection_security_policy=\"mutual_tls\", destination_service=~\"$service\", destination_workload=~\"$dstwl\", destination_workload_namespace=~\"$dstns\"}[1m])) by (destination_workload, destination_workload_namespace, le)) / 1000) or histogram_quantile(0.95, sum(irate(istio_request_duration_seconds_bucket{reporter=\"destination\", connection_security_policy=\"mutual_tls\", destination_service=~\"$service\", destination_workload=~\"$dstwl\", destination_workload_namespace=~\"$dstns\"}[1m])) by (destination_workload, destination_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_workload }}.{{ destination_workload_namespace }} P95 (🔐mTLS)", + "refId": "B", + "step": 2 + }, + { + "expr": "(histogram_quantile(0.99, sum(irate(istio_request_duration_milliseconds_bucket{reporter=\"destination\", connection_security_policy=\"mutual_tls\", destination_service=~\"$service\", destination_workload=~\"$dstwl\", destination_workload_namespace=~\"$dstns\"}[1m])) by (destination_workload, destination_workload_namespace, le)) / 1000) or histogram_quantile(0.99, sum(irate(istio_request_duration_seconds_bucket{reporter=\"destination\", connection_security_policy=\"mutual_tls\", destination_service=~\"$service\", destination_workload=~\"$dstwl\", destination_workload_namespace=~\"$dstns\"}[1m])) by (destination_workload, destination_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_workload }}.{{ destination_workload_namespace }} P99 (🔐mTLS)", + "refId": "C", + "step": 2 + }, + { + "expr": "(histogram_quantile(0.50, sum(irate(istio_request_duration_milliseconds_bucket{reporter=\"destination\", connection_security_policy!=\"mutual_tls\", destination_service=~\"$service\", destination_workload=~\"$dstwl\", destination_workload_namespace=~\"$dstns\"}[1m])) by (destination_workload, destination_workload_namespace, le)) / 1000) or histogram_quantile(0.50, sum(irate(istio_request_duration_seconds_bucket{reporter=\"destination\", connection_security_policy!=\"mutual_tls\", destination_service=~\"$service\", destination_workload=~\"$dstwl\", destination_workload_namespace=~\"$dstns\"}[1m])) by (destination_workload, destination_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_workload }}.{{ destination_workload_namespace }} P50", + "refId": "E", + "step": 2 + }, + { + "expr": "(histogram_quantile(0.90, sum(irate(istio_request_duration_milliseconds_bucket{reporter=\"destination\", connection_security_policy!=\"mutual_tls\", destination_service=~\"$service\", destination_workload=~\"$dstwl\", destination_workload_namespace=~\"$dstns\"}[1m])) by (destination_workload, destination_workload_namespace, le)) / 1000) or histogram_quantile(0.90, sum(irate(istio_request_duration_seconds_bucket{reporter=\"destination\", connection_security_policy!=\"mutual_tls\", destination_service=~\"$service\", destination_workload=~\"$dstwl\", destination_workload_namespace=~\"$dstns\"}[1m])) by (destination_workload, destination_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_workload }}.{{ destination_workload_namespace }} P90", + "refId": "F", + "step": 2 + }, + { + "expr": "(histogram_quantile(0.95, sum(irate(istio_request_duration_milliseconds_bucket{reporter=\"destination\", connection_security_policy!=\"mutual_tls\", destination_service=~\"$service\", destination_workload=~\"$dstwl\", destination_workload_namespace=~\"$dstns\"}[1m])) by (destination_workload, destination_workload_namespace, le)) / 1000) or histogram_quantile(0.95, sum(irate(istio_request_duration_seconds_bucket{reporter=\"destination\", connection_security_policy!=\"mutual_tls\", destination_service=~\"$service\", destination_workload=~\"$dstwl\", destination_workload_namespace=~\"$dstns\"}[1m])) by (destination_workload, destination_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_workload }}.{{ destination_workload_namespace }} P95", + "refId": "G", + "step": 2 + }, + { + "expr": "(histogram_quantile(0.99, sum(irate(istio_request_duration_milliseconds_bucket{reporter=\"destination\", connection_security_policy!=\"mutual_tls\", destination_service=~\"$service\", destination_workload=~\"$dstwl\", destination_workload_namespace=~\"$dstns\"}[1m])) by (destination_workload, destination_workload_namespace, le)) / 1000) or histogram_quantile(0.99, sum(irate(istio_request_duration_seconds_bucket{reporter=\"destination\", connection_security_policy!=\"mutual_tls\", destination_service=~\"$service\", destination_workload=~\"$dstwl\", destination_workload_namespace=~\"$dstns\"}[1m])) by (destination_workload, destination_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_workload }}.{{ destination_workload_namespace }} P99", + "refId": "H", + "step": 2 + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Incoming Request Duration by Source", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "s", + "label": null, + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 6, + "w": 8, + "x": 8, + "y": 41 + }, + "id": 95, + "legend": { + "alignAsTable": false, + "avg": false, + "current": false, + "hideEmpty": true, + "max": false, + "min": false, + "rightSide": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "histogram_quantile(0.50, sum(irate(istio_request_bytes_bucket{reporter=\"destination\", connection_security_policy=\"mutual_tls\", destination_service=~\"$service\", destination_workload=~\"$dstwl\", destination_workload_namespace=~\"$dstns\"}[1m])) by (destination_workload, destination_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_workload }}.{{ destination_workload_namespace }} P50 (🔐mTLS)", + "refId": "D", + "step": 2 + }, + { + "expr": "histogram_quantile(0.90, sum(irate(istio_request_bytes_bucket{reporter=\"destination\", connection_security_policy=\"mutual_tls\", destination_service=~\"$service\", destination_workload=~\"$dstwl\", destination_workload_namespace=~\"$dstns\"}[1m])) by (destination_workload, destination_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_workload }}.{{ destination_workload_namespace }} P90 (🔐mTLS)", + "refId": "A", + "step": 2 + }, + { + "expr": "histogram_quantile(0.95, sum(irate(istio_request_bytes_bucket{reporter=\"destination\", connection_security_policy=\"mutual_tls\", destination_service=~\"$service\", destination_workload=~\"$dstwl\", destination_workload_namespace=~\"$dstns\"}[1m])) by (destination_workload, destination_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_workload }}.{{ destination_workload_namespace }} P95 (🔐mTLS)", + "refId": "B", + "step": 2 + }, + { + "expr": "histogram_quantile(0.99, sum(irate(istio_request_bytes_bucket{reporter=\"destination\", connection_security_policy=\"mutual_tls\", destination_service=~\"$service\", destination_workload=~\"$dstwl\", destination_workload_namespace=~\"$dstns\"}[1m])) by (destination_workload, destination_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_workload }}.{{ destination_workload_namespace }} P99 (🔐mTLS)", + "refId": "C", + "step": 2 + }, + { + "expr": "histogram_quantile(0.50, sum(irate(istio_request_bytes_bucket{reporter=\"destination\", connection_security_policy!=\"mutual_tls\", destination_service=~\"$service\", destination_workload=~\"$dstwl\", destination_workload_namespace=~\"$dstns\"}[1m])) by (destination_workload, destination_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_workload }}.{{ destination_workload_namespace }} P50", + "refId": "E", + "step": 2 + }, + { + "expr": "histogram_quantile(0.90, sum(irate(istio_request_bytes_bucket{reporter=\"destination\", connection_security_policy!=\"mutual_tls\", destination_service=~\"$service\", destination_workload=~\"$dstwl\", destination_workload_namespace=~\"$dstns\"}[1m])) by (destination_workload, destination_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_workload }}.{{ destination_workload_namespace }} P90", + "refId": "F", + "step": 2 + }, + { + "expr": "histogram_quantile(0.95, sum(irate(istio_request_bytes_bucket{reporter=\"destination\", connection_security_policy!=\"mutual_tls\", destination_service=~\"$service\", destination_workload=~\"$dstwl\", destination_workload_namespace=~\"$dstns\"}[1m])) by (destination_workload, destination_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_workload }}.{{ destination_workload_namespace }} P95", + "refId": "G", + "step": 2 + }, + { + "expr": "histogram_quantile(0.99, sum(irate(istio_request_bytes_bucket{reporter=\"destination\", connection_security_policy!=\"mutual_tls\", destination_service=~\"$service\", destination_workload=~\"$dstwl\", destination_workload_namespace=~\"$dstns\"}[1m])) by (destination_workload, destination_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_workload }}.{{ destination_workload_namespace }} P99", + "refId": "H", + "step": 2 + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Incoming Request Size By Source", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "decbytes", + "label": null, + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 6, + "w": 8, + "x": 16, + "y": 41 + }, + "id": 96, + "legend": { + "alignAsTable": false, + "avg": false, + "current": false, + "hideEmpty": true, + "max": false, + "min": false, + "rightSide": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "histogram_quantile(0.50, sum(irate(istio_response_bytes_bucket{reporter=\"destination\", connection_security_policy=\"mutual_tls\", destination_service=~\"$service\", destination_workload=~\"$dstwl\", destination_workload_namespace=~\"$dstns\"}[1m])) by (destination_workload, destination_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_workload }}.{{ destination_workload_namespace }} P50 (🔐mTLS)", + "refId": "D", + "step": 2 + }, + { + "expr": "histogram_quantile(0.90, sum(irate(istio_response_bytes_bucket{reporter=\"destination\", connection_security_policy=\"mutual_tls\", destination_service=~\"$service\", destination_workload=~\"$dstwl\", destination_workload_namespace=~\"$dstns\"}[1m])) by (destination_workload, destination_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_workload }}.{{ destination_workload_namespace }} P90 (🔐mTLS)", + "refId": "A", + "step": 2 + }, + { + "expr": "histogram_quantile(0.95, sum(irate(istio_response_bytes_bucket{reporter=\"destination\", connection_security_policy=\"mutual_tls\", destination_service=~\"$service\", destination_workload=~\"$dstwl\", destination_workload_namespace=~\"$dstns\"}[1m])) by (destination_workload, destination_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_workload }}.{{ destination_workload_namespace }} P95 (🔐mTLS)", + "refId": "B", + "step": 2 + }, + { + "expr": "histogram_quantile(0.99, sum(irate(istio_response_bytes_bucket{reporter=\"destination\", connection_security_policy=\"mutual_tls\", destination_service=~\"$service\", destination_workload=~\"$dstwl\", destination_workload_namespace=~\"$dstns\"}[1m])) by (destination_workload, destination_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_workload }}.{{ destination_workload_namespace }} P99 (🔐mTLS)", + "refId": "C", + "step": 2 + }, + { + "expr": "histogram_quantile(0.50, sum(irate(istio_response_bytes_bucket{reporter=\"destination\", connection_security_policy!=\"mutual_tls\", destination_service=~\"$service\", destination_workload=~\"$dstwl\", destination_workload_namespace=~\"$dstns\"}[1m])) by (destination_workload, destination_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_workload }}.{{ destination_workload_namespace }} P50", + "refId": "E", + "step": 2 + }, + { + "expr": "histogram_quantile(0.90, sum(irate(istio_response_bytes_bucket{reporter=\"destination\", connection_security_policy!=\"mutual_tls\", destination_service=~\"$service\", destination_workload=~\"$dstwl\", destination_workload_namespace=~\"$dstns\"}[1m])) by (destination_workload, destination_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_workload }}.{{ destination_workload_namespace }} P90", + "refId": "F", + "step": 2 + }, + { + "expr": "histogram_quantile(0.95, sum(irate(istio_response_bytes_bucket{reporter=\"destination\", connection_security_policy!=\"mutual_tls\", destination_service=~\"$service\", destination_workload=~\"$dstwl\", destination_workload_namespace=~\"$dstns\"}[1m])) by (destination_workload, destination_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_workload }}.{{ destination_workload_namespace }} P95", + "refId": "G", + "step": 2 + }, + { + "expr": "histogram_quantile(0.99, sum(irate(istio_response_bytes_bucket{reporter=\"destination\", connection_security_policy!=\"mutual_tls\", destination_service=~\"$service\", destination_workload=~\"$dstwl\", destination_workload_namespace=~\"$dstns\"}[1m])) by (destination_workload, destination_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_workload }}.{{ destination_workload_namespace }} P99", + "refId": "H", + "step": 2 + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Response Size By Source", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "decbytes", + "label": null, + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 6, + "w": 12, + "x": 0, + "y": 47 + }, + "id": 92, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "round(sum(irate(istio_tcp_received_bytes_total{reporter=\"source\", connection_security_policy=\"mutual_tls\", destination_service=~\"$service\", destination_workload=~\"$dstwl\", destination_workload_namespace=~\"$dstns\"}[1m])) by (destination_workload, destination_workload_namespace), 0.001)", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_workload }}.{{ destination_workload_namespace}} (🔐mTLS)", + "refId": "A", + "step": 2 + }, + { + "expr": "round(sum(irate(istio_tcp_received_bytes_total{reporter=\"source\", connection_security_policy!=\"mutual_tls\", destination_service=~\"$service\", destination_workload=~\"$dstwl\", destination_workload_namespace=~\"$dstns\"}[1m])) by (destination_workload, destination_workload_namespace), 0.001)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{ destination_workload }}.{{ destination_workload_namespace}}", + "refId": "B", + "step": 2 + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Bytes Received from Incoming TCP Connection", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "Bps", + "label": null, + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 6, + "w": 12, + "x": 12, + "y": 47 + }, + "id": 93, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "round(sum(irate(istio_tcp_sent_bytes_total{connection_security_policy=\"mutual_tls\", reporter=\"source\", destination_service=~\"$service\", destination_workload=~\"$dstwl\", destination_workload_namespace=~\"$dstns\"}[1m])) by (destination_workload, destination_workload_namespace), 0.001)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{ destination_workload }}.{{destination_workload_namespace }} (🔐mTLS)", + "refId": "A", + "step": 2 + }, + { + "expr": "round(sum(irate(istio_tcp_sent_bytes_total{connection_security_policy!=\"mutual_tls\", reporter=\"source\", destination_service=~\"$service\", destination_workload=~\"$dstwl\", destination_workload_namespace=~\"$dstns\"}[1m])) by (destination_workload, destination_workload_namespace), 0.001)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{ destination_workload }}.{{destination_workload_namespace }}", + "refId": "B", + "step": 2 + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Bytes Sent to Incoming TCP Connection", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "Bps", + "label": null, + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + } + ], + "refresh": "10s", + "schemaVersion": 16, + "style": "dark", + "tags": [], + "templating": { + "list": [ + { + "allValue": null, + "datasource": "Prometheus", + "hide": 0, + "includeAll": false, + "label": "Service", + "multi": false, + "name": "service", + "options": [], + "query": "label_values(destination_service)", + "refresh": 1, + "regex": "", + "sort": 0, + "tagValuesQuery": "", + "tags": [], + "tagsQuery": "", + "type": "query", + "useTags": false + }, + { + "allValue": null, + "current": { + "text": "All", + "value": "$__all" + }, + "datasource": "Prometheus", + "hide": 0, + "includeAll": true, + "label": "Client Workload Namespace", + "multi": true, + "name": "srcns", + "options": [], + "query": "query_result( sum(istio_requests_total{reporter=\"destination\", destination_service=\"$service\"}) by (source_workload_namespace) or sum(istio_tcp_sent_bytes_total{reporter=\"destination\", destination_service=~\"$service\"}) by (source_workload_namespace))", + "refresh": 1, + "regex": "/.*namespace=\"([^\"]*).*/", + "sort": 2, + "tagValuesQuery": "", + "tags": [], + "tagsQuery": "", + "type": "query", + "useTags": false + }, + { + "allValue": null, + "current": { + "text": "All", + "value": "$__all" + }, + "datasource": "Prometheus", + "hide": 0, + "includeAll": true, + "label": "Client Workload", + "multi": true, + "name": "srcwl", + "options": [], + "query": "query_result( sum(istio_requests_total{reporter=\"destination\", destination_service=~\"$service\", source_workload_namespace=~\"$srcns\"}) by (source_workload) or sum(istio_tcp_sent_bytes_total{reporter=\"destination\", destination_service=~\"$service\", source_workload_namespace=~\"$srcns\"}) by (source_workload))", + "refresh": 1, + "regex": "/.*workload=\"([^\"]*).*/", + "sort": 3, + "tagValuesQuery": "", + "tags": [], + "tagsQuery": "", + "type": "query", + "useTags": false + }, + { + "allValue": null, + "current": { + "text": "All", + "value": "$__all" + }, + "datasource": "Prometheus", + "hide": 0, + "includeAll": true, + "label": "Service Workload Namespace", + "multi": true, + "name": "dstns", + "options": [], + "query": "query_result( sum(istio_requests_total{reporter=\"destination\", destination_service=\"$service\"}) by (destination_workload_namespace) or sum(istio_tcp_sent_bytes_total{reporter=\"destination\", destination_service=~\"$service\"}) by (destination_workload_namespace))", + "refresh": 1, + "regex": "/.*namespace=\"([^\"]*).*/", + "sort": 2, + "tagValuesQuery": "", + "tags": [], + "tagsQuery": "", + "type": "query", + "useTags": false + }, + { + "allValue": null, + "current": { + "text": "All", + "value": "$__all" + }, + "datasource": "Prometheus", + "hide": 0, + "includeAll": true, + "label": "Service Workload", + "multi": true, + "name": "dstwl", + "options": [], + "query": "query_result( sum(istio_requests_total{reporter=\"destination\", destination_service=~\"$service\", destination_workload_namespace=~\"$dstns\"}) by (destination_workload) or sum(istio_tcp_sent_bytes_total{reporter=\"destination\", destination_service=~\"$service\", destination_workload_namespace=~\"$dstns\"}) by (destination_workload))", + "refresh": 1, + "regex": "/.*workload=\"([^\"]*).*/", + "sort": 3, + "tagValuesQuery": "", + "tags": [], + "tagsQuery": "", + "type": "query", + "useTags": false + } + ] + }, + "time": { + "from": "now-5m", + "to": "now" + }, + "timepicker": { + "refresh_intervals": [ + "5s", + "10s", + "30s", + "1m", + "5m", + "15m", + "30m", + "1h", + "2h", + "1d" + ], + "time_options": [ + "5m", + "15m", + "1h", + "6h", + "12h", + "24h", + "2d", + "7d", + "30d" + ] + }, + "timezone": "", + "title": "Istio Service Dashboard", + "uid": "LJ_uJAvmk", + "version": 1 +} +' +--- +apiVersion: v1 +kind: ConfigMap +metadata: + name: istio-grafana-configuration-dashboards-istio-workload-dashboard + namespace: istio-system + labels: + app: grafana + chart: grafana + heritage: Tiller + release: istio + istio: grafana +data: + istio-workload-dashboard.json: '{ + "__inputs": [ + { + "name": "DS_PROMETHEUS", + "label": "Prometheus", + "description": "", + "type": "datasource", + "pluginId": "prometheus", + "pluginName": "Prometheus" + } + ], + "__requires": [ + { + "type": "grafana", + "id": "grafana", + "name": "Grafana", + "version": "5.0.4" + }, + { + "type": "panel", + "id": "graph", + "name": "Graph", + "version": "5.0.0" + }, + { + "type": "datasource", + "id": "prometheus", + "name": "Prometheus", + "version": "5.0.0" + }, + { + "type": "panel", + "id": "singlestat", + "name": "Singlestat", + "version": "5.0.0" + }, + { + "type": "panel", + "id": "text", + "name": "Text", + "version": "5.0.0" + } + ], + "annotations": { + "list": [ + { + "builtIn": 1, + "datasource": "-- Grafana --", + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations & Alerts", + "type": "dashboard" + } + ] + }, + "editable": false, + "gnetId": null, + "graphTooltip": 0, + "id": null, + "iteration": 1531345461465, + "links": [], + "panels": [ + { + "content": "
\nWORKLOAD: $workload.$namespace\n
", + "gridPos": { + "h": 3, + "w": 24, + "x": 0, + "y": 0 + }, + "id": 89, + "links": [], + "mode": "html", + "title": "", + "transparent": true, + "type": "text" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "datasource": "Prometheus", + "format": "ops", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "gridPos": { + "h": 4, + "w": 8, + "x": 0, + "y": 3 + }, + "id": 12, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": true, + "lineColor": "rgb(31, 120, 193)", + "show": true + }, + "tableColumn": "", + "targets": [ + { + "expr": "round(sum(irate(istio_requests_total{reporter=\"destination\",destination_workload_namespace=~\"$namespace\",destination_workload=~\"$workload\"}[5m])), 0.001)", + "format": "time_series", + "intervalFactor": 1, + "refId": "A", + "step": 4 + } + ], + "thresholds": "", + "title": "Incoming Request Volume", + "transparent": false, + "type": "singlestat", + "valueFontSize": "80%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "current" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "rgba(50, 172, 45, 0.97)", + "rgba(237, 129, 40, 0.89)", + "rgba(245, 54, 54, 0.9)" + ], + "datasource": "Prometheus", + "decimals": null, + "format": "percentunit", + "gauge": { + "maxValue": 100, + "minValue": 80, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": false + }, + "gridPos": { + "h": 4, + "w": 8, + "x": 8, + "y": 3 + }, + "id": 14, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": true, + "lineColor": "rgb(31, 120, 193)", + "show": true + }, + "tableColumn": "", + "targets": [ + { + "expr": "sum(irate(istio_requests_total{reporter=\"destination\",destination_workload_namespace=~\"$namespace\",destination_workload=~\"$workload\",response_code!~\"5.*\"}[5m])) / sum(irate(istio_requests_total{reporter=\"destination\",destination_workload_namespace=~\"$namespace\",destination_workload=~\"$workload\"}[5m]))", + "format": "time_series", + "intervalFactor": 1, + "refId": "B" + } + ], + "thresholds": "95, 99, 99.5", + "title": "Incoming Success Rate (non-5xx responses)", + "transparent": false, + "type": "singlestat", + "valueFontSize": "80%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "avg" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 4, + "w": 8, + "x": 16, + "y": 3 + }, + "id": 87, + "legend": { + "alignAsTable": false, + "avg": false, + "current": false, + "hideEmpty": false, + "hideZero": false, + "max": false, + "min": false, + "rightSide": true, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "(histogram_quantile(0.50, sum(irate(istio_request_duration_milliseconds_bucket{reporter=\"destination\",destination_workload=~\"$workload\", destination_workload_namespace=~\"$namespace\"}[1m])) by (le)) / 1000) or histogram_quantile(0.50, sum(irate(istio_request_duration_seconds_bucket{reporter=\"destination\",destination_workload=~\"$workload\", destination_workload_namespace=~\"$namespace\"}[1m])) by (le))", + "format": "time_series", + "interval": "", + "intervalFactor": 1, + "legendFormat": "P50", + "refId": "A" + }, + { + "expr": "(histogram_quantile(0.50, sum(irate(istio_request_duration_milliseconds_bucket{reporter=\"destination\",destination_workload=~\"$workload\", destination_workload_namespace=~\"$namespace\"}[1m])) by (le)) / 1000) or histogram_quantile(0.90, sum(irate(istio_request_duration_seconds_bucket{reporter=\"destination\",destination_workload=~\"$workload\", destination_workload_namespace=~\"$namespace\"}[1m])) by (le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "P90", + "refId": "B" + }, + { + "expr": "(histogram_quantile(0.50, sum(irate(istio_request_duration_milliseconds_bucket{reporter=\"destination\",destination_workload=~\"$workload\", destination_workload_namespace=~\"$namespace\"}[1m])) by (le)) / 1000) or histogram_quantile(0.99, sum(irate(istio_request_duration_seconds_bucket{reporter=\"destination\",destination_workload=~\"$workload\", destination_workload_namespace=~\"$namespace\"}[1m])) by (le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "P99", + "refId": "C" + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Request Duration", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "s", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ] + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "#299c46", + "rgba(237, 129, 40, 0.89)", + "#d44a3a" + ], + "datasource": "Prometheus", + "format": "Bps", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "gridPos": { + "h": 4, + "w": 12, + "x": 0, + "y": 7 + }, + "id": 84, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": true, + "lineColor": "rgb(31, 120, 193)", + "show": true + }, + "tableColumn": "", + "targets": [ + { + "expr": "sum(irate(istio_tcp_sent_bytes_total{reporter=\"destination\", destination_workload_namespace=~\"$namespace\", destination_workload=~\"$workload\"}[1m])) + sum(irate(istio_tcp_received_bytes_total{reporter=\"destination\", destination_workload_namespace=~\"$namespace\", destination_workload=~\"$workload\"}[1m]))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "", + "refId": "A" + } + ], + "thresholds": "", + "title": "TCP Server Traffic", + "transparent": false, + "type": "singlestat", + "valueFontSize": "80%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "avg" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "#299c46", + "rgba(237, 129, 40, 0.89)", + "#d44a3a" + ], + "datasource": "Prometheus", + "format": "Bps", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "gridPos": { + "h": 4, + "w": 12, + "x": 12, + "y": 7 + }, + "id": 85, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": true, + "lineColor": "rgb(31, 120, 193)", + "show": true + }, + "tableColumn": "", + "targets": [ + { + "expr": "sum(irate(istio_tcp_sent_bytes_total{reporter=\"source\", source_workload_namespace=~\"$namespace\", source_workload=~\"$workload\"}[1m])) + sum(irate(istio_tcp_received_bytes_total{reporter=\"source\", source_workload_namespace=~\"$namespace\", source_workload=~\"$workload\"}[1m]))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "", + "refId": "A" + } + ], + "thresholds": "", + "title": "TCP Client Traffic", + "transparent": false, + "type": "singlestat", + "valueFontSize": "80%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "avg" + }, + { + "content": "
\nINBOUND WORKLOADS\n
", + "gridPos": { + "h": 3, + "w": 24, + "x": 0, + "y": 11 + }, + "id": 45, + "links": [], + "mode": "html", + "title": "", + "transparent": true, + "type": "text" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 0, + "gridPos": { + "h": 6, + "w": 12, + "x": 0, + "y": 14 + }, + "id": 25, + "legend": { + "avg": false, + "current": false, + "hideEmpty": true, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null as zero", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "round(sum(irate(istio_requests_total{connection_security_policy=\"mutual_tls\", destination_workload_namespace=~\"$namespace\", destination_workload=~\"$workload\", reporter=\"destination\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[5m])) by (source_workload, source_workload_namespace, response_code), 0.001)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{ source_workload }}.{{ source_workload_namespace }} : {{ response_code }} (🔐mTLS)", + "refId": "B", + "step": 2 + }, + { + "expr": "round(sum(irate(istio_requests_total{connection_security_policy!=\"mutual_tls\", destination_workload_namespace=~\"$namespace\", destination_workload=~\"$workload\", reporter=\"destination\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[5m])) by (source_workload, source_workload_namespace, response_code), 0.001)", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ source_workload }}.{{ source_workload_namespace }} : {{ response_code }}", + "refId": "A", + "step": 2 + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Incoming Requests by Source And Response Code", + "tooltip": { + "shared": false, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [ + "total" + ] + }, + "yaxes": [ + { + "format": "ops", + "label": null, + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ] + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 6, + "w": 12, + "x": 12, + "y": 14 + }, + "id": 26, + "legend": { + "avg": false, + "current": false, + "hideEmpty": true, + "hideZero": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(irate(istio_requests_total{reporter=\"destination\", connection_security_policy=\"mutual_tls\", destination_workload_namespace=~\"$namespace\", destination_workload=~\"$workload\",response_code!~\"5.*\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[5m])) by (source_workload, source_workload_namespace) / sum(irate(istio_requests_total{reporter=\"destination\", connection_security_policy=\"mutual_tls\", destination_workload_namespace=~\"$namespace\", destination_workload=~\"$workload\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[5m])) by (source_workload, source_workload_namespace)", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ source_workload }}.{{ source_workload_namespace }} (🔐mTLS)", + "refId": "A", + "step": 2 + }, + { + "expr": "sum(irate(istio_requests_total{reporter=\"destination\", connection_security_policy!=\"mutual_tls\", destination_workload_namespace=~\"$namespace\", destination_workload=~\"$workload\",response_code!~\"5.*\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[5m])) by (source_workload, source_workload_namespace) / sum(irate(istio_requests_total{reporter=\"destination\", connection_security_policy!=\"mutual_tls\", destination_workload_namespace=~\"$namespace\", destination_workload=~\"$workload\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[5m])) by (source_workload, source_workload_namespace)", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ source_workload }}.{{ source_workload_namespace }}", + "refId": "B", + "step": 2 + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Incoming Success Rate (non-5xx responses) By Source", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "percentunit", + "label": null, + "logBase": 1, + "max": "1.01", + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ] + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "description": "", + "fill": 1, + "gridPos": { + "h": 6, + "w": 8, + "x": 0, + "y": 20 + }, + "id": 27, + "legend": { + "alignAsTable": false, + "avg": false, + "current": false, + "hideEmpty": true, + "hideZero": false, + "max": false, + "min": false, + "rightSide": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "(histogram_quantile(0.50, sum(irate(istio_request_duration_milliseconds_bucket{reporter=\"destination\", connection_security_policy=\"mutual_tls\", destination_workload=~\"$workload\", destination_workload_namespace=~\"$namespace\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le)) / 1000) or histogram_quantile(0.50, sum(irate(istio_request_duration_seconds_bucket{reporter=\"destination\", connection_security_policy=\"mutual_tls\", destination_workload=~\"$workload\", destination_workload_namespace=~\"$namespace\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{source_workload}}.{{source_workload_namespace}} P50 (🔐mTLS)", + "refId": "D", + "step": 2 + }, + { + "expr": "(histogram_quantile(0.90, sum(irate(istio_request_duration_milliseconds_bucket{reporter=\"destination\", connection_security_policy=\"mutual_tls\", destination_workload=~\"$workload\", destination_workload_namespace=~\"$namespace\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le)) / 1000) or histogram_quantile(0.90, sum(irate(istio_request_duration_seconds_bucket{reporter=\"destination\", connection_security_policy=\"mutual_tls\", destination_workload=~\"$workload\", destination_workload_namespace=~\"$namespace\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{source_workload}}.{{source_workload_namespace}} P90 (🔐mTLS)", + "refId": "A", + "step": 2 + }, + { + "expr": "(histogram_quantile(0.95, sum(irate(istio_request_duration_milliseconds_bucket{reporter=\"destination\", connection_security_policy=\"mutual_tls\", destination_workload=~\"$workload\", destination_workload_namespace=~\"$namespace\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le)) / 1000) or histogram_quantile(0.95, sum(irate(istio_request_duration_seconds_bucket{reporter=\"destination\", connection_security_policy=\"mutual_tls\", destination_workload=~\"$workload\", destination_workload_namespace=~\"$namespace\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{source_workload}}.{{source_workload_namespace}} P95 (🔐mTLS)", + "refId": "B", + "step": 2 + }, + { + "expr": "(histogram_quantile(0.99, sum(irate(istio_request_duration_milliseconds_bucket{reporter=\"destination\", connection_security_policy=\"mutual_tls\", destination_workload=~\"$workload\", destination_workload_namespace=~\"$namespace\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le)) / 1000) or histogram_quantile(0.99, sum(irate(istio_request_duration_seconds_bucket{reporter=\"destination\", connection_security_policy=\"mutual_tls\", destination_workload=~\"$workload\", destination_workload_namespace=~\"$namespace\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{source_workload}}.{{source_workload_namespace}} P99 (🔐mTLS)", + "refId": "C", + "step": 2 + }, + { + "expr": "(histogram_quantile(0.50, sum(irate(istio_request_duration_milliseconds_bucket{reporter=\"destination\", connection_security_policy!=\"mutual_tls\", destination_workload=~\"$workload\", destination_workload_namespace=~\"$namespace\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le)) / 1000) or histogram_quantile(0.50, sum(irate(istio_request_duration_seconds_bucket{reporter=\"destination\", connection_security_policy!=\"mutual_tls\", destination_workload=~\"$workload\", destination_workload_namespace=~\"$namespace\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{source_workload}}.{{source_workload_namespace}} P50", + "refId": "E", + "step": 2 + }, + { + "expr": "(histogram_quantile(0.90, sum(irate(istio_request_duration_milliseconds_bucket{reporter=\"destination\", connection_security_policy!=\"mutual_tls\", destination_workload=~\"$workload\", destination_workload_namespace=~\"$namespace\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le)) / 1000) or histogram_quantile(0.90, sum(irate(istio_request_duration_seconds_bucket{reporter=\"destination\", connection_security_policy!=\"mutual_tls\", destination_workload=~\"$workload\", destination_workload_namespace=~\"$namespace\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{source_workload}}.{{source_workload_namespace}} P90", + "refId": "F", + "step": 2 + }, + { + "expr": "(histogram_quantile(0.95, sum(irate(istio_request_duration_milliseconds_bucket{reporter=\"destination\", connection_security_policy!=\"mutual_tls\", destination_workload=~\"$workload\", destination_workload_namespace=~\"$namespace\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le)) / 1000) or histogram_quantile(0.95, sum(irate(istio_request_duration_seconds_bucket{reporter=\"destination\", connection_security_policy!=\"mutual_tls\", destination_workload=~\"$workload\", destination_workload_namespace=~\"$namespace\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{source_workload}}.{{source_workload_namespace}} P95", + "refId": "G", + "step": 2 + }, + { + "expr": "(histogram_quantile(0.99, sum(irate(istio_request_duration_milliseconds_bucket{reporter=\"destination\", connection_security_policy!=\"mutual_tls\", destination_workload=~\"$workload\", destination_workload_namespace=~\"$namespace\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le)) / 1000) or histogram_quantile(0.99, sum(irate(istio_request_duration_seconds_bucket{reporter=\"destination\", connection_security_policy!=\"mutual_tls\", destination_workload=~\"$workload\", destination_workload_namespace=~\"$namespace\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{source_workload}}.{{source_workload_namespace}} P99", + "refId": "H", + "step": 2 + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Incoming Request Duration by Source", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "s", + "label": null, + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ] + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 6, + "w": 8, + "x": 8, + "y": 20 + }, + "id": 28, + "legend": { + "alignAsTable": false, + "avg": false, + "current": false, + "hideEmpty": true, + "max": false, + "min": false, + "rightSide": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "histogram_quantile(0.50, sum(irate(istio_request_bytes_bucket{reporter=\"destination\", connection_security_policy=\"mutual_tls\", destination_workload=~\"$workload\", destination_workload_namespace=~\"$namespace\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{source_workload}}.{{source_workload_namespace}} P50 (🔐mTLS)", + "refId": "D", + "step": 2 + }, + { + "expr": "histogram_quantile(0.90, sum(irate(istio_request_bytes_bucket{reporter=\"destination\", connection_security_policy=\"mutual_tls\", destination_workload=~\"$workload\", destination_workload_namespace=~\"$namespace\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{source_workload}}.{{source_workload_namespace}} P90 (🔐mTLS)", + "refId": "A", + "step": 2 + }, + { + "expr": "histogram_quantile(0.95, sum(irate(istio_request_bytes_bucket{reporter=\"destination\", connection_security_policy=\"mutual_tls\", destination_workload=~\"$workload\", destination_workload_namespace=~\"$namespace\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{source_workload}}.{{source_workload_namespace}} P95 (🔐mTLS)", + "refId": "B", + "step": 2 + }, + { + "expr": "histogram_quantile(0.99, sum(irate(istio_request_bytes_bucket{reporter=\"destination\", connection_security_policy=\"mutual_tls\", destination_workload=~\"$workload\", destination_workload_namespace=~\"$namespace\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{source_workload}}.{{source_workload_namespace}} P99 (🔐mTLS)", + "refId": "C", + "step": 2 + }, + { + "expr": "histogram_quantile(0.50, sum(irate(istio_request_bytes_bucket{reporter=\"destination\", connection_security_policy!=\"mutual_tls\", destination_workload=~\"$workload\", destination_workload_namespace=~\"$namespace\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{source_workload}}.{{source_workload_namespace}} P50", + "refId": "E", + "step": 2 + }, + { + "expr": "histogram_quantile(0.90, sum(irate(istio_request_bytes_bucket{reporter=\"destination\", connection_security_policy!=\"mutual_tls\", destination_workload=~\"$workload\", destination_workload_namespace=~\"$namespace\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{source_workload}}.{{source_workload_namespace}} P90", + "refId": "F", + "step": 2 + }, + { + "expr": "histogram_quantile(0.95, sum(irate(istio_request_bytes_bucket{reporter=\"destination\", connection_security_policy!=\"mutual_tls\", destination_workload=~\"$workload\", destination_workload_namespace=~\"$namespace\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{source_workload}}.{{source_workload_namespace}} P95", + "refId": "G", + "step": 2 + }, + { + "expr": "histogram_quantile(0.99, sum(irate(istio_request_bytes_bucket{reporter=\"destination\", connection_security_policy!=\"mutual_tls\", destination_workload=~\"$workload\", destination_workload_namespace=~\"$namespace\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{source_workload}}.{{source_workload_namespace}} P99", + "refId": "H", + "step": 2 + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Incoming Request Size By Source", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "decbytes", + "label": null, + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ] + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 6, + "w": 8, + "x": 16, + "y": 20 + }, + "id": 68, + "legend": { + "alignAsTable": false, + "avg": false, + "current": false, + "hideEmpty": true, + "max": false, + "min": false, + "rightSide": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "histogram_quantile(0.50, sum(irate(istio_response_bytes_bucket{reporter=\"destination\", connection_security_policy=\"mutual_tls\", destination_workload=~\"$workload\", destination_workload_namespace=~\"$namespace\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{source_workload}}.{{source_workload_namespace}} P50 (🔐mTLS)", + "refId": "D", + "step": 2 + }, + { + "expr": "histogram_quantile(0.90, sum(irate(istio_response_bytes_bucket{reporter=\"destination\", connection_security_policy=\"mutual_tls\", destination_workload=~\"$workload\", destination_workload_namespace=~\"$namespace\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{source_workload}}.{{source_workload_namespace}} P90 (🔐mTLS)", + "refId": "A", + "step": 2 + }, + { + "expr": "histogram_quantile(0.95, sum(irate(istio_response_bytes_bucket{reporter=\"destination\", connection_security_policy=\"mutual_tls\", destination_workload=~\"$workload\", destination_workload_namespace=~\"$namespace\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{source_workload}}.{{source_workload_namespace}} P95 (🔐mTLS)", + "refId": "B", + "step": 2 + }, + { + "expr": "histogram_quantile(0.99, sum(irate(istio_response_bytes_bucket{reporter=\"destination\", connection_security_policy=\"mutual_tls\", destination_workload=~\"$workload\", destination_workload_namespace=~\"$namespace\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{source_workload}}.{{source_workload_namespace}} P99 (🔐mTLS)", + "refId": "C", + "step": 2 + }, + { + "expr": "histogram_quantile(0.50, sum(irate(istio_response_bytes_bucket{reporter=\"destination\", connection_security_policy!=\"mutual_tls\", destination_workload=~\"$workload\", destination_workload_namespace=~\"$namespace\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{source_workload}}.{{source_workload_namespace}} P50", + "refId": "E", + "step": 2 + }, + { + "expr": "histogram_quantile(0.90, sum(irate(istio_response_bytes_bucket{reporter=\"destination\", connection_security_policy!=\"mutual_tls\", destination_workload=~\"$workload\", destination_workload_namespace=~\"$namespace\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{source_workload}}.{{source_workload_namespace}} P90", + "refId": "F", + "step": 2 + }, + { + "expr": "histogram_quantile(0.95, sum(irate(istio_response_bytes_bucket{reporter=\"destination\", connection_security_policy!=\"mutual_tls\", destination_workload=~\"$workload\", destination_workload_namespace=~\"$namespace\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{source_workload}}.{{source_workload_namespace}} P95", + "refId": "G", + "step": 2 + }, + { + "expr": "histogram_quantile(0.99, sum(irate(istio_response_bytes_bucket{reporter=\"destination\", connection_security_policy!=\"mutual_tls\", destination_workload=~\"$workload\", destination_workload_namespace=~\"$namespace\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{source_workload}}.{{source_workload_namespace}} P99", + "refId": "H", + "step": 2 + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Response Size By Source", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "decbytes", + "label": null, + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ] + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 6, + "w": 12, + "x": 0, + "y": 26 + }, + "id": 80, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "round(sum(irate(istio_tcp_received_bytes_total{reporter=\"destination\", connection_security_policy=\"mutual_tls\", destination_workload_namespace=~\"$namespace\", destination_workload=~\"$workload\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace), 0.001)", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ source_workload }}.{{ source_workload_namespace}} (🔐mTLS)", + "refId": "A", + "step": 2 + }, + { + "expr": "round(sum(irate(istio_tcp_received_bytes_total{reporter=\"destination\", connection_security_policy!=\"mutual_tls\", destination_workload_namespace=~\"$namespace\", destination_workload=~\"$workload\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace), 0.001)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{ source_workload }}.{{ source_workload_namespace}}", + "refId": "B", + "step": 2 + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Bytes Received from Incoming TCP Connection", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "Bps", + "label": null, + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ] + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 6, + "w": 12, + "x": 12, + "y": 26 + }, + "id": 82, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "round(sum(irate(istio_tcp_sent_bytes_total{connection_security_policy=\"mutual_tls\", reporter=\"destination\", destination_workload_namespace=~\"$namespace\", destination_workload=~\"$workload\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace), 0.001)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{ source_workload }}.{{ source_workload_namespace}} (🔐mTLS)", + "refId": "A", + "step": 2 + }, + { + "expr": "round(sum(irate(istio_tcp_sent_bytes_total{connection_security_policy!=\"mutual_tls\", reporter=\"destination\", destination_workload_namespace=~\"$namespace\", destination_workload=~\"$workload\", source_workload=~\"$srcwl\", source_workload_namespace=~\"$srcns\"}[1m])) by (source_workload, source_workload_namespace), 0.001)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{ source_workload }}.{{ source_workload_namespace}}", + "refId": "B", + "step": 2 + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Bytes Sent to Incoming TCP Connection", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "Bps", + "label": null, + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ] + }, + { + "content": "
\nOUTBOUND SERVICES\n
", + "gridPos": { + "h": 3, + "w": 24, + "x": 0, + "y": 32 + }, + "id": 69, + "links": [], + "mode": "html", + "title": "", + "transparent": true, + "type": "text" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 0, + "gridPos": { + "h": 6, + "w": 12, + "x": 0, + "y": 35 + }, + "id": 70, + "legend": { + "avg": false, + "current": false, + "hideEmpty": true, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null as zero", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "round(sum(irate(istio_requests_total{connection_security_policy=\"mutual_tls\", source_workload_namespace=~\"$namespace\", source_workload=~\"$workload\", reporter=\"source\", destination_service=~\"$dstsvc\"}[5m])) by (destination_service, response_code), 0.001)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{ destination_service }} : {{ response_code }} (🔐mTLS)", + "refId": "B", + "step": 2 + }, + { + "expr": "round(sum(irate(istio_requests_total{connection_security_policy!=\"mutual_tls\", source_workload_namespace=~\"$namespace\", source_workload=~\"$workload\", reporter=\"source\", destination_service=~\"$dstsvc\"}[5m])) by (destination_service, response_code), 0.001)", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_service }} : {{ response_code }}", + "refId": "A", + "step": 2 + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Outgoing Requests by Destination And Response Code", + "tooltip": { + "shared": false, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [ + "total" + ] + }, + "yaxes": [ + { + "format": "ops", + "label": null, + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ] + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 6, + "w": 12, + "x": 12, + "y": 35 + }, + "id": 71, + "legend": { + "avg": false, + "current": false, + "hideEmpty": true, + "hideZero": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(irate(istio_requests_total{reporter=\"source\", connection_security_policy=\"mutual_tls\", source_workload_namespace=~\"$namespace\", source_workload=~\"$workload\",response_code!~\"5.*\", destination_service=~\"$dstsvc\"}[5m])) by (destination_service) / sum(irate(istio_requests_total{reporter=\"source\", connection_security_policy=\"mutual_tls\", source_workload_namespace=~\"$namespace\", source_workload=~\"$workload\", destination_service=~\"$dstsvc\"}[5m])) by (destination_service)", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_service }} (🔐mTLS)", + "refId": "A", + "step": 2 + }, + { + "expr": "sum(irate(istio_requests_total{reporter=\"source\", connection_security_policy!=\"mutual_tls\", source_workload_namespace=~\"$namespace\", source_workload=~\"$workload\",response_code!~\"5.*\", destination_service=~\"$dstsvc\"}[5m])) by (destination_service) / sum(irate(istio_requests_total{reporter=\"source\", connection_security_policy!=\"mutual_tls\", source_workload_namespace=~\"$namespace\", source_workload=~\"$workload\", destination_service=~\"$dstsvc\"}[5m])) by (destination_service)", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{destination_service }}", + "refId": "B", + "step": 2 + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Outgoing Success Rate (non-5xx responses) By Destination", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "percentunit", + "label": null, + "logBase": 1, + "max": "1.01", + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ] + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "description": "", + "fill": 1, + "gridPos": { + "h": 6, + "w": 8, + "x": 0, + "y": 41 + }, + "id": 72, + "legend": { + "alignAsTable": false, + "avg": false, + "current": false, + "hideEmpty": true, + "hideZero": false, + "max": false, + "min": false, + "rightSide": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "(histogram_quantile(0.50, sum(irate(istio_request_duration_milliseconds_bucket{reporter=\"source\", connection_security_policy=\"mutual_tls\", source_workload=~\"$workload\", source_workload_namespace=~\"$namespace\", destination_service=~\"$dstsvc\"}[1m])) by (destination_service, le)) / 1000) or histogram_quantile(0.50, sum(irate(istio_request_duration_seconds_bucket{reporter=\"source\", connection_security_policy=\"mutual_tls\", source_workload=~\"$workload\", source_workload_namespace=~\"$namespace\", destination_service=~\"$dstsvc\"}[1m])) by (destination_service, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_service }} P50 (🔐mTLS)", + "refId": "D", + "step": 2 + }, + { + "expr": "(histogram_quantile(0.90, sum(irate(istio_request_duration_milliseconds_bucket{reporter=\"source\", connection_security_policy=\"mutual_tls\", source_workload=~\"$workload\", source_workload_namespace=~\"$namespace\", destination_service=~\"$dstsvc\"}[1m])) by (destination_service, le)) / 1000) or histogram_quantile(0.90, sum(irate(istio_request_duration_seconds_bucket{reporter=\"source\", connection_security_policy=\"mutual_tls\", source_workload=~\"$workload\", source_workload_namespace=~\"$namespace\", destination_service=~\"$dstsvc\"}[1m])) by (destination_service, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_service }} P90 (🔐mTLS)", + "refId": "A", + "step": 2 + }, + { + "expr": "(histogram_quantile(0.95, sum(irate(istio_request_duration_milliseconds_bucket{reporter=\"source\", connection_security_policy=\"mutual_tls\", source_workload=~\"$workload\", source_workload_namespace=~\"$namespace\", destination_service=~\"$dstsvc\"}[1m])) by (destination_service, le)) / 1000) or histogram_quantile(0.95, sum(irate(istio_request_duration_seconds_bucket{reporter=\"source\", connection_security_policy=\"mutual_tls\", source_workload=~\"$workload\", source_workload_namespace=~\"$namespace\", destination_service=~\"$dstsvc\"}[1m])) by (destination_service, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_service }} P95 (🔐mTLS)", + "refId": "B", + "step": 2 + }, + { + "expr": "(histogram_quantile(0.99, sum(irate(istio_request_duration_milliseconds_bucket{reporter=\"source\", connection_security_policy=\"mutual_tls\", source_workload=~\"$workload\", source_workload_namespace=~\"$namespace\", destination_service=~\"$dstsvc\"}[1m])) by (destination_service, le)) / 1000) or histogram_quantile(0.99, sum(irate(istio_request_duration_seconds_bucket{reporter=\"source\", connection_security_policy=\"mutual_tls\", source_workload=~\"$workload\", source_workload_namespace=~\"$namespace\", destination_service=~\"$dstsvc\"}[1m])) by (destination_service, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_service }} P99 (🔐mTLS)", + "refId": "C", + "step": 2 + }, + { + "expr": "(histogram_quantile(0.50, sum(irate(istio_request_duration_milliseconds_bucket{reporter=\"source\", connection_security_policy!=\"mutual_tls\", source_workload=~\"$workload\", source_workload_namespace=~\"$namespace\", destination_service=~\"$dstsvc\"}[1m])) by (destination_service, le)) / 1000) or histogram_quantile(0.50, sum(irate(istio_request_duration_seconds_bucket{reporter=\"source\", connection_security_policy!=\"mutual_tls\", source_workload=~\"$workload\", source_workload_namespace=~\"$namespace\", destination_service=~\"$dstsvc\"}[1m])) by (destination_service, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_service }} P50", + "refId": "E", + "step": 2 + }, + { + "expr": "(histogram_quantile(0.90, sum(irate(istio_request_duration_milliseconds_bucket{reporter=\"source\", connection_security_policy!=\"mutual_tls\", source_workload=~\"$workload\", source_workload_namespace=~\"$namespace\", destination_service=~\"$dstsvc\"}[1m])) by (destination_service, le)) / 1000) or histogram_quantile(0.90, sum(irate(istio_request_duration_seconds_bucket{reporter=\"source\", connection_security_policy!=\"mutual_tls\", source_workload=~\"$workload\", source_workload_namespace=~\"$namespace\", destination_service=~\"$dstsvc\"}[1m])) by (destination_service, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_service }} P90", + "refId": "F", + "step": 2 + }, + { + "expr": "(histogram_quantile(0.95, sum(irate(istio_request_duration_milliseconds_bucket{reporter=\"source\", connection_security_policy!=\"mutual_tls\", source_workload=~\"$workload\", source_workload_namespace=~\"$namespace\", destination_service=~\"$dstsvc\"}[1m])) by (destination_service, le)) / 1000) or histogram_quantile(0.95, sum(irate(istio_request_duration_seconds_bucket{reporter=\"source\", connection_security_policy!=\"mutual_tls\", source_workload=~\"$workload\", source_workload_namespace=~\"$namespace\", destination_service=~\"$dstsvc\"}[1m])) by (destination_service, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_service }} P95", + "refId": "G", + "step": 2 + }, + { + "expr": "(histogram_quantile(0.99, sum(irate(istio_request_duration_milliseconds_bucket{reporter=\"source\", connection_security_policy!=\"mutual_tls\", source_workload=~\"$workload\", source_workload_namespace=~\"$namespace\", destination_service=~\"$dstsvc\"}[1m])) by (destination_service, le)) / 1000) or histogram_quantile(0.99, sum(irate(istio_request_duration_seconds_bucket{reporter=\"source\", connection_security_policy!=\"mutual_tls\", source_workload=~\"$workload\", source_workload_namespace=~\"$namespace\", destination_service=~\"$dstsvc\"}[1m])) by (destination_service, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_service }} P99", + "refId": "H", + "step": 2 + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Outgoing Request Duration by Destination", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "s", + "label": null, + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ] + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 6, + "w": 8, + "x": 8, + "y": 41 + }, + "id": 73, + "legend": { + "alignAsTable": false, + "avg": false, + "current": false, + "hideEmpty": true, + "max": false, + "min": false, + "rightSide": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "histogram_quantile(0.50, sum(irate(istio_request_bytes_bucket{reporter=\"source\", connection_security_policy=\"mutual_tls\", source_workload=~\"$workload\", source_workload_namespace=~\"$namespace\", destination_service=~\"$dstsvc\"}[1m])) by (destination_service, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_service }} P50 (🔐mTLS)", + "refId": "D", + "step": 2 + }, + { + "expr": "histogram_quantile(0.90, sum(irate(istio_request_bytes_bucket{reporter=\"source\", connection_security_policy=\"mutual_tls\", source_workload=~\"$workload\", source_workload_namespace=~\"$namespace\", destination_service=~\"$dstsvc\"}[1m])) by (destination_service, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_service }} P90 (🔐mTLS)", + "refId": "A", + "step": 2 + }, + { + "expr": "histogram_quantile(0.95, sum(irate(istio_request_bytes_bucket{reporter=\"source\", connection_security_policy=\"mutual_tls\", source_workload=~\"$workload\", source_workload_namespace=~\"$namespace\", destination_service=~\"$dstsvc\"}[1m])) by (destination_service, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_service }} P95 (🔐mTLS)", + "refId": "B", + "step": 2 + }, + { + "expr": "histogram_quantile(0.99, sum(irate(istio_request_bytes_bucket{reporter=\"source\", connection_security_policy=\"mutual_tls\", source_workload=~\"$workload\", source_workload_namespace=~\"$namespace\", destination_service=~\"$dstsvc\"}[1m])) by (destination_service, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_service }} P99 (🔐mTLS)", + "refId": "C", + "step": 2 + }, + { + "expr": "histogram_quantile(0.50, sum(irate(istio_request_bytes_bucket{reporter=\"source\", connection_security_policy!=\"mutual_tls\", source_workload=~\"$workload\", source_workload_namespace=~\"$namespace\", destination_service=~\"$dstsvc\"}[1m])) by (destination_service, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_service }} P50", + "refId": "E", + "step": 2 + }, + { + "expr": "histogram_quantile(0.90, sum(irate(istio_request_bytes_bucket{reporter=\"source\", connection_security_policy!=\"mutual_tls\", source_workload=~\"$workload\", source_workload_namespace=~\"$namespace\", destination_service=~\"$dstsvc\"}[1m])) by (destination_service, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_service }} P90", + "refId": "F", + "step": 2 + }, + { + "expr": "histogram_quantile(0.95, sum(irate(istio_request_bytes_bucket{reporter=\"source\", connection_security_policy!=\"mutual_tls\", source_workload=~\"$workload\", source_workload_namespace=~\"$namespace\", destination_service=~\"$dstsvc\"}[1m])) by (destination_service, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_service }} P95", + "refId": "G", + "step": 2 + }, + { + "expr": "histogram_quantile(0.99, sum(irate(istio_request_bytes_bucket{reporter=\"source\", connection_security_policy!=\"mutual_tls\", source_workload=~\"$workload\", source_workload_namespace=~\"$namespace\", destination_service=~\"$dstsvc\"}[1m])) by (destination_service, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_service }} P99", + "refId": "H", + "step": 2 + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Outgoing Request Size By Destination", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "decbytes", + "label": null, + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ] + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 6, + "w": 8, + "x": 16, + "y": 41 + }, + "id": 74, + "legend": { + "alignAsTable": false, + "avg": false, + "current": false, + "hideEmpty": true, + "max": false, + "min": false, + "rightSide": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "histogram_quantile(0.50, sum(irate(istio_response_bytes_bucket{reporter=\"source\", connection_security_policy=\"mutual_tls\", source_workload=~\"$workload\", source_workload_namespace=~\"$namespace\", destination_service=~\"$dstsvc\"}[1m])) by (destination_service, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_service }} P50 (🔐mTLS)", + "refId": "D", + "step": 2 + }, + { + "expr": "histogram_quantile(0.90, sum(irate(istio_response_bytes_bucket{reporter=\"source\", connection_security_policy=\"mutual_tls\", source_workload=~\"$workload\", source_workload_namespace=~\"$namespace\", destination_service=~\"$dstsvc\"}[1m])) by (destination_service, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_service }} P90 (🔐mTLS)", + "refId": "A", + "step": 2 + }, + { + "expr": "histogram_quantile(0.95, sum(irate(istio_response_bytes_bucket{reporter=\"source\", connection_security_policy=\"mutual_tls\", source_workload=~\"$workload\", source_workload_namespace=~\"$namespace\", destination_service=~\"$dstsvc\"}[1m])) by (destination_service, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_service }} P95 (🔐mTLS)", + "refId": "B", + "step": 2 + }, + { + "expr": "histogram_quantile(0.99, sum(irate(istio_response_bytes_bucket{reporter=\"source\", connection_security_policy=\"mutual_tls\", source_workload=~\"$workload\", source_workload_namespace=~\"$namespace\", destination_service=~\"$dstsvc\"}[1m])) by (destination_service, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_service }} P99 (🔐mTLS)", + "refId": "C", + "step": 2 + }, + { + "expr": "histogram_quantile(0.50, sum(irate(istio_response_bytes_bucket{reporter=\"source\", connection_security_policy!=\"mutual_tls\", source_workload=~\"$workload\", source_workload_namespace=~\"$namespace\", destination_service=~\"$dstsvc\"}[1m])) by (destination_service, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_service }} P50", + "refId": "E", + "step": 2 + }, + { + "expr": "histogram_quantile(0.90, sum(irate(istio_response_bytes_bucket{reporter=\"source\", connection_security_policy!=\"mutual_tls\", source_workload=~\"$workload\", source_workload_namespace=~\"$namespace\", destination_service=~\"$dstsvc\"}[1m])) by (destination_service, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_service }} P90", + "refId": "F", + "step": 2 + }, + { + "expr": "histogram_quantile(0.95, sum(irate(istio_response_bytes_bucket{reporter=\"source\", connection_security_policy!=\"mutual_tls\", source_workload=~\"$workload\", source_workload_namespace=~\"$namespace\", destination_service=~\"$dstsvc\"}[1m])) by (destination_service, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_service }} P95", + "refId": "G", + "step": 2 + }, + { + "expr": "histogram_quantile(0.99, sum(irate(istio_response_bytes_bucket{reporter=\"source\", connection_security_policy!=\"mutual_tls\", source_workload=~\"$workload\", source_workload_namespace=~\"$namespace\", destination_service=~\"$dstsvc\"}[1m])) by (destination_service, le))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ destination_service }} P99", + "refId": "H", + "step": 2 + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Response Size By Destination", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "decbytes", + "label": null, + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ] + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 6, + "w": 12, + "x": 0, + "y": 47 + }, + "id": 76, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "round(sum(irate(istio_tcp_sent_bytes_total{connection_security_policy=\"mutual_tls\", reporter=\"source\", source_workload_namespace=~\"$namespace\", source_workload=~\"$workload\", destination_service=~\"$dstsvc\"}[1m])) by (destination_service), 0.001)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{ destination_service }} (🔐mTLS)", + "refId": "A", + "step": 2 + }, + { + "expr": "round(sum(irate(istio_tcp_sent_bytes_total{connection_security_policy!=\"mutual_tls\", reporter=\"source\", source_workload_namespace=~\"$namespace\", source_workload=~\"$workload\", destination_service=~\"$dstsvc\"}[1m])) by (destination_service), 0.001)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{ destination_service }}", + "refId": "B", + "step": 2 + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Bytes Sent on Outgoing TCP Connection", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "Bps", + "label": null, + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ] + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 6, + "w": 12, + "x": 12, + "y": 47 + }, + "id": 78, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "round(sum(irate(istio_tcp_received_bytes_total{reporter=\"source\", connection_security_policy=\"mutual_tls\", source_workload_namespace=~\"$namespace\", source_workload=~\"$workload\", destination_service=~\"$dstsvc\"}[1m])) by (destination_service), 0.001)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{ destination_service }} (🔐mTLS)", + "refId": "A", + "step": 2 + }, + { + "expr": "round(sum(irate(istio_tcp_received_bytes_total{reporter=\"source\", connection_security_policy!=\"mutual_tls\", source_workload_namespace=~\"$namespace\", source_workload=~\"$workload\", destination_service=~\"$dstsvc\"}[1m])) by (destination_service), 0.001)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{ destination_service }}", + "refId": "B", + "step": 2 + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Bytes Received from Outgoing TCP Connection", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "Bps", + "label": null, + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ] + } + ], + "refresh": "10s", + "schemaVersion": 16, + "style": "dark", + "tags": [], + "templating": { + "list": [ + { + "allValue": null, + "current": {}, + "datasource": "Prometheus", + "hide": 0, + "includeAll": false, + "label": "Namespace", + "multi": false, + "name": "namespace", + "options": [], + "query": "query_result(sum(istio_requests_total) by (destination_workload_namespace) or sum(istio_tcp_sent_bytes_total) by (destination_workload_namespace))", + "refresh": 1, + "regex": "/.*_namespace=\"([^\"]*).*/", + "sort": 0, + "tagValuesQuery": "", + "tags": [], + "tagsQuery": "", + "type": "query", + "useTags": false + }, + { + "allValue": null, + "current": {}, + "datasource": "Prometheus", + "hide": 0, + "includeAll": false, + "label": "Workload", + "multi": false, + "name": "workload", + "options": [], + "query": "query_result((sum(istio_requests_total{destination_workload_namespace=~\"$namespace\"}) by (destination_workload) or sum(istio_requests_total{source_workload_namespace=~\"$namespace\"}) by (source_workload)) or (sum(istio_tcp_sent_bytes_total{destination_workload_namespace=~\"$namespace\"}) by (destination_workload) or sum(istio_tcp_sent_bytes_total{source_workload_namespace=~\"$namespace\"}) by (source_workload)))", + "refresh": 1, + "regex": "/.*workload=\"([^\"]*).*/", + "sort": 1, + "tagValuesQuery": "", + "tags": [], + "tagsQuery": "", + "type": "query", + "useTags": false + }, + { + "allValue": null, + "current": {}, + "datasource": "Prometheus", + "hide": 0, + "includeAll": true, + "label": "Inbound Workload Namespace", + "multi": true, + "name": "srcns", + "options": [], + "query": "query_result( sum(istio_requests_total{reporter=\"destination\", destination_workload=\"$workload\", destination_workload_namespace=~\"$namespace\"}) by (source_workload_namespace) or sum(istio_tcp_sent_bytes_total{reporter=\"destination\", destination_workload=\"$workload\", destination_workload_namespace=~\"$namespace\"}) by (source_workload_namespace))", + "refresh": 1, + "regex": "/.*namespace=\"([^\"]*).*/", + "sort": 2, + "tagValuesQuery": "", + "tags": [], + "tagsQuery": "", + "type": "query", + "useTags": false + }, + { + "allValue": null, + "current": {}, + "datasource": "Prometheus", + "hide": 0, + "includeAll": true, + "label": "Inbound Workload", + "multi": true, + "name": "srcwl", + "options": [], + "query": "query_result( sum(istio_requests_total{reporter=\"destination\", destination_workload=\"$workload\", destination_workload_namespace=~\"$namespace\", source_workload_namespace=~\"$srcns\"}) by (source_workload) or sum(istio_tcp_sent_bytes_total{reporter=\"destination\", destination_workload=\"$workload\", destination_workload_namespace=~\"$namespace\", source_workload_namespace=~\"$srcns\"}) by (source_workload))", + "refresh": 1, + "regex": "/.*workload=\"([^\"]*).*/", + "sort": 3, + "tagValuesQuery": "", + "tags": [], + "tagsQuery": "", + "type": "query", + "useTags": false + }, + { + "allValue": null, + "current": {}, + "datasource": "Prometheus", + "hide": 0, + "includeAll": true, + "label": "Destination Service", + "multi": true, + "name": "dstsvc", + "options": [], + "query": "query_result( sum(istio_requests_total{reporter=\"source\", source_workload=~\"$workload\", source_workload_namespace=~\"$namespace\"}) by (destination_service) or sum(istio_tcp_sent_bytes_total{reporter=\"source\", source_workload=~\"$workload\", source_workload_namespace=~\"$namespace\"}) by (destination_service))", + "refresh": 1, + "regex": "/.*destination_service=\"([^\"]*).*/", + "sort": 4, + "tagValuesQuery": "", + "tags": [], + "tagsQuery": "", + "type": "query", + "useTags": false + } + ] + }, + "time": { + "from": "now-5m", + "to": "now" + }, + "timepicker": { + "refresh_intervals": [ + "5s", + "10s", + "30s", + "1m", + "5m", + "15m", + "30m", + "1h", + "2h", + "1d" + ], + "time_options": [ + "5m", + "15m", + "1h", + "6h", + "12h", + "24h", + "2d", + "7d", + "30d" + ] + }, + "timezone": "", + "title": "Istio Workload Dashboard", + "uid": "UbsSZTDik", + "version": 1 +} +' +--- +apiVersion: v1 +kind: ConfigMap +metadata: + name: istio-grafana-configuration-dashboards-mixer-dashboard + namespace: istio-system + labels: + app: grafana + chart: grafana + heritage: Tiller + release: istio + istio: grafana +data: + mixer-dashboard.json: '{ + "__inputs": [ + { + "name": "DS_PROMETHEUS", + "label": "Prometheus", + "description": "", + "type": "datasource", + "pluginId": "prometheus", + "pluginName": "Prometheus" + } + ], + "__requires": [ + { + "type": "grafana", + "id": "grafana", + "name": "Grafana", + "version": "5.2.3" + }, + { + "type": "panel", + "id": "graph", + "name": "Graph", + "version": "5.0.0" + }, + { + "type": "datasource", + "id": "prometheus", + "name": "Prometheus", + "version": "5.0.0" + }, + { + "type": "panel", + "id": "text", + "name": "Text", + "version": "5.0.0" + } + ], + "annotations": { + "list": [ + { + "builtIn": 1, + "datasource": "-- Grafana --", + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "limit": 100, + "name": "Annotations & Alerts", + "showIn": 0, + "type": "dashboard" + } + ] + }, + "editable": false, + "gnetId": null, + "graphTooltip": 1, + "id": null, + "iteration": 1543881232533, + "links": [], + "panels": [ + { + "content": "

Deployed Versions

", + "gridPos": { + "h": 3, + "w": 24, + "x": 0, + "y": 0 + }, + "height": "40", + "id": 62, + "links": [], + "mode": "html", + "title": "", + "transparent": true, + "type": "text" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 5, + "w": 24, + "x": 0, + "y": 3 + }, + "id": 64, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(istio_build{component=\"mixer\"}) by (tag)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{ tag }}", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Mixer Versions", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "content": "

Resource Usage

", + "gridPos": { + "h": 3, + "w": 24, + "x": 0, + "y": 8 + }, + "height": "40", + "id": 29, + "links": [], + "mode": "html", + "title": "", + "transparent": true, + "type": "text" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 7, + "w": 6, + "x": 0, + "y": 11 + }, + "id": 5, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(process_virtual_memory_bytes{job=~\"istio-telemetry|istio-policy\"}) by (job)", + "format": "time_series", + "instant": false, + "intervalFactor": 2, + "legendFormat": "Virtual Memory ({{ job }})", + "refId": "I" + }, + { + "expr": "sum(process_resident_memory_bytes{job=~\"istio-telemetry|istio-policy\"}) by (job)", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "Resident Memory ({{ job }})", + "refId": "H" + }, + { + "expr": "sum(go_memstats_heap_sys_bytes{job=~\"istio-telemetry|istio-policy\"}) by (job)", + "format": "time_series", + "hide": true, + "intervalFactor": 2, + "legendFormat": "heap sys ({{ job }})", + "refId": "A" + }, + { + "expr": "sum(go_memstats_heap_alloc_bytes{job=~\"istio-telemetry|istio-policy\"}) by (job)", + "format": "time_series", + "hide": true, + "intervalFactor": 2, + "legendFormat": "heap alloc ({{ job }})", + "refId": "D" + }, + { + "expr": "sum(go_memstats_alloc_bytes{job=~\"istio-telemetry|istio-policy\"}) by (job)", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "Alloc ({{ job }})", + "refId": "F" + }, + { + "expr": "sum(go_memstats_heap_inuse_bytes{job=~\"istio-telemetry|istio-policy\"}) by (job)", + "format": "time_series", + "hide": false, + "intervalFactor": 2, + "legendFormat": "Heap in-use ({{ job }})", + "refId": "E" + }, + { + "expr": "sum(go_memstats_stack_inuse_bytes{job=~\"istio-telemetry|istio-policy\"}) by (job)", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "Stack in-use ({{ job }})", + "refId": "G" + }, + { + "expr": "sum(label_replace(container_memory_usage_bytes{job=\"kubernetes-cadvisor\", container=~\"mixer|istio-proxy\", pod=~\"istio-telemetry-.*|istio-policy-.*\"}, \"service\", \"$1\" , \"pod\", \"(istio-telemetry|istio-policy)-.*\")) by (service)", + "format": "time_series", + "hide": false, + "intervalFactor": 2, + "legendFormat": "{{ service }} total (k8s)", + "refId": "C" + }, + { + "expr": "sum(label_replace(container_memory_usage_bytes{job=\"kubernetes-cadvisor\", container=~\"mixer|istio-proxy\", pod=~\"istio-telemetry-.*|istio-policy-.*\"}, \"service\", \"$1\" , \"pod\", \"(istio-telemetry|istio-policy)-.*\")) by (container, service)", + "format": "time_series", + "hide": false, + "intervalFactor": 2, + "legendFormat": "{{ service }} - {{ container }} (k8s)", + "refId": "B" + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Memory", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "bytes", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 7, + "w": 6, + "x": 6, + "y": 11 + }, + "id": 6, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "label_replace(sum(rate(container_cpu_usage_seconds_total{job=\"kubernetes-cadvisor\",container=~\"mixer|istio-proxy\", pod=~\"istio-telemetry-.*|istio-policy-.*\"}[1m])) by (pod), \"service\", \"$1\" , \"pod\", \"(istio-telemetry|istio-policy)-.*\")", + "format": "time_series", + "hide": false, + "intervalFactor": 2, + "legendFormat": "{{ service }} total (k8s)", + "refId": "A" + }, + { + "expr": "label_replace(sum(rate(container_cpu_usage_seconds_total{job=\"kubernetes-cadvisor\",container=~\"mixer|istio-proxy\", pod=~\"istio-telemetry-.*|istio-policy-.*\"}[1m])) by (container, pod), \"service\", \"$1\" , \"pod\", \"(istio-telemetry|istio-policy)-.*\")", + "format": "time_series", + "hide": false, + "intervalFactor": 2, + "legendFormat": "{{ service }} - {{ container }} (k8s)", + "refId": "B" + }, + { + "expr": "sum(irate(process_cpu_seconds_total{job=~\"istio-telemetry|istio-policy\"}[1m])) by (job)", + "format": "time_series", + "hide": false, + "intervalFactor": 2, + "legendFormat": "{{ job }} (self-reported)", + "refId": "C" + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "CPU", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 7, + "w": 6, + "x": 12, + "y": 11 + }, + "id": 7, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(process_open_fds{job=~\"istio-telemetry|istio-policy\"}) by (job)", + "format": "time_series", + "hide": true, + "instant": false, + "interval": "", + "intervalFactor": 2, + "legendFormat": "Open FDs ({{ job }})", + "refId": "A" + }, + { + "expr": "sum(label_replace(container_fs_usage_bytes{job=\"kubernetes-cadvisor\", container=~\"mixer|istio-proxy\", pod=~\"istio-telemetry-.*|istio-policy-.*\"}, \"service\", \"$1\" , \"pod\", \"(istio-telemetry|istio-policy)-.*\")) by (container, service)", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "{{ service }} - {{ container }}", + "refId": "B" + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Disk", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "bytes", + "label": "", + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "decimals": null, + "format": "none", + "label": "", + "logBase": 1024, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 7, + "w": 6, + "x": 18, + "y": 11 + }, + "id": 4, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": false, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(go_goroutines{job=~\"istio-telemetry|istio-policy\"}) by (job)", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "Number of Goroutines ({{ job }})", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Goroutines", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": "", + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "content": "

Mixer Overview

", + "gridPos": { + "h": 3, + "w": 24, + "x": 0, + "y": 18 + }, + "height": "40px", + "id": 30, + "links": [], + "mode": "html", + "title": "", + "transparent": true, + "type": "text" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 6, + "w": 6, + "x": 0, + "y": 21 + }, + "id": 9, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(rate(grpc_io_server_completed_rpcs[1m]))", + "format": "time_series", + "hide": false, + "intervalFactor": 2, + "legendFormat": "mixer (Total)", + "refId": "B" + }, + { + "expr": "sum(rate(grpc_io_server_completed_rpcs[1m])) by (grpc_server_method)", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "mixer ({{ grpc_server_method }})", + "refId": "C" + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Incoming Requests", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "ops", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 6, + "w": 6, + "x": 6, + "y": 21 + }, + "id": 8, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [ + { + "alias": "{}", + "yaxis": 1 + } + ], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "histogram_quantile(0.5, sum(rate(grpc_io_server_server_latency_bucket{}[1m])) by (grpc_server_method, le))", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "{{ grpc_server_method }} 0.5", + "refId": "B" + }, + { + "expr": "histogram_quantile(0.9, sum(rate(grpc_io_server_server_latency_bucket{}[1m])) by (grpc_server_method, le))", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "{{ grpc_server_method }} 0.9", + "refId": "C" + }, + { + "expr": "histogram_quantile(0.99, sum(rate(grpc_io_server_server_latency_bucket{}[1m])) by (grpc_server_method, le))", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "{{ grpc_server_method }} 0.99", + "refId": "D" + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Response Durations", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "ms", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 6, + "w": 6, + "x": 12, + "y": 21 + }, + "id": 11, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(rate(grpc_server_handled_total{grpc_code=~\"Unknown|Unimplemented|Internal|DataLoss\"}[1m])) by (grpc_method)", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "Mixer {{ grpc_method }}", + "refId": "B" + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Server Error Rate (5xx responses)", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 6, + "w": 6, + "x": 18, + "y": 21 + }, + "id": 12, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(irate(grpc_server_handled_total{grpc_code!=\"OK\",grpc_service=~\".*Mixer\"}[1m])) by (grpc_method)", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "Mixer {{ grpc_method }}", + "refId": "B" + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Non-successes (4xxs)", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "content": "

Adapters and Config

", + "gridPos": { + "h": 3, + "w": 24, + "x": 0, + "y": 27 + }, + "id": 28, + "links": [], + "mode": "html", + "title": "", + "transparent": true, + "type": "text" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 7, + "w": 12, + "x": 0, + "y": 30 + }, + "id": 13, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(irate(mixer_runtime_dispatches_total{adapter=~\"$adapter\"}[1m])) by (adapter)", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "{{ adapter }}", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Adapter Dispatch Count", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 7, + "w": 12, + "x": 12, + "y": 30 + }, + "id": 14, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "histogram_quantile(0.5, sum(irate(mixer_runtime_dispatch_duration_seconds_bucket{adapter=~\"$adapter\"}[1m])) by (adapter, le))", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "{{ adapter }} - p50", + "refId": "A" + }, + { + "expr": "histogram_quantile(0.9, sum(irate(mixer_runtime_dispatch_duration_seconds_bucket{adapter=~\"$adapter\"}[1m])) by (adapter, le))", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "{{ adapter }} - p90 ", + "refId": "B" + }, + { + "expr": "histogram_quantile(0.99, sum(irate(mixer_runtime_dispatch_duration_seconds_bucket{adapter=~\"$adapter\"}[1m])) by (adapter, le))", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "{{ adapter }} - p99", + "refId": "C" + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Adapter Dispatch Duration", + "tooltip": { + "shared": true, + "sort": 1, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "s", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 7, + "w": 6, + "x": 0, + "y": 37 + }, + "id": 60, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "scalar(topk(1, max(mixer_config_rule_config_count) by (configID)))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Rules", + "refId": "A" + }, + { + "expr": "scalar(topk(1, max(mixer_config_rule_config_error_count) by (configID)))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Config Errors", + "refId": "B" + }, + { + "expr": "scalar(topk(1, max(mixer_config_rule_config_match_error_count) by (configID)))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Match Errors", + "refId": "C" + }, + { + "expr": "scalar(topk(1, max(mixer_config_unsatisfied_action_handler_count) by (configID)))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Unsatisfied Actions", + "refId": "D" + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Rules", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 7, + "w": 6, + "x": 6, + "y": 37 + }, + "id": 56, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "scalar(topk(1, max(mixer_config_instance_config_count) by (configID)))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Instances", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Instances in Latest Config", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 7, + "w": 6, + "x": 12, + "y": 37 + }, + "id": 54, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "scalar(topk(1, max(mixer_config_handler_config_count) by (configID)))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Handlers", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Handlers in Latest Config", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 7, + "w": 6, + "x": 18, + "y": 37 + }, + "id": 58, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "scalar(topk(1, max(mixer_config_attribute_count) by (configID)))", + "format": "time_series", + "instant": false, + "intervalFactor": 1, + "legendFormat": "Attributes", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Attributes in Latest Config", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "content": "

Individual Adapters

", + "gridPos": { + "h": 3, + "w": 24, + "x": 0, + "y": 44 + }, + "id": 23, + "links": [], + "mode": "html", + "title": "", + "transparent": true, + "type": "text" + }, + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 47 + }, + "id": 46, + "panels": [], + "repeat": "adapter", + "title": "$adapter Adapter", + "type": "row" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 7, + "w": 12, + "x": 0, + "y": 48 + }, + "id": 17, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "label_replace(irate(mixer_runtime_dispatches_total{adapter=~\"$adapter\"}[1m]),\"handler\", \"$1 ($3)\", \"handler\", \"(.*)\\\\.(.*)\\\\.(.*)\")", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "{{ handler }} (error: {{ error }})", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Dispatch Count By Handler", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 7, + "w": 12, + "x": 12, + "y": 48 + }, + "id": 18, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "label_replace(histogram_quantile(0.5, sum(rate(mixer_runtime_dispatch_duration_seconds_bucket{adapter=~\"$adapter\"}[1m])) by (handler, error, le)), \"handler_short\", \"$1 ($3)\", \"handler\", \"(.*)\\\\.(.*)\\\\.(.*)\")", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "p50 - {{ handler_short }} (error: {{ error }})", + "refId": "A" + }, + { + "expr": "label_replace(histogram_quantile(0.9, sum(irate(mixer_runtime_dispatch_duration_seconds_bucket{adapter=~\"$adapter\"}[1m])) by (handler, error, le)), \"handler_short\", \"$1 ($3)\", \"handler\", \"(.*)\\\\.(.*)\\\\.(.*)\")", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "p90 - {{ handler_short }} (error: {{ error }})", + "refId": "D" + }, + { + "expr": "label_replace(histogram_quantile(0.99, sum(irate(mixer_runtime_dispatch_duration_seconds_bucket{adapter=~\"$adapter\"}[1m])) by (handler, error, le)), \"handler_short\", \"$1 ($3)\", \"handler\", \"(.*)\\\\.(.*)\\\\.(.*)\")", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "p99 - {{ handler_short }} (error: {{ error }})", + "refId": "E" + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Dispatch Duration By Handler", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "s", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + } + ], + "refresh": "5s", + "schemaVersion": 16, + "style": "dark", + "tags": [], + "templating": { + "list": [ + { + "allValue": null, + "current": {}, + "datasource": "Prometheus", + "hide": 0, + "includeAll": true, + "label": "Adapter", + "multi": true, + "name": "adapter", + "options": [], + "query": "label_values(adapter)", + "refresh": 2, + "regex": "", + "sort": 1, + "tagValuesQuery": "", + "tags": [], + "tagsQuery": "", + "type": "query", + "useTags": false + } + ] + }, + "time": { + "from": "now-5m", + "to": "now" + }, + "timepicker": { + "refresh_intervals": [ + "5s", + "10s", + "30s", + "1m", + "5m", + "15m", + "30m", + "1h", + "2h", + "1d" + ], + "time_options": [ + "5m", + "15m", + "1h", + "6h", + "12h", + "24h", + "2d", + "7d", + "30d" + ] + }, + "timezone": "", + "title": "Istio Mixer Dashboard", + "version": 4 +} +' +--- +apiVersion: v1 +kind: ConfigMap +metadata: + name: istio-grafana-configuration-dashboards-pilot-dashboard + namespace: istio-system + labels: + app: grafana + chart: grafana + heritage: Tiller + release: istio + istio: grafana +data: + pilot-dashboard.json: '{ + "annotations": { + "list": [ + { + "builtIn": 1, + "datasource": "-- Grafana --", + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations & Alerts", + "type": "dashboard" + } + ] + }, + "editable": false, + "gnetId": null, + "graphTooltip": 1, + "id": 11, + "links": [], + "panels": [ + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 0 + }, + "id": 60, + "panels": [], + "title": "Deployed Versions", + "type": "row" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 5, + "w": 24, + "x": 0, + "y": 1 + }, + "id": 56, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(istio_build{component=\"pilot\"}) by (tag)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{ tag }}", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Pilot Versions", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 6 + }, + "id": 62, + "panels": [], + "title": "Resource Usage", + "type": "row" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 7, + "w": 6, + "x": 0, + "y": 7 + }, + "id": 5, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "process_virtual_memory_bytes{job=\"pilot\"}", + "format": "time_series", + "instant": false, + "intervalFactor": 2, + "legendFormat": "Virtual Memory", + "refId": "I", + "step": 2 + }, + { + "expr": "process_resident_memory_bytes{job=\"pilot\"}", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "Resident Memory", + "refId": "H", + "step": 2 + }, + { + "expr": "go_memstats_heap_sys_bytes{job=\"pilot\"}", + "format": "time_series", + "hide": true, + "intervalFactor": 2, + "legendFormat": "heap sys", + "refId": "A" + }, + { + "expr": "go_memstats_heap_alloc_bytes{job=\"pilot\"}", + "format": "time_series", + "hide": true, + "intervalFactor": 2, + "legendFormat": "heap alloc", + "refId": "D" + }, + { + "expr": "go_memstats_alloc_bytes{job=\"pilot\"}", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "Alloc", + "refId": "F", + "step": 2 + }, + { + "expr": "go_memstats_heap_inuse_bytes{job=\"pilot\"}", + "format": "time_series", + "hide": false, + "intervalFactor": 2, + "legendFormat": "Heap in-use", + "refId": "E", + "step": 2 + }, + { + "expr": "go_memstats_stack_inuse_bytes{job=\"pilot\"}", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "Stack in-use", + "refId": "G", + "step": 2 + }, + { + "expr": "container_memory_usage_bytes{job=\"kubernetes-cadvisor\", container=~\"discovery\", pod=~\"istio-pilot-.*\"}", + "format": "time_series", + "hide": false, + "intervalFactor": 2, + "legendFormat": "Discovery (container)", + "refId": "B", + "step": 2 + }, + { + "expr": "container_memory_usage_bytes{job=\"kubernetes-cadvisor\", container=~\"istio-proxy\", pod=~\"istio-pilot-.*\"}", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Sidecar (container)", + "refId": "C" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Memory", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "bytes", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 7, + "w": 6, + "x": 6, + "y": 7 + }, + "id": 6, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(irate(container_cpu_usage_seconds_total{job=\"kubernetes-cadvisor\",container=\"discovery\", pod=~\"istio-pilot-.*\"}[1m]))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Discovery (container)", + "refId": "A" + }, + { + "expr": "irate(process_cpu_seconds_total{job=\"pilot\"}[1m])", + "format": "time_series", + "hide": false, + "intervalFactor": 2, + "legendFormat": "Discovery (process)", + "refId": "C", + "step": 2 + }, + { + "expr": "sum(irate(container_cpu_usage_seconds_total{job=\"kubernetes-cadvisor\",container=\"istio-proxy\", pod=~\"istio-pilot-.*\"}[1m]))", + "format": "time_series", + "hide": false, + "intervalFactor": 2, + "legendFormat": "Sidecar (container)", + "refId": "B", + "step": 2 + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "CPU", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 7, + "w": 6, + "x": 12, + "y": 7 + }, + "id": 7, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "container_fs_usage_bytes{job=\"kubernetes-cadvisor\", container=\"discovery\", pod=~\"istio-pilot-.*\"}", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "Discovery", + "refId": "B", + "step": 2 + }, + { + "expr": "container_fs_usage_bytes{job=\"kubernetes-cadvisor\", container=\"istio-proxy\", pod=~\"istio-pilot-.*\"}", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Sidecar", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Disk", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "bytes", + "label": "", + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "decimals": null, + "format": "none", + "label": "", + "logBase": 1024, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 7, + "w": 6, + "x": 18, + "y": 7 + }, + "id": 4, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": false, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "go_goroutines{job=\"pilot\"}", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "Number of Goroutines", + "refId": "A", + "step": 2 + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Goroutines", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": "", + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 14 + }, + "id": 58, + "panels": [], + "title": "Pilot Push Information", + "type": "row" + }, + { + "aliasColors": {}, + "bars": true, + "dashLength": 10, + "dashes": false, + "description": "Shows the rate of pilot pushes", + "fill": 1, + "gridPos": { + "h": 8, + "w": 8, + "x": 0, + "y": 15 + }, + "id": 622, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": false, + "linewidth": 1, + "links": [], + "nullPointMode": "null as zero", + "paceLength": 10, + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": true, + "steppedLine": false, + "targets": [ + { + "expr": "sum(irate(pilot_xds_pushes{type=\"cds\"}[1m]))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Cluster", + "refId": "C" + }, + { + "expr": "sum(irate(pilot_xds_pushes{type=\"eds\"}[1m]))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Endpoints", + "refId": "D" + }, + { + "expr": "sum(irate(pilot_xds_pushes{type=\"lds\"}[1m]))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Listeners", + "refId": "A" + }, + { + "expr": "sum(irate(pilot_xds_pushes{type=\"rds\"}[1m]))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Routes", + "refId": "E" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Pilot Pushes", + "tooltip": { + "shared": false, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [ + "total" + ] + }, + "yaxes": [ + { + "format": "ops", + "label": null, + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "description": "Captures a variety of pilot errors", + "fill": 1, + "gridPos": { + "h": 8, + "w": 8, + "x": 8, + "y": 15 + }, + "id": 67, + "legend": { + "avg": false, + "current": false, + "hideEmpty": true, + "hideZero": true, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(pilot_xds_cds_reject{job=\"pilot\"}) or (absent(pilot_xds_cds_reject{job=\"pilot\"}) - 1)", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "Rejected CDS Configs", + "refId": "C" + }, + { + "expr": "sum(pilot_xds_eds_reject{job=\"pilot\"}) or (absent(pilot_xds_eds_reject{job=\"pilot\"}) - 1)", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "Rejected EDS Configs", + "refId": "D" + }, + { + "expr": "sum(pilot_xds_rds_reject{job=\"pilot\"}) or (absent(pilot_xds_rds_reject{job=\"pilot\"}) - 1)", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "Rejected RDS Configs", + "refId": "A" + }, + { + "expr": "sum(pilot_xds_lds_reject{job=\"pilot\"}) or (absent(pilot_xds_lds_reject{job=\"pilot\"}) - 1)", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "Rejected LDS Configs", + "refId": "B" + }, + { + "expr": "sum(rate(pilot_xds_write_timeout{job=\"pilot\"}[1m]))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Write Timeouts", + "refId": "F" + }, + { + "expr": "sum(rate(pilot_total_xds_internal_errors{job=\"pilot\"}[1m]))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "Internal Errors", + "refId": "H" + }, + { + "expr": "sum(rate(pilot_total_xds_rejects{job=\"pilot\"}[1m]))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "Config Rejection Rate", + "refId": "E" + }, + { + "expr": "sum(rate(pilot_xds_push_context_errors{job=\"pilot\"}[1m]))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "Push Context Errors", + "refId": "K" + }, + { + "expr": "sum(rate(pilot_xds_pushes{type!~\"lds|cds|rds|eds\"}[1m])) by (type)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Push Errors ({{ type }})", + "refId": "L" + }, + { + "expr": "sum(rate(pilot_xds_push_errors{job=\"pilot\"}[1m])) by (type)", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "Push Errors ({{ type }})", + "refId": "I" + }, + { + "expr": "sum(rate(pilot_xds_push_timeout{job=\"pilot\"}[1m]))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Push Timeouts", + "refId": "G" + }, + { + "expr": "sum(rate(pilot_xds_push_timeout_failures{job=\"pilot\"}[1m]))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Push Timeouts Failures", + "refId": "J" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Pilot Errors", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "description": "Shows the total time it takes to push a config update to a proxy", + "fill": 1, + "gridPos": { + "h": 8, + "w": 8, + "x": 16, + "y": 15 + }, + "id": 624, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "histogram_quantile(0.5, sum(rate(pilot_proxy_convergence_time_bucket[1m])) by (le))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "p50 ", + "refId": "A" + }, + { + "expr": "histogram_quantile(0.9, sum(rate(pilot_proxy_convergence_time_bucket[1m])) by (le))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "p90", + "refId": "B" + }, + { + "expr": "histogram_quantile(0.99, sum(rate(pilot_proxy_convergence_time_bucket[1m])) by (le))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "p99", + "refId": "C" + }, + { + "expr": "histogram_quantile(0.999, sum(rate(pilot_proxy_convergence_time_bucket[1m])) by (le))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "p99.9", + "refId": "D" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Proxy Push Time", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "s", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 8, + "w": 8, + "x": 0, + "y": 23 + }, + "id": 45, + "legend": { + "avg": false, + "current": false, + "hideEmpty": true, + "hideZero": true, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null as zero", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "pilot_conflict_inbound_listener{job=\"pilot\"}", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "Inbound Listeners", + "refId": "B" + }, + { + "expr": "pilot_conflict_outbound_listener_http_over_current_tcp{job=\"pilot\"}", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "Outbound Listeners (http over current tcp)", + "refId": "A" + }, + { + "expr": "pilot_conflict_outbound_listener_tcp_over_current_tcp{job=\"pilot\"}", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "Outbound Listeners (tcp over current tcp)", + "refId": "C" + }, + { + "expr": "pilot_conflict_outbound_listener_tcp_over_current_http{job=\"pilot\"}", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "Outbound Listeners (tcp over current http)", + "refId": "D" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Conflicts", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 8, + "w": 8, + "x": 8, + "y": 23 + }, + "id": 47, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "pilot_virt_services{job=\"pilot\"}", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Virtual Services", + "refId": "A" + }, + { + "expr": "pilot_services{job=\"pilot\"}", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Services", + "refId": "B" + }, + { + "expr": "pilot_xds{job=\"pilot\"}", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Connected Endpoints", + "refId": "E" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "ADS Monitoring", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "columns": [], + "datasource": "Prometheus", + "description": "Clusters in this table do not have any endpoints known to pilot. This could be from referencing subsets that do not have any instances, or pods marked as NotReady", + "fontSize": "100%", + "gridPos": { + "h": 8, + "w": 8, + "x": 16, + "y": 23 + }, + "id": 51, + "links": [], + "pageSize": null, + "scroll": true, + "showHeader": true, + "sort": { + "col": null, + "desc": false + }, + "styles": [ + { + "alias": "Time", + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "pattern": "Time", + "type": "date" + }, + { + "alias": "Clusters", + "colorMode": null, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "decimals": 2, + "pattern": "/.*/", + "thresholds": [], + "type": "number", + "unit": "short" + } + ], + "targets": [ + { + "expr": "sum(pilot_xds_eds_instances{job=\"pilot\", cluster=~\".+\\\\|.+\"}) by (cluster) < 1", + "format": "time_series", + "hide": false, + "instant": true, + "intervalFactor": 1, + "legendFormat": "{{cluster}}", + "refId": "B" + } + ], + "timeFrom": null, + "timeShift": null, + "title": "Clusters with no known endpoints", + "transform": "timeseries_aggregations", + "type": "table" + }, + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 31 + }, + "id": 64, + "panels": [], + "title": "Envoy Information", + "type": "row" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "description": "Shows details about Envoy proxies in the mesh", + "fill": 1, + "gridPos": { + "h": 8, + "w": 8, + "x": 0, + "y": 32 + }, + "id": 40, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(irate(envoy_cluster_upstream_cx_total{cluster_name=\"xds-grpc\"}[1m]))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "XDS Connections", + "refId": "C" + }, + { + "expr": "sum(irate(envoy_cluster_upstream_cx_connect_fail{cluster_name=\"xds-grpc\"}[1m]))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "XDS Connection Failures", + "refId": "A" + }, + { + "expr": "sum(increase(envoy_server_hot_restart_epoch[1m]))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Envoy Restarts", + "refId": "B" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Envoy Details", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "ops", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "ops", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 8, + "w": 8, + "x": 8, + "y": 32 + }, + "id": 41, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(envoy_cluster_upstream_cx_active{cluster_name=\"xds-grpc\"})", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "XDS Active Connections", + "refId": "C", + "step": 2 + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "XDS Active Connections", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "description": "Shows the size of XDS requests and responses", + "fill": 1, + "gridPos": { + "h": 8, + "w": 8, + "x": 16, + "y": 32 + }, + "id": 42, + "legend": { + "avg": false, + "current": false, + "hideEmpty": false, + "hideZero": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "max(rate(envoy_cluster_upstream_cx_rx_bytes_total{cluster_name=\"xds-grpc\"}[1m]))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "XDS Response Bytes Max", + "refId": "D" + }, + { + "expr": "quantile(0.5, rate(envoy_cluster_upstream_cx_rx_bytes_total{cluster_name=\"xds-grpc\"}[1m]))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "XDS Response Bytes Average", + "refId": "B" + }, + { + "expr": "max(rate(envoy_cluster_upstream_cx_tx_bytes_total{cluster_name=\"xds-grpc\"}[1m]))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "XDS Request Bytes Max", + "refId": "A" + }, + { + "expr": "quantile(.5, rate(envoy_cluster_upstream_cx_tx_bytes_total{cluster_name=\"xds-grpc\"}[1m]))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "XDS Request Bytes Average", + "refId": "C" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "XDS Requests Size", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "Bps", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "ops", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + } + ], + "refresh": "5s", + "schemaVersion": 18, + "style": "dark", + "tags": [], + "templating": { + "list": [] + }, + "time": { + "from": "now-5m", + "to": "now" + }, + "timepicker": { + "refresh_intervals": [ + "5s", + "10s", + "30s", + "1m", + "5m", + "15m", + "30m", + "1h", + "2h", + "1d" + ], + "time_options": [ + "5m", + "15m", + "1h", + "6h", + "12h", + "24h", + "2d", + "7d", + "30d" + ] + }, + "timezone": "browser", + "title": "Istio Pilot Dashboard", + "uid": "3--MLVZZk", + "version": 11 +}' +--- + +--- +# Source: istio/charts/grafana/templates/configmap.yaml +apiVersion: v1 +kind: ConfigMap +metadata: + name: istio-grafana + namespace: istio-system + labels: + app: grafana + chart: grafana + heritage: Tiller + release: istio + istio: grafana +data: + datasources.yaml: | + apiVersion: 1 + datasources: + - access: proxy + editable: true + isDefault: true + jsonData: + timeInterval: 5s + name: Prometheus + orgId: 1 + type: prometheus + url: http://prometheus:9090 + + dashboardproviders.yaml: | + apiVersion: 1 + providers: + - disableDeletion: false + folder: istio + name: istio + options: + path: /var/lib/grafana/dashboards/istio + orgId: 1 + type: file + +--- +# Source: istio/charts/kiali/templates/configmap.yaml +apiVersion: v1 +kind: ConfigMap +metadata: + name: kiali + namespace: istio-system + labels: + app: kiali + chart: kiali + heritage: Tiller + release: istio +data: + config.yaml: | + istio_namespace: istio-system + deployment: + accessible_namespaces: ['**'] + auth: + strategy: login + server: + port: 20001 + web_root: /kiali + external_services: + tracing: + url: + in_cluster_url: http://tracing/jaeger + grafana: + url: + in_cluster_url: http://grafana:3000 + prometheus: + url: http://prometheus:9090 + +--- +# Source: istio/charts/prometheus/templates/configmap.yaml +apiVersion: v1 +kind: ConfigMap +metadata: + name: prometheus + namespace: istio-system + labels: + app: prometheus + chart: prometheus + heritage: Tiller + release: istio +data: + prometheus.yml: |- + global: + scrape_interval: 15s + scrape_configs: + + - job_name: 'istio-mesh' + kubernetes_sd_configs: + - role: endpoints + namespaces: + names: + - istio-system + + relabel_configs: + - source_labels: [__meta_kubernetes_service_name, __meta_kubernetes_endpoint_port_name] + action: keep + regex: istio-telemetry;prometheus + + # Scrape config for envoy stats + - job_name: 'envoy-stats' + metrics_path: /stats/prometheus + kubernetes_sd_configs: + - role: pod + + relabel_configs: + - source_labels: [__meta_kubernetes_pod_container_port_name] + action: keep + regex: '.*-envoy-prom' + - source_labels: [__address__, __meta_kubernetes_pod_annotation_prometheus_io_port] + action: replace + regex: ([^:]+)(?::\d+)?;(\d+) + replacement: $1:15090 + target_label: __address__ + - action: labelmap + regex: __meta_kubernetes_pod_label_(.+) + - source_labels: [__meta_kubernetes_namespace] + action: replace + target_label: namespace + - source_labels: [__meta_kubernetes_pod_name] + action: replace + target_label: pod_name + + - job_name: 'istio-policy' + kubernetes_sd_configs: + - role: endpoints + namespaces: + names: + - istio-system + + + relabel_configs: + - source_labels: [__meta_kubernetes_service_name, __meta_kubernetes_endpoint_port_name] + action: keep + regex: istio-policy;http-monitoring + + - job_name: 'istio-telemetry' + kubernetes_sd_configs: + - role: endpoints + namespaces: + names: + - istio-system + + relabel_configs: + - source_labels: [__meta_kubernetes_service_name, __meta_kubernetes_endpoint_port_name] + action: keep + regex: istio-telemetry;http-monitoring + + - job_name: 'pilot' + kubernetes_sd_configs: + - role: endpoints + namespaces: + names: + - istio-system + + relabel_configs: + - source_labels: [__meta_kubernetes_service_name, __meta_kubernetes_endpoint_port_name] + action: keep + regex: istio-pilot;http-monitoring + + - job_name: 'galley' + kubernetes_sd_configs: + - role: endpoints + namespaces: + names: + - istio-system + + relabel_configs: + - source_labels: [__meta_kubernetes_service_name, __meta_kubernetes_endpoint_port_name] + action: keep + regex: istio-galley;http-monitoring + + - job_name: 'citadel' + kubernetes_sd_configs: + - role: endpoints + namespaces: + names: + - istio-system + + relabel_configs: + - source_labels: [__meta_kubernetes_service_name, __meta_kubernetes_endpoint_port_name] + action: keep + regex: istio-citadel;http-monitoring + + - job_name: 'sidecar-injector' + + kubernetes_sd_configs: + - role: endpoints + namespaces: + names: + - istio-system + + relabel_configs: + - source_labels: [__meta_kubernetes_service_name, __meta_kubernetes_endpoint_port_name] + action: keep + regex: istio-sidecar-injector;http-monitoring + + # scrape config for API servers + - job_name: 'kubernetes-apiservers' + kubernetes_sd_configs: + - role: endpoints + namespaces: + names: + - default + scheme: https + tls_config: + ca_file: /var/run/secrets/kubernetes.io/serviceaccount/ca.crt + bearer_token_file: /var/run/secrets/kubernetes.io/serviceaccount/token + relabel_configs: + - source_labels: [__meta_kubernetes_service_name, __meta_kubernetes_endpoint_port_name] + action: keep + regex: kubernetes;https + + # scrape config for nodes (kubelet) + - job_name: 'kubernetes-nodes' + scheme: https + tls_config: + ca_file: /var/run/secrets/kubernetes.io/serviceaccount/ca.crt + bearer_token_file: /var/run/secrets/kubernetes.io/serviceaccount/token + kubernetes_sd_configs: + - role: node + relabel_configs: + - action: labelmap + regex: __meta_kubernetes_node_label_(.+) + - target_label: __address__ + replacement: kubernetes.default.svc:443 + - source_labels: [__meta_kubernetes_node_name] + regex: (.+) + target_label: __metrics_path__ + replacement: /api/v1/nodes/${1}/proxy/metrics + + # Scrape config for Kubelet cAdvisor. + # + # This is required for Kubernetes 1.7.3 and later, where cAdvisor metrics + # (those whose names begin with 'container_') have been removed from the + # Kubelet metrics endpoint. This job scrapes the cAdvisor endpoint to + # retrieve those metrics. + # + # In Kubernetes 1.7.0-1.7.2, these metrics are only exposed on the cAdvisor + # HTTP endpoint; use "replacement: /api/v1/nodes/${1}:4194/proxy/metrics" + # in that case (and ensure cAdvisor's HTTP server hasn't been disabled with + # the --cadvisor-port=0 Kubelet flag). + # + # This job is not necessary and should be removed in Kubernetes 1.6 and + # earlier versions, or it will cause the metrics to be scraped twice. + - job_name: 'kubernetes-cadvisor' + scheme: https + tls_config: + ca_file: /var/run/secrets/kubernetes.io/serviceaccount/ca.crt + bearer_token_file: /var/run/secrets/kubernetes.io/serviceaccount/token + kubernetes_sd_configs: + - role: node + relabel_configs: + - action: labelmap + regex: __meta_kubernetes_node_label_(.+) + - target_label: __address__ + replacement: kubernetes.default.svc:443 + - source_labels: [__meta_kubernetes_node_name] + regex: (.+) + target_label: __metrics_path__ + replacement: /api/v1/nodes/${1}/proxy/metrics/cadvisor + + # scrape config for service endpoints. + - job_name: 'kubernetes-service-endpoints' + kubernetes_sd_configs: + - role: endpoints + relabel_configs: + - source_labels: [__meta_kubernetes_service_annotation_prometheus_io_scrape] + action: keep + regex: true + - source_labels: [__meta_kubernetes_service_annotation_prometheus_io_scheme] + action: replace + target_label: __scheme__ + regex: (https?) + - source_labels: [__meta_kubernetes_service_annotation_prometheus_io_path] + action: replace + target_label: __metrics_path__ + regex: (.+) + - source_labels: [__address__, __meta_kubernetes_service_annotation_prometheus_io_port] + action: replace + target_label: __address__ + regex: ([^:]+)(?::\d+)?;(\d+) + replacement: $1:$2 + - action: labelmap + regex: __meta_kubernetes_service_label_(.+) + - source_labels: [__meta_kubernetes_namespace] + action: replace + target_label: kubernetes_namespace + - source_labels: [__meta_kubernetes_service_name] + action: replace + target_label: kubernetes_name + + - job_name: 'kubernetes-pods' + kubernetes_sd_configs: + - role: pod + relabel_configs: # If first two labels are present, pod should be scraped by the istio-secure job. + - source_labels: [__meta_kubernetes_pod_annotation_prometheus_io_scrape] + action: keep + regex: true + # Keep target if there's no sidecar or if prometheus.io/scheme is explicitly set to "http" + - source_labels: [__meta_kubernetes_pod_annotation_sidecar_istio_io_status, __meta_kubernetes_pod_annotation_prometheus_io_scheme] + action: keep + regex: ((;.*)|(.*;http)) + - source_labels: [__meta_kubernetes_pod_annotation_istio_mtls] + action: drop + regex: (true) + - source_labels: [__meta_kubernetes_pod_annotation_prometheus_io_path] + action: replace + target_label: __metrics_path__ + regex: (.+) + - source_labels: [__address__, __meta_kubernetes_pod_annotation_prometheus_io_port] + action: replace + regex: ([^:]+)(?::\d+)?;(\d+) + replacement: $1:$2 + target_label: __address__ + - action: labelmap + regex: __meta_kubernetes_pod_label_(.+) + - source_labels: [__meta_kubernetes_namespace] + action: replace + target_label: namespace + - source_labels: [__meta_kubernetes_pod_name] + action: replace + target_label: pod_name + + - job_name: 'kubernetes-pods-istio-secure' + scheme: https + tls_config: + ca_file: /etc/istio-certs/root-cert.pem + cert_file: /etc/istio-certs/cert-chain.pem + key_file: /etc/istio-certs/key.pem + insecure_skip_verify: true # prometheus does not support secure naming. + kubernetes_sd_configs: + - role: pod + relabel_configs: + - source_labels: [__meta_kubernetes_pod_annotation_prometheus_io_scrape] + action: keep + regex: true + # sidecar status annotation is added by sidecar injector and + # istio_workload_mtls_ability can be specifically placed on a pod to indicate its ability to receive mtls traffic. + - source_labels: [__meta_kubernetes_pod_annotation_sidecar_istio_io_status, __meta_kubernetes_pod_annotation_istio_mtls] + action: keep + regex: (([^;]+);([^;]*))|(([^;]*);(true)) + - source_labels: [__meta_kubernetes_pod_annotation_prometheus_io_scheme] + action: drop + regex: (http) + - source_labels: [__meta_kubernetes_pod_annotation_prometheus_io_path] + action: replace + target_label: __metrics_path__ + regex: (.+) + - source_labels: [__address__] # Only keep address that is host:port + action: keep # otherwise an extra target with ':443' is added for https scheme + regex: ([^:]+):(\d+) + - source_labels: [__address__, __meta_kubernetes_pod_annotation_prometheus_io_port] + action: replace + regex: ([^:]+)(?::\d+)?;(\d+) + replacement: $1:$2 + target_label: __address__ + - action: labelmap + regex: __meta_kubernetes_pod_label_(.+) + - source_labels: [__meta_kubernetes_namespace] + action: replace + target_label: namespace + - source_labels: [__meta_kubernetes_pod_name] + action: replace + target_label: pod_name + +--- +# Source: istio/charts/security/templates/configmap.yaml +apiVersion: v1 +kind: ConfigMap +metadata: + name: istio-security-custom-resources + namespace: istio-system + labels: + app: security + chart: security + heritage: Tiller + release: istio + istio: citadel +data: + custom-resources.yaml: |- + # Authentication policy to enable permissive mode for all services (that have sidecar) in the mesh. + apiVersion: "authentication.istio.io/v1alpha1" + kind: "MeshPolicy" + metadata: + name: "default" + labels: + app: security + chart: security + heritage: Tiller + release: istio + spec: + peers: + - mtls: + mode: PERMISSIVE + run.sh: |- + #!/bin/sh + + set -x + + if [ "$#" -ne "1" ]; then + echo "first argument should be path to custom resource yaml" + exit 1 + fi + + pathToResourceYAML=${1} + + kubectl get validatingwebhookconfiguration istio-galley 2>/dev/null + if [ "$?" -eq 0 ]; then + echo "istio-galley validatingwebhookconfiguration found - waiting for istio-galley deployment to be ready" + while true; do + kubectl -n istio-system get deployment istio-galley 2>/dev/null + if [ "$?" -eq 0 ]; then + break + fi + sleep 1 + done + kubectl -n istio-system rollout status deployment istio-galley + if [ "$?" -ne 0 ]; then + echo "istio-galley deployment rollout status check failed" + exit 1 + fi + echo "istio-galley deployment ready for configuration validation" + fi + sleep 5 + kubectl apply -f ${pathToResourceYAML} + + +--- +# Source: istio/templates/configmap.yaml + +apiVersion: v1 +kind: ConfigMap +metadata: + name: istio + namespace: istio-system + labels: + app: istio + chart: istio + heritage: Tiller + release: istio +data: + mesh: |- + # Set the following variable to true to disable policy checks by Mixer. + # Note that metrics will still be reported to Mixer. + disablePolicyChecks: false + + disableMixerHttpReports: false + # reportBatchMaxEntries is the number of requests that are batched before telemetry data is sent to the mixer server + reportBatchMaxEntries: 100 + # reportBatchMaxTime is the max waiting time before the telemetry data of a request is sent to the mixer server + reportBatchMaxTime: 1s + + # Set enableTracing to false to disable request tracing. + enableTracing: true + + # Set accessLogFile to empty string to disable access log. + accessLogFile: "/dev/stdout" + + # If accessLogEncoding is TEXT, value will be used directly as the log format + # example: "[%START_TIME%] %REQ(:METHOD)% %REQ(X-ENVOY-ORIGINAL-PATH?:PATH)% %PROTOCOL%\n" + # If AccessLogEncoding is JSON, value will be parsed as map[string]string + # example: '{"start_time": "%START_TIME%", "req_method": "%REQ(:METHOD)%"}' + # Leave empty to use default log format + accessLogFormat: "" + + # Set accessLogEncoding to JSON or TEXT to configure sidecar access log + accessLogEncoding: 'TEXT' + + enableEnvoyAccessLogService: false + mixerCheckServer: istio-policy.istio-system.svc.cluster.local:9091 + mixerReportServer: istio-telemetry.istio-system.svc.cluster.local:9091 + # policyCheckFailOpen allows traffic in cases when the mixer policy service cannot be reached. + # Default is false which means the traffic is denied when the client is unable to connect to Mixer. + policyCheckFailOpen: false + # Let Pilot give ingresses the public IP of the Istio ingressgateway + ingressService: istio-ingressgateway + + # Default connect timeout for dynamic clusters generated by Pilot and returned via XDS + connectTimeout: 10s + + # Automatic protocol detection uses a set of heuristics to + # determine whether the connection is using TLS or not (on the + # server side), as well as the application protocol being used + # (e.g., http vs tcp). These heuristics rely on the client sending + # the first bits of data. For server first protocols like MySQL, + # MongoDB, etc., Envoy will timeout on the protocol detection after + # the specified period, defaulting to non mTLS plain TCP + # traffic. Set this field to tweak the period that Envoy will wait + # for the client to send the first bits of data. (MUST BE >=1ms) + protocolDetectionTimeout: 100ms + + # DNS refresh rate for Envoy clusters of type STRICT_DNS + dnsRefreshRate: 300s + + # Unix Domain Socket through which envoy communicates with NodeAgent SDS to get + # key/cert for mTLS. Use secret-mount files instead of SDS if set to empty. + sdsUdsPath: "" + + # The trust domain corresponds to the trust root of a system. + # Refer to https://github.com/spiffe/spiffe/blob/master/standards/SPIFFE-ID.md#21-trust-domain + trustDomain: "" + + # The trust domain aliases represent the aliases of trust_domain. + # For example, if we have + # trustDomain: td1 + # trustDomainAliases: [“td2”, "td3"] + # Any service with the identity "td1/ns/foo/sa/a-service-account", "td2/ns/foo/sa/a-service-account", + # or "td3/ns/foo/sa/a-service-account" will be treated the same in the Istio mesh. + trustDomainAliases: + + # If true, automatically configure client side mTLS settings to match the corresponding service's + # server side mTLS authentication policy, when destination rule for that service does not specify + # TLS settings. + enableAutoMtls: true + + # Set the default behavior of the sidecar for handling outbound traffic from the application: + # ALLOW_ANY - outbound traffic to unknown destinations will be allowed, in case there are no + # services or ServiceEntries for the destination port + # REGISTRY_ONLY - restrict outbound traffic to services defined in the service registry as well + # as those defined through ServiceEntries + outboundTrafficPolicy: + mode: ALLOW_ANY + localityLbSetting: + enabled: true + # The namespace to treat as the administrative root namespace for istio + # configuration. + rootNamespace: istio-system + + # Configures DNS certificates provisioned through Chiron linked into Pilot. + certificates: + [] + configSources: + - address: istio-galley.istio-system.svc:9901 + + defaultConfig: + # + # TCP connection timeout between Envoy & the application, and between Envoys. Used for static clusters + # defined in Envoy's configuration file + connectTimeout: 10s + # + ### ADVANCED SETTINGS ############# + # Where should envoy's configuration be stored in the istio-proxy container + configPath: "/etc/istio/proxy" + binaryPath: "/usr/local/bin/envoy" + # The pseudo service name used for Envoy. + serviceCluster: istio-proxy + # These settings that determine how long an old Envoy + # process should be kept alive after an occasional reload. + drainDuration: 45s + parentShutdownDuration: 1m0s + # + # The mode used to redirect inbound connections to Envoy. This setting + # has no effect on outbound traffic: iptables REDIRECT is always used for + # outbound connections. + # If "REDIRECT", use iptables REDIRECT to NAT and redirect to Envoy. + # The "REDIRECT" mode loses source addresses during redirection. + # If "TPROXY", use iptables TPROXY to redirect to Envoy. + # The "TPROXY" mode preserves both the source and destination IP + # addresses and ports, so that they can be used for advanced filtering + # and manipulation. + # The "TPROXY" mode also configures the sidecar to run with the + # CAP_NET_ADMIN capability, which is required to use TPROXY. + #interceptionMode: REDIRECT + # + # Port where Envoy listens (on local host) for admin commands + # You can exec into the istio-proxy container in a pod and + # curl the admin port (curl http://localhost:15000/) to obtain + # diagnostic information from Envoy. See + # https://lyft.github.io/envoy/docs/operations/admin.html + # for more details + proxyAdminPort: 15000 + # + # Set concurrency to a specific number to control the number of Proxy worker threads. + # If set to 0 (default), then start worker thread for each CPU thread/core. + concurrency: 2 + # + tracing: + zipkin: + # Address of the Zipkin collector + address: zipkin.istio-system:9411 + # + # Mutual TLS authentication between sidecars and istio control plane. + controlPlaneAuthPolicy: NONE + # + # Address where istio Pilot service is running + discoveryAddress: istio-pilot.istio-system:15010 + + # Configuration file for the mesh networks to be used by the Split Horizon EDS. + meshNetworks: |- + networks: {} + +--- +# Source: istio/templates/sidecar-injector-configmap.yaml + +apiVersion: v1 +kind: ConfigMap +metadata: + name: istio-sidecar-injector + namespace: istio-system + labels: + app: istio + chart: istio + heritage: Tiller + release: istio + istio: sidecar-injector +data: + values: |- + {"certmanager":{"enabled":false},"galley":{"enableAnalysis":false,"enableServiceDiscovery":false,"enabled":true,"global":{"arch":{"amd64":2,"ppc64le":2,"s390x":2},"certificates":[],"configValidation":true,"controlPlaneSecurityEnabled":false,"defaultNodeSelector":{},"defaultPodDisruptionBudget":{"enabled":true},"defaultResources":{"requests":{"cpu":"10m"}},"defaultTolerations":[],"disablePolicyChecks":false,"enableHelmTest":false,"enableTracing":true,"hub":"docker.io/istio","imagePullPolicy":"IfNotPresent","imagePullSecrets":[],"k8sIngress":{"enableHttps":false,"enabled":false,"gatewayName":"ingressgateway"},"localityLbSetting":{"enabled":true},"logging":{"level":"default:info"},"meshExpansion":{"enabled":false,"useILB":false},"meshID":"","meshNetworks":{},"monitoringPort":15014,"mtls":{"auto":true,"enabled":false},"multiCluster":{"clusterName":"","enabled":false},"network":"","oneNamespace":false,"operatorManageWebhooks":false,"outboundTrafficPolicy":{"mode":"ALLOW_ANY"},"policyCheckFailOpen":false,"priorityClassName":"","proxy":{"accessLogEncoding":"TEXT","accessLogFile":"/dev/stdout","accessLogFormat":"","autoInject":"enabled","clusterDomain":"cluster.local","componentLogLevel":"","concurrency":2,"dnsRefreshRate":"300s","enableCoreDump":false,"enableCoreDumpImage":"ubuntu:xenial","envoyAccessLogService":{"enabled":false,"tcpKeepalive":{"interval":"10s","probes":3,"time":"10s"},"tlsSettings":{"mode":"DISABLE","subjectAltNames":[]}},"envoyMetricsService":{"enabled":false,"tcpKeepalive":{"interval":"10s","probes":3,"time":"10s"},"tlsSettings":{"mode":"DISABLE","subjectAltNames":[]}},"envoyStatsd":{"enabled":false},"excludeIPRanges":"","excludeInboundPorts":"","excludeOutboundPorts":"","image":"proxyv2","includeIPRanges":"*","includeInboundPorts":"*","kubevirtInterfaces":"","logLevel":"","privileged":false,"protocolDetectionTimeout":"100ms","readinessFailureThreshold":30,"readinessInitialDelaySeconds":1,"readinessPeriodSeconds":2,"resources":{"limits":{"cpu":"2000m","memory":"1024Mi"},"requests":{"cpu":"10m","memory":"40Mi"}},"statusPort":15020,"tracer":"zipkin"},"proxy_init":{"image":"proxyv2","resources":{"limits":{"cpu":"100m","memory":"50Mi"},"requests":{"cpu":"10m","memory":"10Mi"}}},"sds":{"enabled":false,"token":{"aud":"istio-ca"},"udsPath":""},"tag":"1.5.0","tracer":{"datadog":{"address":"$(HOST_IP):8126"},"lightstep":{"accessToken":"","address":"","cacertPath":"","secure":true},"stackdriver":{"debug":false,"maxNumberOfAnnotations":200,"maxNumberOfAttributes":200,"maxNumberOfMessageEvents":200},"zipkin":{"address":""}},"trustDomain":"","trustDomainAliases":[],"useMCP":true},"image":"galley","nodeSelector":{},"podAnnotations":{},"podAntiAffinityLabelSelector":[],"podAntiAffinityTermLabelSelector":[],"replicaCount":1,"rollingMaxSurge":"100%","rollingMaxUnavailable":"25%","tolerations":[]},"gateways":{"enabled":true,"global":{"arch":{"amd64":2,"ppc64le":2,"s390x":2},"certificates":[],"configValidation":true,"controlPlaneSecurityEnabled":false,"defaultNodeSelector":{},"defaultPodDisruptionBudget":{"enabled":true},"defaultResources":{"requests":{"cpu":"10m"}},"defaultTolerations":[],"disablePolicyChecks":false,"enableHelmTest":false,"enableTracing":true,"hub":"docker.io/istio","imagePullPolicy":"IfNotPresent","imagePullSecrets":[],"k8sIngress":{"enableHttps":false,"enabled":false,"gatewayName":"ingressgateway"},"localityLbSetting":{"enabled":true},"logging":{"level":"default:info"},"meshExpansion":{"enabled":false,"useILB":false},"meshID":"","meshNetworks":{},"monitoringPort":15014,"mtls":{"auto":true,"enabled":false},"multiCluster":{"clusterName":"","enabled":false},"network":"","oneNamespace":false,"operatorManageWebhooks":false,"outboundTrafficPolicy":{"mode":"ALLOW_ANY"},"policyCheckFailOpen":false,"priorityClassName":"","proxy":{"accessLogEncoding":"TEXT","accessLogFile":"/dev/stdout","accessLogFormat":"","autoInject":"enabled","clusterDomain":"cluster.local","componentLogLevel":"","concurrency":2,"dnsRefreshRate":"300s","enableCoreDump":false,"enableCoreDumpImage":"ubuntu:xenial","envoyAccessLogService":{"enabled":false,"tcpKeepalive":{"interval":"10s","probes":3,"time":"10s"},"tlsSettings":{"mode":"DISABLE","subjectAltNames":[]}},"envoyMetricsService":{"enabled":false,"tcpKeepalive":{"interval":"10s","probes":3,"time":"10s"},"tlsSettings":{"mode":"DISABLE","subjectAltNames":[]}},"envoyStatsd":{"enabled":false},"excludeIPRanges":"","excludeInboundPorts":"","excludeOutboundPorts":"","image":"proxyv2","includeIPRanges":"*","includeInboundPorts":"*","kubevirtInterfaces":"","logLevel":"","privileged":false,"protocolDetectionTimeout":"100ms","readinessFailureThreshold":30,"readinessInitialDelaySeconds":1,"readinessPeriodSeconds":2,"resources":{"limits":{"cpu":"2000m","memory":"1024Mi"},"requests":{"cpu":"10m","memory":"40Mi"}},"statusPort":15020,"tracer":"zipkin"},"proxy_init":{"image":"proxyv2","resources":{"limits":{"cpu":"100m","memory":"50Mi"},"requests":{"cpu":"10m","memory":"10Mi"}}},"sds":{"enabled":false,"token":{"aud":"istio-ca"},"udsPath":""},"tag":"1.5.0","tracer":{"datadog":{"address":"$(HOST_IP):8126"},"lightstep":{"accessToken":"","address":"","cacertPath":"","secure":true},"stackdriver":{"debug":false,"maxNumberOfAnnotations":200,"maxNumberOfAttributes":200,"maxNumberOfMessageEvents":200},"zipkin":{"address":""}},"trustDomain":"","trustDomainAliases":[],"useMCP":true},"istio-egressgateway":{"autoscaleEnabled":false,"autoscaleMax":5,"autoscaleMin":1,"cpu":{"targetAverageUtilization":80},"enabled":true,"env":{"ISTIO_META_ROUTER_MODE":"standard"},"labels":{"app":"istio-egressgateway","istio":"egressgateway"},"nodeSelector":{},"podAnnotations":{},"podAntiAffinityLabelSelector":[],"podAntiAffinityTermLabelSelector":[],"ports":[{"name":"http2","port":80},{"name":"https","port":443},{"name":"tls","port":15443,"targetPort":15443}],"resources":{"limits":{"cpu":"2000m","memory":"1024Mi"},"requests":{"cpu":"10m","memory":"40Mi"}},"rollingMaxSurge":"100%","rollingMaxUnavailable":"25%","secretVolumes":[{"mountPath":"/etc/istio/egressgateway-certs","name":"egressgateway-certs","secretName":"istio-egressgateway-certs"},{"mountPath":"/etc/istio/egressgateway-ca-certs","name":"egressgateway-ca-certs","secretName":"istio-egressgateway-ca-certs"}],"serviceAnnotations":{},"tolerations":[],"type":"ClusterIP"},"istio-ilbgateway":{"autoscaleEnabled":true,"autoscaleMax":5,"autoscaleMin":1,"cpu":{"targetAverageUtilization":80},"enabled":false,"labels":{"app":"istio-ilbgateway","istio":"ilbgateway"},"loadBalancerIP":"","nodeSelector":{},"podAnnotations":{},"ports":[{"name":"grpc-pilot-mtls","port":15011},{"name":"grpc-pilot","port":15010},{"name":"tcp-citadel-grpc-tls","port":8060,"targetPort":8060},{"name":"tcp-dns","port":5353}],"resources":{"requests":{"cpu":"800m","memory":"512Mi"}},"rollingMaxSurge":"100%","rollingMaxUnavailable":"25%","secretVolumes":[{"mountPath":"/etc/istio/ilbgateway-certs","name":"ilbgateway-certs","secretName":"istio-ilbgateway-certs"},{"mountPath":"/etc/istio/ilbgateway-ca-certs","name":"ilbgateway-ca-certs","secretName":"istio-ilbgateway-ca-certs"}],"serviceAnnotations":{"cloud.google.com/load-balancer-type":"internal"},"tolerations":[],"type":"LoadBalancer"},"istio-ingressgateway":{"autoscaleEnabled":false,"autoscaleMax":5,"autoscaleMin":1,"cpu":{"targetAverageUtilization":80},"enabled":true,"env":{"ISTIO_META_ROUTER_MODE":"standard"},"externalIPs":[],"labels":{"app":"istio-ingressgateway","istio":"ingressgateway"},"loadBalancerIP":"","loadBalancerSourceRanges":[],"meshExpansionPorts":[{"name":"tcp-pilot-grpc-tls","port":15011,"targetPort":15011},{"name":"tcp-mixer-grpc-tls","port":15004,"targetPort":15004},{"name":"tcp-citadel-grpc-tls","port":8060,"targetPort":8060},{"name":"tcp-dns-tls","port":853,"targetPort":853}],"nodeSelector":{},"podAnnotations":{},"podAntiAffinityLabelSelector":[],"podAntiAffinityTermLabelSelector":[],"ports":[{"name":"status-port","port":15020,"targetPort":15020},{"name":"http2","nodePort":31380,"port":80,"targetPort":80},{"name":"https","nodePort":31390,"port":443},{"name":"tcp","nodePort":31400,"port":31400},{"name":"https-kiali","port":15029,"targetPort":15029},{"name":"https-prometheus","port":15030,"targetPort":15030},{"name":"https-grafana","port":15031,"targetPort":15031},{"name":"https-tracing","port":15032,"targetPort":15032},{"name":"tls","port":15443,"targetPort":15443}],"resources":{"limits":{"cpu":"2000m","memory":"1024Mi"},"requests":{"cpu":"10m","memory":"40Mi"}},"rollingMaxSurge":"100%","rollingMaxUnavailable":"25%","sds":{"enabled":false,"image":"node-agent-k8s","resources":{"limits":{"cpu":"2000m","memory":"1024Mi"},"requests":{"cpu":"100m","memory":"128Mi"}}},"secretVolumes":[{"mountPath":"/etc/istio/ingressgateway-certs","name":"ingressgateway-certs","secretName":"istio-ingressgateway-certs"},{"mountPath":"/etc/istio/ingressgateway-ca-certs","name":"ingressgateway-ca-certs","secretName":"istio-ingressgateway-ca-certs"}],"serviceAnnotations":{},"tolerations":[],"type":"LoadBalancer"}},"global":{"arch":{"amd64":2,"ppc64le":2,"s390x":2},"certificates":[],"configValidation":true,"controlPlaneSecurityEnabled":false,"defaultNodeSelector":{},"defaultPodDisruptionBudget":{"enabled":true},"defaultResources":{"requests":{"cpu":"10m"}},"defaultTolerations":[],"disablePolicyChecks":false,"enableHelmTest":false,"enableTracing":true,"hub":"docker.io/istio","imagePullPolicy":"IfNotPresent","imagePullSecrets":[],"k8sIngress":{"enableHttps":false,"enabled":false,"gatewayName":"ingressgateway"},"localityLbSetting":{"enabled":true},"logging":{"level":"default:info"},"meshExpansion":{"enabled":false,"useILB":false},"meshID":"","meshNetworks":{},"monitoringPort":15014,"mtls":{"auto":true,"enabled":false},"multiCluster":{"clusterName":"","enabled":false},"network":"","oneNamespace":false,"operatorManageWebhooks":false,"outboundTrafficPolicy":{"mode":"ALLOW_ANY"},"policyCheckFailOpen":false,"priorityClassName":"","proxy":{"accessLogEncoding":"TEXT","accessLogFile":"/dev/stdout","accessLogFormat":"","autoInject":"enabled","clusterDomain":"cluster.local","componentLogLevel":"","concurrency":2,"dnsRefreshRate":"300s","enableCoreDump":false,"enableCoreDumpImage":"ubuntu:xenial","envoyAccessLogService":{"enabled":false,"host":null,"port":null,"tcpKeepalive":{"interval":"10s","probes":3,"time":"10s"},"tlsSettings":{"caCertificates":null,"clientCertificate":null,"mode":"DISABLE","privateKey":null,"sni":null,"subjectAltNames":[]}},"envoyMetricsService":{"enabled":false,"host":null,"port":null,"tcpKeepalive":{"interval":"10s","probes":3,"time":"10s"},"tlsSettings":{"caCertificates":null,"clientCertificate":null,"mode":"DISABLE","privateKey":null,"sni":null,"subjectAltNames":[]}},"envoyStatsd":{"enabled":false,"host":null,"port":null},"excludeIPRanges":"","excludeInboundPorts":"","excludeOutboundPorts":"","image":"proxyv2","includeIPRanges":"*","includeInboundPorts":"*","kubevirtInterfaces":"","logLevel":"","outlierLogPath":null,"privileged":false,"protocolDetectionTimeout":"100ms","readinessFailureThreshold":30,"readinessInitialDelaySeconds":1,"readinessPeriodSeconds":2,"resources":{"limits":{"cpu":"2000m","memory":"1024Mi"},"requests":{"cpu":"10m","memory":"40Mi"}},"statusPort":15020,"tracer":"zipkin"},"proxy_init":{"image":"proxyv2","resources":{"limits":{"cpu":"100m","memory":"50Mi"},"requests":{"cpu":"10m","memory":"10Mi"}}},"sds":{"enabled":false,"token":{"aud":"istio-ca"},"udsPath":""},"tag":"1.5.0","tracer":{"datadog":{"address":"$(HOST_IP):8126"},"lightstep":{"accessToken":"","address":"","cacertPath":"","secure":true},"stackdriver":{"debug":false,"maxNumberOfAnnotations":200,"maxNumberOfAttributes":200,"maxNumberOfMessageEvents":200},"zipkin":{"address":""}},"trustDomain":"","trustDomainAliases":[],"useMCP":true},"grafana":{"accessMode":"ReadWriteMany","contextPath":"/grafana","dashboardProviders":{"dashboardproviders.yaml":{"apiVersion":1,"providers":[{"disableDeletion":false,"folder":"istio","name":"istio","options":{"path":"/var/lib/grafana/dashboards/istio"},"orgId":1,"type":"file"}]}},"datasources":{"datasources.yaml":{"apiVersion":1,"datasources":[{"access":"proxy","editable":true,"isDefault":true,"jsonData":{"timeInterval":"5s"},"name":"Prometheus","orgId":1,"type":"prometheus","url":"http://prometheus:9090"}]}},"enabled":true,"env":{},"envSecrets":{},"global":{"arch":{"amd64":2,"ppc64le":2,"s390x":2},"certificates":[],"configValidation":true,"controlPlaneSecurityEnabled":false,"defaultNodeSelector":{},"defaultPodDisruptionBudget":{"enabled":true},"defaultResources":{"requests":{"cpu":"10m"}},"defaultTolerations":[],"disablePolicyChecks":false,"enableHelmTest":false,"enableTracing":true,"hub":"docker.io/istio","imagePullPolicy":"IfNotPresent","imagePullSecrets":[],"k8sIngress":{"enableHttps":false,"enabled":false,"gatewayName":"ingressgateway"},"localityLbSetting":{"enabled":true},"logging":{"level":"default:info"},"meshExpansion":{"enabled":false,"useILB":false},"meshID":"","meshNetworks":{},"monitoringPort":15014,"mtls":{"auto":true,"enabled":false},"multiCluster":{"clusterName":"","enabled":false},"network":"","oneNamespace":false,"operatorManageWebhooks":false,"outboundTrafficPolicy":{"mode":"ALLOW_ANY"},"policyCheckFailOpen":false,"priorityClassName":"","proxy":{"accessLogEncoding":"TEXT","accessLogFile":"/dev/stdout","accessLogFormat":"","autoInject":"enabled","clusterDomain":"cluster.local","componentLogLevel":"","concurrency":2,"dnsRefreshRate":"300s","enableCoreDump":false,"enableCoreDumpImage":"ubuntu:xenial","envoyAccessLogService":{"enabled":false,"tcpKeepalive":{"interval":"10s","probes":3,"time":"10s"},"tlsSettings":{"mode":"DISABLE","subjectAltNames":[]}},"envoyMetricsService":{"enabled":false,"tcpKeepalive":{"interval":"10s","probes":3,"time":"10s"},"tlsSettings":{"mode":"DISABLE","subjectAltNames":[]}},"envoyStatsd":{"enabled":false},"excludeIPRanges":"","excludeInboundPorts":"","excludeOutboundPorts":"","image":"proxyv2","includeIPRanges":"*","includeInboundPorts":"*","kubevirtInterfaces":"","logLevel":"","privileged":false,"protocolDetectionTimeout":"100ms","readinessFailureThreshold":30,"readinessInitialDelaySeconds":1,"readinessPeriodSeconds":2,"resources":{"limits":{"cpu":"2000m","memory":"1024Mi"},"requests":{"cpu":"10m","memory":"40Mi"}},"statusPort":15020,"tracer":"zipkin"},"proxy_init":{"image":"proxyv2","resources":{"limits":{"cpu":"100m","memory":"50Mi"},"requests":{"cpu":"10m","memory":"10Mi"}}},"sds":{"enabled":false,"token":{"aud":"istio-ca"},"udsPath":""},"tag":"1.5.0","tracer":{"datadog":{"address":"$(HOST_IP):8126"},"lightstep":{"accessToken":"","address":"","cacertPath":"","secure":true},"stackdriver":{"debug":false,"maxNumberOfAnnotations":200,"maxNumberOfAttributes":200,"maxNumberOfMessageEvents":200},"zipkin":{"address":""}},"trustDomain":"","trustDomainAliases":[],"useMCP":true},"image":{"repository":"grafana/grafana","tag":"6.4.3"},"ingress":{"annotations":{},"enabled":false,"hosts":["grafana.local"],"tls":[]},"nodeSelector":{},"persist":false,"podAntiAffinityLabelSelector":[],"podAntiAffinityTermLabelSelector":[],"replicaCount":1,"security":{"enabled":false,"passphraseKey":"passphrase","secretName":"grafana","usernameKey":"username"},"service":{"annotations":{},"externalPort":3000,"loadBalancerSourceRanges":[],"name":"http","type":"ClusterIP"},"storageClassName":"","tolerations":[]},"istio_cni":{"enabled":false},"istiocoredns":{"enabled":false},"kiali":{"contextPath":"/kiali","createDemoSecret":true,"dashboard":{"auth":{"strategy":"login"},"grafanaInClusterURL":"http://grafana:3000","jaegerInClusterURL":"http://tracing/jaeger","secretName":"kiali","viewOnlyMode":false},"enabled":true,"global":{"arch":{"amd64":2,"ppc64le":2,"s390x":2},"certificates":[],"configValidation":true,"controlPlaneSecurityEnabled":false,"defaultNodeSelector":{},"defaultPodDisruptionBudget":{"enabled":true},"defaultResources":{"requests":{"cpu":"10m"}},"defaultTolerations":[],"disablePolicyChecks":false,"enableHelmTest":false,"enableTracing":true,"hub":"docker.io/istio","imagePullPolicy":"IfNotPresent","imagePullSecrets":[],"k8sIngress":{"enableHttps":false,"enabled":false,"gatewayName":"ingressgateway"},"localityLbSetting":{"enabled":true},"logging":{"level":"default:info"},"meshExpansion":{"enabled":false,"useILB":false},"meshID":"","meshNetworks":{},"monitoringPort":15014,"mtls":{"auto":true,"enabled":false},"multiCluster":{"clusterName":"","enabled":false},"network":"","oneNamespace":false,"operatorManageWebhooks":false,"outboundTrafficPolicy":{"mode":"ALLOW_ANY"},"policyCheckFailOpen":false,"priorityClassName":"","proxy":{"accessLogEncoding":"TEXT","accessLogFile":"/dev/stdout","accessLogFormat":"","autoInject":"enabled","clusterDomain":"cluster.local","componentLogLevel":"","concurrency":2,"dnsRefreshRate":"300s","enableCoreDump":false,"enableCoreDumpImage":"ubuntu:xenial","envoyAccessLogService":{"enabled":false,"tcpKeepalive":{"interval":"10s","probes":3,"time":"10s"},"tlsSettings":{"mode":"DISABLE","subjectAltNames":[]}},"envoyMetricsService":{"enabled":false,"tcpKeepalive":{"interval":"10s","probes":3,"time":"10s"},"tlsSettings":{"mode":"DISABLE","subjectAltNames":[]}},"envoyStatsd":{"enabled":false},"excludeIPRanges":"","excludeInboundPorts":"","excludeOutboundPorts":"","image":"proxyv2","includeIPRanges":"*","includeInboundPorts":"*","kubevirtInterfaces":"","logLevel":"","privileged":false,"protocolDetectionTimeout":"100ms","readinessFailureThreshold":30,"readinessInitialDelaySeconds":1,"readinessPeriodSeconds":2,"resources":{"limits":{"cpu":"2000m","memory":"1024Mi"},"requests":{"cpu":"10m","memory":"40Mi"}},"statusPort":15020,"tracer":"zipkin"},"proxy_init":{"image":"proxyv2","resources":{"limits":{"cpu":"100m","memory":"50Mi"},"requests":{"cpu":"10m","memory":"10Mi"}}},"sds":{"enabled":false,"token":{"aud":"istio-ca"},"udsPath":""},"tag":"1.5.0","tracer":{"datadog":{"address":"$(HOST_IP):8126"},"lightstep":{"accessToken":"","address":"","cacertPath":"","secure":true},"stackdriver":{"debug":false,"maxNumberOfAnnotations":200,"maxNumberOfAttributes":200,"maxNumberOfMessageEvents":200},"zipkin":{"address":""}},"trustDomain":"","trustDomainAliases":[],"useMCP":true},"hub":"quay.io/kiali","image":"kiali","ingress":{"annotations":{},"enabled":false,"hosts":["kiali.local"]},"nodeSelector":{},"podAnnotations":{},"podAntiAffinityLabelSelector":[],"podAntiAffinityTermLabelSelector":[],"prometheusAddr":"http://prometheus:9090","replicaCount":1,"security":{"cert_file":"/kiali-cert/cert-chain.pem","enabled":false,"private_key_file":"/kiali-cert/key.pem"},"tag":"v1.9","tolerations":[]},"mixer":{"adapters":{"kubernetesenv":{"enabled":true},"prometheus":{"enabled":true,"metricsExpiryDuration":"10m"},"stdio":{"enabled":true,"outputAsJson":true},"useAdapterCRDs":false},"env":{"GOMAXPROCS":"6"},"global":{"arch":{"amd64":2,"ppc64le":2,"s390x":2},"certificates":[],"configValidation":true,"controlPlaneSecurityEnabled":false,"defaultNodeSelector":{},"defaultPodDisruptionBudget":{"enabled":true},"defaultResources":{"requests":{"cpu":"10m"}},"defaultTolerations":[],"disablePolicyChecks":false,"enableHelmTest":false,"enableTracing":true,"hub":"docker.io/istio","imagePullPolicy":"IfNotPresent","imagePullSecrets":[],"k8sIngress":{"enableHttps":false,"enabled":false,"gatewayName":"ingressgateway"},"localityLbSetting":{"enabled":true},"logging":{"level":"default:info"},"meshExpansion":{"enabled":false,"useILB":false},"meshID":"","meshNetworks":{},"monitoringPort":15014,"mtls":{"auto":true,"enabled":false},"multiCluster":{"clusterName":"","enabled":false},"network":"","oneNamespace":false,"operatorManageWebhooks":false,"outboundTrafficPolicy":{"mode":"ALLOW_ANY"},"policyCheckFailOpen":false,"priorityClassName":"","proxy":{"accessLogEncoding":"TEXT","accessLogFile":"/dev/stdout","accessLogFormat":"","autoInject":"enabled","clusterDomain":"cluster.local","componentLogLevel":"","concurrency":2,"dnsRefreshRate":"300s","enableCoreDump":false,"enableCoreDumpImage":"ubuntu:xenial","envoyAccessLogService":{"enabled":false,"tcpKeepalive":{"interval":"10s","probes":3,"time":"10s"},"tlsSettings":{"mode":"DISABLE","subjectAltNames":[]}},"envoyMetricsService":{"enabled":false,"tcpKeepalive":{"interval":"10s","probes":3,"time":"10s"},"tlsSettings":{"mode":"DISABLE","subjectAltNames":[]}},"envoyStatsd":{"enabled":false},"excludeIPRanges":"","excludeInboundPorts":"","excludeOutboundPorts":"","image":"proxyv2","includeIPRanges":"*","includeInboundPorts":"*","kubevirtInterfaces":"","logLevel":"","privileged":false,"protocolDetectionTimeout":"100ms","readinessFailureThreshold":30,"readinessInitialDelaySeconds":1,"readinessPeriodSeconds":2,"resources":{"limits":{"cpu":"2000m","memory":"1024Mi"},"requests":{"cpu":"10m","memory":"40Mi"}},"statusPort":15020,"tracer":"zipkin"},"proxy_init":{"image":"proxyv2","resources":{"limits":{"cpu":"100m","memory":"50Mi"},"requests":{"cpu":"10m","memory":"10Mi"}}},"sds":{"enabled":false,"token":{"aud":"istio-ca"},"udsPath":""},"tag":"1.5.0","tracer":{"datadog":{"address":"$(HOST_IP):8126"},"lightstep":{"accessToken":"","address":"","cacertPath":"","secure":true},"stackdriver":{"debug":false,"maxNumberOfAnnotations":200,"maxNumberOfAttributes":200,"maxNumberOfMessageEvents":200},"zipkin":{"address":""}},"trustDomain":"","trustDomainAliases":[],"useMCP":true},"image":"mixer","nodeSelector":{},"podAnnotations":{},"podAntiAffinityLabelSelector":[],"podAntiAffinityTermLabelSelector":[],"policy":{"autoscaleEnabled":false,"autoscaleMax":5,"autoscaleMin":1,"cpu":{"targetAverageUtilization":80},"enabled":true,"replicaCount":1,"resources":{"requests":{"cpu":"10m","memory":"100Mi"}},"rollingMaxSurge":"100%","rollingMaxUnavailable":"25%"},"telemetry":{"autoscaleEnabled":false,"autoscaleMax":5,"autoscaleMin":1,"cpu":{"targetAverageUtilization":80},"enabled":true,"loadshedding":{"latencyThreshold":"100ms","mode":"enforce"},"replicaCount":1,"reportBatchMaxEntries":100,"reportBatchMaxTime":"1s","resources":{"limits":{"cpu":"4800m","memory":"4G"},"requests":{"cpu":"50m","memory":"100Mi"}},"rollingMaxSurge":"100%","rollingMaxUnavailable":"25%","sessionAffinityEnabled":false},"tolerations":[]},"nodeagent":{"enabled":false},"pilot":{"autoscaleEnabled":false,"autoscaleMax":5,"autoscaleMin":1,"configSource":{},"cpu":{"targetAverageUtilization":80},"enableProtocolSniffingForInbound":false,"enableProtocolSniffingForOutbound":true,"enabled":true,"env":{"PILOT_PUSH_THROTTLE":100},"global":{"arch":{"amd64":2,"ppc64le":2,"s390x":2},"certificates":[],"configValidation":true,"controlPlaneSecurityEnabled":false,"defaultNodeSelector":{},"defaultPodDisruptionBudget":{"enabled":true},"defaultResources":{"requests":{"cpu":"10m"}},"defaultTolerations":[],"disablePolicyChecks":false,"enableHelmTest":false,"enableTracing":true,"hub":"docker.io/istio","imagePullPolicy":"IfNotPresent","imagePullSecrets":[],"k8sIngress":{"enableHttps":false,"enabled":false,"gatewayName":"ingressgateway"},"localityLbSetting":{"enabled":true},"logging":{"level":"default:info"},"meshExpansion":{"enabled":false,"useILB":false},"meshID":"","meshNetworks":{},"monitoringPort":15014,"mtls":{"auto":true,"enabled":false},"multiCluster":{"clusterName":"","enabled":false},"network":"","oneNamespace":false,"operatorManageWebhooks":false,"outboundTrafficPolicy":{"mode":"ALLOW_ANY"},"policyCheckFailOpen":false,"priorityClassName":"","proxy":{"accessLogEncoding":"TEXT","accessLogFile":"/dev/stdout","accessLogFormat":"","autoInject":"enabled","clusterDomain":"cluster.local","componentLogLevel":"","concurrency":2,"dnsRefreshRate":"300s","enableCoreDump":false,"enableCoreDumpImage":"ubuntu:xenial","envoyAccessLogService":{"enabled":false,"tcpKeepalive":{"interval":"10s","probes":3,"time":"10s"},"tlsSettings":{"mode":"DISABLE","subjectAltNames":[]}},"envoyMetricsService":{"enabled":false,"tcpKeepalive":{"interval":"10s","probes":3,"time":"10s"},"tlsSettings":{"mode":"DISABLE","subjectAltNames":[]}},"envoyStatsd":{"enabled":false},"excludeIPRanges":"","excludeInboundPorts":"","excludeOutboundPorts":"","image":"proxyv2","includeIPRanges":"*","includeInboundPorts":"*","kubevirtInterfaces":"","logLevel":"","privileged":false,"protocolDetectionTimeout":"100ms","readinessFailureThreshold":30,"readinessInitialDelaySeconds":1,"readinessPeriodSeconds":2,"resources":{"limits":{"cpu":"2000m","memory":"1024Mi"},"requests":{"cpu":"10m","memory":"40Mi"}},"statusPort":15020,"tracer":"zipkin"},"proxy_init":{"image":"proxyv2","resources":{"limits":{"cpu":"100m","memory":"50Mi"},"requests":{"cpu":"10m","memory":"10Mi"}}},"sds":{"enabled":false,"token":{"aud":"istio-ca"},"udsPath":""},"tag":"1.5.0","tracer":{"datadog":{"address":"$(HOST_IP):8126"},"lightstep":{"accessToken":"","address":"","cacertPath":"","secure":true},"stackdriver":{"debug":false,"maxNumberOfAnnotations":200,"maxNumberOfAttributes":200,"maxNumberOfMessageEvents":200},"zipkin":{"address":""}},"trustDomain":"","trustDomainAliases":[],"useMCP":true},"image":"pilot","keepaliveMaxServerConnectionAge":"30m","nodeSelector":{},"podAnnotations":{},"podAntiAffinityLabelSelector":[],"podAntiAffinityTermLabelSelector":[],"resources":{"requests":{"cpu":"10m","memory":"100Mi"}},"rollingMaxSurge":"100%","rollingMaxUnavailable":"25%","sidecar":true,"tolerations":[],"traceSampling":100},"prometheus":{"contextPath":"/prometheus","enabled":true,"global":{"arch":{"amd64":2,"ppc64le":2,"s390x":2},"certificates":[],"configValidation":true,"controlPlaneSecurityEnabled":false,"defaultNodeSelector":{},"defaultPodDisruptionBudget":{"enabled":true},"defaultResources":{"requests":{"cpu":"10m"}},"defaultTolerations":[],"disablePolicyChecks":false,"enableHelmTest":false,"enableTracing":true,"hub":"docker.io/istio","imagePullPolicy":"IfNotPresent","imagePullSecrets":[],"k8sIngress":{"enableHttps":false,"enabled":false,"gatewayName":"ingressgateway"},"localityLbSetting":{"enabled":true},"logging":{"level":"default:info"},"meshExpansion":{"enabled":false,"useILB":false},"meshID":"","meshNetworks":{},"monitoringPort":15014,"mtls":{"auto":true,"enabled":false},"multiCluster":{"clusterName":"","enabled":false},"network":"","oneNamespace":false,"operatorManageWebhooks":false,"outboundTrafficPolicy":{"mode":"ALLOW_ANY"},"policyCheckFailOpen":false,"priorityClassName":"","proxy":{"accessLogEncoding":"TEXT","accessLogFile":"/dev/stdout","accessLogFormat":"","autoInject":"enabled","clusterDomain":"cluster.local","componentLogLevel":"","concurrency":2,"dnsRefreshRate":"300s","enableCoreDump":false,"enableCoreDumpImage":"ubuntu:xenial","envoyAccessLogService":{"enabled":false,"tcpKeepalive":{"interval":"10s","probes":3,"time":"10s"},"tlsSettings":{"mode":"DISABLE","subjectAltNames":[]}},"envoyMetricsService":{"enabled":false,"tcpKeepalive":{"interval":"10s","probes":3,"time":"10s"},"tlsSettings":{"mode":"DISABLE","subjectAltNames":[]}},"envoyStatsd":{"enabled":false},"excludeIPRanges":"","excludeInboundPorts":"","excludeOutboundPorts":"","image":"proxyv2","includeIPRanges":"*","includeInboundPorts":"*","kubevirtInterfaces":"","logLevel":"","privileged":false,"protocolDetectionTimeout":"100ms","readinessFailureThreshold":30,"readinessInitialDelaySeconds":1,"readinessPeriodSeconds":2,"resources":{"limits":{"cpu":"2000m","memory":"1024Mi"},"requests":{"cpu":"10m","memory":"40Mi"}},"statusPort":15020,"tracer":"zipkin"},"proxy_init":{"image":"proxyv2","resources":{"limits":{"cpu":"100m","memory":"50Mi"},"requests":{"cpu":"10m","memory":"10Mi"}}},"sds":{"enabled":false,"token":{"aud":"istio-ca"},"udsPath":""},"tag":"1.5.0","tracer":{"datadog":{"address":"$(HOST_IP):8126"},"lightstep":{"accessToken":"","address":"","cacertPath":"","secure":true},"stackdriver":{"debug":false,"maxNumberOfAnnotations":200,"maxNumberOfAttributes":200,"maxNumberOfMessageEvents":200},"zipkin":{"address":""}},"trustDomain":"","trustDomainAliases":[],"useMCP":true},"hub":"docker.io/prom","image":"prometheus","ingress":{"enabled":false,"hosts":["prometheus.local"]},"nodeSelector":{},"podAntiAffinityLabelSelector":[],"podAntiAffinityTermLabelSelector":[],"replicaCount":1,"retention":"6h","scrapeInterval":"15s","security":{"enabled":true},"service":{"annotations":{},"nodePort":{"enabled":false,"port":32090}},"tag":"v2.12.0","tolerations":[]},"security":{"citadelHealthCheck":false,"createMeshPolicy":true,"enableNamespacesByDefault":true,"enabled":true,"env":{},"global":{"arch":{"amd64":2,"ppc64le":2,"s390x":2},"certificates":[],"configValidation":true,"controlPlaneSecurityEnabled":false,"defaultNodeSelector":{},"defaultPodDisruptionBudget":{"enabled":true},"defaultResources":{"requests":{"cpu":"10m"}},"defaultTolerations":[],"disablePolicyChecks":false,"enableHelmTest":false,"enableTracing":true,"hub":"docker.io/istio","imagePullPolicy":"IfNotPresent","imagePullSecrets":[],"k8sIngress":{"enableHttps":false,"enabled":false,"gatewayName":"ingressgateway"},"localityLbSetting":{"enabled":true},"logging":{"level":"default:info"},"meshExpansion":{"enabled":false,"useILB":false},"meshID":"","meshNetworks":{},"monitoringPort":15014,"mtls":{"auto":true,"enabled":false},"multiCluster":{"clusterName":"","enabled":false},"network":"","oneNamespace":false,"operatorManageWebhooks":false,"outboundTrafficPolicy":{"mode":"ALLOW_ANY"},"policyCheckFailOpen":false,"priorityClassName":"","proxy":{"accessLogEncoding":"TEXT","accessLogFile":"/dev/stdout","accessLogFormat":"","autoInject":"enabled","clusterDomain":"cluster.local","componentLogLevel":"","concurrency":2,"dnsRefreshRate":"300s","enableCoreDump":false,"enableCoreDumpImage":"ubuntu:xenial","envoyAccessLogService":{"enabled":false,"tcpKeepalive":{"interval":"10s","probes":3,"time":"10s"},"tlsSettings":{"mode":"DISABLE","subjectAltNames":[]}},"envoyMetricsService":{"enabled":false,"tcpKeepalive":{"interval":"10s","probes":3,"time":"10s"},"tlsSettings":{"mode":"DISABLE","subjectAltNames":[]}},"envoyStatsd":{"enabled":false},"excludeIPRanges":"","excludeInboundPorts":"","excludeOutboundPorts":"","image":"proxyv2","includeIPRanges":"*","includeInboundPorts":"*","kubevirtInterfaces":"","logLevel":"","privileged":false,"protocolDetectionTimeout":"100ms","readinessFailureThreshold":30,"readinessInitialDelaySeconds":1,"readinessPeriodSeconds":2,"resources":{"limits":{"cpu":"2000m","memory":"1024Mi"},"requests":{"cpu":"10m","memory":"40Mi"}},"statusPort":15020,"tracer":"zipkin"},"proxy_init":{"image":"proxyv2","resources":{"limits":{"cpu":"100m","memory":"50Mi"},"requests":{"cpu":"10m","memory":"10Mi"}}},"sds":{"enabled":false,"token":{"aud":"istio-ca"},"udsPath":""},"tag":"1.5.0","tracer":{"datadog":{"address":"$(HOST_IP):8126"},"lightstep":{"accessToken":"","address":"","cacertPath":"","secure":true},"stackdriver":{"debug":false,"maxNumberOfAnnotations":200,"maxNumberOfAttributes":200,"maxNumberOfMessageEvents":200},"zipkin":{"address":""}},"trustDomain":"","trustDomainAliases":[],"useMCP":true},"image":"citadel","nodeSelector":{},"podAnnotations":{},"podAntiAffinityLabelSelector":[],"podAntiAffinityTermLabelSelector":[],"replicaCount":1,"rollingMaxSurge":"100%","rollingMaxUnavailable":"25%","selfSigned":true,"tolerations":[],"workloadCertTtl":"2160h"},"sidecarInjectorWebhook":{"alwaysInjectSelector":[],"enableNamespacesByDefault":false,"enabled":true,"global":{"arch":{"amd64":2,"ppc64le":2,"s390x":2},"certificates":[],"configValidation":true,"controlPlaneSecurityEnabled":false,"defaultNodeSelector":{},"defaultPodDisruptionBudget":{"enabled":true},"defaultResources":{"requests":{"cpu":"10m"}},"defaultTolerations":[],"disablePolicyChecks":false,"enableHelmTest":false,"enableTracing":true,"hub":"docker.io/istio","imagePullPolicy":"IfNotPresent","imagePullSecrets":[],"k8sIngress":{"enableHttps":false,"enabled":false,"gatewayName":"ingressgateway"},"localityLbSetting":{"enabled":true},"logging":{"level":"default:info"},"meshExpansion":{"enabled":false,"useILB":false},"meshID":"","meshNetworks":{},"monitoringPort":15014,"mtls":{"auto":true,"enabled":false},"multiCluster":{"clusterName":"","enabled":false},"network":"","oneNamespace":false,"operatorManageWebhooks":false,"outboundTrafficPolicy":{"mode":"ALLOW_ANY"},"policyCheckFailOpen":false,"priorityClassName":"","proxy":{"accessLogEncoding":"TEXT","accessLogFile":"/dev/stdout","accessLogFormat":"","autoInject":"enabled","clusterDomain":"cluster.local","componentLogLevel":"","concurrency":2,"dnsRefreshRate":"300s","enableCoreDump":false,"enableCoreDumpImage":"ubuntu:xenial","envoyAccessLogService":{"enabled":false,"tcpKeepalive":{"interval":"10s","probes":3,"time":"10s"},"tlsSettings":{"mode":"DISABLE","subjectAltNames":[]}},"envoyMetricsService":{"enabled":false,"tcpKeepalive":{"interval":"10s","probes":3,"time":"10s"},"tlsSettings":{"mode":"DISABLE","subjectAltNames":[]}},"envoyStatsd":{"enabled":false},"excludeIPRanges":"","excludeInboundPorts":"","excludeOutboundPorts":"","image":"proxyv2","includeIPRanges":"*","includeInboundPorts":"*","kubevirtInterfaces":"","logLevel":"","privileged":false,"protocolDetectionTimeout":"100ms","readinessFailureThreshold":30,"readinessInitialDelaySeconds":1,"readinessPeriodSeconds":2,"resources":{"limits":{"cpu":"2000m","memory":"1024Mi"},"requests":{"cpu":"10m","memory":"40Mi"}},"statusPort":15020,"tracer":"zipkin"},"proxy_init":{"image":"proxyv2","resources":{"limits":{"cpu":"100m","memory":"50Mi"},"requests":{"cpu":"10m","memory":"10Mi"}}},"sds":{"enabled":false,"token":{"aud":"istio-ca"},"udsPath":""},"tag":"1.5.0","tracer":{"datadog":{"address":"$(HOST_IP):8126"},"lightstep":{"accessToken":"","address":"","cacertPath":"","secure":true},"stackdriver":{"debug":false,"maxNumberOfAnnotations":200,"maxNumberOfAttributes":200,"maxNumberOfMessageEvents":200},"zipkin":{"address":""}},"trustDomain":"","trustDomainAliases":[],"useMCP":true},"image":"sidecar_injector","injectedAnnotations":{},"neverInjectSelector":[],"nodeSelector":{},"podAnnotations":{},"podAntiAffinityLabelSelector":[],"podAntiAffinityTermLabelSelector":[],"replicaCount":1,"rewriteAppHTTPProbe":false,"rollingMaxSurge":"100%","rollingMaxUnavailable":"25%","tolerations":[]},"tracing":{"enabled":true,"global":{"arch":{"amd64":2,"ppc64le":2,"s390x":2},"certificates":[],"configValidation":true,"controlPlaneSecurityEnabled":false,"defaultNodeSelector":{},"defaultPodDisruptionBudget":{"enabled":true},"defaultResources":{"requests":{"cpu":"10m"}},"defaultTolerations":[],"disablePolicyChecks":false,"enableHelmTest":false,"enableTracing":true,"hub":"docker.io/istio","imagePullPolicy":"IfNotPresent","imagePullSecrets":[],"k8sIngress":{"enableHttps":false,"enabled":false,"gatewayName":"ingressgateway"},"localityLbSetting":{"enabled":true},"logging":{"level":"default:info"},"meshExpansion":{"enabled":false,"useILB":false},"meshID":"","meshNetworks":{},"monitoringPort":15014,"mtls":{"auto":true,"enabled":false},"multiCluster":{"clusterName":"","enabled":false},"network":"","oneNamespace":false,"operatorManageWebhooks":false,"outboundTrafficPolicy":{"mode":"ALLOW_ANY"},"policyCheckFailOpen":false,"priorityClassName":"","proxy":{"accessLogEncoding":"TEXT","accessLogFile":"/dev/stdout","accessLogFormat":"","autoInject":"enabled","clusterDomain":"cluster.local","componentLogLevel":"","concurrency":2,"dnsRefreshRate":"300s","enableCoreDump":false,"enableCoreDumpImage":"ubuntu:xenial","envoyAccessLogService":{"enabled":false,"tcpKeepalive":{"interval":"10s","probes":3,"time":"10s"},"tlsSettings":{"mode":"DISABLE","subjectAltNames":[]}},"envoyMetricsService":{"enabled":false,"tcpKeepalive":{"interval":"10s","probes":3,"time":"10s"},"tlsSettings":{"mode":"DISABLE","subjectAltNames":[]}},"envoyStatsd":{"enabled":false},"excludeIPRanges":"","excludeInboundPorts":"","excludeOutboundPorts":"","image":"proxyv2","includeIPRanges":"*","includeInboundPorts":"*","kubevirtInterfaces":"","logLevel":"","privileged":false,"protocolDetectionTimeout":"100ms","readinessFailureThreshold":30,"readinessInitialDelaySeconds":1,"readinessPeriodSeconds":2,"resources":{"limits":{"cpu":"2000m","memory":"1024Mi"},"requests":{"cpu":"10m","memory":"40Mi"}},"statusPort":15020,"tracer":"zipkin"},"proxy_init":{"image":"proxyv2","resources":{"limits":{"cpu":"100m","memory":"50Mi"},"requests":{"cpu":"10m","memory":"10Mi"}}},"sds":{"enabled":false,"token":{"aud":"istio-ca"},"udsPath":""},"tag":"1.5.0","tracer":{"datadog":{"address":"$(HOST_IP):8126"},"lightstep":{"accessToken":"","address":"","cacertPath":"","secure":true},"stackdriver":{"debug":false,"maxNumberOfAnnotations":200,"maxNumberOfAttributes":200,"maxNumberOfMessageEvents":200},"zipkin":{"address":""}},"trustDomain":"","trustDomainAliases":[],"useMCP":true},"ingress":{"enabled":false},"jaeger":{"accessMode":"ReadWriteMany","hub":"docker.io/jaegertracing","image":"all-in-one","memory":{"max_traces":50000},"persist":false,"podAnnotations":{},"spanStorageType":"badger","storageClassName":"","tag":1.16},"nodeSelector":{},"podAntiAffinityLabelSelector":[],"podAntiAffinityTermLabelSelector":[],"provider":"jaeger","service":{"annotations":{},"externalPort":80,"name":"http","type":"ClusterIP"},"tolerations":[],"zipkin":{"hub":"docker.io/openzipkin","image":"zipkin","javaOptsHeap":700,"maxSpans":500000,"node":{"cpus":2},"podAnnotations":{},"probeStartupDelay":200,"queryPort":9411,"resources":{"limits":{"cpu":"300m","memory":"900Mi"},"requests":{"cpu":"150m","memory":"900Mi"}},"tag":"2.14.2"}}} + + config: |- + policy: enabled + alwaysInjectSelector: + [] + neverInjectSelector: + [] + template: |- + rewriteAppHTTPProbe: {{ valueOrDefault .Values.sidecarInjectorWebhook.rewriteAppHTTPProbe false }} + initContainers: + {{ if ne (annotation .ObjectMeta `sidecar.istio.io/interceptionMode` .ProxyConfig.InterceptionMode) `NONE` }} + {{ if .Values.istio_cni.enabled -}} + - name: istio-validation + {{ else -}} + - name: istio-init + {{ end -}} + {{- if contains "/" .Values.global.proxy_init.image }} + image: "{{ .Values.global.proxy_init.image }}" + {{- else }} + image: "{{ .Values.global.hub }}/{{ .Values.global.proxy_init.image }}:{{ .Values.global.tag }}" + {{- end }} + command: + - istio-iptables + - "-p" + - "15001" + - "-z" + - "15006" + - "-u" + - 1337 + - "-m" + - "{{ annotation .ObjectMeta `sidecar.istio.io/interceptionMode` .ProxyConfig.InterceptionMode }}" + - "-i" + - "{{ annotation .ObjectMeta `traffic.sidecar.istio.io/includeOutboundIPRanges` .Values.global.proxy.includeIPRanges }}" + - "-x" + - "{{ annotation .ObjectMeta `traffic.sidecar.istio.io/excludeOutboundIPRanges` .Values.global.proxy.excludeIPRanges }}" + - "-b" + - "{{ annotation .ObjectMeta `traffic.sidecar.istio.io/includeInboundPorts` `*` }}" + - "-d" + - "{{ excludeInboundPort (annotation .ObjectMeta `status.sidecar.istio.io/port` .Values.global.proxy.statusPort) (annotation .ObjectMeta `traffic.sidecar.istio.io/excludeInboundPorts` .Values.global.proxy.excludeInboundPorts) }}" + {{ if or (isset .ObjectMeta.Annotations `traffic.sidecar.istio.io/excludeOutboundPorts`) (ne (valueOrDefault .Values.global.proxy.excludeOutboundPorts "") "") -}} + - "-o" + - "{{ annotation .ObjectMeta `traffic.sidecar.istio.io/excludeOutboundPorts` .Values.global.proxy.excludeOutboundPorts }}" + {{ end -}} + {{ if (isset .ObjectMeta.Annotations `traffic.sidecar.istio.io/kubevirtInterfaces`) -}} + - "-k" + - "{{ index .ObjectMeta.Annotations `traffic.sidecar.istio.io/kubevirtInterfaces` }}" + {{ end -}} + {{ if .Values.istio_cni.enabled -}} + - "--run-validation" + - "--skip-rule-apply" + {{ end -}} + imagePullPolicy: "{{ valueOrDefault .Values.global.imagePullPolicy `Always` }}" + {{- if .Values.global.proxy_init.resources }} + resources: + {{ toYaml .Values.global.proxy_init.resources | indent 4 }} + {{- else }} + resources: {} + {{- end }} + securityContext: + allowPrivilegeEscalation: {{ .Values.global.proxy.privileged }} + privileged: {{ .Values.global.proxy.privileged }} + capabilities: + {{- if not .Values.istio_cni.enabled }} + add: + - NET_ADMIN + - NET_RAW + {{- end }} + drop: + - ALL + readOnlyRootFilesystem: false + {{- if not .Values.istio_cni.enabled }} + runAsGroup: 0 + runAsNonRoot: false + runAsUser: 0 + {{- else }} + runAsGroup: 1337 + runAsUser: 1337 + runAsNonRoot: true + {{- end }} + restartPolicy: Always + {{ end -}} + {{- if eq (annotation .ObjectMeta `sidecar.istio.io/enableCoreDump` .Values.global.proxy.enableCoreDump) "true" }} + - name: enable-core-dump + args: + - -c + - sysctl -w kernel.core_pattern=/var/lib/istio/core.proxy && ulimit -c unlimited + command: + - /bin/sh + image: {{ $.Values.global.proxy.enableCoreDumpImage }} + imagePullPolicy: IfNotPresent + resources: {} + securityContext: + allowPrivilegeEscalation: true + capabilities: + add: + - SYS_ADMIN + drop: + - ALL + privileged: true + readOnlyRootFilesystem: false + runAsGroup: 0 + runAsNonRoot: false + runAsUser: 0 + {{ end }} + containers: + - name: istio-proxy + {{- if contains "/" (annotation .ObjectMeta `sidecar.istio.io/proxyImage` .Values.global.proxy.image) }} + image: "{{ annotation .ObjectMeta `sidecar.istio.io/proxyImage` .Values.global.proxy.image }}" + {{- else }} + image: "{{ annotation .ObjectMeta `sidecar.istio.io/proxyImage` .Values.global.hub }}/{{ .Values.global.proxy.image }}:{{ .Values.global.tag }}" + {{- end }} + ports: + - containerPort: 15090 + protocol: TCP + name: http-envoy-prom + args: + - proxy + - sidecar + - --domain + - $(POD_NAMESPACE).svc.{{ .Values.global.proxy.clusterDomain }} + - --configPath + - "{{ .ProxyConfig.ConfigPath }}" + - --binaryPath + - "{{ .ProxyConfig.BinaryPath }}" + - --serviceCluster + {{ if ne "" (index .ObjectMeta.Labels "app") -}} + - "{{ index .ObjectMeta.Labels `app` }}.$(POD_NAMESPACE)" + {{ else -}} + - "{{ valueOrDefault .DeploymentMeta.Name `istio-proxy` }}.{{ valueOrDefault .DeploymentMeta.Namespace `default` }}" + {{ end -}} + - --drainDuration + - "{{ formatDuration .ProxyConfig.DrainDuration }}" + - --parentShutdownDuration + - "{{ formatDuration .ProxyConfig.ParentShutdownDuration }}" + - --discoveryAddress + - "{{ annotation .ObjectMeta `sidecar.istio.io/discoveryAddress` .ProxyConfig.DiscoveryAddress }}" + {{- if eq .Values.global.proxy.tracer "lightstep" }} + - --lightstepAddress + - "{{ .ProxyConfig.GetTracing.GetLightstep.GetAddress }}" + - --lightstepAccessToken + - "{{ .ProxyConfig.GetTracing.GetLightstep.GetAccessToken }}" + - --lightstepSecure={{ .ProxyConfig.GetTracing.GetLightstep.GetSecure }} + {{- if .ProxyConfig.GetTracing.GetLightstep.GetSecure }} + - --lightstepCacertPath + - "{{ .ProxyConfig.GetTracing.GetLightstep.GetCacertPath }}" + {{- end }} + {{- else if eq .Values.global.proxy.tracer "zipkin" }} + - --zipkinAddress + - "{{ .ProxyConfig.GetTracing.GetZipkin.GetAddress }}" + {{- else if eq .Values.global.proxy.tracer "datadog" }} + - --datadogAgentAddress + - "{{ .ProxyConfig.GetTracing.GetDatadog.GetAddress }}" + {{- end }} + {{- if .Values.global.proxy.logLevel }} + - --proxyLogLevel={{ .Values.global.proxy.logLevel }} + {{- end}} + {{- if .Values.global.proxy.componentLogLevel }} + - --proxyComponentLogLevel={{ .Values.global.proxy.componentLogLevel }} + {{- end}} + {{- if .Values.global.proxy.outlierLogPath }} + - --outlierLogPath={{ .Values.global.proxy.outlierLogPath }} + {{- end}} + - --dnsRefreshRate + - {{ .Values.global.proxy.dnsRefreshRate }} + - --connectTimeout + - "{{ formatDuration .ProxyConfig.ConnectTimeout }}" + {{- if .Values.global.proxy.envoyStatsd.enabled }} + - --statsdUdpAddress + - "{{ .ProxyConfig.StatsdUdpAddress }}" + {{- end }} + {{- if .Values.global.proxy.envoyMetricsService.enabled }} + - --envoyMetricsService + - '{{ protoToJSON .ProxyConfig.EnvoyMetricsService }}' + {{- end }} + {{- if .Values.global.proxy.envoyAccessLogService.enabled }} + - --envoyAccessLogService + - '{{ protoToJSON .ProxyConfig.EnvoyAccessLogService }}' + {{- end }} + - --proxyAdminPort + - "{{ .ProxyConfig.ProxyAdminPort }}" + {{ if gt .ProxyConfig.Concurrency 0 -}} + - --concurrency + - "{{ .ProxyConfig.Concurrency }}" + {{ end -}} + - --controlPlaneAuthPolicy + - "{{ annotation .ObjectMeta `sidecar.istio.io/controlPlaneAuthPolicy` .ProxyConfig.ControlPlaneAuthPolicy }}" + {{- if (ne (annotation .ObjectMeta "status.sidecar.istio.io/port" (valueOrDefault .Values.global.proxy.statusPort 0 )) `0`) }} + - --statusPort + - "{{ annotation .ObjectMeta `status.sidecar.istio.io/port` .Values.global.proxy.statusPort }}" + {{- end }} + {{- if .Values.global.trustDomain }} + - --trust-domain={{ .Values.global.trustDomain }} + {{- end }} + {{- if .Values.global.proxy.lifecycle }} + lifecycle: + {{ toYaml .Values.global.proxy.lifecycle | indent 4 }} + {{- end }} + env: + - name: POD_NAME + valueFrom: + fieldRef: + fieldPath: metadata.name + - name: ISTIO_META_POD_PORTS + value: |- + [ + {{- $first := true }} + {{- range $index1, $c := .Spec.Containers }} + {{- range $index2, $p := $c.Ports }} + {{- if (structToJSON $p) }} + {{if not $first}},{{end}}{{ structToJSON $p }} + {{- $first = false }} + {{- end }} + {{- end}} + {{- end}} + ] + - name: ISTIO_META_CLUSTER_ID + value: "{{ valueOrDefault .Values.global.multiCluster.clusterName `Kubernetes` }}" + - name: POD_NAMESPACE + valueFrom: + fieldRef: + fieldPath: metadata.namespace + - name: INSTANCE_IP + valueFrom: + fieldRef: + fieldPath: status.podIP + - name: SERVICE_ACCOUNT + valueFrom: + fieldRef: + fieldPath: spec.serviceAccountName + {{- if .Values.global.mtls.auto }} + - name: ISTIO_AUTO_MTLS_ENABLED + value: "true" + {{- end }} + {{- if eq .Values.global.proxy.tracer "datadog" }} + - name: HOST_IP + valueFrom: + fieldRef: + fieldPath: status.hostIP + {{- if isset .ObjectMeta.Annotations `apm.datadoghq.com/env` }} + {{- range $key, $value := fromJSON (index .ObjectMeta.Annotations `apm.datadoghq.com/env`) }} + - name: {{ $key }} + value: "{{ $value }}" + {{- end }} + {{- end }} + {{- end }} + - name: ISTIO_META_POD_NAME + valueFrom: + fieldRef: + fieldPath: metadata.name + - name: ISTIO_META_CONFIG_NAMESPACE + valueFrom: + fieldRef: + fieldPath: metadata.namespace + - name: SDS_ENABLED + value: {{ $.Values.global.sds.enabled }} + - name: ISTIO_META_INTERCEPTION_MODE + value: "{{ or (index .ObjectMeta.Annotations `sidecar.istio.io/interceptionMode`) .ProxyConfig.InterceptionMode.String }}" + {{- if .Values.global.network }} + - name: ISTIO_META_NETWORK + value: "{{ .Values.global.network }}" + {{- end }} + {{ if .ObjectMeta.Annotations }} + - name: ISTIO_METAJSON_ANNOTATIONS + value: | + {{ toJSON .ObjectMeta.Annotations }} + {{ end }} + {{ if .ObjectMeta.Labels }} + - name: ISTIO_METAJSON_LABELS + value: | + {{ toJSON .ObjectMeta.Labels }} + {{ end }} + {{- if .DeploymentMeta.Name }} + - name: ISTIO_META_WORKLOAD_NAME + value: {{ .DeploymentMeta.Name }} + {{ end }} + {{- if and .TypeMeta.APIVersion .DeploymentMeta.Name }} + - name: ISTIO_META_OWNER + value: kubernetes://apis/{{ .TypeMeta.APIVersion }}/namespaces/{{ valueOrDefault .DeploymentMeta.Namespace `default` }}/{{ toLower .TypeMeta.Kind}}s/{{ .DeploymentMeta.Name }} + {{- end}} + {{- if (isset .ObjectMeta.Annotations `sidecar.istio.io/bootstrapOverride`) }} + - name: ISTIO_BOOTSTRAP_OVERRIDE + value: "/etc/istio/custom-bootstrap/custom_bootstrap.json" + {{- end }} + {{- if .Values.global.sds.customTokenDirectory }} + - name: ISTIO_META_SDS_TOKEN_PATH + value: "{{ .Values.global.sds.customTokenDirectory -}}/sdstoken" + {{- end }} + {{- if .Values.global.meshID }} + - name: ISTIO_META_MESH_ID + value: "{{ .Values.global.meshID }}" + {{- else if .Values.global.trustDomain }} + - name: ISTIO_META_MESH_ID + value: "{{ .Values.global.trustDomain }}" + {{- end }} + {{- if eq .Values.global.proxy.tracer "stackdriver" }} + - name: STACKDRIVER_TRACING_ENABLED + value: "true" + - name: STACKDRIVER_TRACING_DEBUG + value: "{{ .ProxyConfig.GetTracing.GetStackdriver.GetDebug }}" + {{- if .ProxyConfig.GetTracing.GetStackdriver.GetMaxNumberOfAnnotations }} + - name: STACKDRIVER_TRACING_MAX_NUMBER_OF_ANNOTATIONS + value: "{{ .ProxyConfig.GetTracing.GetStackdriver.GetMaxNumberOfAnnotations.Value }}" + {{- end }} + {{- if .ProxyConfig.GetTracing.GetStackdriver.GetMaxNumberOfAttributes }} + - name: STACKDRIVER_TRACING_MAX_NUMBER_OF_ATTRIBUTES + value: "{{ .ProxyConfig.GetTracing.GetStackdriver.GetMaxNumberOfAttributes.Value }}" + {{- end }} + {{- if .ProxyConfig.GetTracing.GetStackdriver.GetMaxNumberOfMessageEvents }} + - name: STACKDRIVER_TRACING_MAX_NUMBER_OF_MESSAGE_EVENTS + value: "{{ .ProxyConfig.GetTracing.GetStackdriver.GetMaxNumberOfMessageEvents.Value }}" + {{- end }} + {{- end }} + imagePullPolicy: {{ .Values.global.imagePullPolicy }} + {{ if ne (annotation .ObjectMeta `status.sidecar.istio.io/port` (valueOrDefault .Values.global.proxy.statusPort 0 )) `0` }} + readinessProbe: + httpGet: + path: /healthz/ready + port: {{ annotation .ObjectMeta `status.sidecar.istio.io/port` .Values.global.proxy.statusPort }} + initialDelaySeconds: {{ annotation .ObjectMeta `readiness.status.sidecar.istio.io/initialDelaySeconds` .Values.global.proxy.readinessInitialDelaySeconds }} + periodSeconds: {{ annotation .ObjectMeta `readiness.status.sidecar.istio.io/periodSeconds` .Values.global.proxy.readinessPeriodSeconds }} + failureThreshold: {{ annotation .ObjectMeta `readiness.status.sidecar.istio.io/failureThreshold` .Values.global.proxy.readinessFailureThreshold }} + {{ end -}} + securityContext: + allowPrivilegeEscalation: {{ .Values.global.proxy.privileged }} + capabilities: + {{ if eq (annotation .ObjectMeta `sidecar.istio.io/interceptionMode` .ProxyConfig.InterceptionMode) `TPROXY` -}} + add: + - NET_ADMIN + {{- end }} + drop: + - ALL + privileged: {{ .Values.global.proxy.privileged }} + readOnlyRootFilesystem: {{ ne (annotation .ObjectMeta `sidecar.istio.io/enableCoreDump` .Values.global.proxy.enableCoreDump) "true" }} + runAsGroup: 1337 + {{ if eq (annotation .ObjectMeta `sidecar.istio.io/interceptionMode` .ProxyConfig.InterceptionMode) `TPROXY` -}} + runAsNonRoot: false + runAsUser: 0 + {{- else -}} + runAsNonRoot: true + runAsUser: 1337 + {{- end }} + resources: + {{ if or (isset .ObjectMeta.Annotations `sidecar.istio.io/proxyCPU`) (isset .ObjectMeta.Annotations `sidecar.istio.io/proxyMemory`) -}} + requests: + {{ if (isset .ObjectMeta.Annotations `sidecar.istio.io/proxyCPU`) -}} + cpu: "{{ index .ObjectMeta.Annotations `sidecar.istio.io/proxyCPU` }}" + {{ end}} + {{ if (isset .ObjectMeta.Annotations `sidecar.istio.io/proxyMemory`) -}} + memory: "{{ index .ObjectMeta.Annotations `sidecar.istio.io/proxyMemory` }}" + {{ end }} + {{ else -}} + {{- if .Values.global.proxy.resources }} + {{ toYaml .Values.global.proxy.resources | indent 4 }} + {{- end }} + {{ end -}} + volumeMounts: + {{ if (isset .ObjectMeta.Annotations `sidecar.istio.io/bootstrapOverride`) }} + - mountPath: /etc/istio/custom-bootstrap + name: custom-bootstrap-volume + {{- end }} + - mountPath: /etc/istio/proxy + name: istio-envoy + {{- if .Values.global.sds.enabled }} + - mountPath: /var/run/sds + name: sds-uds-path + readOnly: true + - mountPath: /var/run/secrets/tokens + name: istio-token + {{- if .Values.global.sds.customTokenDirectory }} + - mountPath: "{{ .Values.global.sds.customTokenDirectory -}}" + name: custom-sds-token + readOnly: true + {{- end }} + {{- else }} + - mountPath: /etc/certs/ + name: istio-certs + readOnly: true + {{- end }} + {{- if and (eq .Values.global.proxy.tracer "lightstep") .Values.global.tracer.lightstep.cacertPath }} + - mountPath: {{ directory .ProxyConfig.GetTracing.GetLightstep.GetCacertPath }} + name: lightstep-certs + readOnly: true + {{- end }} + {{- if isset .ObjectMeta.Annotations `sidecar.istio.io/userVolumeMount` }} + {{ range $index, $value := fromJSON (index .ObjectMeta.Annotations `sidecar.istio.io/userVolumeMount`) }} + - name: "{{ $index }}" + {{ toYaml $value | indent 4 }} + {{ end }} + {{- end }} + volumes: + {{- if (isset .ObjectMeta.Annotations `sidecar.istio.io/bootstrapOverride`) }} + - name: custom-bootstrap-volume + configMap: + name: {{ annotation .ObjectMeta `sidecar.istio.io/bootstrapOverride` "" }} + {{- end }} + - emptyDir: + medium: Memory + name: istio-envoy + {{- if .Values.global.sds.enabled }} + - name: sds-uds-path + hostPath: + path: /var/run/sds + - name: istio-token + projected: + sources: + - serviceAccountToken: + path: istio-token + expirationSeconds: 43200 + audience: {{ .Values.global.sds.token.aud }} + {{- if .Values.global.sds.customTokenDirectory }} + - name: custom-sds-token + secret: + secretName: sdstokensecret + {{- end }} + {{- else }} + - name: istio-certs + secret: + optional: true + {{ if eq .Spec.ServiceAccountName "" }} + secretName: istio.default + {{ else -}} + secretName: {{ printf "istio.%s" .Spec.ServiceAccountName }} + {{ end -}} + {{- if isset .ObjectMeta.Annotations `sidecar.istio.io/userVolume` }} + {{range $index, $value := fromJSON (index .ObjectMeta.Annotations `sidecar.istio.io/userVolume`) }} + - name: "{{ $index }}" + {{ toYaml $value | indent 2 }} + {{ end }} + {{ end }} + {{- end }} + {{- if and (eq .Values.global.proxy.tracer "lightstep") .Values.global.tracer.lightstep.cacertPath }} + - name: lightstep-certs + secret: + optional: true + secretName: lightstep.cacert + {{- end }} + {{- if .Values.global.podDNSSearchNamespaces }} + dnsConfig: + searches: + {{- range .Values.global.podDNSSearchNamespaces }} + - {{ render . }} + {{- end }} + {{- end }} + podRedirectAnnot: + sidecar.istio.io/interceptionMode: "{{ annotation .ObjectMeta `sidecar.istio.io/interceptionMode` .ProxyConfig.InterceptionMode }}" + traffic.sidecar.istio.io/includeOutboundIPRanges: "{{ annotation .ObjectMeta `traffic.sidecar.istio.io/includeOutboundIPRanges` .Values.global.proxy.includeIPRanges }}" + traffic.sidecar.istio.io/excludeOutboundIPRanges: "{{ annotation .ObjectMeta `traffic.sidecar.istio.io/excludeOutboundIPRanges` .Values.global.proxy.excludeIPRanges }}" + traffic.sidecar.istio.io/includeInboundPorts: "{{ annotation .ObjectMeta `traffic.sidecar.istio.io/includeInboundPorts` (includeInboundPorts .Spec.Containers) }}" + traffic.sidecar.istio.io/excludeInboundPorts: "{{ excludeInboundPort (annotation .ObjectMeta `status.sidecar.istio.io/port` .Values.global.proxy.statusPort) (annotation .ObjectMeta `traffic.sidecar.istio.io/excludeInboundPorts` .Values.global.proxy.excludeInboundPorts) }}" + {{ if or (isset .ObjectMeta.Annotations `traffic.sidecar.istio.io/excludeOutboundPorts`) (ne .Values.global.proxy.excludeOutboundPorts "") }} + traffic.sidecar.istio.io/excludeOutboundPorts: "{{ annotation .ObjectMeta `traffic.sidecar.istio.io/excludeOutboundPorts` .Values.global.proxy.excludeOutboundPorts }}" + {{- end }} + traffic.sidecar.istio.io/kubevirtInterfaces: "{{ index .ObjectMeta.Annotations `traffic.sidecar.istio.io/kubevirtInterfaces` }}" + injectedAnnotations: + +--- +# Source: istio/charts/galley/templates/serviceaccount.yaml +apiVersion: v1 +kind: ServiceAccount +metadata: + name: istio-galley-service-account + namespace: istio-system + labels: + app: galley + chart: galley + heritage: Tiller + release: istio + +--- +# Source: istio/charts/gateways/templates/serviceaccount.yaml + +apiVersion: v1 +kind: ServiceAccount +metadata: + name: istio-egressgateway-service-account + namespace: istio-system + labels: + app: istio-egressgateway + chart: gateways + heritage: Tiller + release: istio +--- +apiVersion: v1 +kind: ServiceAccount +metadata: + name: istio-ingressgateway-service-account + namespace: istio-system + labels: + app: istio-ingressgateway + chart: gateways + heritage: Tiller + release: istio +--- + + +--- +# Source: istio/charts/grafana/templates/create-custom-resources-job.yaml +apiVersion: v1 +kind: ServiceAccount +metadata: + name: istio-grafana-post-install-account + namespace: istio-system + labels: + app: grafana + chart: grafana + heritage: Tiller + release: istio +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: istio-grafana-post-install-istio-system + labels: + app: grafana + chart: grafana + heritage: Tiller + release: istio +rules: +- apiGroups: ["authentication.istio.io"] # needed to create default authn policy + resources: ["*"] + verbs: ["*"] +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: istio-grafana-post-install-role-binding-istio-system + labels: + app: grafana + chart: grafana + heritage: Tiller + release: istio +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: istio-grafana-post-install-istio-system +subjects: + - kind: ServiceAccount + name: istio-grafana-post-install-account + namespace: istio-system +--- +apiVersion: batch/v1 +kind: Job +metadata: + name: istio-grafana-post-install-1.5.0 + namespace: istio-system + annotations: + "helm.sh/hook": post-install + "helm.sh/hook-delete-policy": hook-succeeded + labels: + app: grafana + chart: grafana + heritage: Tiller + release: istio +spec: + template: + metadata: + name: istio-grafana-post-install + labels: + app: istio-grafana + chart: grafana + heritage: Tiller + release: istio + annotations: + sidecar.istio.io/inject: "false" + spec: + serviceAccountName: istio-grafana-post-install-account + containers: + - name: kubectl + image: "docker.io/istio/kubectl:1.5.0" + command: [ "/bin/bash", "/tmp/grafana/run.sh", "/tmp/grafana/custom-resources.yaml" ] + volumeMounts: + - mountPath: "/tmp/grafana" + name: tmp-configmap-grafana + volumes: + - name: tmp-configmap-grafana + configMap: + name: istio-grafana-custom-resources + restartPolicy: OnFailure + affinity: + nodeAffinity: + requiredDuringSchedulingIgnoredDuringExecution: + nodeSelectorTerms: + - matchExpressions: + - key: beta.kubernetes.io/arch + operator: In + values: + - "amd64" + - "ppc64le" + - "s390x" + preferredDuringSchedulingIgnoredDuringExecution: + - weight: 2 + preference: + matchExpressions: + - key: beta.kubernetes.io/arch + operator: In + values: + - "amd64" + - weight: 2 + preference: + matchExpressions: + - key: beta.kubernetes.io/arch + operator: In + values: + - "ppc64le" + - weight: 2 + preference: + matchExpressions: + - key: beta.kubernetes.io/arch + operator: In + values: + - "s390x" + +--- +# Source: istio/charts/kiali/templates/serviceaccount.yaml +apiVersion: v1 +kind: ServiceAccount +metadata: + name: kiali-service-account + namespace: istio-system + labels: + app: kiali + chart: kiali + heritage: Tiller + release: istio + +--- +# Source: istio/charts/mixer/templates/serviceaccount.yaml + +apiVersion: v1 +kind: ServiceAccount +metadata: + name: istio-mixer-service-account + namespace: istio-system + labels: + app: mixer + chart: mixer + heritage: Tiller + release: istio + +--- +# Source: istio/charts/pilot/templates/serviceaccount.yaml +apiVersion: v1 +kind: ServiceAccount +metadata: + name: istio-pilot-service-account + namespace: istio-system + labels: + app: pilot + chart: pilot + heritage: Tiller + release: istio + +--- +# Source: istio/charts/prometheus/templates/serviceaccount.yaml +apiVersion: v1 +kind: ServiceAccount +metadata: + name: prometheus + namespace: istio-system + labels: + app: prometheus + chart: prometheus + heritage: Tiller + release: istio + +--- +# Source: istio/charts/security/templates/create-custom-resources-job.yaml + +apiVersion: v1 +kind: ServiceAccount +metadata: + name: istio-security-post-install-account + namespace: istio-system + labels: + app: security + chart: security + heritage: Tiller + release: istio +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: istio-security-post-install-istio-system + labels: + app: security + chart: security + heritage: Tiller + release: istio +rules: +- apiGroups: ["authentication.istio.io"] # needed to create default authn policy + resources: ["*"] + verbs: ["*"] +- apiGroups: ["networking.istio.io"] # needed to create security destination rules + resources: ["*"] + verbs: ["*"] +- apiGroups: ["admissionregistration.k8s.io"] + resources: ["validatingwebhookconfigurations"] + verbs: ["get"] +- apiGroups: ["extensions", "apps"] + resources: ["deployments", "replicasets"] + verbs: ["get", "list", "watch"] +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: istio-security-post-install-role-binding-istio-system + labels: + app: security + chart: security + heritage: Tiller + release: istio +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: istio-security-post-install-istio-system +subjects: + - kind: ServiceAccount + name: istio-security-post-install-account + namespace: istio-system +--- +apiVersion: batch/v1 +kind: Job +metadata: + name: istio-security-post-install-1.5.0 + namespace: istio-system + annotations: + "helm.sh/hook": post-install,post-upgrade + "helm.sh/hook-delete-policy": hook-succeeded + labels: + app: security + chart: security + heritage: Tiller + release: istio +spec: + template: + metadata: + name: istio-security-post-install + labels: + app: security + chart: security + heritage: Tiller + release: istio + annotations: + sidecar.istio.io/inject: "false" + spec: + serviceAccountName: istio-security-post-install-account + containers: + - name: kubectl + image: "docker.io/istio/kubectl:1.5.0" + imagePullPolicy: IfNotPresent + command: [ "/bin/bash", "/tmp/security/run.sh", "/tmp/security/custom-resources.yaml" ] + volumeMounts: + - mountPath: "/tmp/security" + name: tmp-configmap-security + volumes: + - name: tmp-configmap-security + configMap: + name: istio-security-custom-resources + restartPolicy: OnFailure + affinity: + nodeAffinity: + requiredDuringSchedulingIgnoredDuringExecution: + nodeSelectorTerms: + - matchExpressions: + - key: beta.kubernetes.io/arch + operator: In + values: + - "amd64" + - "ppc64le" + - "s390x" + preferredDuringSchedulingIgnoredDuringExecution: + - weight: 2 + preference: + matchExpressions: + - key: beta.kubernetes.io/arch + operator: In + values: + - "amd64" + - weight: 2 + preference: + matchExpressions: + - key: beta.kubernetes.io/arch + operator: In + values: + - "ppc64le" + - weight: 2 + preference: + matchExpressions: + - key: beta.kubernetes.io/arch + operator: In + values: + - "s390x" + +--- +# Source: istio/charts/security/templates/serviceaccount.yaml +apiVersion: v1 +kind: ServiceAccount +metadata: + name: istio-citadel-service-account + namespace: istio-system + labels: + app: security + chart: security + heritage: Tiller + release: istio + +--- +# Source: istio/charts/sidecarInjectorWebhook/templates/serviceaccount.yaml +apiVersion: v1 +kind: ServiceAccount +metadata: + name: istio-sidecar-injector-service-account + namespace: istio-system + labels: + app: sidecarInjectorWebhook + chart: sidecarInjectorWebhook + heritage: Tiller + release: istio + istio: sidecar-injector + +--- +# Source: istio/templates/serviceaccount.yaml +apiVersion: v1 +kind: ServiceAccount +metadata: + name: istio-multi + namespace: istio-system +--- +apiVersion: v1 +kind: ServiceAccount +metadata: + name: istio-reader + namespace: istio-system + +--- +# Source: istio/charts/galley/templates/clusterrole.yaml +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: istio-galley-istio-system + labels: + app: galley + chart: galley + heritage: Tiller + release: istio +rules: + # For reading Istio resources +- apiGroups: [ + "authentication.istio.io", + "config.istio.io", + "networking.istio.io", + "rbac.istio.io", + "security.istio.io"] + resources: ["*"] + verbs: ["get", "list", "watch"] + # For updating Istio resource statuses +- apiGroups: [ + "authentication.istio.io", + "config.istio.io", + "networking.istio.io", + "rbac.istio.io", + "security.istio.io"] + resources: ["*/status"] + verbs: ["update"] +- apiGroups: ["admissionregistration.k8s.io"] + resources: ["validatingwebhookconfigurations"] + verbs: ["get", "list", "watch", "update"] +# permissions to verify the webhook is ready and rejecting +# invalid config. We use --server-dry-run so no config is persisted. +- apiGroups: ["networking.istio.io"] + verbs: ["create"] + resources: ["gateways"] +- apiGroups: ["extensions","apps"] + resources: ["deployments"] + verbs: ["get", "list", "watch"] +- apiGroups: [""] + resources: ["pods", "nodes", "services", "endpoints", "namespaces"] + verbs: ["get", "list", "watch"] +- apiGroups: ["extensions"] + resources: ["ingresses"] + verbs: ["get", "list", "watch"] +- apiGroups: ["apiextensions.k8s.io"] + resources: ["customresourcedefinitions"] + verbs: ["get", "list", "watch"] +- apiGroups: ["rbac.authorization.k8s.io"] + resources: ["clusterroles"] + verbs: ["get", "list", "watch"] + +--- +# Source: istio/charts/kiali/templates/clusterrole.yaml +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: kiali + labels: + app: kiali + chart: kiali + heritage: Tiller + release: istio +rules: +- apiGroups: [""] + resources: + - configmaps + - endpoints + - namespaces + - nodes + - pods + - pods/log + - replicationcontrollers + - services + verbs: + - get + - list + - watch +- apiGroups: ["extensions", "apps"] + resources: + - deployments + - replicasets + - statefulsets + verbs: + - get + - list + - watch +- apiGroups: ["autoscaling"] + resources: + - horizontalpodautoscalers + verbs: + - get + - list + - watch +- apiGroups: ["batch"] + resources: + - cronjobs + - jobs + verbs: + - get + - list + - watch +- apiGroups: + - config.istio.io + - networking.istio.io + - authentication.istio.io + - rbac.istio.io + - security.istio.io + resources: ["*"] + verbs: + - create + - delete + - get + - list + - patch + - watch +- apiGroups: ["monitoring.kiali.io"] + resources: + - monitoringdashboards + verbs: + - get + - list +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: kiali-viewer + labels: + app: kiali + chart: kiali + heritage: Tiller + release: istio +rules: +- apiGroups: [""] + resources: + - configmaps + - endpoints + - namespaces + - nodes + - pods + - pods/log + - replicationcontrollers + - services + verbs: + - get + - list + - watch +- apiGroups: ["extensions", "apps"] + resources: + - deployments + - replicasets + - statefulsets + verbs: + - get + - list + - watch +- apiGroups: ["autoscaling"] + resources: + - horizontalpodautoscalers + verbs: + - get + - list + - watch +- apiGroups: ["batch"] + resources: + - cronjobs + - jobs + verbs: + - get + - list + - watch +- apiGroups: + - config.istio.io + - networking.istio.io + - authentication.istio.io + - rbac.istio.io + - security.istio.io + resources: ["*"] + verbs: + - get + - list + - watch +- apiGroups: ["monitoring.kiali.io"] + resources: + - monitoringdashboards + verbs: + - get + - list + +--- +# Source: istio/charts/mixer/templates/clusterrole.yaml + +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: istio-mixer-istio-system + labels: + app: mixer + chart: mixer + heritage: Tiller + release: istio +rules: +- apiGroups: ["config.istio.io"] # istio CRD watcher + resources: ["*"] + verbs: ["create", "get", "list", "watch", "patch"] +- apiGroups: ["apiextensions.k8s.io"] + resources: ["customresourcedefinitions"] + verbs: ["get", "list", "watch"] +- apiGroups: [""] + resources: ["configmaps", "endpoints", "pods", "services", "namespaces", "secrets", "replicationcontrollers"] + verbs: ["get", "list", "watch"] +- apiGroups: ["extensions", "apps"] + resources: ["replicasets"] + verbs: ["get", "list", "watch"] + +--- +# Source: istio/charts/pilot/templates/clusterrole.yaml +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: istio-pilot-istio-system + labels: + app: pilot + chart: pilot + heritage: Tiller + release: istio +rules: +- apiGroups: + - config.istio.io + - rbac.istio.io + - security.istio.io + - networking.istio.io + - authentication.istio.io + resources: ["*"] + verbs: ["get", "list", "watch"] +- apiGroups: ["extensions"] + resources: ["ingresses", "ingresses/status"] + verbs: ["*"] +- apiGroups: [""] + resources: ["configmaps"] + verbs: ["create", "get", "list", "watch", "update"] +- apiGroups: [""] + resources: ["endpoints", "pods", "services", "namespaces", "nodes"] + verbs: ["get", "list", "watch"] +- apiGroups: ["discovery.k8s.io"] + resources: ["endpointslices"] + verbs: ["get", "list", "watch"] +- apiGroups: [""] + resources: ["secrets"] + verbs: ["create", "get", "watch", "list", "update", "delete"] +- apiGroups: ["certificates.k8s.io"] + resources: + - "certificatesigningrequests" + - "certificatesigningrequests/approval" + - "certificatesigningrequests/status" + verbs: ["update", "create", "get", "delete"] + +--- +# Source: istio/charts/prometheus/templates/clusterrole.yaml +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: prometheus-istio-system + labels: + app: prometheus + chart: prometheus + heritage: Tiller + release: istio +rules: +- apiGroups: [""] + resources: + - nodes + - services + - endpoints + - pods + - nodes/proxy + verbs: ["get", "list", "watch"] +- apiGroups: [""] + resources: + - configmaps + verbs: ["get"] +- nonResourceURLs: ["/metrics"] + verbs: ["get"] + +--- +# Source: istio/charts/security/templates/clusterrole.yaml +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: istio-citadel-istio-system + labels: + app: security + chart: security + heritage: Tiller + release: istio +rules: +- apiGroups: [""] + resources: ["configmaps"] + verbs: ["create", "get", "update"] +- apiGroups: [""] + resources: ["secrets"] + verbs: ["create", "get", "watch", "list", "update", "delete"] +- apiGroups: [""] + resources: ["serviceaccounts", "services", "namespaces"] + verbs: ["get", "watch", "list"] +- apiGroups: ["authentication.k8s.io"] + resources: ["tokenreviews"] + verbs: ["create"] + +--- +# Source: istio/charts/sidecarInjectorWebhook/templates/clusterrole.yaml +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: istio-sidecar-injector-istio-system + labels: + app: sidecarInjectorWebhook + chart: sidecarInjectorWebhook + heritage: Tiller + release: istio + istio: sidecar-injector +rules: +- apiGroups: [""] + resources: ["configmaps"] + verbs: ["get", "list", "watch"] +- apiGroups: ["admissionregistration.k8s.io"] + resources: ["mutatingwebhookconfigurations"] + verbs: ["get", "list", "watch", "patch"] + +--- +# Source: istio/templates/clusterrole.yaml +kind: ClusterRole +apiVersion: rbac.authorization.k8s.io/v1 +metadata: + name: istio-reader +rules: + - apiGroups: [''] + resources: ['nodes', 'pods', 'services', 'endpoints', "replicationcontrollers"] + verbs: ['get', 'watch', 'list'] + - apiGroups: ["extensions", "apps"] + resources: ["replicasets"] + verbs: ["get", "list", "watch"] + +--- +# Source: istio/charts/galley/templates/clusterrolebinding.yaml +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: istio-galley-admin-role-binding-istio-system + labels: + app: galley + chart: galley + heritage: Tiller + release: istio +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: istio-galley-istio-system +subjects: + - kind: ServiceAccount + name: istio-galley-service-account + namespace: istio-system + +--- +# Source: istio/charts/kiali/templates/clusterrolebinding.yaml + +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: istio-kiali-admin-role-binding-istio-system + labels: + app: kiali + chart: kiali + heritage: Tiller + release: istio +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: kiali +subjects: +- kind: ServiceAccount + name: kiali-service-account + namespace: istio-system + +--- +# Source: istio/charts/mixer/templates/clusterrolebinding.yaml + +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: istio-mixer-admin-role-binding-istio-system + labels: + app: mixer + chart: mixer + heritage: Tiller + release: istio +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: istio-mixer-istio-system +subjects: + - kind: ServiceAccount + name: istio-mixer-service-account + namespace: istio-system + +--- +# Source: istio/charts/pilot/templates/clusterrolebinding.yaml +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: istio-pilot-istio-system + labels: + app: pilot + chart: pilot + heritage: Tiller + release: istio +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: istio-pilot-istio-system +subjects: + - kind: ServiceAccount + name: istio-pilot-service-account + namespace: istio-system + +--- +# Source: istio/charts/prometheus/templates/clusterrolebindings.yaml +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: prometheus-istio-system + labels: + app: prometheus + chart: prometheus + heritage: Tiller + release: istio +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: prometheus-istio-system +subjects: +- kind: ServiceAccount + name: prometheus + namespace: istio-system + +--- +# Source: istio/charts/security/templates/clusterrolebinding.yaml +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: istio-citadel-istio-system + labels: + app: security + chart: security + heritage: Tiller + release: istio +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: istio-citadel-istio-system +subjects: + - kind: ServiceAccount + name: istio-citadel-service-account + namespace: istio-system + +--- +# Source: istio/charts/sidecarInjectorWebhook/templates/clusterrolebinding.yaml +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: istio-sidecar-injector-admin-role-binding-istio-system + labels: + app: sidecarInjectorWebhook + chart: sidecarInjectorWebhook + heritage: Tiller + release: istio + istio: sidecar-injector +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: istio-sidecar-injector-istio-system +subjects: + - kind: ServiceAccount + name: istio-sidecar-injector-service-account + namespace: istio-system + +--- +# Source: istio/templates/clusterrolebinding.yaml +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: istio-multi + labels: + chart: istio-1.5.0 +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: istio-reader +subjects: +- kind: ServiceAccount + name: istio-multi + namespace: istio-system +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: istio-reader + labels: + chart: istio-1.5.0 +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: istio-reader +subjects: +- kind: ServiceAccount + name: istio-reader + namespace: istio-system + +--- +# Source: istio/charts/gateways/templates/role.yaml + +apiVersion: rbac.authorization.k8s.io/v1 +kind: Role +metadata: + name: istio-ingressgateway-sds + namespace: istio-system +rules: +- apiGroups: [""] + resources: ["secrets"] + verbs: ["get", "watch", "list"] +--- + +--- +# Source: istio/charts/gateways/templates/rolebindings.yaml + +apiVersion: rbac.authorization.k8s.io/v1 +kind: RoleBinding +metadata: + name: istio-ingressgateway-sds + namespace: istio-system +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: Role + name: istio-ingressgateway-sds +subjects: +- kind: ServiceAccount + name: istio-ingressgateway-service-account +--- + +--- +# Source: istio/charts/galley/templates/service.yaml +apiVersion: v1 +kind: Service +metadata: + name: istio-galley + namespace: istio-system + labels: + app: galley + chart: galley + heritage: Tiller + release: istio + istio: galley +spec: + ports: + - port: 443 + targetPort: 9443 + name: https-validation + - port: 15014 + name: http-monitoring + - port: 9901 + name: grpc-mcp + selector: + istio: galley + +--- +# Source: istio/charts/gateways/templates/service.yaml + +apiVersion: v1 +kind: Service +metadata: + name: istio-egressgateway + namespace: istio-system + annotations: + labels: + chart: gateways + heritage: Tiller + release: istio + app: istio-egressgateway + istio: egressgateway +spec: + type: ClusterIP + selector: + release: istio + app: istio-egressgateway + istio: egressgateway + ports: + - + name: http2 + port: 80 + - + name: https + port: 443 + - + name: tls + port: 15443 + targetPort: 15443 +--- +apiVersion: v1 +kind: Service +metadata: + name: istio-ingressgateway + namespace: istio-system + annotations: + labels: + chart: gateways + heritage: Tiller + release: istio + app: istio-ingressgateway + istio: ingressgateway +spec: + type: LoadBalancer + selector: + release: istio + app: istio-ingressgateway + istio: ingressgateway + ports: + - + name: status-port + port: 15020 + targetPort: 15020 + - + name: http2 + nodePort: 31380 + port: 80 + targetPort: 80 + - + name: https + nodePort: 31390 + port: 443 + - + name: tcp + nodePort: 31400 + port: 31400 + - + name: https-kiali + port: 15029 + targetPort: 15029 + - + name: https-prometheus + port: 15030 + targetPort: 15030 + - + name: https-grafana + port: 15031 + targetPort: 15031 + - + name: https-tracing + port: 15032 + targetPort: 15032 + - + name: tls + port: 15443 + targetPort: 15443 +--- + +--- +# Source: istio/charts/grafana/templates/service.yaml +apiVersion: v1 +kind: Service +metadata: + name: grafana + namespace: istio-system + annotations: + labels: + app: grafana + chart: grafana + heritage: Tiller + release: istio +spec: + type: ClusterIP + ports: + - port: 3000 + targetPort: 3000 + protocol: TCP + name: http + selector: + app: grafana + + +--- +# Source: istio/charts/kiali/templates/service.yaml +apiVersion: v1 +kind: Service +metadata: + name: kiali + namespace: istio-system + labels: + app: kiali + chart: kiali + heritage: Tiller + release: istio +spec: + ports: + - name: http-kiali + protocol: TCP + port: 20001 + selector: + app: kiali + +--- +# Source: istio/charts/mixer/templates/service.yaml + +apiVersion: v1 +kind: Service +metadata: + name: istio-policy + namespace: istio-system + annotations: + networking.istio.io/exportTo: "*" + labels: + app: mixer + chart: mixer + heritage: Tiller + release: istio + istio: mixer +spec: + ports: + - name: grpc-mixer + port: 9091 + - name: grpc-mixer-mtls + port: 15004 + - name: http-monitoring + port: 15014 + selector: + istio: mixer + istio-mixer-type: policy +--- +apiVersion: v1 +kind: Service +metadata: + name: istio-telemetry + namespace: istio-system + annotations: + networking.istio.io/exportTo: "*" + labels: + app: mixer + chart: mixer + heritage: Tiller + release: istio + istio: mixer +spec: + ports: + - name: grpc-mixer + port: 9091 + - name: grpc-mixer-mtls + port: 15004 + - name: http-monitoring + port: 15014 + - name: prometheus + port: 42422 + selector: + istio: mixer + istio-mixer-type: telemetry +--- + + +--- +# Source: istio/charts/pilot/templates/service.yaml +apiVersion: v1 +kind: Service +metadata: + name: istio-pilot + namespace: istio-system + labels: + app: pilot + chart: pilot + heritage: Tiller + release: istio + istio: pilot +spec: + ports: + - port: 15010 + name: grpc-xds # direct + - port: 15011 + name: https-xds # mTLS + - port: 8080 + name: http-legacy-discovery # direct + - port: 15014 + name: http-monitoring + selector: + istio: pilot + +--- +# Source: istio/charts/prometheus/templates/service.yaml +apiVersion: v1 +kind: Service +metadata: + name: prometheus + namespace: istio-system + annotations: + prometheus.io/scrape: 'true' + labels: + app: prometheus + chart: prometheus + heritage: Tiller + release: istio +spec: + selector: + app: prometheus + ports: + - name: http-prometheus + protocol: TCP + port: 9090 + +--- +# Source: istio/charts/security/templates/service.yaml +apiVersion: v1 +kind: Service +metadata: + # we use the normal name here (e.g. 'prometheus') + # as grafana is configured to use this as a data source + name: istio-citadel + namespace: istio-system + labels: + app: security + chart: security + heritage: Tiller + release: istio + istio: citadel +spec: + ports: + - name: grpc-citadel + port: 8060 + targetPort: 8060 + protocol: TCP + - name: http-monitoring + port: 15014 + selector: + istio: citadel + +--- +# Source: istio/charts/sidecarInjectorWebhook/templates/service.yaml +apiVersion: v1 +kind: Service +metadata: + name: istio-sidecar-injector + namespace: istio-system + labels: + app: sidecarInjectorWebhook + chart: sidecarInjectorWebhook + heritage: Tiller + release: istio + istio: sidecar-injector +spec: + ports: + - port: 443 + name: https-inject + targetPort: 9443 + - port: 15014 + name: http-monitoring + selector: + istio: sidecar-injector + +--- +# Source: istio/charts/galley/templates/deployment.yaml +apiVersion: apps/v1 +kind: Deployment +metadata: + name: istio-galley + namespace: istio-system + labels: + app: galley + chart: galley + heritage: Tiller + release: istio + istio: galley +spec: + replicas: 1 + selector: + matchLabels: + istio: galley + strategy: + rollingUpdate: + maxSurge: 100% + maxUnavailable: 25% + template: + metadata: + labels: + app: galley + chart: galley + heritage: Tiller + release: istio + istio: galley + annotations: + sidecar.istio.io/inject: "false" + spec: + serviceAccountName: istio-galley-service-account + containers: + - name: galley + image: "docker.io/istio/galley:1.5.0" + imagePullPolicy: IfNotPresent + ports: + - containerPort: 9443 + - containerPort: 15014 + - containerPort: 9901 + command: + - /usr/local/bin/galley + - server + - --meshConfigFile=/etc/mesh-config/mesh + - --livenessProbeInterval=1s + - --livenessProbePath=/tmp/healthliveness + - --readinessProbePath=/tmp/healthready + - --readinessProbeInterval=1s + - --deployment-namespace=istio-system + - --insecure=true + - --enable-reconcileWebhookConfiguration=true + - --monitoringPort=15014 + - --log_output_level=default:info + volumeMounts: + - name: certs + mountPath: /etc/certs + readOnly: true + - name: config + mountPath: /etc/config + readOnly: true + - name: mesh-config + mountPath: /etc/mesh-config + readOnly: true + livenessProbe: + exec: + command: + - /usr/local/bin/galley + - probe + - --probe-path=/tmp/healthliveness + - --interval=10s + initialDelaySeconds: 5 + periodSeconds: 5 + readinessProbe: + exec: + command: + - /usr/local/bin/galley + - probe + - --probe-path=/tmp/healthready + - --interval=10s + initialDelaySeconds: 5 + periodSeconds: 5 + resources: + requests: + cpu: 10m + + volumes: + - name: certs + secret: + secretName: istio.istio-galley-service-account + # galley expects /etc/config to exist even though it doesn't include any files. + - name: config + emptyDir: + medium: Memory + - name: mesh-config + configMap: + name: istio + affinity: + nodeAffinity: + requiredDuringSchedulingIgnoredDuringExecution: + nodeSelectorTerms: + - matchExpressions: + - key: beta.kubernetes.io/arch + operator: In + values: + - "amd64" + - "ppc64le" + - "s390x" + preferredDuringSchedulingIgnoredDuringExecution: + - weight: 2 + preference: + matchExpressions: + - key: beta.kubernetes.io/arch + operator: In + values: + - "amd64" + - weight: 2 + preference: + matchExpressions: + - key: beta.kubernetes.io/arch + operator: In + values: + - "ppc64le" + - weight: 2 + preference: + matchExpressions: + - key: beta.kubernetes.io/arch + operator: In + values: + - "s390x" +--- +# Source: istio/charts/gateways/templates/deployment.yaml + +apiVersion: apps/v1 +kind: Deployment +metadata: + name: istio-egressgateway + namespace: istio-system + labels: + app: istio-egressgateway + chart: gateways + heritage: Tiller + istio: egressgateway + release: istio + +spec: + replicas: 1 + selector: + matchLabels: + app: istio-egressgateway + istio: egressgateway + strategy: + rollingUpdate: + maxSurge: 100% + maxUnavailable: 25% + template: + metadata: + labels: + app: istio-egressgateway + chart: gateways + heritage: Tiller + istio: egressgateway + release: istio + + annotations: + sidecar.istio.io/inject: "false" + spec: + serviceAccountName: istio-egressgateway-service-account + containers: + - name: istio-proxy + image: "docker.io/istio/proxyv2:1.5.0" + imagePullPolicy: IfNotPresent + ports: + - containerPort: 80 + - containerPort: 443 + - containerPort: 15443 + - containerPort: 15090 + protocol: TCP + name: http-envoy-prom + args: + - proxy + - router + - --domain + - $(POD_NAMESPACE).svc.cluster.local + - --log_output_level=default:info + - --drainDuration + - '45s' #drainDuration + - --parentShutdownDuration + - '1m0s' #parentShutdownDuration + - --connectTimeout + - '10s' #connectTimeout + - --serviceCluster + - istio-egressgateway + - --zipkinAddress + - zipkin:9411 + - --proxyAdminPort + - "15000" + - --statusPort + - "15020" + - --controlPlaneAuthPolicy + - NONE + - --discoveryAddress + - istio-pilot:15010 + readinessProbe: + failureThreshold: 30 + httpGet: + path: /healthz/ready + port: 15020 + scheme: HTTP + initialDelaySeconds: 1 + periodSeconds: 2 + successThreshold: 1 + timeoutSeconds: 1 + resources: + limits: + cpu: 2000m + memory: 1024Mi + requests: + cpu: 10m + memory: 40Mi + + env: + - name: NODE_NAME + valueFrom: + fieldRef: + apiVersion: v1 + fieldPath: spec.nodeName + - name: POD_NAME + valueFrom: + fieldRef: + apiVersion: v1 + fieldPath: metadata.name + - name: POD_NAMESPACE + valueFrom: + fieldRef: + apiVersion: v1 + fieldPath: metadata.namespace + - name: INSTANCE_IP + valueFrom: + fieldRef: + apiVersion: v1 + fieldPath: status.podIP + - name: HOST_IP + valueFrom: + fieldRef: + apiVersion: v1 + fieldPath: status.hostIP + - name: SERVICE_ACCOUNT + valueFrom: + fieldRef: + fieldPath: spec.serviceAccountName + - name: ISTIO_AUTO_MTLS_ENABLED + value: "true" + - name: ISTIO_META_POD_NAME + valueFrom: + fieldRef: + apiVersion: v1 + fieldPath: metadata.name + - name: ISTIO_META_CONFIG_NAMESPACE + valueFrom: + fieldRef: + fieldPath: metadata.namespace + - name: ISTIO_METAJSON_LABELS + value: | + {"app":"istio-egressgateway","chart":"gateways","heritage":"Tiller","istio":"egressgateway","release":"istio"} + - name: ISTIO_META_CLUSTER_ID + value: "Kubernetes" + - name: SDS_ENABLED + value: "false" + - name: ISTIO_META_WORKLOAD_NAME + value: istio-egressgateway + - name: ISTIO_META_OWNER + value: kubernetes://apis/apps/v1/namespaces/istio-system/deployments/istio-egressgateway + - name: ISTIO_META_ROUTER_MODE + value: standard + + volumeMounts: + - name: istio-certs + mountPath: /etc/certs + readOnly: true + - name: egressgateway-certs + mountPath: "/etc/istio/egressgateway-certs" + readOnly: true + - name: egressgateway-ca-certs + mountPath: "/etc/istio/egressgateway-ca-certs" + readOnly: true + volumes: + - name: istio-certs + secret: + secretName: istio.istio-egressgateway-service-account + optional: true + - name: egressgateway-certs + secret: + secretName: "istio-egressgateway-certs" + optional: true + - name: egressgateway-ca-certs + secret: + secretName: "istio-egressgateway-ca-certs" + optional: true + affinity: + nodeAffinity: + requiredDuringSchedulingIgnoredDuringExecution: + nodeSelectorTerms: + - matchExpressions: + - key: beta.kubernetes.io/arch + operator: In + values: + - "amd64" + - "ppc64le" + - "s390x" + preferredDuringSchedulingIgnoredDuringExecution: + - weight: 2 + preference: + matchExpressions: + - key: beta.kubernetes.io/arch + operator: In + values: + - "amd64" + - weight: 2 + preference: + matchExpressions: + - key: beta.kubernetes.io/arch + operator: In + values: + - "ppc64le" + - weight: 2 + preference: + matchExpressions: + - key: beta.kubernetes.io/arch + operator: In + values: + - "s390x" +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: istio-ingressgateway + namespace: istio-system + labels: + app: istio-ingressgateway + chart: gateways + heritage: Tiller + istio: ingressgateway + release: istio + +spec: + replicas: 1 + selector: + matchLabels: + app: istio-ingressgateway + istio: ingressgateway + strategy: + rollingUpdate: + maxSurge: 100% + maxUnavailable: 25% + template: + metadata: + labels: + app: istio-ingressgateway + chart: gateways + heritage: Tiller + istio: ingressgateway + release: istio + + annotations: + sidecar.istio.io/inject: "false" + spec: + serviceAccountName: istio-ingressgateway-service-account + containers: + - name: istio-proxy + image: "docker.io/istio/proxyv2:1.5.0" + imagePullPolicy: IfNotPresent + ports: + - containerPort: 15020 + - containerPort: 80 + - containerPort: 443 + - containerPort: 31400 + - containerPort: 15029 + - containerPort: 15030 + - containerPort: 15031 + - containerPort: 15032 + - containerPort: 15443 + - containerPort: 15090 + protocol: TCP + name: http-envoy-prom + args: + - proxy + - router + - --domain + - $(POD_NAMESPACE).svc.cluster.local + - --log_output_level=default:info + - --drainDuration + - '45s' #drainDuration + - --parentShutdownDuration + - '1m0s' #parentShutdownDuration + - --connectTimeout + - '10s' #connectTimeout + - --serviceCluster + - istio-ingressgateway + - --zipkinAddress + - zipkin:9411 + - --proxyAdminPort + - "15000" + - --statusPort + - "15020" + - --controlPlaneAuthPolicy + - NONE + - --discoveryAddress + - istio-pilot:15010 + readinessProbe: + failureThreshold: 30 + httpGet: + path: /healthz/ready + port: 15020 + scheme: HTTP + initialDelaySeconds: 1 + periodSeconds: 2 + successThreshold: 1 + timeoutSeconds: 1 + resources: + limits: + cpu: 2000m + memory: 1024Mi + requests: + cpu: 10m + memory: 40Mi + + env: + - name: NODE_NAME + valueFrom: + fieldRef: + apiVersion: v1 + fieldPath: spec.nodeName + - name: POD_NAME + valueFrom: + fieldRef: + apiVersion: v1 + fieldPath: metadata.name + - name: POD_NAMESPACE + valueFrom: + fieldRef: + apiVersion: v1 + fieldPath: metadata.namespace + - name: INSTANCE_IP + valueFrom: + fieldRef: + apiVersion: v1 + fieldPath: status.podIP + - name: HOST_IP + valueFrom: + fieldRef: + apiVersion: v1 + fieldPath: status.hostIP + - name: SERVICE_ACCOUNT + valueFrom: + fieldRef: + fieldPath: spec.serviceAccountName + - name: ISTIO_AUTO_MTLS_ENABLED + value: "true" + - name: ISTIO_META_POD_NAME + valueFrom: + fieldRef: + apiVersion: v1 + fieldPath: metadata.name + - name: ISTIO_META_CONFIG_NAMESPACE + valueFrom: + fieldRef: + fieldPath: metadata.namespace + - name: ISTIO_METAJSON_LABELS + value: | + {"app":"istio-ingressgateway","chart":"gateways","heritage":"Tiller","istio":"ingressgateway","release":"istio"} + - name: ISTIO_META_CLUSTER_ID + value: "Kubernetes" + - name: SDS_ENABLED + value: "false" + - name: ISTIO_META_WORKLOAD_NAME + value: istio-ingressgateway + - name: ISTIO_META_OWNER + value: kubernetes://apis/apps/v1/namespaces/istio-system/deployments/istio-ingressgateway + - name: ISTIO_META_ROUTER_MODE + value: standard + + + volumeMounts: + - name: istio-certs + mountPath: /etc/certs + readOnly: true + - name: ingressgateway-certs + mountPath: "/etc/istio/ingressgateway-certs" + readOnly: true + - name: ingressgateway-ca-certs + mountPath: "/etc/istio/ingressgateway-ca-certs" + readOnly: true + volumes: + - name: istio-certs + secret: + secretName: istio.istio-ingressgateway-service-account + optional: true + - name: ingressgateway-certs + secret: + secretName: "istio-ingressgateway-certs" + optional: true + - name: ingressgateway-ca-certs + secret: + secretName: "istio-ingressgateway-ca-certs" + optional: true + affinity: + nodeAffinity: + requiredDuringSchedulingIgnoredDuringExecution: + nodeSelectorTerms: + - matchExpressions: + - key: beta.kubernetes.io/arch + operator: In + values: + - "amd64" + - "ppc64le" + - "s390x" + preferredDuringSchedulingIgnoredDuringExecution: + - weight: 2 + preference: + matchExpressions: + - key: beta.kubernetes.io/arch + operator: In + values: + - "amd64" + - weight: 2 + preference: + matchExpressions: + - key: beta.kubernetes.io/arch + operator: In + values: + - "ppc64le" + - weight: 2 + preference: + matchExpressions: + - key: beta.kubernetes.io/arch + operator: In + values: + - "s390x" +--- + +--- +# Source: istio/charts/grafana/templates/deployment.yaml +apiVersion: apps/v1 +kind: Deployment +metadata: + name: grafana + namespace: istio-system + labels: + app: grafana + chart: grafana + heritage: Tiller + release: istio +spec: + replicas: 1 + selector: + matchLabels: + app: grafana + template: + metadata: + labels: + app: grafana + chart: grafana + heritage: Tiller + release: istio + annotations: + sidecar.istio.io/inject: "false" + prometheus.io/scrape: "true" + spec: + securityContext: + runAsUser: 472 + fsGroup: 472 + containers: + - name: grafana + image: "grafana/grafana:6.4.3" + imagePullPolicy: IfNotPresent + ports: + - containerPort: 3000 + readinessProbe: + httpGet: + path: /api/health + port: 3000 + env: + - name: GRAFANA_PORT + value: "3000" + - name: GF_AUTH_BASIC_ENABLED + value: "false" + - name: GF_AUTH_ANONYMOUS_ENABLED + value: "true" + - name: GF_AUTH_ANONYMOUS_ORG_ROLE + value: Admin + - name: GF_PATHS_DATA + value: /data/grafana + resources: + requests: + cpu: 10m + + volumeMounts: + - name: data + mountPath: /data/grafana + - name: dashboards-istio-citadel-dashboard + mountPath: "/var/lib/grafana/dashboards/istio/citadel-dashboard.json" + subPath: citadel-dashboard.json + readOnly: true + - name: dashboards-istio-galley-dashboard + mountPath: "/var/lib/grafana/dashboards/istio/galley-dashboard.json" + subPath: galley-dashboard.json + readOnly: true + - name: dashboards-istio-istio-mesh-dashboard + mountPath: "/var/lib/grafana/dashboards/istio/istio-mesh-dashboard.json" + subPath: istio-mesh-dashboard.json + readOnly: true + - name: dashboards-istio-istio-performance-dashboard + mountPath: "/var/lib/grafana/dashboards/istio/istio-performance-dashboard.json" + subPath: istio-performance-dashboard.json + readOnly: true + - name: dashboards-istio-istio-service-dashboard + mountPath: "/var/lib/grafana/dashboards/istio/istio-service-dashboard.json" + subPath: istio-service-dashboard.json + readOnly: true + - name: dashboards-istio-istio-workload-dashboard + mountPath: "/var/lib/grafana/dashboards/istio/istio-workload-dashboard.json" + subPath: istio-workload-dashboard.json + readOnly: true + - name: dashboards-istio-mixer-dashboard + mountPath: "/var/lib/grafana/dashboards/istio/mixer-dashboard.json" + subPath: mixer-dashboard.json + readOnly: true + - name: dashboards-istio-pilot-dashboard + mountPath: "/var/lib/grafana/dashboards/istio/pilot-dashboard.json" + subPath: pilot-dashboard.json + readOnly: true + - name: config + mountPath: "/etc/grafana/provisioning/datasources/datasources.yaml" + subPath: datasources.yaml + - name: config + mountPath: "/etc/grafana/provisioning/dashboards/dashboardproviders.yaml" + subPath: dashboardproviders.yaml + affinity: + nodeAffinity: + requiredDuringSchedulingIgnoredDuringExecution: + nodeSelectorTerms: + - matchExpressions: + - key: beta.kubernetes.io/arch + operator: In + values: + - "amd64" + - "ppc64le" + - "s390x" + preferredDuringSchedulingIgnoredDuringExecution: + - weight: 2 + preference: + matchExpressions: + - key: beta.kubernetes.io/arch + operator: In + values: + - "amd64" + - weight: 2 + preference: + matchExpressions: + - key: beta.kubernetes.io/arch + operator: In + values: + - "ppc64le" + - weight: 2 + preference: + matchExpressions: + - key: beta.kubernetes.io/arch + operator: In + values: + - "s390x" + volumes: + - name: config + configMap: + name: istio-grafana + - name: data + emptyDir: {} + - name: dashboards-istio-citadel-dashboard + configMap: + name: istio-grafana-configuration-dashboards-citadel-dashboard + - name: dashboards-istio-galley-dashboard + configMap: + name: istio-grafana-configuration-dashboards-galley-dashboard + - name: dashboards-istio-istio-mesh-dashboard + configMap: + name: istio-grafana-configuration-dashboards-istio-mesh-dashboard + - name: dashboards-istio-istio-performance-dashboard + configMap: + name: istio-grafana-configuration-dashboards-istio-performance-dashboard + - name: dashboards-istio-istio-service-dashboard + configMap: + name: istio-grafana-configuration-dashboards-istio-service-dashboard + - name: dashboards-istio-istio-workload-dashboard + configMap: + name: istio-grafana-configuration-dashboards-istio-workload-dashboard + - name: dashboards-istio-mixer-dashboard + configMap: + name: istio-grafana-configuration-dashboards-mixer-dashboard + - name: dashboards-istio-pilot-dashboard + configMap: + name: istio-grafana-configuration-dashboards-pilot-dashboard + +--- +# Source: istio/charts/kiali/templates/deployment.yaml +apiVersion: apps/v1 +kind: Deployment +metadata: + name: kiali + namespace: istio-system + labels: + app: kiali + chart: kiali + heritage: Tiller + release: istio +spec: + replicas: 1 + selector: + matchLabels: + app: kiali + template: + metadata: + name: kiali + labels: + app: kiali + chart: kiali + heritage: Tiller + release: istio + annotations: + sidecar.istio.io/inject: "false" + scheduler.alpha.kubernetes.io/critical-pod: "" + prometheus.io/scrape: "true" + prometheus.io/port: "9090" + kiali.io/runtimes: go,kiali + spec: + serviceAccountName: kiali-service-account + containers: + - image: "quay.io/kiali/kiali:v1.9" + imagePullPolicy: IfNotPresent + name: kiali + command: + - "/opt/kiali/kiali" + - "-config" + - "/kiali-configuration/config.yaml" + - "-v" + - "3" + readinessProbe: + httpGet: + path: /kiali/healthz + port: 20001 + scheme: 'HTTP' + initialDelaySeconds: 5 + periodSeconds: 30 + livenessProbe: + httpGet: + path: /kiali/healthz + port: 20001 + scheme: 'HTTP' + initialDelaySeconds: 5 + periodSeconds: 30 + env: + - name: ACTIVE_NAMESPACE + valueFrom: + fieldRef: + fieldPath: metadata.namespace + volumeMounts: + - name: kiali-configuration + mountPath: "/kiali-configuration" + - name: kiali-cert + mountPath: "/kiali-cert" + - name: kiali-secret + mountPath: "/kiali-secret" + resources: + requests: + cpu: 10m + + volumes: + - name: kiali-configuration + configMap: + name: kiali + - name: kiali-cert + secret: + secretName: istio.kiali-service-account + optional: true + - name: kiali-secret + secret: + secretName: kiali + optional: true + affinity: + nodeAffinity: + requiredDuringSchedulingIgnoredDuringExecution: + nodeSelectorTerms: + - matchExpressions: + - key: beta.kubernetes.io/arch + operator: In + values: + - "amd64" + - "ppc64le" + - "s390x" + preferredDuringSchedulingIgnoredDuringExecution: + - weight: 2 + preference: + matchExpressions: + - key: beta.kubernetes.io/arch + operator: In + values: + - "amd64" + - weight: 2 + preference: + matchExpressions: + - key: beta.kubernetes.io/arch + operator: In + values: + - "ppc64le" + - weight: 2 + preference: + matchExpressions: + - key: beta.kubernetes.io/arch + operator: In + values: + - "s390x" + +--- +# Source: istio/charts/mixer/templates/deployment.yaml + +apiVersion: apps/v1 +kind: Deployment +metadata: + name: istio-policy + namespace: istio-system + labels: + app: istio-mixer + chart: mixer + heritage: Tiller + release: istio + istio: mixer +spec: + replicas: 1 + strategy: + rollingUpdate: + maxSurge: 100% + maxUnavailable: 25% + selector: + matchLabels: + istio: mixer + istio-mixer-type: policy + template: + metadata: + labels: + app: policy + chart: mixer + heritage: Tiller + release: istio + istio: mixer + istio-mixer-type: policy + annotations: + sidecar.istio.io/inject: "false" + spec: + serviceAccountName: istio-mixer-service-account + volumes: + - name: istio-certs + secret: + secretName: istio.istio-mixer-service-account + optional: true + - name: uds-socket + emptyDir: {} + - name: policy-adapter-secret + secret: + secretName: policy-adapter-secret + optional: true + affinity: + nodeAffinity: + requiredDuringSchedulingIgnoredDuringExecution: + nodeSelectorTerms: + - matchExpressions: + - key: beta.kubernetes.io/arch + operator: In + values: + - "amd64" + - "ppc64le" + - "s390x" + preferredDuringSchedulingIgnoredDuringExecution: + - weight: 2 + preference: + matchExpressions: + - key: beta.kubernetes.io/arch + operator: In + values: + - "amd64" + - weight: 2 + preference: + matchExpressions: + - key: beta.kubernetes.io/arch + operator: In + values: + - "ppc64le" + - weight: 2 + preference: + matchExpressions: + - key: beta.kubernetes.io/arch + operator: In + values: + - "s390x" + containers: + - name: mixer + image: "docker.io/istio/mixer:1.5.0" + imagePullPolicy: IfNotPresent + ports: + - containerPort: 15014 + - containerPort: 42422 + args: + - --monitoringPort=15014 + - --address + - unix:///sock/mixer.socket + - --log_output_level=default:info + - --configStoreURL=mcp://istio-galley.istio-system.svc:9901 + - --configDefaultNamespace=istio-system + - --useAdapterCRDs=false + - --useTemplateCRDs=false + - --trace_zipkin_url=http://zipkin.istio-system:9411/api/v1/spans + env: + - name: POD_NAMESPACE + valueFrom: + fieldRef: + apiVersion: v1 + fieldPath: metadata.namespace + - name: GOMAXPROCS + value: "6" + resources: + requests: + cpu: 10m + memory: 100Mi + + volumeMounts: + - name: istio-certs + mountPath: /etc/certs + readOnly: true + - name: uds-socket + mountPath: /sock + livenessProbe: + httpGet: + path: /version + port: 15014 + initialDelaySeconds: 5 + periodSeconds: 5 + - name: istio-proxy + image: "docker.io/istio/proxyv2:1.5.0" + imagePullPolicy: IfNotPresent + ports: + - containerPort: 9091 + - containerPort: 15004 + - containerPort: 15090 + protocol: TCP + name: http-envoy-prom + args: + - proxy + - --domain + - $(POD_NAMESPACE).svc.cluster.local + - --serviceCluster + - istio-policy + - --templateFile + - /etc/istio/proxy/envoy_policy.yaml.tmpl + - --controlPlaneAuthPolicy + - NONE + - --log_output_level=default:info + env: + - name: POD_NAME + valueFrom: + fieldRef: + apiVersion: v1 + fieldPath: metadata.name + - name: POD_NAMESPACE + valueFrom: + fieldRef: + apiVersion: v1 + fieldPath: metadata.namespace + - name: INSTANCE_IP + valueFrom: + fieldRef: + apiVersion: v1 + fieldPath: status.podIP + - name: SDS_ENABLED + value: "false" + resources: + limits: + cpu: 2000m + memory: 1024Mi + requests: + cpu: 10m + memory: 40Mi + + volumeMounts: + - name: istio-certs + mountPath: /etc/certs + readOnly: true + - name: uds-socket + mountPath: /sock + - name: policy-adapter-secret + mountPath: /var/run/secrets/istio.io/policy/adapter + readOnly: true + +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: istio-telemetry + namespace: istio-system + labels: + app: istio-mixer + chart: mixer + heritage: Tiller + release: istio + istio: mixer +spec: + replicas: 1 + strategy: + rollingUpdate: + maxSurge: 100% + maxUnavailable: 25% + selector: + matchLabels: + istio: mixer + istio-mixer-type: telemetry + template: + metadata: + labels: + app: telemetry + chart: mixer + heritage: Tiller + release: istio + istio: mixer + istio-mixer-type: telemetry + annotations: + sidecar.istio.io/inject: "false" + spec: + serviceAccountName: istio-mixer-service-account + volumes: + - name: istio-certs + secret: + secretName: istio.istio-mixer-service-account + optional: true + - name: uds-socket + emptyDir: {} + - name: telemetry-adapter-secret + secret: + secretName: telemetry-adapter-secret + optional: true + affinity: + nodeAffinity: + requiredDuringSchedulingIgnoredDuringExecution: + nodeSelectorTerms: + - matchExpressions: + - key: beta.kubernetes.io/arch + operator: In + values: + - "amd64" + - "ppc64le" + - "s390x" + preferredDuringSchedulingIgnoredDuringExecution: + - weight: 2 + preference: + matchExpressions: + - key: beta.kubernetes.io/arch + operator: In + values: + - "amd64" + - weight: 2 + preference: + matchExpressions: + - key: beta.kubernetes.io/arch + operator: In + values: + - "ppc64le" + - weight: 2 + preference: + matchExpressions: + - key: beta.kubernetes.io/arch + operator: In + values: + - "s390x" + containers: + - name: mixer + image: "docker.io/istio/mixer:1.5.0" + imagePullPolicy: IfNotPresent + ports: + - containerPort: 15014 + - containerPort: 42422 + args: + - --monitoringPort=15014 + - --address + - unix:///sock/mixer.socket + - --log_output_level=default:info + - --configStoreURL=mcp://istio-galley.istio-system.svc:9901 + - --configDefaultNamespace=istio-system + - --useAdapterCRDs=false + - --useTemplateCRDs=false + - --trace_zipkin_url=http://zipkin.istio-system:9411/api/v1/spans + - --averageLatencyThreshold + - 100ms + - --loadsheddingMode + - enforce + env: + - name: POD_NAMESPACE + valueFrom: + fieldRef: + apiVersion: v1 + fieldPath: metadata.namespace + - name: GOMAXPROCS + value: "6" + resources: + limits: + cpu: 4800m + memory: 4G + requests: + cpu: 50m + memory: 100Mi + + volumeMounts: + - name: istio-certs + mountPath: /etc/certs + readOnly: true + - name: telemetry-adapter-secret + mountPath: /var/run/secrets/istio.io/telemetry/adapter + readOnly: true + - name: uds-socket + mountPath: /sock + livenessProbe: + httpGet: + path: /version + port: 15014 + initialDelaySeconds: 5 + periodSeconds: 5 + - name: istio-proxy + image: "docker.io/istio/proxyv2:1.5.0" + imagePullPolicy: IfNotPresent + ports: + - containerPort: 9091 + - containerPort: 15004 + - containerPort: 15090 + protocol: TCP + name: http-envoy-prom + args: + - proxy + - --domain + - $(POD_NAMESPACE).svc.cluster.local + - --serviceCluster + - istio-telemetry + - --templateFile + - /etc/istio/proxy/envoy_telemetry.yaml.tmpl + - --controlPlaneAuthPolicy + - NONE + - --log_output_level=default:info + env: + - name: POD_NAME + valueFrom: + fieldRef: + apiVersion: v1 + fieldPath: metadata.name + - name: POD_NAMESPACE + valueFrom: + fieldRef: + apiVersion: v1 + fieldPath: metadata.namespace + - name: INSTANCE_IP + valueFrom: + fieldRef: + apiVersion: v1 + fieldPath: status.podIP + - name: SDS_ENABLED + value: "false" + resources: + limits: + cpu: 2000m + memory: 1024Mi + requests: + cpu: 10m + memory: 40Mi + + volumeMounts: + - name: istio-certs + mountPath: /etc/certs + readOnly: true + - name: uds-socket + mountPath: /sock + +--- + +--- +# Source: istio/charts/pilot/templates/deployment.yaml +apiVersion: apps/v1 +kind: Deployment +metadata: + name: istio-pilot + namespace: istio-system + # TODO: default template doesn't have this, which one is right ? + labels: + app: pilot + chart: pilot + heritage: Tiller + release: istio + istio: pilot +spec: + replicas: 1 + strategy: + rollingUpdate: + maxSurge: 100% + maxUnavailable: 25% + selector: + matchLabels: + istio: pilot + template: + metadata: + labels: + app: pilot + chart: pilot + heritage: Tiller + release: istio + istio: pilot + annotations: + sidecar.istio.io/inject: "false" + spec: + serviceAccountName: istio-pilot-service-account + containers: + - name: discovery + image: "docker.io/istio/pilot:1.5.0" + imagePullPolicy: IfNotPresent + args: + - "discovery" + - --monitoringAddr=:15014 + - --log_output_level=default:info + - --domain + - cluster.local + - --secureGrpcAddr + - "" + - --keepaliveMaxServerConnectionAge + - "30m" + ports: + - containerPort: 8080 + - containerPort: 15010 + readinessProbe: + httpGet: + path: /ready + port: 8080 + initialDelaySeconds: 5 + periodSeconds: 5 + timeoutSeconds: 5 + env: + - name: POD_NAME + valueFrom: + fieldRef: + apiVersion: v1 + fieldPath: metadata.name + - name: POD_NAMESPACE + valueFrom: + fieldRef: + apiVersion: v1 + fieldPath: metadata.namespace + - name: PILOT_PUSH_THROTTLE + value: "100" + - name: PILOT_TRACE_SAMPLING + value: "100" + - name: PILOT_ENABLE_PROTOCOL_SNIFFING_FOR_OUTBOUND + value: "true" + - name: PILOT_ENABLE_PROTOCOL_SNIFFING_FOR_INBOUND + value: "false" + resources: + requests: + cpu: 10m + memory: 100Mi + + volumeMounts: + - name: config-volume + mountPath: /etc/istio/config + - name: istio-certs + mountPath: /etc/certs + readOnly: true + - name: istio-proxy + image: "docker.io/istio/proxyv2:1.5.0" + imagePullPolicy: IfNotPresent + ports: + - containerPort: 15003 + - containerPort: 15005 + - containerPort: 15007 + - containerPort: 15011 + args: + - proxy + - --domain + - $(POD_NAMESPACE).svc.cluster.local + - --serviceCluster + - istio-pilot + - --templateFile + - /etc/istio/proxy/envoy_pilot.yaml.tmpl + - --controlPlaneAuthPolicy + - NONE + - --log_output_level=default:info + env: + - name: POD_NAME + valueFrom: + fieldRef: + apiVersion: v1 + fieldPath: metadata.name + - name: POD_NAMESPACE + valueFrom: + fieldRef: + apiVersion: v1 + fieldPath: metadata.namespace + - name: INSTANCE_IP + valueFrom: + fieldRef: + apiVersion: v1 + fieldPath: status.podIP + - name: SDS_ENABLED + value: "false" + resources: + limits: + cpu: 2000m + memory: 1024Mi + requests: + cpu: 10m + memory: 40Mi + + volumeMounts: + - name: istio-certs + mountPath: /etc/certs + readOnly: true + volumes: + - name: config-volume + configMap: + name: istio + - name: istio-certs + secret: + secretName: istio.istio-pilot-service-account + optional: true + affinity: + nodeAffinity: + requiredDuringSchedulingIgnoredDuringExecution: + nodeSelectorTerms: + - matchExpressions: + - key: beta.kubernetes.io/arch + operator: In + values: + - "amd64" + - "ppc64le" + - "s390x" + preferredDuringSchedulingIgnoredDuringExecution: + - weight: 2 + preference: + matchExpressions: + - key: beta.kubernetes.io/arch + operator: In + values: + - "amd64" + - weight: 2 + preference: + matchExpressions: + - key: beta.kubernetes.io/arch + operator: In + values: + - "ppc64le" + - weight: 2 + preference: + matchExpressions: + - key: beta.kubernetes.io/arch + operator: In + values: + - "s390x" + +--- +# Source: istio/charts/prometheus/templates/deployment.yaml +# TODO: the original template has service account, roles, etc +apiVersion: apps/v1 +kind: Deployment +metadata: + name: prometheus + namespace: istio-system + labels: + app: prometheus + chart: prometheus + heritage: Tiller + release: istio +spec: + replicas: 1 + selector: + matchLabels: + app: prometheus + template: + metadata: + labels: + app: prometheus + chart: prometheus + heritage: Tiller + release: istio + annotations: + sidecar.istio.io/inject: "false" + spec: + serviceAccountName: prometheus + containers: + - name: prometheus + image: "docker.io/prom/prometheus:v2.12.0" + imagePullPolicy: IfNotPresent + args: + - '--storage.tsdb.retention=6h' + - '--config.file=/etc/prometheus/prometheus.yml' + ports: + - containerPort: 9090 + name: http + livenessProbe: + httpGet: + path: /-/healthy + port: 9090 + readinessProbe: + httpGet: + path: /-/ready + port: 9090 + resources: + requests: + cpu: 10m + + volumeMounts: + - name: config-volume + mountPath: /etc/prometheus + - mountPath: /etc/istio-certs + name: istio-certs + volumes: + - name: config-volume + configMap: + name: prometheus + - name: istio-certs + secret: + defaultMode: 420 + secretName: istio.default + affinity: + nodeAffinity: + requiredDuringSchedulingIgnoredDuringExecution: + nodeSelectorTerms: + - matchExpressions: + - key: beta.kubernetes.io/arch + operator: In + values: + - "amd64" + - "ppc64le" + - "s390x" + preferredDuringSchedulingIgnoredDuringExecution: + - weight: 2 + preference: + matchExpressions: + - key: beta.kubernetes.io/arch + operator: In + values: + - "amd64" + - weight: 2 + preference: + matchExpressions: + - key: beta.kubernetes.io/arch + operator: In + values: + - "ppc64le" + - weight: 2 + preference: + matchExpressions: + - key: beta.kubernetes.io/arch + operator: In + values: + - "s390x" + +--- +# Source: istio/charts/security/templates/deployment.yaml +# istio CA watching all namespaces +apiVersion: apps/v1 +kind: Deployment +metadata: + name: istio-citadel + namespace: istio-system + labels: + app: security + chart: security + heritage: Tiller + release: istio + istio: citadel +spec: + replicas: 1 + selector: + matchLabels: + istio: citadel + strategy: + rollingUpdate: + maxSurge: 100% + maxUnavailable: 25% + template: + metadata: + labels: + app: security + chart: security + heritage: Tiller + release: istio + istio: citadel + annotations: + sidecar.istio.io/inject: "false" + spec: + serviceAccountName: istio-citadel-service-account + containers: + - name: citadel + image: "docker.io/istio/citadel:1.5.0" + imagePullPolicy: IfNotPresent + args: + - --append-dns-names=true + - --grpc-port=8060 + - --citadel-storage-namespace=istio-system + - --custom-dns-names=istio-pilot-service-account.istio-system:istio-pilot.istio-system + - --monitoring-port=15014 + - --self-signed-ca=true + - --workload-cert-ttl=2160h + env: + - name: CITADEL_ENABLE_NAMESPACES_BY_DEFAULT + value: "true" + resources: + requests: + cpu: 10m + + affinity: + nodeAffinity: + requiredDuringSchedulingIgnoredDuringExecution: + nodeSelectorTerms: + - matchExpressions: + - key: beta.kubernetes.io/arch + operator: In + values: + - "amd64" + - "ppc64le" + - "s390x" + preferredDuringSchedulingIgnoredDuringExecution: + - weight: 2 + preference: + matchExpressions: + - key: beta.kubernetes.io/arch + operator: In + values: + - "amd64" + - weight: 2 + preference: + matchExpressions: + - key: beta.kubernetes.io/arch + operator: In + values: + - "ppc64le" + - weight: 2 + preference: + matchExpressions: + - key: beta.kubernetes.io/arch + operator: In + values: + - "s390x" + +--- +# Source: istio/charts/sidecarInjectorWebhook/templates/deployment.yaml +apiVersion: apps/v1 +kind: Deployment +metadata: + name: istio-sidecar-injector + namespace: istio-system + labels: + app: sidecarInjectorWebhook + chart: sidecarInjectorWebhook + heritage: Tiller + release: istio + istio: sidecar-injector +spec: + replicas: 1 + selector: + matchLabels: + istio: sidecar-injector + strategy: + rollingUpdate: + maxSurge: 100% + maxUnavailable: 25% + template: + metadata: + labels: + app: sidecarInjectorWebhook + chart: sidecarInjectorWebhook + heritage: Tiller + release: istio + istio: sidecar-injector + annotations: + sidecar.istio.io/inject: "false" + spec: + serviceAccountName: istio-sidecar-injector-service-account + containers: + - name: sidecar-injector-webhook + image: "docker.io/istio/sidecar_injector:1.5.0" + imagePullPolicy: IfNotPresent + args: + - --caCertFile=/etc/istio/certs/root-cert.pem + - --tlsCertFile=/etc/istio/certs/cert-chain.pem + - --tlsKeyFile=/etc/istio/certs/key.pem + - --injectConfig=/etc/istio/inject/config + - --meshConfig=/etc/istio/config/mesh + - --healthCheckInterval=2s + - --healthCheckFile=/tmp/health + - --reconcileWebhookConfig=true + volumeMounts: + - name: config-volume + mountPath: /etc/istio/config + readOnly: true + - name: certs + mountPath: /etc/istio/certs + readOnly: true + - name: inject-config + mountPath: /etc/istio/inject + readOnly: true + livenessProbe: + exec: + command: + - /usr/local/bin/sidecar-injector + - probe + - --probe-path=/tmp/health + - --interval=4s + initialDelaySeconds: 4 + periodSeconds: 4 + readinessProbe: + exec: + command: + - /usr/local/bin/sidecar-injector + - probe + - --probe-path=/tmp/health + - --interval=4s + initialDelaySeconds: 4 + periodSeconds: 4 + resources: + requests: + cpu: 10m + + volumes: + - name: config-volume + configMap: + name: istio + - name: certs + secret: + secretName: istio.istio-sidecar-injector-service-account + - name: inject-config + configMap: + name: istio-sidecar-injector + items: + - key: config + path: config + - key: values + path: values + affinity: + nodeAffinity: + requiredDuringSchedulingIgnoredDuringExecution: + nodeSelectorTerms: + - matchExpressions: + - key: beta.kubernetes.io/arch + operator: In + values: + - "amd64" + - "ppc64le" + - "s390x" + preferredDuringSchedulingIgnoredDuringExecution: + - weight: 2 + preference: + matchExpressions: + - key: beta.kubernetes.io/arch + operator: In + values: + - "amd64" + - weight: 2 + preference: + matchExpressions: + - key: beta.kubernetes.io/arch + operator: In + values: + - "ppc64le" + - weight: 2 + preference: + matchExpressions: + - key: beta.kubernetes.io/arch + operator: In + values: + - "s390x" + +--- +# Source: istio/charts/tracing/templates/deployment-jaeger.yaml + + +apiVersion: apps/v1 +kind: Deployment +metadata: + name: istio-tracing + namespace: istio-system + labels: + app: jaeger + chart: tracing + heritage: Tiller + release: istio +spec: + selector: + matchLabels: + app: jaeger + template: + metadata: + labels: + app: jaeger + chart: tracing + heritage: Tiller + release: istio + annotations: + sidecar.istio.io/inject: "false" + prometheus.io/scrape: "true" + prometheus.io/port: "14269" + spec: + containers: + - name: jaeger + image: "docker.io/jaegertracing/all-in-one:1.16" + imagePullPolicy: IfNotPresent + ports: + - containerPort: 9411 + - containerPort: 16686 + - containerPort: 14250 + - containerPort: 14267 + - containerPort: 14268 + - containerPort: 14269 + - containerPort: 5775 + protocol: UDP + - containerPort: 6831 + protocol: UDP + - containerPort: 6832 + protocol: UDP + env: + - name: POD_NAMESPACE + valueFrom: + fieldRef: + apiVersion: v1 + fieldPath: metadata.namespace + - name: BADGER_EPHEMERAL + value: "false" + - name: SPAN_STORAGE_TYPE + value: "badger" + - name: BADGER_DIRECTORY_VALUE + value: "/badger/data" + - name: BADGER_DIRECTORY_KEY + value: "/badger/key" + - name: COLLECTOR_ZIPKIN_HTTP_PORT + value: "9411" + - name: MEMORY_MAX_TRACES + value: "50000" + - name: QUERY_BASE_PATH + value: /jaeger + livenessProbe: + httpGet: + path: / + port: 14269 + readinessProbe: + httpGet: + path: / + port: 14269 + volumeMounts: + - name: data + mountPath: /badger + resources: + requests: + cpu: 10m + + affinity: + nodeAffinity: + requiredDuringSchedulingIgnoredDuringExecution: + nodeSelectorTerms: + - matchExpressions: + - key: beta.kubernetes.io/arch + operator: In + values: + - "amd64" + - "ppc64le" + - "s390x" + preferredDuringSchedulingIgnoredDuringExecution: + - weight: 2 + preference: + matchExpressions: + - key: beta.kubernetes.io/arch + operator: In + values: + - "amd64" + - weight: 2 + preference: + matchExpressions: + - key: beta.kubernetes.io/arch + operator: In + values: + - "ppc64le" + - weight: 2 + preference: + matchExpressions: + - key: beta.kubernetes.io/arch + operator: In + values: + - "s390x" + volumes: + - name: data + emptyDir: {} + + +--- +# Source: istio/charts/tracing/templates/service-jaeger.yaml + + +apiVersion: v1 +kind: List +metadata: + name: jaeger-services + namespace: istio-system + labels: + app: jaeger + chart: tracing + heritage: Tiller + release: istio +items: +- apiVersion: v1 + kind: Service + metadata: + name: jaeger-query + namespace: istio-system + annotations: + labels: + app: jaeger + jaeger-infra: jaeger-service + chart: tracing + heritage: Tiller + release: istio + spec: + ports: + - name: query-http + port: 16686 + protocol: TCP + targetPort: 16686 + selector: + app: jaeger +- apiVersion: v1 + kind: Service + metadata: + name: jaeger-collector + namespace: istio-system + labels: + app: jaeger + jaeger-infra: collector-service + chart: tracing + heritage: Tiller + release: istio + spec: + ports: + - name: jaeger-collector-tchannel + port: 14267 + protocol: TCP + targetPort: 14267 + - name: jaeger-collector-http + port: 14268 + targetPort: 14268 + protocol: TCP + - name: jaeger-collector-grpc + port: 14250 + targetPort: 14250 + protocol: TCP + selector: + app: jaeger + type: ClusterIP +- apiVersion: v1 + kind: Service + metadata: + name: jaeger-collector-headless + namespace: istio-system + labels: + app: jaeger + jaeger-infra: collector-service + chart: tracing + heritage: Tiller + release: istio + spec: + ports: + - name: jaeger-collector-grpc + port: 14250 + targetPort: 14250 + protocol: TCP + selector: + app: jaeger + clusterIP: None +- apiVersion: v1 + kind: Service + metadata: + name: jaeger-agent + namespace: istio-system + labels: + app: jaeger + jaeger-infra: agent-service + chart: tracing + heritage: Tiller + release: istio + spec: + ports: + - name: agent-zipkin-thrift + port: 5775 + protocol: UDP + targetPort: 5775 + - name: agent-compact + port: 6831 + protocol: UDP + targetPort: 6831 + - name: agent-binary + port: 6832 + protocol: UDP + targetPort: 6832 + clusterIP: None + selector: + app: jaeger + + + +--- +# Source: istio/charts/tracing/templates/service.yaml +apiVersion: v1 +kind: List +metadata: + name: tracing-services + namespace: istio-system + labels: + app: jaeger + chart: tracing + heritage: Tiller + release: istio +items: +- apiVersion: v1 + kind: Service + metadata: + name: zipkin + namespace: istio-system + labels: + app: jaeger + chart: tracing + heritage: Tiller + release: istio + spec: + ports: + - port: 9411 + targetPort: 9411 + protocol: TCP + name: http + selector: + app: jaeger +- apiVersion: v1 + kind: Service + metadata: + name: tracing + namespace: istio-system + annotations: + labels: + app: jaeger + chart: tracing + heritage: Tiller + release: istio + spec: + type: ClusterIP + ports: + - name: http-query + port: 80 + protocol: TCP + + targetPort: 16686 + + selector: + app: jaeger + +--- +# Source: istio/charts/sidecarInjectorWebhook/templates/mutatingwebhook.yaml + +apiVersion: admissionregistration.k8s.io/v1beta1 +kind: MutatingWebhookConfiguration +metadata: + name: istio-sidecar-injector + labels: + app: sidecarInjectorWebhook + chart: sidecarInjectorWebhook + heritage: Tiller + release: istio +webhooks: + - name: sidecar-injector.istio.io + clientConfig: + service: + name: istio-sidecar-injector + namespace: istio-system + path: "/inject" + caBundle: "" + rules: + - operations: [ "CREATE" ] + apiGroups: [""] + apiVersions: ["v1"] + resources: ["pods"] + failurePolicy: Fail + namespaceSelector: + matchLabels: + istio-injection: enabled + +--- +# Source: istio/charts/galley/templates/validatingwebhookconfiguration.yaml.tpl + + + +--- +# Source: istio/charts/gateways/templates/autoscale.yaml + + +--- +# Source: istio/charts/gateways/templates/preconfigured.yaml + + +--- +# Source: istio/charts/grafana/templates/grafana-ports-mtls.yaml + + +--- +# Source: istio/charts/grafana/templates/ingress.yaml + +--- +# Source: istio/charts/grafana/templates/pvc.yaml + + +--- +# Source: istio/charts/grafana/templates/tests/test-grafana-connection.yaml + + +--- +# Source: istio/charts/kiali/templates/ingress.yaml + +--- +# Source: istio/charts/kiali/templates/tests/test-kiali-connection.yaml + + +--- +# Source: istio/charts/mixer/templates/autoscale.yaml + + +--- +# Source: istio/charts/pilot/templates/autoscale.yaml + + +--- +# Source: istio/charts/pilot/templates/configmap.yaml + + +--- +# Source: istio/charts/pilot/templates/meshexpansion.yaml + + + +--- +# Source: istio/charts/prometheus/templates/ingress.yaml + +--- +# Source: istio/charts/prometheus/templates/tests/test-prometheus-connection.yaml + + +--- +# Source: istio/charts/security/templates/enable-mesh-mtls.yaml + + +--- +# Source: istio/charts/security/templates/enable-mesh-permissive.yaml + + +--- +# Source: istio/charts/security/templates/meshexpansion.yaml + + +--- +# Source: istio/charts/security/templates/tests/test-citadel-connection.yaml + + +--- +# Source: istio/charts/tracing/templates/deployment-zipkin.yaml + + +--- +# Source: istio/charts/tracing/templates/ingress.yaml + +--- +# Source: istio/charts/tracing/templates/pvc.yaml + + +--- +# Source: istio/charts/tracing/templates/tests/test-tracing-connection.yaml + + +--- +# Source: istio/templates/endpoints.yaml + + +--- +# Source: istio/templates/install-custom-resources.sh.tpl + + +--- +# Source: istio/templates/service.yaml + + +--- +# Source: istio/charts/galley/templates/validatingwebhookconfiguration.yaml + +apiVersion: admissionregistration.k8s.io/v1beta1 +kind: ValidatingWebhookConfiguration +metadata: + name: istio-galley + labels: + app: galley + chart: galley + heritage: Tiller + release: istio + istio: galley +webhooks: + - name: pilot.validation.istio.io + clientConfig: + service: + name: istio-galley + namespace: istio-system + path: "/admitpilot" + caBundle: "" + rules: + - operations: + - CREATE + - UPDATE + apiGroups: + - config.istio.io + apiVersions: + - v1alpha2 + resources: + - httpapispecs + - httpapispecbindings + - quotaspecs + - quotaspecbindings + - operations: + - CREATE + - UPDATE + apiGroups: + - rbac.istio.io + apiVersions: + - "*" + resources: + - "*" + - operations: + - CREATE + - UPDATE + apiGroups: + - security.istio.io + apiVersions: + - "*" + resources: + - "*" + - operations: + - CREATE + - UPDATE + apiGroups: + - authentication.istio.io + apiVersions: + - "*" + resources: + - "*" + - operations: + - CREATE + - UPDATE + apiGroups: + - networking.istio.io + apiVersions: + - "*" + resources: + - destinationrules + - envoyfilters + - gateways + - serviceentries + - sidecars + - virtualservices + # Fail open until the validation webhook is ready. The webhook controller + # will update this to `Fail` and patch in the `caBundle` when the webhook + # endpoint is ready. + failurePolicy: Ignore + sideEffects: None + - name: mixer.validation.istio.io + clientConfig: + service: + name: istio-galley + namespace: istio-system + path: "/admitmixer" + caBundle: "" + rules: + - operations: + - CREATE + - UPDATE + apiGroups: + - config.istio.io + apiVersions: + - v1alpha2 + resources: + - rules + - attributemanifests + - adapters + - handlers + - instances + - templates + # Fail open until the validation webhook is ready. The webhook controller + # will update this to `Fail` and patch in the `caBundle` when the webhook + # endpoint is ready. + failurePolicy: Ignore + sideEffects: None +--- +# Source: istio/charts/mixer/templates/config.yaml + +apiVersion: "config.istio.io/v1alpha2" +kind: attributemanifest +metadata: + name: istioproxy + namespace: istio-system + labels: + app: mixer + chart: mixer + heritage: Tiller + release: istio +spec: + attributes: + origin.ip: + valueType: IP_ADDRESS + origin.uid: + valueType: STRING + origin.user: + valueType: STRING + request.headers: + valueType: STRING_MAP + request.id: + valueType: STRING + request.host: + valueType: STRING + request.method: + valueType: STRING + request.path: + valueType: STRING + request.url_path: + valueType: STRING + request.query_params: + valueType: STRING_MAP + request.reason: + valueType: STRING + request.referer: + valueType: STRING + request.scheme: + valueType: STRING + request.total_size: + valueType: INT64 + request.size: + valueType: INT64 + request.time: + valueType: TIMESTAMP + request.useragent: + valueType: STRING + response.code: + valueType: INT64 + response.duration: + valueType: DURATION + response.headers: + valueType: STRING_MAP + response.total_size: + valueType: INT64 + response.size: + valueType: INT64 + response.time: + valueType: TIMESTAMP + response.grpc_status: + valueType: STRING + response.grpc_message: + valueType: STRING + source.uid: + valueType: STRING + source.user: # DEPRECATED + valueType: STRING + source.principal: + valueType: STRING + destination.uid: + valueType: STRING + destination.principal: + valueType: STRING + destination.port: + valueType: INT64 + connection.event: + valueType: STRING + connection.id: + valueType: STRING + connection.received.bytes: + valueType: INT64 + connection.received.bytes_total: + valueType: INT64 + connection.sent.bytes: + valueType: INT64 + connection.sent.bytes_total: + valueType: INT64 + connection.duration: + valueType: DURATION + connection.mtls: + valueType: BOOL + connection.requested_server_name: + valueType: STRING + context.protocol: + valueType: STRING + context.proxy_error_code: + valueType: STRING + context.timestamp: + valueType: TIMESTAMP + context.time: + valueType: TIMESTAMP + # Deprecated, kept for compatibility + context.reporter.local: + valueType: BOOL + context.reporter.kind: + valueType: STRING + context.reporter.uid: + valueType: STRING + api.service: + valueType: STRING + api.version: + valueType: STRING + api.operation: + valueType: STRING + api.protocol: + valueType: STRING + request.auth.principal: + valueType: STRING + request.auth.audiences: + valueType: STRING + request.auth.presenter: + valueType: STRING + request.auth.claims: + valueType: STRING_MAP + request.auth.raw_claims: + valueType: STRING + request.api_key: + valueType: STRING + rbac.permissive.response_code: + valueType: STRING + rbac.permissive.effective_policy_id: + valueType: STRING + check.error_code: + valueType: INT64 + check.error_message: + valueType: STRING + check.cache_hit: + valueType: BOOL + quota.cache_hit: + valueType: BOOL + context.proxy_version: + valueType: STRING + +--- +apiVersion: "config.istio.io/v1alpha2" +kind: attributemanifest +metadata: + name: kubernetes + namespace: istio-system + labels: + app: mixer + chart: mixer + heritage: Tiller + release: istio +spec: + attributes: + source.ip: + valueType: IP_ADDRESS + source.labels: + valueType: STRING_MAP + source.metadata: + valueType: STRING_MAP + source.name: + valueType: STRING + source.namespace: + valueType: STRING + source.owner: + valueType: STRING + source.serviceAccount: + valueType: STRING + source.services: + valueType: STRING + source.workload.uid: + valueType: STRING + source.workload.name: + valueType: STRING + source.workload.namespace: + valueType: STRING + destination.ip: + valueType: IP_ADDRESS + destination.labels: + valueType: STRING_MAP + destination.metadata: + valueType: STRING_MAP + destination.owner: + valueType: STRING + destination.name: + valueType: STRING + destination.container.name: + valueType: STRING + destination.namespace: + valueType: STRING + destination.service.uid: + valueType: STRING + destination.service.name: + valueType: STRING + destination.service.namespace: + valueType: STRING + destination.service.host: + valueType: STRING + destination.serviceAccount: + valueType: STRING + destination.workload.uid: + valueType: STRING + destination.workload.name: + valueType: STRING + destination.workload.namespace: + valueType: STRING +--- +apiVersion: "config.istio.io/v1alpha2" +kind: handler +metadata: + name: stdio + namespace: istio-system + labels: + app: mixer + chart: mixer + heritage: Tiller + release: istio +spec: + compiledAdapter: stdio + params: + outputAsJson: true +--- +apiVersion: "config.istio.io/v1alpha2" +kind: instance +metadata: + name: accesslog + namespace: istio-system + labels: + app: mixer + chart: mixer + heritage: Tiller + release: istio +spec: + compiledTemplate: logentry + params: + severity: '"Info"' + timestamp: request.time + variables: + sourceIp: source.ip | ip("0.0.0.0") + sourceApp: source.labels["app"] | "" + sourcePrincipal: source.principal | "" + sourceName: source.name | "" + sourceWorkload: source.workload.name | "" + sourceNamespace: source.namespace | "" + sourceOwner: source.owner | "" + destinationApp: destination.labels["app"] | "" + destinationIp: destination.ip | ip("0.0.0.0") + destinationServiceHost: destination.service.host | request.host | "" + destinationWorkload: destination.workload.name | "" + destinationName: destination.name | "" + destinationNamespace: destination.namespace | "" + destinationOwner: destination.owner | "" + destinationPrincipal: destination.principal | "" + apiClaims: request.auth.raw_claims | "" + apiKey: request.api_key | request.headers["x-api-key"] | "" + protocol: api.protocol | context.protocol | "http" + method: request.method | "" + url: request.path | "" + responseCode: response.code | 0 + responseFlags: context.proxy_error_code | "" + responseSize: response.size | 0 + permissiveResponseCode: rbac.permissive.response_code | "none" + permissiveResponsePolicyID: rbac.permissive.effective_policy_id | "none" + requestSize: request.size | 0 + requestId: request.headers["x-request-id"] | "" + clientTraceId: request.headers["x-client-trace-id"] | "" + latency: response.duration | "0ms" + connection_security_policy: conditional((context.reporter.kind | "inbound") == "outbound", "unknown", conditional(connection.mtls | false, "mutual_tls", "none")) + requestedServerName: connection.requested_server_name | "" + userAgent: request.useragent | "" + responseTimestamp: response.time + receivedBytes: request.total_size | 0 + sentBytes: response.total_size | 0 + referer: request.referer | "" + httpAuthority: request.headers[":authority"] | request.host | "" + xForwardedFor: request.headers["x-forwarded-for"] | "0.0.0.0" + reporter: conditional((context.reporter.kind | "inbound") == "outbound", "source", "destination") + grpcStatus: response.grpc_status | "" + grpcMessage: response.grpc_message | "" + monitored_resource_type: '"global"' +--- +apiVersion: "config.istio.io/v1alpha2" +kind: instance +metadata: + name: tcpaccesslog + namespace: istio-system + labels: + app: mixer + chart: mixer + heritage: Tiller + release: istio +spec: + compiledTemplate: logentry + params: + severity: '"Info"' + timestamp: context.time | timestamp("2017-01-01T00:00:00Z") + variables: + connectionEvent: connection.event | "" + sourceIp: source.ip | ip("0.0.0.0") + sourceApp: source.labels["app"] | "" + sourcePrincipal: source.principal | "" + sourceName: source.name | "" + sourceWorkload: source.workload.name | "" + sourceNamespace: source.namespace | "" + sourceOwner: source.owner | "" + destinationApp: destination.labels["app"] | "" + destinationIp: destination.ip | ip("0.0.0.0") + destinationServiceHost: destination.service.host | "" + destinationWorkload: destination.workload.name | "" + destinationName: destination.name | "" + destinationNamespace: destination.namespace | "" + destinationOwner: destination.owner | "" + destinationPrincipal: destination.principal | "" + protocol: context.protocol | "tcp" + connectionDuration: connection.duration | "0ms" + connection_security_policy: conditional((context.reporter.kind | "inbound") == "outbound", "unknown", conditional(connection.mtls | false, "mutual_tls", "none")) + requestedServerName: connection.requested_server_name | "" + receivedBytes: connection.received.bytes | 0 + sentBytes: connection.sent.bytes | 0 + totalReceivedBytes: connection.received.bytes_total | 0 + totalSentBytes: connection.sent.bytes_total | 0 + reporter: conditional((context.reporter.kind | "inbound") == "outbound", "source", "destination") + responseFlags: context.proxy_error_code | "" + monitored_resource_type: '"global"' +--- +apiVersion: "config.istio.io/v1alpha2" +kind: rule +metadata: + name: stdio + namespace: istio-system + labels: + app: mixer + chart: mixer + heritage: Tiller + release: istio +spec: + match: context.protocol == "http" || context.protocol == "grpc" + actions: + - handler: stdio + instances: + - accesslog +--- +apiVersion: "config.istio.io/v1alpha2" +kind: rule +metadata: + name: stdiotcp + namespace: istio-system + labels: + app: mixer + chart: mixer + heritage: Tiller + release: istio +spec: + match: context.protocol == "tcp" + actions: + - handler: stdio + instances: + - tcpaccesslog +--- +apiVersion: "config.istio.io/v1alpha2" +kind: instance +metadata: + name: requestcount + namespace: istio-system + labels: + app: mixer + chart: mixer + heritage: Tiller + release: istio +spec: + compiledTemplate: metric + params: + value: "1" + dimensions: + reporter: conditional((context.reporter.kind | "inbound") == "outbound", "source", "destination") + source_workload: source.workload.name | "unknown" + source_workload_namespace: source.workload.namespace | "unknown" + source_principal: source.principal | "unknown" + source_app: source.labels["app"] | "unknown" + source_version: source.labels["version"] | "unknown" + destination_workload: destination.workload.name | "unknown" + destination_workload_namespace: destination.workload.namespace | "unknown" + destination_principal: destination.principal | "unknown" + destination_app: destination.labels["app"] | "unknown" + destination_version: destination.labels["version"] | "unknown" + destination_service: destination.service.host | conditional((destination.service.name | "unknown") == "unknown", "unknown", request.host) + destination_service_name: destination.service.name | "unknown" + destination_service_namespace: destination.service.namespace | "unknown" + request_protocol: api.protocol | context.protocol | "unknown" + response_code: response.code | 200 + grpc_response_status: response.grpc_status | "" + response_flags: context.proxy_error_code | "-" + connection_security_policy: conditional((context.reporter.kind | "inbound") == "outbound", "unknown", conditional(connection.mtls | false, "mutual_tls", "none")) + monitored_resource_type: '"UNSPECIFIED"' +--- +apiVersion: "config.istio.io/v1alpha2" +kind: instance +metadata: + name: requestduration + namespace: istio-system + labels: + app: mixer + chart: mixer + heritage: Tiller + release: istio +spec: + compiledTemplate: metric + params: + value: response.duration | "0ms" + dimensions: + reporter: conditional((context.reporter.kind | "inbound") == "outbound", "source", "destination") + source_workload: source.workload.name | "unknown" + source_workload_namespace: source.workload.namespace | "unknown" + source_principal: source.principal | "unknown" + source_app: source.labels["app"] | "unknown" + source_version: source.labels["version"] | "unknown" + destination_workload: destination.workload.name | "unknown" + destination_workload_namespace: destination.workload.namespace | "unknown" + destination_principal: destination.principal | "unknown" + destination_app: destination.labels["app"] | "unknown" + destination_version: destination.labels["version"] | "unknown" + destination_service: destination.service.host | conditional((destination.service.name | "unknown") == "unknown", "unknown", request.host) + destination_service_name: destination.service.name | "unknown" + destination_service_namespace: destination.service.namespace | "unknown" + request_protocol: api.protocol | context.protocol | "unknown" + response_code: response.code | 200 + grpc_response_status: response.grpc_status | "" + response_flags: context.proxy_error_code | "-" + connection_security_policy: conditional((context.reporter.kind | "inbound") == "outbound", "unknown", conditional(connection.mtls | false, "mutual_tls", "none")) + monitored_resource_type: '"UNSPECIFIED"' +--- +apiVersion: "config.istio.io/v1alpha2" +kind: instance +metadata: + name: requestsize + namespace: istio-system + labels: + app: mixer + chart: mixer + heritage: Tiller + release: istio +spec: + compiledTemplate: metric + params: + value: request.size | 0 + dimensions: + reporter: conditional((context.reporter.kind | "inbound") == "outbound", "source", "destination") + source_workload: source.workload.name | "unknown" + source_workload_namespace: source.workload.namespace | "unknown" + source_principal: source.principal | "unknown" + source_app: source.labels["app"] | "unknown" + source_version: source.labels["version"] | "unknown" + destination_workload: destination.workload.name | "unknown" + destination_workload_namespace: destination.workload.namespace | "unknown" + destination_principal: destination.principal | "unknown" + destination_app: destination.labels["app"] | "unknown" + destination_version: destination.labels["version"] | "unknown" + destination_service: destination.service.host | conditional((destination.service.name | "unknown") == "unknown", "unknown", request.host) + destination_service_name: destination.service.name | "unknown" + destination_service_namespace: destination.service.namespace | "unknown" + request_protocol: api.protocol | context.protocol | "unknown" + response_code: response.code | 200 + grpc_response_status: response.grpc_status | "" + response_flags: context.proxy_error_code | "-" + connection_security_policy: conditional((context.reporter.kind | "inbound") == "outbound", "unknown", conditional(connection.mtls | false, "mutual_tls", "none")) + monitored_resource_type: '"UNSPECIFIED"' +--- +apiVersion: "config.istio.io/v1alpha2" +kind: instance +metadata: + name: responsesize + namespace: istio-system + labels: + app: mixer + chart: mixer + heritage: Tiller + release: istio +spec: + compiledTemplate: metric + params: + value: response.size | 0 + dimensions: + reporter: conditional((context.reporter.kind | "inbound") == "outbound", "source", "destination") + source_workload: source.workload.name | "unknown" + source_workload_namespace: source.workload.namespace | "unknown" + source_principal: source.principal | "unknown" + source_app: source.labels["app"] | "unknown" + source_version: source.labels["version"] | "unknown" + destination_workload: destination.workload.name | "unknown" + destination_workload_namespace: destination.workload.namespace | "unknown" + destination_principal: destination.principal | "unknown" + destination_app: destination.labels["app"] | "unknown" + destination_version: destination.labels["version"] | "unknown" + destination_service: destination.service.host | conditional((destination.service.name | "unknown") == "unknown", "unknown", request.host) + destination_service_name: destination.service.name | "unknown" + destination_service_namespace: destination.service.namespace | "unknown" + request_protocol: api.protocol | context.protocol | "unknown" + response_code: response.code | 200 + grpc_response_status: response.grpc_status | "" + response_flags: context.proxy_error_code | "-" + connection_security_policy: conditional((context.reporter.kind | "inbound") == "outbound", "unknown", conditional(connection.mtls | false, "mutual_tls", "none")) + monitored_resource_type: '"UNSPECIFIED"' +--- +apiVersion: "config.istio.io/v1alpha2" +kind: instance +metadata: + name: tcpbytesent + namespace: istio-system + labels: + app: mixer + chart: mixer + heritage: Tiller + release: istio +spec: + compiledTemplate: metric + params: + value: connection.sent.bytes | 0 + dimensions: + reporter: conditional((context.reporter.kind | "inbound") == "outbound", "source", "destination") + source_workload: source.workload.name | "unknown" + source_workload_namespace: source.workload.namespace | "unknown" + source_principal: source.principal | "unknown" + source_app: source.labels["app"] | "unknown" + source_version: source.labels["version"] | "unknown" + destination_workload: destination.workload.name | "unknown" + destination_workload_namespace: destination.workload.namespace | "unknown" + destination_principal: destination.principal | "unknown" + destination_app: destination.labels["app"] | "unknown" + destination_version: destination.labels["version"] | "unknown" + destination_service: destination.service.host | "unknown" + destination_service_name: destination.service.name | "unknown" + destination_service_namespace: destination.service.namespace | "unknown" + connection_security_policy: conditional((context.reporter.kind | "inbound") == "outbound", "unknown", conditional(connection.mtls | false, "mutual_tls", "none")) + response_flags: context.proxy_error_code | "-" + monitored_resource_type: '"UNSPECIFIED"' +--- +apiVersion: "config.istio.io/v1alpha2" +kind: instance +metadata: + name: tcpbytereceived + namespace: istio-system + labels: + app: mixer + chart: mixer + heritage: Tiller + release: istio +spec: + compiledTemplate: metric + params: + value: connection.received.bytes | 0 + dimensions: + reporter: conditional((context.reporter.kind | "inbound") == "outbound", "source", "destination") + source_workload: source.workload.name | "unknown" + source_workload_namespace: source.workload.namespace | "unknown" + source_principal: source.principal | "unknown" + source_app: source.labels["app"] | "unknown" + source_version: source.labels["version"] | "unknown" + destination_workload: destination.workload.name | "unknown" + destination_workload_namespace: destination.workload.namespace | "unknown" + destination_principal: destination.principal | "unknown" + destination_app: destination.labels["app"] | "unknown" + destination_version: destination.labels["version"] | "unknown" + destination_service: destination.service.host | "unknown" + destination_service_name: destination.service.name | "unknown" + destination_service_namespace: destination.service.namespace | "unknown" + connection_security_policy: conditional((context.reporter.kind | "inbound") == "outbound", "unknown", conditional(connection.mtls | false, "mutual_tls", "none")) + response_flags: context.proxy_error_code | "-" + monitored_resource_type: '"UNSPECIFIED"' +--- +apiVersion: "config.istio.io/v1alpha2" +kind: instance +metadata: + name: tcpconnectionsopened + namespace: istio-system + labels: + app: mixer + chart: mixer + heritage: Tiller + release: istio +spec: + compiledTemplate: metric + params: + value: "1" + dimensions: + reporter: conditional((context.reporter.kind | "inbound") == "outbound", "source", "destination") + source_workload: source.workload.name | "unknown" + source_workload_namespace: source.workload.namespace | "unknown" + source_principal: source.principal | "unknown" + source_app: source.labels["app"] | "unknown" + source_version: source.labels["version"] | "unknown" + destination_workload: destination.workload.name | "unknown" + destination_workload_namespace: destination.workload.namespace | "unknown" + destination_principal: destination.principal | "unknown" + destination_app: destination.labels["app"] | "unknown" + destination_version: destination.labels["version"] | "unknown" + destination_service: destination.service.host | "unknown" + destination_service_name: destination.service.name | "unknown" + destination_service_namespace: destination.service.namespace | "unknown" + connection_security_policy: conditional((context.reporter.kind | "inbound") == "outbound", "unknown", conditional(connection.mtls | false, "mutual_tls", "none")) + response_flags: context.proxy_error_code | "-" + monitored_resource_type: '"UNSPECIFIED"' +--- +apiVersion: "config.istio.io/v1alpha2" +kind: instance +metadata: + name: tcpconnectionsclosed + namespace: istio-system + labels: + app: mixer + chart: mixer + heritage: Tiller + release: istio +spec: + compiledTemplate: metric + params: + value: "1" + dimensions: + reporter: conditional((context.reporter.kind | "inbound") == "outbound", "source", "destination") + source_workload: source.workload.name | "unknown" + source_workload_namespace: source.workload.namespace | "unknown" + source_principal: source.principal | "unknown" + source_app: source.labels["app"] | "unknown" + source_version: source.labels["version"] | "unknown" + destination_workload: destination.workload.name | "unknown" + destination_workload_namespace: destination.workload.namespace | "unknown" + destination_principal: destination.principal | "unknown" + destination_app: destination.labels["app"] | "unknown" + destination_version: destination.labels["version"] | "unknown" + destination_service: destination.service.host | "unknown" + destination_service_name: destination.service.name | "unknown" + destination_service_namespace: destination.service.namespace | "unknown" + connection_security_policy: conditional((context.reporter.kind | "inbound") == "outbound", "unknown", conditional(connection.mtls | false, "mutual_tls", "none")) + response_flags: context.proxy_error_code | "-" + monitored_resource_type: '"UNSPECIFIED"' +--- +apiVersion: "config.istio.io/v1alpha2" +kind: handler +metadata: + name: prometheus + namespace: istio-system + labels: + app: mixer + chart: mixer + heritage: Tiller + release: istio +spec: + compiledAdapter: prometheus + params: + metricsExpirationPolicy: + metricsExpiryDuration: "10m" + metrics: + - name: requests_total + instance_name: requestcount.instance.istio-system + kind: COUNTER + label_names: + - reporter + - source_app + - source_principal + - source_workload + - source_workload_namespace + - source_version + - destination_app + - destination_principal + - destination_workload + - destination_workload_namespace + - destination_version + - destination_service + - destination_service_name + - destination_service_namespace + - request_protocol + - response_code + - grpc_response_status + - response_flags + - connection_security_policy + - name: request_duration_seconds + instance_name: requestduration.instance.istio-system + kind: DISTRIBUTION + label_names: + - reporter + - source_app + - source_principal + - source_workload + - source_workload_namespace + - source_version + - destination_app + - destination_principal + - destination_workload + - destination_workload_namespace + - destination_version + - destination_service + - destination_service_name + - destination_service_namespace + - request_protocol + - response_code + - grpc_response_status + - response_flags + - connection_security_policy + buckets: + explicit_buckets: + bounds: [0.005, 0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 1, 2.5, 5, 10] + - name: request_bytes + instance_name: requestsize.instance.istio-system + kind: DISTRIBUTION + label_names: + - reporter + - source_app + - source_principal + - source_workload + - source_workload_namespace + - source_version + - destination_app + - destination_principal + - destination_workload + - destination_workload_namespace + - destination_version + - destination_service + - destination_service_name + - destination_service_namespace + - request_protocol + - response_code + - grpc_response_status + - response_flags + - connection_security_policy + buckets: + exponentialBuckets: + numFiniteBuckets: 8 + scale: 1 + growthFactor: 10 + - name: response_bytes + instance_name: responsesize.instance.istio-system + kind: DISTRIBUTION + label_names: + - reporter + - source_app + - source_principal + - source_workload + - source_workload_namespace + - source_version + - destination_app + - destination_principal + - destination_workload + - destination_workload_namespace + - destination_version + - destination_service + - destination_service_name + - destination_service_namespace + - request_protocol + - response_code + - grpc_response_status + - response_flags + - connection_security_policy + buckets: + exponentialBuckets: + numFiniteBuckets: 8 + scale: 1 + growthFactor: 10 + - name: tcp_sent_bytes_total + instance_name: tcpbytesent.instance.istio-system + kind: COUNTER + label_names: + - reporter + - source_app + - source_principal + - source_workload + - source_workload_namespace + - source_version + - destination_app + - destination_principal + - destination_workload + - destination_workload_namespace + - destination_version + - destination_service + - destination_service_name + - destination_service_namespace + - connection_security_policy + - response_flags + - name: tcp_received_bytes_total + instance_name: tcpbytereceived.instance.istio-system + kind: COUNTER + label_names: + - reporter + - source_app + - source_principal + - source_workload + - source_workload_namespace + - source_version + - destination_app + - destination_principal + - destination_workload + - destination_workload_namespace + - destination_version + - destination_service + - destination_service_name + - destination_service_namespace + - connection_security_policy + - response_flags + - name: tcp_connections_opened_total + instance_name: tcpconnectionsopened.instance.istio-system + kind: COUNTER + label_names: + - reporter + - source_app + - source_principal + - source_workload + - source_workload_namespace + - source_version + - destination_app + - destination_principal + - destination_workload + - destination_workload_namespace + - destination_version + - destination_service + - destination_service_name + - destination_service_namespace + - connection_security_policy + - response_flags + - name: tcp_connections_closed_total + instance_name: tcpconnectionsclosed.instance.istio-system + kind: COUNTER + label_names: + - reporter + - source_app + - source_principal + - source_workload + - source_workload_namespace + - source_version + - destination_app + - destination_principal + - destination_workload + - destination_workload_namespace + - destination_version + - destination_service + - destination_service_name + - destination_service_namespace + - connection_security_policy + - response_flags +--- +apiVersion: "config.istio.io/v1alpha2" +kind: rule +metadata: + name: promhttp + namespace: istio-system + labels: + app: mixer + chart: mixer + heritage: Tiller + release: istio +spec: + match: (context.protocol == "http" || context.protocol == "grpc") && (match((request.useragent | "-"), "kube-probe*") == false) && (match((request.useragent | "-"), "Prometheus*") == false) + actions: + - handler: prometheus + instances: + - requestcount + - requestduration + - requestsize + - responsesize +--- +apiVersion: "config.istio.io/v1alpha2" +kind: rule +metadata: + name: promtcp + namespace: istio-system + labels: + app: mixer + chart: mixer + heritage: Tiller + release: istio +spec: + match: context.protocol == "tcp" + actions: + - handler: prometheus + instances: + - tcpbytesent + - tcpbytereceived +--- +apiVersion: "config.istio.io/v1alpha2" +kind: rule +metadata: + name: promtcpconnectionopen + namespace: istio-system + labels: + app: mixer + chart: mixer + heritage: Tiller + release: istio +spec: + match: context.protocol == "tcp" && ((connection.event | "na") == "open") + actions: + - handler: prometheus + instances: + - tcpconnectionsopened +--- +apiVersion: "config.istio.io/v1alpha2" +kind: rule +metadata: + name: promtcpconnectionclosed + namespace: istio-system + labels: + app: mixer + chart: mixer + heritage: Tiller + release: istio +spec: + match: context.protocol == "tcp" && ((connection.event | "na") == "close") + actions: + - handler: prometheus + instances: + - tcpconnectionsclosed +--- +apiVersion: "config.istio.io/v1alpha2" +kind: handler +metadata: + name: kubernetesenv + namespace: istio-system + labels: + app: mixer + chart: mixer + heritage: Tiller + release: istio +spec: + compiledAdapter: kubernetesenv + params: {} + # when running from mixer root, use the following config after adding a + # symbolic link to a kubernetes config file via: + # + # $ ln -s ~/.kube/config mixer/adapter/kubernetes/kubeconfig + # + # kubeconfig_path: "mixer/adapter/kubernetes/kubeconfig" + +--- +apiVersion: "config.istio.io/v1alpha2" +kind: rule +metadata: + name: kubeattrgenrulerule + namespace: istio-system + labels: + app: mixer + chart: mixer + heritage: Tiller + release: istio +spec: + actions: + - handler: kubernetesenv + instances: + - attributes +--- +apiVersion: "config.istio.io/v1alpha2" +kind: rule +metadata: + name: tcpkubeattrgenrulerule + namespace: istio-system + labels: + app: mixer + chart: mixer + heritage: Tiller + release: istio +spec: + match: context.protocol == "tcp" + actions: + - handler: kubernetesenv + instances: + - attributes +--- +apiVersion: "config.istio.io/v1alpha2" +kind: instance +metadata: + name: attributes + namespace: istio-system + labels: + app: mixer + chart: mixer + heritage: Tiller + release: istio +spec: + compiledTemplate: kubernetes + params: + # Pass the required attribute data to the adapter + source_uid: source.uid | "" + source_ip: source.ip | ip("0.0.0.0") # default to unspecified ip addr + destination_uid: destination.uid | "" + destination_port: destination.port | 0 + attributeBindings: + # Fill the new attributes from the adapter produced output. + # $out refers to an instance of OutputTemplate message + source.ip: $out.source_pod_ip | ip("0.0.0.0") + source.uid: $out.source_pod_uid | "unknown" + source.labels: $out.source_labels | emptyStringMap() + source.name: $out.source_pod_name | "unknown" + source.namespace: $out.source_namespace | "default" + source.owner: $out.source_owner | "unknown" + source.serviceAccount: $out.source_service_account_name | "unknown" + source.workload.uid: $out.source_workload_uid | "unknown" + source.workload.name: $out.source_workload_name | "unknown" + source.workload.namespace: $out.source_workload_namespace | "unknown" + destination.ip: $out.destination_pod_ip | ip("0.0.0.0") + destination.uid: $out.destination_pod_uid | "unknown" + destination.labels: $out.destination_labels | emptyStringMap() + destination.name: $out.destination_pod_name | "unknown" + destination.container.name: $out.destination_container_name | "unknown" + destination.namespace: $out.destination_namespace | "default" + destination.owner: $out.destination_owner | "unknown" + destination.serviceAccount: $out.destination_service_account_name | "unknown" + destination.workload.uid: $out.destination_workload_uid | "unknown" + destination.workload.name: $out.destination_workload_name | "unknown" + destination.workload.namespace: $out.destination_workload_namespace | "unknown" +--- +# Configuration needed by Mixer. +# Mixer cluster is delivered via CDS +# Specify mixer cluster settings +apiVersion: networking.istio.io/v1alpha3 +kind: DestinationRule +metadata: + name: istio-policy + namespace: istio-system + labels: + app: mixer + chart: mixer + heritage: Tiller + release: istio +spec: + host: istio-policy.istio-system.svc.cluster.local + trafficPolicy: + portLevelSettings: + - port: + number: 15004 # grpc-mixer-mtls + tls: + mode: ISTIO_MUTUAL + - port: + number: 9091 # grpc-mixer + tls: + mode: DISABLE + connectionPool: + http: + http2MaxRequests: 10000 + maxRequestsPerConnection: 10000 +--- +apiVersion: networking.istio.io/v1alpha3 +kind: DestinationRule +metadata: + name: istio-telemetry + namespace: istio-system + labels: + app: mixer + chart: mixer + heritage: Tiller + release: istio +spec: + host: istio-telemetry.istio-system.svc.cluster.local + trafficPolicy: + portLevelSettings: + - port: + number: 15004 # grpc-mixer-mtls + tls: + mode: ISTIO_MUTUAL + - port: + number: 9091 # grpc-mixer + tls: + mode: DISABLE + connectionPool: + http: + http2MaxRequests: 10000 + maxRequestsPerConnection: 10000 +--- + diff --git a/istio-manifests/namespace.yaml b/istio-manifests/namespace.yaml new file mode 100644 index 0000000..96fb18e --- /dev/null +++ b/istio-manifests/namespace.yaml @@ -0,0 +1,7 @@ +apiVersion: v1 +kind: Namespace +metadata: + name: istio-system + labels: + istio-injection: disabled +--- diff --git a/kubernetes-manifests-tracing/README.md b/kubernetes-manifests-tracing/README.md new file mode 100644 index 0000000..ed852b7 --- /dev/null +++ b/kubernetes-manifests-tracing/README.md @@ -0,0 +1,8 @@ +# ./kubernetes-manifests + +:warning: Kubernetes manifests provided in this directory are not directly +deployable to a cluster. They are meant to be used with `skaffold` command to +insert the correct `image:` tags. + +Use the manifests in [/release](/release) directory which are configured with +pre-built public images. diff --git a/kubernetes-manifests-tracing/adservice.yaml b/kubernetes-manifests-tracing/adservice.yaml new file mode 100644 index 0000000..4cb02bc --- /dev/null +++ b/kubernetes-manifests-tracing/adservice.yaml @@ -0,0 +1,72 @@ +# Copyright 2018 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +apiVersion: apps/v1 +kind: Deployment +metadata: + name: adservice +spec: + selector: + matchLabels: + app: adservice + template: + metadata: + labels: + app: adservice + spec: + terminationGracePeriodSeconds: 5 + containers: + - name: server + image: adservice + ports: + - containerPort: 9555 + env: + - name: PORT + value: "9555" + # - name: DISABLE_STATS + # value: "1" + # - name: DISABLE_TRACING + # value: "1" + - name: JAEGER_SERVICE_ADDR + value: "jaeger-collector:14268" + resources: + requests: + cpu: 200m + memory: 180Mi + limits: + cpu: 300m + memory: 300Mi + readinessProbe: + initialDelaySeconds: 20 + periodSeconds: 15 + exec: + command: ["/bin/grpc_health_probe", "-addr=:9555"] + livenessProbe: + initialDelaySeconds: 20 + periodSeconds: 15 + exec: + command: ["/bin/grpc_health_probe", "-addr=:9555"] +--- +apiVersion: v1 +kind: Service +metadata: + name: adservice +spec: + type: ClusterIP + selector: + app: adservice + ports: + - name: grpc + port: 9555 + targetPort: 9555 diff --git a/kubernetes-manifests-tracing/cartservice.yaml b/kubernetes-manifests-tracing/cartservice.yaml new file mode 100644 index 0000000..31175da --- /dev/null +++ b/kubernetes-manifests-tracing/cartservice.yaml @@ -0,0 +1,69 @@ +# Copyright 2018 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +apiVersion: apps/v1 +kind: Deployment +metadata: + name: cartservice +spec: + selector: + matchLabels: + app: cartservice + template: + metadata: + labels: + app: cartservice + spec: + terminationGracePeriodSeconds: 5 + containers: + - name: server + image: cartservice + ports: + - containerPort: 7070 + env: + - name: REDIS_ADDR + value: "redis-cart:6379" + - name: PORT + value: "7070" + - name: LISTEN_ADDR + value: "0.0.0.0" + resources: + requests: + cpu: 200m + memory: 64Mi + limits: + cpu: 300m + memory: 128Mi + readinessProbe: + initialDelaySeconds: 15 + exec: + command: ["/bin/grpc_health_probe", "-addr=:7070", "-rpc-timeout=5s"] + livenessProbe: + initialDelaySeconds: 15 + periodSeconds: 10 + exec: + command: ["/bin/grpc_health_probe", "-addr=:7070", "-rpc-timeout=5s"] +--- +apiVersion: v1 +kind: Service +metadata: + name: cartservice +spec: + type: ClusterIP + selector: + app: cartservice + ports: + - name: grpc + port: 7070 + targetPort: 7070 diff --git a/kubernetes-manifests-tracing/checkoutservice.yaml b/kubernetes-manifests-tracing/checkoutservice.yaml new file mode 100644 index 0000000..0016509 --- /dev/null +++ b/kubernetes-manifests-tracing/checkoutservice.yaml @@ -0,0 +1,81 @@ +# Copyright 2018 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +apiVersion: apps/v1 +kind: Deployment +metadata: + name: checkoutservice +spec: + selector: + matchLabels: + app: checkoutservice + template: + metadata: + labels: + app: checkoutservice + spec: + containers: + - name: server + image: checkoutservice + ports: + - containerPort: 5050 + readinessProbe: + exec: + command: ["/bin/grpc_health_probe", "-addr=:5050"] + livenessProbe: + exec: + command: ["/bin/grpc_health_probe", "-addr=:5050"] + env: + - name: PORT + value: "5050" + - name: PRODUCT_CATALOG_SERVICE_ADDR + value: "productcatalogservice:3550" + - name: SHIPPING_SERVICE_ADDR + value: "shippingservice:50051" + - name: PAYMENT_SERVICE_ADDR + value: "paymentservice:50051" + - name: EMAIL_SERVICE_ADDR + value: "emailservice:5000" + - name: CURRENCY_SERVICE_ADDR + value: "currencyservice:7000" + - name: CART_SERVICE_ADDR + value: "cartservice:7070" + # - name: DISABLE_STATS + # value: "1" + # - name: DISABLE_TRACING + # value: "1" + # - name: DISABLE_PROFILER + # value: "1" + - name: JAEGER_SERVICE_ADDR + value: "jaeger-collector:14268" + resources: + requests: + cpu: 100m + memory: 64Mi + limits: + cpu: 200m + memory: 128Mi +--- +apiVersion: v1 +kind: Service +metadata: + name: checkoutservice +spec: + type: ClusterIP + selector: + app: checkoutservice + ports: + - name: grpc + port: 5050 + targetPort: 5050 diff --git a/kubernetes-manifests-tracing/currencyservice.yaml b/kubernetes-manifests-tracing/currencyservice.yaml new file mode 100644 index 0000000..5c10ec7 --- /dev/null +++ b/kubernetes-manifests-tracing/currencyservice.yaml @@ -0,0 +1,69 @@ +# Copyright 2018 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +apiVersion: apps/v1 +kind: Deployment +metadata: + name: currencyservice +spec: + selector: + matchLabels: + app: currencyservice + template: + metadata: + labels: + app: currencyservice + spec: + terminationGracePeriodSeconds: 5 + containers: + - name: server + image: currencyservice + ports: + - name: grpc + containerPort: 7000 + env: + - name: PORT + value: "7000" + # - name: DISABLE_TRACING + # value: "1" + # - name: DISABLE_PROFILER + # value: "1" + # - name: DISABLE_DEBUGGER + # value: "1" + readinessProbe: + exec: + command: ["/bin/grpc_health_probe", "-addr=:7000"] + livenessProbe: + exec: + command: ["/bin/grpc_health_probe", "-addr=:7000"] + resources: + requests: + cpu: 100m + memory: 64Mi + limits: + cpu: 200m + memory: 128Mi +--- +apiVersion: v1 +kind: Service +metadata: + name: currencyservice +spec: + type: ClusterIP + selector: + app: currencyservice + ports: + - name: grpc + port: 7000 + targetPort: 7000 diff --git a/kubernetes-manifests-tracing/emailservice.yaml b/kubernetes-manifests-tracing/emailservice.yaml new file mode 100644 index 0000000..c728b7a --- /dev/null +++ b/kubernetes-manifests-tracing/emailservice.yaml @@ -0,0 +1,68 @@ +# Copyright 2018 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +apiVersion: apps/v1 +kind: Deployment +metadata: + name: emailservice +spec: + selector: + matchLabels: + app: emailservice + template: + metadata: + labels: + app: emailservice + spec: + terminationGracePeriodSeconds: 5 + containers: + - name: server + image: emailservice + ports: + - containerPort: 8080 + env: + - name: PORT + value: "8080" + # - name: DISABLE_TRACING + # value: "1" + # - name: DISABLE_PROFILER + # value: "1" + readinessProbe: + periodSeconds: 5 + exec: + command: ["/bin/grpc_health_probe", "-addr=:8080"] + livenessProbe: + periodSeconds: 5 + exec: + command: ["/bin/grpc_health_probe", "-addr=:8080"] + resources: + requests: + cpu: 100m + memory: 64Mi + limits: + cpu: 200m + memory: 128Mi +--- +apiVersion: v1 +kind: Service +metadata: + name: emailservice +spec: + type: ClusterIP + selector: + app: emailservice + ports: + - name: grpc + port: 5000 + targetPort: 8080 diff --git a/kubernetes-manifests-tracing/frontend.yaml b/kubernetes-manifests-tracing/frontend.yaml new file mode 100644 index 0000000..10d0056 --- /dev/null +++ b/kubernetes-manifests-tracing/frontend.yaml @@ -0,0 +1,106 @@ +# Copyright 2018 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +apiVersion: apps/v1 +kind: Deployment +metadata: + name: frontend +spec: + selector: + matchLabels: + app: frontend + template: + metadata: + labels: + app: frontend + annotations: + sidecar.istio.io/rewriteAppHTTPProbers: "true" + spec: + containers: + - name: server + image: frontend + ports: + - containerPort: 8080 + readinessProbe: + initialDelaySeconds: 10 + httpGet: + path: "/_healthz" + port: 8080 + httpHeaders: + - name: "Cookie" + value: "shop_session-id=x-readiness-probe" + livenessProbe: + initialDelaySeconds: 10 + httpGet: + path: "/_healthz" + port: 8080 + httpHeaders: + - name: "Cookie" + value: "shop_session-id=x-liveness-probe" + env: + - name: PORT + value: "8080" + - name: PRODUCT_CATALOG_SERVICE_ADDR + value: "productcatalogservice:3550" + - name: CURRENCY_SERVICE_ADDR + value: "currencyservice:7000" + - name: CART_SERVICE_ADDR + value: "cartservice:7070" + - name: RECOMMENDATION_SERVICE_ADDR + value: "recommendationservice:8080" + - name: SHIPPING_SERVICE_ADDR + value: "shippingservice:50051" + - name: CHECKOUT_SERVICE_ADDR + value: "checkoutservice:5050" + - name: AD_SERVICE_ADDR + value: "adservice:9555" + # - name: DISABLE_TRACING + # value: "1" + # - name: DISABLE_PROFILER + # value: "1" + - name: JAEGER_SERVICE_ADDR + value: "jaeger-collector:14268" + resources: + requests: + cpu: 100m + memory: 64Mi + limits: + cpu: 200m + memory: 128Mi +--- +apiVersion: v1 +kind: Service +metadata: + name: frontend +spec: + type: ClusterIP + selector: + app: frontend + ports: + - name: http + port: 80 + targetPort: 8080 +--- +apiVersion: v1 +kind: Service +metadata: + name: frontend-external +spec: + type: LoadBalancer + selector: + app: frontend + ports: + - name: http + port: 80 + targetPort: 8080 diff --git a/kubernetes-manifests-tracing/loadgenerator.yaml b/kubernetes-manifests-tracing/loadgenerator.yaml new file mode 100644 index 0000000..53e947e --- /dev/null +++ b/kubernetes-manifests-tracing/loadgenerator.yaml @@ -0,0 +1,46 @@ +# Copyright 2018 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +apiVersion: apps/v1 +kind: Deployment +metadata: + name: loadgenerator +spec: + selector: + matchLabels: + app: loadgenerator + replicas: 1 + template: + metadata: + labels: + app: loadgenerator + annotations: + sidecar.istio.io/rewriteAppHTTPProbers: "true" + spec: + terminationGracePeriodSeconds: 5 + restartPolicy: Always + containers: + - name: main + image: loadgenerator + env: + - name: FRONTEND_ADDR + value: "frontend:80" + - name: USERS + value: "10" + resources: + requests: + cpu: 300m + memory: 256Mi + limits: + cpu: 500m + memory: 512Mi \ No newline at end of file diff --git a/kubernetes-manifests-tracing/paymentservice.yaml b/kubernetes-manifests-tracing/paymentservice.yaml new file mode 100644 index 0000000..fa62c08 --- /dev/null +++ b/kubernetes-manifests-tracing/paymentservice.yaml @@ -0,0 +1,62 @@ +# Copyright 2018 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +apiVersion: apps/v1 +kind: Deployment +metadata: + name: paymentservice +spec: + selector: + matchLabels: + app: paymentservice + template: + metadata: + labels: + app: paymentservice + spec: + terminationGracePeriodSeconds: 5 + containers: + - name: server + image: paymentservice + ports: + - containerPort: 50051 + env: + - name: PORT + value: "50051" + readinessProbe: + exec: + command: ["/bin/grpc_health_probe", "-addr=:50051"] + livenessProbe: + exec: + command: ["/bin/grpc_health_probe", "-addr=:50051"] + resources: + requests: + cpu: 100m + memory: 64Mi + limits: + cpu: 200m + memory: 128Mi +--- +apiVersion: v1 +kind: Service +metadata: + name: paymentservice +spec: + type: ClusterIP + selector: + app: paymentservice + ports: + - name: grpc + port: 50051 + targetPort: 50051 diff --git a/kubernetes-manifests-tracing/productcatalogservice.yaml b/kubernetes-manifests-tracing/productcatalogservice.yaml new file mode 100644 index 0000000..a3a3b79 --- /dev/null +++ b/kubernetes-manifests-tracing/productcatalogservice.yaml @@ -0,0 +1,70 @@ +# Copyright 2018 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +apiVersion: apps/v1 +kind: Deployment +metadata: + name: productcatalogservice +spec: + selector: + matchLabels: + app: productcatalogservice + template: + metadata: + labels: + app: productcatalogservice + spec: + terminationGracePeriodSeconds: 5 + containers: + - name: server + image: productcatalogservice + ports: + - containerPort: 3550 + env: + - name: PORT + value: "3550" + # - name: DISABLE_STATS + # value: "1" + # - name: DISABLE_TRACING + # value: "1" + # - name: DISABLE_PROFILER + # value: "1" + - name: JAEGER_SERVICE_ADDR + value: "jaeger-collector:14268" + readinessProbe: + exec: + command: ["/bin/grpc_health_probe", "-addr=:3550"] + livenessProbe: + exec: + command: ["/bin/grpc_health_probe", "-addr=:3550"] + resources: + requests: + cpu: 100m + memory: 64Mi + limits: + cpu: 200m + memory: 128Mi +--- +apiVersion: v1 +kind: Service +metadata: + name: productcatalogservice +spec: + type: ClusterIP + selector: + app: productcatalogservice + ports: + - name: grpc + port: 3550 + targetPort: 3550 diff --git a/kubernetes-manifests-tracing/recommendationservice.yaml b/kubernetes-manifests-tracing/recommendationservice.yaml new file mode 100644 index 0000000..0e75f9f --- /dev/null +++ b/kubernetes-manifests-tracing/recommendationservice.yaml @@ -0,0 +1,72 @@ +# Copyright 2018 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +apiVersion: apps/v1 +kind: Deployment +metadata: + name: recommendationservice +spec: + selector: + matchLabels: + app: recommendationservice + template: + metadata: + labels: + app: recommendationservice + spec: + terminationGracePeriodSeconds: 5 + containers: + - name: server + image: recommendationservice + ports: + - containerPort: 8080 + readinessProbe: + periodSeconds: 5 + exec: + command: ["/bin/grpc_health_probe", "-addr=:8080"] + livenessProbe: + periodSeconds: 5 + exec: + command: ["/bin/grpc_health_probe", "-addr=:8080"] + env: + - name: PORT + value: "8080" + - name: PRODUCT_CATALOG_SERVICE_ADDR + value: "productcatalogservice:3550" + # - name: DISABLE_TRACING + # value: "1" + # - name: DISABLE_PROFILER + # value: "1" + # - name: DISABLE_DEBUGGER + # value: "1" + resources: + requests: + cpu: 100m + memory: 220Mi + limits: + cpu: 200m + memory: 450Mi +--- +apiVersion: v1 +kind: Service +metadata: + name: recommendationservice +spec: + type: ClusterIP + selector: + app: recommendationservice + ports: + - name: grpc + port: 8080 + targetPort: 8080 diff --git a/kubernetes-manifests-tracing/redis.yaml b/kubernetes-manifests-tracing/redis.yaml new file mode 100644 index 0000000..b67649b --- /dev/null +++ b/kubernetes-manifests-tracing/redis.yaml @@ -0,0 +1,66 @@ +# Copyright 2018 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +apiVersion: apps/v1 +kind: Deployment +metadata: + name: redis-cart +spec: + selector: + matchLabels: + app: redis-cart + template: + metadata: + labels: + app: redis-cart + spec: + containers: + - name: redis + image: redis:alpine + ports: + - containerPort: 6379 + readinessProbe: + periodSeconds: 5 + tcpSocket: + port: 6379 + livenessProbe: + periodSeconds: 5 + tcpSocket: + port: 6379 + volumeMounts: + - mountPath: /data + name: redis-data + resources: + limits: + memory: 256Mi + cpu: 125m + requests: + cpu: 70m + memory: 200Mi + volumes: + - name: redis-data + emptyDir: {} +--- +apiVersion: v1 +kind: Service +metadata: + name: redis-cart +spec: + type: ClusterIP + selector: + app: redis-cart + ports: + - name: redis + port: 6379 + targetPort: 6379 diff --git a/kubernetes-manifests-tracing/shippingservice.yaml b/kubernetes-manifests-tracing/shippingservice.yaml new file mode 100644 index 0000000..cf857af --- /dev/null +++ b/kubernetes-manifests-tracing/shippingservice.yaml @@ -0,0 +1,70 @@ +# Copyright 2018 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +apiVersion: apps/v1 +kind: Deployment +metadata: + name: shippingservice +spec: + selector: + matchLabels: + app: shippingservice + template: + metadata: + labels: + app: shippingservice + spec: + containers: + - name: server + image: shippingservice + ports: + - containerPort: 50051 + env: + - name: PORT + value: "50051" + - name: DISABLE_STATS + value: "1" + - name: DISABLE_TRACING + value: "1" + - name: DISABLE_PROFILER + value: "1" + - name: JAEGER_SERVICE_ADDR + value: "jaeger-collector:14268" + readinessProbe: + periodSeconds: 5 + exec: + command: ["/bin/grpc_health_probe", "-addr=:50051"] + livenessProbe: + exec: + command: ["/bin/grpc_health_probe", "-addr=:50051"] + resources: + requests: + cpu: 100m + memory: 64Mi + limits: + cpu: 200m + memory: 128Mi +--- +apiVersion: v1 +kind: Service +metadata: + name: shippingservice +spec: + type: ClusterIP + selector: + app: shippingservice + ports: + - name: grpc + port: 50051 + targetPort: 50051 diff --git a/kubernetes-manifests/adservice.yaml b/kubernetes-manifests/adservice.yaml index 05dd9bb..6367ca0 100644 --- a/kubernetes-manifests/adservice.yaml +++ b/kubernetes-manifests/adservice.yaml @@ -34,12 +34,12 @@ spec: env: - name: PORT value: "9555" - # - name: DISABLE_STATS - # value: "1" - # - name: DISABLE_TRACING - # value: "1" - #- name: JAEGER_SERVICE_ADDR - # value: "jaeger-collector:14268" + - name: DISABLE_STATS + value: "1" + - name: DISABLE_TRACING + value: "1" + - name: JAEGER_SERVICE_ADDR + value: "jaeger-collector:14268" resources: requests: cpu: 200m diff --git a/kubernetes-manifests/checkoutservice.yaml b/kubernetes-manifests/checkoutservice.yaml index 3e244c4..136ab06 100644 --- a/kubernetes-manifests/checkoutservice.yaml +++ b/kubernetes-manifests/checkoutservice.yaml @@ -51,14 +51,14 @@ spec: value: "currencyservice:7000" - name: CART_SERVICE_ADDR value: "cartservice:7070" - # - name: DISABLE_STATS - # value: "1" - # - name: DISABLE_TRACING - # value: "1" - # - name: DISABLE_PROFILER - # value: "1" - # - name: JAEGER_SERVICE_ADDR - # value: "jaeger-collector:14268" + - name: DISABLE_STATS + value: "1" + - name: DISABLE_TRACING + value: "1" + - name: DISABLE_PROFILER + value: "1" + - name: JAEGER_SERVICE_ADDR + value: "jaeger-collector:14268" resources: requests: cpu: 100m diff --git a/kubernetes-manifests/emailservice.yaml b/kubernetes-manifests/emailservice.yaml index bc7e6b9..6cbfee2 100644 --- a/kubernetes-manifests/emailservice.yaml +++ b/kubernetes-manifests/emailservice.yaml @@ -34,8 +34,8 @@ spec: env: - name: PORT value: "8080" - # - name: DISABLE_TRACING - # value: "1" + - name: DISABLE_TRACING + value: "1" - name: DISABLE_PROFILER value: "1" readinessProbe: diff --git a/kubernetes-manifests/frontend.yaml b/kubernetes-manifests/frontend.yaml index da1c7cc..c2ff4d8 100644 --- a/kubernetes-manifests/frontend.yaml +++ b/kubernetes-manifests/frontend.yaml @@ -65,12 +65,12 @@ spec: value: "checkoutservice:5050" - name: AD_SERVICE_ADDR value: "adservice:9555" - # - name: DISABLE_TRACING - # value: "1" - # - name: DISABLE_PROFILER - # value: "1" - # - name: JAEGER_SERVICE_ADDR - # value: "jaeger-collector:14268" + - name: DISABLE_TRACING + value: "1" + - name: DISABLE_PROFILER + value: "1" + - name: JAEGER_SERVICE_ADDR + value: "jaeger-collector:14268" resources: requests: cpu: 100m diff --git a/kubernetes-manifests/productcatalogservice.yaml b/kubernetes-manifests/productcatalogservice.yaml index 6949be0..89f5e32 100644 --- a/kubernetes-manifests/productcatalogservice.yaml +++ b/kubernetes-manifests/productcatalogservice.yaml @@ -34,14 +34,14 @@ spec: env: - name: PORT value: "3550" - # - name: DISABLE_STATS - # value: "1" - # - name: DISABLE_TRACING - # value: "1" - # - name: DISABLE_PROFILER - # value: "1" - # - name: JAEGER_SERVICE_ADDR - # value: "jaeger-collector:14268" + - name: DISABLE_STATS + value: "1" + - name: DISABLE_TRACING + value: "1" + - name: DISABLE_PROFILER + value: "1" + - name: JAEGER_SERVICE_ADDR + value: "jaeger-collector:14268" readinessProbe: exec: command: ["/bin/grpc_health_probe", "-addr=:3550"] diff --git a/kubernetes-manifests/recommendationservice.yaml b/kubernetes-manifests/recommendationservice.yaml index 0e75f9f..9319e35 100644 --- a/kubernetes-manifests/recommendationservice.yaml +++ b/kubernetes-manifests/recommendationservice.yaml @@ -44,12 +44,12 @@ spec: value: "8080" - name: PRODUCT_CATALOG_SERVICE_ADDR value: "productcatalogservice:3550" - # - name: DISABLE_TRACING - # value: "1" - # - name: DISABLE_PROFILER - # value: "1" - # - name: DISABLE_DEBUGGER - # value: "1" + - name: DISABLE_TRACING + value: "1" + - name: DISABLE_PROFILER + value: "1" + - name: DISABLE_DEBUGGER + value: "1" resources: requests: cpu: 100m diff --git a/kubernetes-manifests/shippingservice.yaml b/kubernetes-manifests/shippingservice.yaml index e3027a1..cf857af 100644 --- a/kubernetes-manifests/shippingservice.yaml +++ b/kubernetes-manifests/shippingservice.yaml @@ -33,14 +33,14 @@ spec: env: - name: PORT value: "50051" - # - name: DISABLE_STATS - # value: "1" - # - name: DISABLE_TRACING - # value: "1" - # - name: DISABLE_PROFILER - # value: "1" - # - name: JAEGER_SERVICE_ADDR - # value: "jaeger-collector:14268" + - name: DISABLE_STATS + value: "1" + - name: DISABLE_TRACING + value: "1" + - name: DISABLE_PROFILER + value: "1" + - name: JAEGER_SERVICE_ADDR + value: "jaeger-collector:14268" readinessProbe: periodSeconds: 5 exec: diff --git a/skaffold.yaml b/skaffold.yaml index dfd6aeb..ae75fb4 100644 --- a/skaffold.yaml +++ b/skaffold.yaml @@ -17,7 +17,7 @@ kind: Config build: artifacts: # image tags are relative; to specify an image repo (e.g. GCR), you - # must provide a "default repo" using one of the methods described + # must provide a "default repo" using one of the methods described # here: # https://skaffold.dev/docs/concepts/#image-repository-handling - image: emailservice @@ -48,6 +48,7 @@ deploy: kubectl: manifests: - ./kubernetes-manifests/**.yaml + # - ./istio-manifests/**.yaml profiles: # "gcb" profile allows building and pushing the images # on Google Container Builder without requiring docker @@ -63,3 +64,26 @@ profiles: diskSizeGb: 300 machineType: N1_HIGHCPU_32 timeout: 4000s + +- name: gcb-tracing + build: + googleCloudBuild: + diskSizeGb: 300 + machineType: N1_HIGHCPU_32 + timeout: 4000s + deploy: + kubectl: + manifests: + - ./kubernetes-manifests-tracing/**.yaml + +- name: gcb-istio + build: + googleCloudBuild: + diskSizeGb: 300 + machineType: N1_HIGHCPU_32 + timeout: 4000s + deploy: + kubectl: + manifests: + - ./kubernetes-manifests/**.yaml + - ./istio-manifests/**.yaml From 3469a4c436d460d6a24dae91d8edac72c1abc12c Mon Sep 17 00:00:00 2001 From: Tony Hallworth Date: Tue, 17 Mar 2020 21:35:22 +1100 Subject: [PATCH 2/2] sidecar deployment --- istio-manifests/frontend-gateway.yaml | 32 ++-- istio-manifests/istio-demo.yaml | 167 ++++++++++-------- kubernetes-manifests-tracing/adservice.yaml | 2 +- .../checkoutservice.yaml | 2 +- kubernetes-manifests-tracing/frontend.yaml | 2 +- .../productcatalogservice.yaml | 2 +- .../shippingservice.yaml | 2 +- kubernetes-manifests/frontend.yaml | 26 +-- patch.sh | 45 +++++ skaffold.yaml | 3 +- 10 files changed, 173 insertions(+), 110 deletions(-) create mode 100755 patch.sh diff --git a/istio-manifests/frontend-gateway.yaml b/istio-manifests/frontend-gateway.yaml index b3a1a64..8de200b 100644 --- a/istio-manifests/frontend-gateway.yaml +++ b/istio-manifests/frontend-gateway.yaml @@ -12,21 +12,21 @@ # See the License for the specific language governing permissions and # limitations under the License. -apiVersion: networking.istio.io/v1alpha3 -kind: Gateway -metadata: - name: frontend-gateway -spec: - selector: - istio: ingressgateway # use Istio default gateway implementation - servers: - - port: - number: 80 - name: http - protocol: HTTP - hosts: - - "*" ---- +# apiVersion: networking.istio.io/v1alpha3 +# kind: Gateway +# metadata: +# name: frontend-gateway +# spec: +# selector: +# istio: ingressgateway # use Istio default gateway implementation +# servers: +# - port: +# number: 80 +# name: http +# protocol: HTTP +# hosts: +# - "*" +# --- apiVersion: networking.istio.io/v1alpha3 kind: VirtualService metadata: @@ -35,7 +35,7 @@ spec: hosts: - "*" gateways: - - frontend-gateway + - ingressgateway.istio-system http: - route: - destination: diff --git a/istio-manifests/istio-demo.yaml b/istio-manifests/istio-demo.yaml index 7e176e5..cee0933 100644 --- a/istio-manifests/istio-demo.yaml +++ b/istio-manifests/istio-demo.yaml @@ -214,7 +214,7 @@ metadata: release: istio istio: galley data: - validatingwebhookconfiguration.yaml: |- + validatingwebhookconfiguration.yaml: |- apiVersion: admissionregistration.k8s.io/v1beta1 kind: ValidatingWebhookConfiguration metadata: @@ -334,7 +334,7 @@ metadata: release: istio istio: grafana data: - custom-resources.yaml: |- + custom-resources.yaml: |- apiVersion: authentication.istio.io/v1alpha1 kind: Policy metadata: @@ -350,18 +350,18 @@ data: - name: grafana ports: - number: 3000 - run.sh: |- + run.sh: |- #!/bin/sh - + set -x - + if [ "$#" -ne "1" ]; then echo "first argument should be path to custom resource yaml" exit 1 fi - + pathToResourceYAML=${1} - + kubectl get validatingwebhookconfiguration istio-galley 2>/dev/null if [ "$?" -eq 0 ]; then echo "istio-galley validatingwebhookconfiguration found - waiting for istio-galley deployment to be ready" @@ -381,7 +381,7 @@ data: fi sleep 5 kubectl apply -f ${pathToResourceYAML} - + --- # Source: istio/charts/grafana/templates/configmap-dashboards.yaml @@ -14696,7 +14696,7 @@ data: orgId: 1 type: prometheus url: http://prometheus:9090 - + dashboardproviders.yaml: | apiVersion: 1 providers: @@ -14707,7 +14707,7 @@ data: path: /var/lib/grafana/dashboards/istio orgId: 1 type: file - + --- # Source: istio/charts/kiali/templates/configmap.yaml apiVersion: v1 @@ -14732,10 +14732,10 @@ data: web_root: /kiali external_services: tracing: - url: + url: in_cluster_url: http://tracing/jaeger grafana: - url: + url: in_cluster_url: http://grafana:3000 prometheus: url: http://prometheus:9090 @@ -15051,7 +15051,7 @@ metadata: release: istio istio: citadel data: - custom-resources.yaml: |- + custom-resources.yaml: |- # Authentication policy to enable permissive mode for all services (that have sidecar) in the mesh. apiVersion: "authentication.istio.io/v1alpha1" kind: "MeshPolicy" @@ -15066,18 +15066,18 @@ data: peers: - mtls: mode: PERMISSIVE - run.sh: |- + run.sh: |- #!/bin/sh - + set -x - + if [ "$#" -ne "1" ]; then echo "first argument should be path to custom resource yaml" exit 1 fi - + pathToResourceYAML=${1} - + kubectl get validatingwebhookconfiguration istio-galley 2>/dev/null if [ "$?" -eq 0 ]; then echo "istio-galley validatingwebhookconfiguration found - waiting for istio-galley deployment to be ready" @@ -15097,7 +15097,7 @@ data: fi sleep 5 kubectl apply -f ${pathToResourceYAML} - + --- # Source: istio/templates/configmap.yaml @@ -15858,7 +15858,7 @@ spec: configMap: name: istio-grafana-custom-resources restartPolicy: OnFailure - affinity: + affinity: nodeAffinity: requiredDuringSchedulingIgnoredDuringExecution: nodeSelectorTerms: @@ -15890,7 +15890,7 @@ spec: - key: beta.kubernetes.io/arch operator: In values: - - "s390x" + - "s390x" --- # Source: istio/charts/kiali/templates/serviceaccount.yaml @@ -16039,7 +16039,7 @@ spec: configMap: name: istio-security-custom-resources restartPolicy: OnFailure - affinity: + affinity: nodeAffinity: requiredDuringSchedulingIgnoredDuringExecution: nodeSelectorTerms: @@ -16071,7 +16071,7 @@ spec: - key: beta.kubernetes.io/arch operator: In values: - - "s390x" + - "s390x" --- # Source: istio/charts/security/templates/serviceaccount.yaml @@ -16803,7 +16803,7 @@ spec: name: http selector: app: grafana - + --- # Source: istio/charts/kiali/templates/service.yaml @@ -17065,7 +17065,7 @@ spec: resources: requests: cpu: 10m - + volumes: - name: certs secret: @@ -17077,7 +17077,7 @@ spec: - name: mesh-config configMap: name: istio - affinity: + affinity: nodeAffinity: requiredDuringSchedulingIgnoredDuringExecution: nodeSelectorTerms: @@ -17109,7 +17109,7 @@ spec: - key: beta.kubernetes.io/arch operator: In values: - - "s390x" + - "s390x" --- # Source: istio/charts/gateways/templates/deployment.yaml @@ -17124,7 +17124,7 @@ metadata: heritage: Tiller istio: egressgateway release: istio - + spec: replicas: 1 selector: @@ -17143,7 +17143,7 @@ spec: heritage: Tiller istio: egressgateway release: istio - + annotations: sidecar.istio.io/inject: "false" spec: @@ -17200,7 +17200,7 @@ spec: requests: cpu: 10m memory: 40Mi - + env: - name: NODE_NAME valueFrom: @@ -17255,7 +17255,7 @@ spec: value: kubernetes://apis/apps/v1/namespaces/istio-system/deployments/istio-egressgateway - name: ISTIO_META_ROUTER_MODE value: standard - + volumeMounts: - name: istio-certs mountPath: /etc/certs @@ -17279,7 +17279,7 @@ spec: secret: secretName: "istio-egressgateway-ca-certs" optional: true - affinity: + affinity: nodeAffinity: requiredDuringSchedulingIgnoredDuringExecution: nodeSelectorTerms: @@ -17311,7 +17311,7 @@ spec: - key: beta.kubernetes.io/arch operator: In values: - - "s390x" + - "s390x" --- apiVersion: apps/v1 kind: Deployment @@ -17324,7 +17324,7 @@ metadata: heritage: Tiller istio: ingressgateway release: istio - + spec: replicas: 1 selector: @@ -17343,7 +17343,7 @@ spec: heritage: Tiller istio: ingressgateway release: istio - + annotations: sidecar.istio.io/inject: "false" spec: @@ -17406,7 +17406,7 @@ spec: requests: cpu: 10m memory: 40Mi - + env: - name: NODE_NAME valueFrom: @@ -17461,8 +17461,8 @@ spec: value: kubernetes://apis/apps/v1/namespaces/istio-system/deployments/istio-ingressgateway - name: ISTIO_META_ROUTER_MODE value: standard - - + + volumeMounts: - name: istio-certs mountPath: /etc/certs @@ -17486,7 +17486,7 @@ spec: secret: secretName: "istio-ingressgateway-ca-certs" optional: true - affinity: + affinity: nodeAffinity: requiredDuringSchedulingIgnoredDuringExecution: nodeSelectorTerms: @@ -17518,7 +17518,7 @@ spec: - key: beta.kubernetes.io/arch operator: In values: - - "s390x" + - "s390x" --- --- @@ -17576,7 +17576,7 @@ spec: resources: requests: cpu: 10m - + volumeMounts: - name: data mountPath: /data/grafana @@ -17618,7 +17618,7 @@ spec: - name: config mountPath: "/etc/grafana/provisioning/dashboards/dashboardproviders.yaml" subPath: dashboardproviders.yaml - affinity: + affinity: nodeAffinity: requiredDuringSchedulingIgnoredDuringExecution: nodeSelectorTerms: @@ -17650,7 +17650,7 @@ spec: - key: beta.kubernetes.io/arch operator: In values: - - "s390x" + - "s390x" volumes: - name: config configMap: @@ -17729,14 +17729,14 @@ spec: httpGet: path: /kiali/healthz port: 20001 - scheme: 'HTTP' + scheme: 'HTTP' initialDelaySeconds: 5 periodSeconds: 30 livenessProbe: httpGet: path: /kiali/healthz port: 20001 - scheme: 'HTTP' + scheme: 'HTTP' initialDelaySeconds: 5 periodSeconds: 30 env: @@ -17754,7 +17754,7 @@ spec: resources: requests: cpu: 10m - + volumes: - name: kiali-configuration configMap: @@ -17767,7 +17767,7 @@ spec: secret: secretName: kiali optional: true - affinity: + affinity: nodeAffinity: requiredDuringSchedulingIgnoredDuringExecution: nodeSelectorTerms: @@ -17799,7 +17799,7 @@ spec: - key: beta.kubernetes.io/arch operator: In values: - - "s390x" + - "s390x" --- # Source: istio/charts/mixer/templates/deployment.yaml @@ -17849,7 +17849,7 @@ spec: secret: secretName: policy-adapter-secret optional: true - affinity: + affinity: nodeAffinity: requiredDuringSchedulingIgnoredDuringExecution: nodeSelectorTerms: @@ -17881,7 +17881,7 @@ spec: - key: beta.kubernetes.io/arch operator: In values: - - "s390x" + - "s390x" containers: - name: mixer image: "docker.io/istio/mixer:1.5.0" @@ -17911,7 +17911,7 @@ spec: requests: cpu: 10m memory: 100Mi - + volumeMounts: - name: istio-certs mountPath: /etc/certs @@ -17969,7 +17969,7 @@ spec: requests: cpu: 10m memory: 40Mi - + volumeMounts: - name: istio-certs mountPath: /etc/certs @@ -18026,7 +18026,7 @@ spec: secret: secretName: telemetry-adapter-secret optional: true - affinity: + affinity: nodeAffinity: requiredDuringSchedulingIgnoredDuringExecution: nodeSelectorTerms: @@ -18058,7 +18058,7 @@ spec: - key: beta.kubernetes.io/arch operator: In values: - - "s390x" + - "s390x" containers: - name: mixer image: "docker.io/istio/mixer:1.5.0" @@ -18095,7 +18095,7 @@ spec: requests: cpu: 50m memory: 100Mi - + volumeMounts: - name: istio-certs mountPath: /etc/certs @@ -18156,7 +18156,7 @@ spec: requests: cpu: 10m memory: 40Mi - + volumeMounts: - name: istio-certs mountPath: /etc/certs @@ -18164,7 +18164,7 @@ spec: - name: uds-socket mountPath: /sock ---- +--- --- # Source: istio/charts/pilot/templates/deployment.yaml @@ -18248,7 +18248,7 @@ spec: requests: cpu: 10m memory: 100Mi - + volumeMounts: - name: config-volume mountPath: /etc/istio/config @@ -18299,7 +18299,7 @@ spec: requests: cpu: 10m memory: 40Mi - + volumeMounts: - name: istio-certs mountPath: /etc/certs @@ -18312,7 +18312,7 @@ spec: secret: secretName: istio.istio-pilot-service-account optional: true - affinity: + affinity: nodeAffinity: requiredDuringSchedulingIgnoredDuringExecution: nodeSelectorTerms: @@ -18344,7 +18344,7 @@ spec: - key: beta.kubernetes.io/arch operator: In values: - - "s390x" + - "s390x" --- # Source: istio/charts/prometheus/templates/deployment.yaml @@ -18376,12 +18376,27 @@ spec: spec: serviceAccountName: prometheus containers: + - name: sidecar + image: gcr.io/stackdriver-prometheus/stackdriver-prometheus-sidecar:0.7.3 + args: + - "--stackdriver.project-id=tonyh-gke-o11y-anz-openbanking" + - "--prometheus.wal-directory=/data/wal" + - "--prometheus.api-address=http://127.0.0.1:9090" + - "--stackdriver.kubernetes.location=australia-southeast1" + - "--stackdriver.kubernetes.cluster-name=o11y-ob" + ports: + - name: sidecar + containerPort: 9091 + volumeMounts: + - name: data-volume + mountPath: /data - name: prometheus image: "docker.io/prom/prometheus:v2.12.0" imagePullPolicy: IfNotPresent args: - '--storage.tsdb.retention=6h' - '--config.file=/etc/prometheus/prometheus.yml' + - '--storage.tsdb.path=/data' ports: - containerPort: 9090 name: http @@ -18396,13 +18411,17 @@ spec: resources: requests: cpu: 10m - + volumeMounts: + - name: data-volume + mountPath: /data - name: config-volume mountPath: /etc/prometheus - mountPath: /etc/istio-certs name: istio-certs volumes: + - name: data-volume + emptyDir: {} - name: config-volume configMap: name: prometheus @@ -18410,7 +18429,7 @@ spec: secret: defaultMode: 420 secretName: istio.default - affinity: + affinity: nodeAffinity: requiredDuringSchedulingIgnoredDuringExecution: nodeSelectorTerms: @@ -18442,7 +18461,7 @@ spec: - key: beta.kubernetes.io/arch operator: In values: - - "s390x" + - "s390x" --- # Source: istio/charts/security/templates/deployment.yaml @@ -18497,8 +18516,8 @@ spec: resources: requests: cpu: 10m - - affinity: + + affinity: nodeAffinity: requiredDuringSchedulingIgnoredDuringExecution: nodeSelectorTerms: @@ -18530,7 +18549,7 @@ spec: - key: beta.kubernetes.io/arch operator: In values: - - "s390x" + - "s390x" --- # Source: istio/charts/sidecarInjectorWebhook/templates/deployment.yaml @@ -18610,7 +18629,7 @@ spec: resources: requests: cpu: 10m - + volumes: - name: config-volume configMap: @@ -18626,7 +18645,7 @@ spec: path: config - key: values path: values - affinity: + affinity: nodeAffinity: requiredDuringSchedulingIgnoredDuringExecution: nodeSelectorTerms: @@ -18658,7 +18677,7 @@ spec: - key: beta.kubernetes.io/arch operator: In values: - - "s390x" + - "s390x" --- # Source: istio/charts/tracing/templates/deployment-jaeger.yaml @@ -18726,7 +18745,7 @@ spec: - name: MEMORY_MAX_TRACES value: "50000" - name: QUERY_BASE_PATH - value: /jaeger + value: /jaeger livenessProbe: httpGet: path: / @@ -18741,8 +18760,8 @@ spec: resources: requests: cpu: 10m - - affinity: + + affinity: nodeAffinity: requiredDuringSchedulingIgnoredDuringExecution: nodeSelectorTerms: @@ -18774,7 +18793,7 @@ spec: - key: beta.kubernetes.io/arch operator: In values: - - "s390x" + - "s390x" volumes: - name: data emptyDir: {} diff --git a/kubernetes-manifests-tracing/adservice.yaml b/kubernetes-manifests-tracing/adservice.yaml index 4cb02bc..468393e 100644 --- a/kubernetes-manifests-tracing/adservice.yaml +++ b/kubernetes-manifests-tracing/adservice.yaml @@ -39,7 +39,7 @@ spec: # - name: DISABLE_TRACING # value: "1" - name: JAEGER_SERVICE_ADDR - value: "jaeger-collector:14268" + value: "jaeger-collector.istio-sysem.svc:14268" resources: requests: cpu: 200m diff --git a/kubernetes-manifests-tracing/checkoutservice.yaml b/kubernetes-manifests-tracing/checkoutservice.yaml index 0016509..cf94713 100644 --- a/kubernetes-manifests-tracing/checkoutservice.yaml +++ b/kubernetes-manifests-tracing/checkoutservice.yaml @@ -58,7 +58,7 @@ spec: # - name: DISABLE_PROFILER # value: "1" - name: JAEGER_SERVICE_ADDR - value: "jaeger-collector:14268" + value: "jaeger-collector.istio-sysem.svc:14268" resources: requests: cpu: 100m diff --git a/kubernetes-manifests-tracing/frontend.yaml b/kubernetes-manifests-tracing/frontend.yaml index 10d0056..7c9a338 100644 --- a/kubernetes-manifests-tracing/frontend.yaml +++ b/kubernetes-manifests-tracing/frontend.yaml @@ -70,7 +70,7 @@ spec: # - name: DISABLE_PROFILER # value: "1" - name: JAEGER_SERVICE_ADDR - value: "jaeger-collector:14268" + value: "jaeger-collector.istio-sysem.svc:14268" resources: requests: cpu: 100m diff --git a/kubernetes-manifests-tracing/productcatalogservice.yaml b/kubernetes-manifests-tracing/productcatalogservice.yaml index a3a3b79..0bd4ee9 100644 --- a/kubernetes-manifests-tracing/productcatalogservice.yaml +++ b/kubernetes-manifests-tracing/productcatalogservice.yaml @@ -41,7 +41,7 @@ spec: # - name: DISABLE_PROFILER # value: "1" - name: JAEGER_SERVICE_ADDR - value: "jaeger-collector:14268" + value: "jaeger-collector.istio-sysem.svc:14268" readinessProbe: exec: command: ["/bin/grpc_health_probe", "-addr=:3550"] diff --git a/kubernetes-manifests-tracing/shippingservice.yaml b/kubernetes-manifests-tracing/shippingservice.yaml index cf857af..885c45a 100644 --- a/kubernetes-manifests-tracing/shippingservice.yaml +++ b/kubernetes-manifests-tracing/shippingservice.yaml @@ -40,7 +40,7 @@ spec: - name: DISABLE_PROFILER value: "1" - name: JAEGER_SERVICE_ADDR - value: "jaeger-collector:14268" + value: "jaeger-collector.istio-sysem.svc:14268" readinessProbe: periodSeconds: 5 exec: diff --git a/kubernetes-manifests/frontend.yaml b/kubernetes-manifests/frontend.yaml index c2ff4d8..71d75b1 100644 --- a/kubernetes-manifests/frontend.yaml +++ b/kubernetes-manifests/frontend.yaml @@ -91,16 +91,16 @@ spec: - name: http port: 80 targetPort: 8080 ---- -apiVersion: v1 -kind: Service -metadata: - name: frontend-external -spec: - type: LoadBalancer - selector: - app: frontend - ports: - - name: http - port: 80 - targetPort: 8080 +# --- +# apiVersion: v1 +# kind: Service +# metadata: +# name: frontend-external +# spec: +# type: LoadBalancer +# selector: +# app: frontend +# ports: +# - name: http +# port: 80 +# targetPort: 8080 diff --git a/patch.sh b/patch.sh new file mode 100755 index 0000000..27a4b95 --- /dev/null +++ b/patch.sh @@ -0,0 +1,45 @@ +#!/bin/sh +KUBE_NAMESPACE=istio-system +KUBE_CLUSTER=o11y-ob +GCP_REGION=australia-southeast1 +GCP_PROJECT=tonyh-gke-o11y-anz-openbanking +DATA_DIR=/data +DATA_VOLUME=data-volume +SIDECAR_IMAGE_TAG=0.7.3 +set -e +set -u + +usage() { + echo -e "Usage: $0 \n" +} + +if [ $# -le 1 ]; then + usage + exit 1 +fi + +# Override to use a different Docker image name for the sidecar. +export SIDECAR_IMAGE_NAME=${SIDECAR_IMAGE_NAME:-'gcr.io/stackdriver-prometheus/stackdriver-prometheus-sidecar'} + +kubectl -n "${KUBE_NAMESPACE}" patch "$1" "$2" --type strategic --patch " +spec: + template: + spec: + containers: + - name: sidecar + image: ${SIDECAR_IMAGE_NAME}:${SIDECAR_IMAGE_TAG} + imagePullPolicy: Always + args: + - \"--stackdriver.project-id=${GCP_PROJECT}\" + - \"--prometheus.wal-directory=${DATA_DIR}/wal\" + - \"--stackdriver.kubernetes.location=${GCP_REGION}\" + - \"--stackdriver.kubernetes.cluster-name=${KUBE_CLUSTER}\" + #- \"--stackdriver.generic.location=${GCP_REGION}\" + #- \"--stackdriver.generic.namespace=${KUBE_CLUSTER}\" + ports: + - name: sidecar + containerPort: 9091 + volumeMounts: + - name: ${DATA_VOLUME} + mountPath: ${DATA_DIR} +" \ No newline at end of file diff --git a/skaffold.yaml b/skaffold.yaml index ae75fb4..7ff72dc 100644 --- a/skaffold.yaml +++ b/skaffold.yaml @@ -85,5 +85,4 @@ profiles: deploy: kubectl: manifests: - - ./kubernetes-manifests/**.yaml - - ./istio-manifests/**.yaml + - ./kubernetes-manifests-tracing/**.yaml \ No newline at end of file

f(snRYzot3Hv3?2>vT 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