From 0ba873e310e14619aa87a89cdf2508e81bed1077 Mon Sep 17 00:00:00 2001 From: weaveworksbot Date: Fri, 8 May 2020 10:22:10 +0000 Subject: [PATCH] Publish website --- 404.html | 6 +++--- assets/js/{10.bf6f38d4.js => 10.d04c7ada.js} | 2 +- assets/js/{11.3af38cfe.js => 11.ab251275.js} | 2 +- assets/js/{13.9104349a.js => 13.6b55cb59.js} | 2 +- assets/js/{14.a4f3d810.js => 14.affa49a6.js} | 2 +- assets/js/{20.dce5a04e.js => 20.2b1bebf5.js} | 2 +- assets/js/{21.df66561d.js => 21.e1068843.js} | 2 +- assets/js/{23.b3dcc355.js => 23.ec1dec63.js} | 2 +- assets/js/{24.4f54d289.js => 24.721d8c4e.js} | 2 +- assets/js/5.f0e04ff6.js | 1 + assets/js/5.f92a6aca.js | 1 - assets/js/{app.b4b27991.js => app.67d16e10.js} | 4 ++-- dev/dev-guide.html | 4 ++-- dev/index.html | 4 ++-- dev/release-guide.html | 4 ++-- dev/upgrade-guide.html | 4 ++-- index.html | 8 ++++---- install/flagger-install-on-eks-appmesh.html | 4 ++-- install/flagger-install-on-google-cloud.html | 4 ++-- install/flagger-install-on-kubernetes.html | 4 ++-- install/index.html | 4 ++-- intro/faq.html | 4 ++-- intro/index.html | 4 ++-- tutorials/appmesh-progressive-delivery.html | 4 ++-- tutorials/canary-helm-gitops.html | 4 ++-- tutorials/contour-progressive-delivery.html | 4 ++-- tutorials/crossover-progressive-delivery.html | 4 ++-- tutorials/flagger-smi-istio.html | 4 ++-- tutorials/gloo-progressive-delivery.html | 4 ++-- tutorials/index.html | 4 ++-- tutorials/istio-ab-testing.html | 4 ++-- tutorials/istio-progressive-delivery.html | 4 ++-- tutorials/kubernetes-blue-green.html | 4 ++-- tutorials/linkerd-progressive-delivery.html | 4 ++-- tutorials/nginx-progressive-delivery.html | 4 ++-- tutorials/zero-downtime-deployments.html | 4 ++-- usage/alerting.html | 4 ++-- usage/deployment-strategies.html | 4 ++-- usage/how-it-works.html | 4 ++-- usage/index.html | 4 ++-- usage/metrics.html | 4 ++-- usage/monitoring.html | 4 ++-- usage/webhooks.html | 4 ++-- 43 files changed, 78 insertions(+), 78 deletions(-) rename assets/js/{10.bf6f38d4.js => 10.d04c7ada.js} (79%) rename assets/js/{11.3af38cfe.js => 11.ab251275.js} (99%) rename assets/js/{13.9104349a.js => 13.6b55cb59.js} (99%) rename assets/js/{14.a4f3d810.js => 14.affa49a6.js} (98%) rename assets/js/{20.dce5a04e.js => 20.2b1bebf5.js} (99%) rename assets/js/{21.df66561d.js => 21.e1068843.js} (99%) rename assets/js/{23.b3dcc355.js => 23.ec1dec63.js} (99%) rename assets/js/{24.4f54d289.js => 24.721d8c4e.js} (99%) create mode 100644 assets/js/5.f0e04ff6.js delete mode 100644 assets/js/5.f92a6aca.js rename assets/js/{app.b4b27991.js => app.67d16e10.js} (96%) diff --git a/404.html b/404.html index 6c00ac34..e730f266 100644 --- a/404.html +++ b/404.html @@ -13,11 +13,11 @@ - + -

404

That's a Four-Oh-Four.
Take me home.
- +

404

There's nothing here.
Take me home.
+ diff --git a/assets/js/10.bf6f38d4.js b/assets/js/10.d04c7ada.js similarity index 79% rename from assets/js/10.bf6f38d4.js rename to assets/js/10.d04c7ada.js index 336f8d72..1e49516c 100644 --- a/assets/js/10.bf6f38d4.js +++ b/assets/js/10.d04c7ada.js @@ -1 +1 @@ -(window.webpackJsonp=window.webpackJsonp||[]).push([[10],{270:function(t,e,n){"use strict";n.r(e);var s=n(37),l=Object(s.a)({},function(){var t=this.$createElement;return(this._self._c||t)("ContentSlotsDistributor",{attrs:{"slot-key":this.$parent.slotKey}})},[],!1,null,null,null);e.default=l.exports}}]); \ No newline at end of file +(window.webpackJsonp=window.webpackJsonp||[]).push([[10],{271:function(t,e,n){"use strict";n.r(e);var s=n(37),l=Object(s.a)({},function(){var t=this.$createElement;return(this._self._c||t)("ContentSlotsDistributor",{attrs:{"slot-key":this.$parent.slotKey}})},[],!1,null,null,null);e.default=l.exports}}]); \ No newline at end of file diff --git a/assets/js/11.3af38cfe.js b/assets/js/11.ab251275.js similarity index 99% rename from assets/js/11.3af38cfe.js rename to assets/js/11.ab251275.js index d5503238..86643c3d 100644 --- a/assets/js/11.3af38cfe.js +++ b/assets/js/11.ab251275.js @@ -1 +1 @@ -(window.webpackJsonp=window.webpackJsonp||[]).push([[11],{271:function(a,e,s){"use strict";s.r(e);var t=s(37),r=Object(t.a)({},function(){var a=this,e=a.$createElement,s=a._self._c||e;return s("ContentSlotsDistributor",{attrs:{"slot-key":a.$parent.slotKey}},[s("h1",{attrs:{id:"flagger-install-on-eks-app-mesh"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#flagger-install-on-eks-app-mesh","aria-hidden":"true"}},[a._v("#")]),a._v(" Flagger Install on EKS App Mesh")]),a._v(" "),s("p",[a._v("This guide walks you through setting up Flagger and AWS App Mesh on EKS.")]),a._v(" "),s("h2",{attrs:{id:"app-mesh"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#app-mesh","aria-hidden":"true"}},[a._v("#")]),a._v(" App Mesh")]),a._v(" "),s("p",[a._v("The App Mesh integration with EKS is made out of the following components:")]),a._v(" "),s("ul",[s("li",[a._v("Kubernetes custom resources\n"),s("ul",[s("li",[s("code",[a._v("mesh.appmesh.k8s.aws")]),a._v(" defines a logical boundary for network traffic between the services")]),a._v(" "),s("li",[s("code",[a._v("virtualnode.appmesh.k8s.aws")]),a._v(" defines a logical pointer to a Kubernetes workload")]),a._v(" "),s("li",[s("code",[a._v("virtualservice.appmesh.k8s.aws")]),a._v(" defines the routing rules for a workload inside the mesh")])])]),a._v(" "),s("li",[a._v("CRD controller - keeps the custom resources in sync with the App Mesh control plane")]),a._v(" "),s("li",[a._v("Admission controller - injects the Envoy sidecar and assigns Kubernetes pods to App Mesh virtual nodes")]),a._v(" "),s("li",[a._v("Telemetry service - Prometheus instance that collects and stores Envoy's metrics")])]),a._v(" "),s("h2",{attrs:{id:"create-a-kubernetes-cluster"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#create-a-kubernetes-cluster","aria-hidden":"true"}},[a._v("#")]),a._v(" Create a Kubernetes cluster")]),a._v(" "),s("p",[a._v("In order to create an EKS cluster you can use "),s("a",{attrs:{href:"https://eksctl.io",target:"_blank",rel:"noopener noreferrer"}},[a._v("eksctl"),s("OutboundLink")],1),a._v(". Eksctl is an open source command-line utility made by Weaveworks in collaboration with Amazon.")]),a._v(" "),s("p",[a._v("On MacOS you can install eksctl with Homebrew:")]),a._v(" "),s("div",{staticClass:"language-bash extra-class"},[s("pre",{pre:!0,attrs:{class:"language-bash"}},[s("code",[a._v("brew tap weaveworks/tap\nbrew "),s("span",{pre:!0,attrs:{class:"token function"}},[a._v("install")]),a._v(" weaveworks/tap/eksctl\n")])])]),s("p",[a._v("Create an EKS cluster:")]),a._v(" "),s("div",{staticClass:"language-bash extra-class"},[s("pre",{pre:!0,attrs:{class:"language-bash"}},[s("code",[a._v("eksctl create cluster --name"),s("span",{pre:!0,attrs:{class:"token operator"}},[a._v("=")]),a._v("appmesh "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("\\")]),a._v("\n--region"),s("span",{pre:!0,attrs:{class:"token operator"}},[a._v("=")]),a._v("us-west-2 "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("\\")]),a._v("\n--nodes "),s("span",{pre:!0,attrs:{class:"token number"}},[a._v("3")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("\\")]),a._v("\n--node-volume-size"),s("span",{pre:!0,attrs:{class:"token operator"}},[a._v("=")]),s("span",{pre:!0,attrs:{class:"token number"}},[a._v("120")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("\\")]),a._v("\n--appmesh-access\n")])])]),s("p",[a._v("The above command will create a two nodes cluster with App Mesh "),s("a",{attrs:{href:"https://docs.aws.amazon.com/app-mesh/latest/userguide/MESH_IAM_user_policies.html",target:"_blank",rel:"noopener noreferrer"}},[a._v("IAM policy"),s("OutboundLink")],1),a._v(" attached to the EKS node instance role.")]),a._v(" "),s("p",[a._v("Verify the install with:")]),a._v(" "),s("div",{staticClass:"language-bash extra-class"},[s("pre",{pre:!0,attrs:{class:"language-bash"}},[s("code",[a._v("kubectl get nodes\n")])])]),s("h2",{attrs:{id:"install-helm"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#install-helm","aria-hidden":"true"}},[a._v("#")]),a._v(" Install Helm")]),a._v(" "),s("p",[a._v("Install the "),s("a",{attrs:{href:"https://docs.helm.sh/using_helm/#installing-helm",target:"_blank",rel:"noopener noreferrer"}},[a._v("Helm"),s("OutboundLink")],1),a._v(" command-line tool:")]),a._v(" "),s("div",{staticClass:"language-text extra-class"},[s("pre",{pre:!0,attrs:{class:"language-text"}},[s("code",[a._v("brew install kubernetes-helm\n")])])]),s("p",[a._v("Create a service account and a cluster role binding for Tiller:")]),a._v(" "),s("div",{staticClass:"language-bash extra-class"},[s("pre",{pre:!0,attrs:{class:"language-bash"}},[s("code",[a._v("kubectl -n kube-system create sa tiller\n\nkubectl create clusterrolebinding tiller-cluster-rule "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("\\")]),a._v("\n--clusterrole"),s("span",{pre:!0,attrs:{class:"token operator"}},[a._v("=")]),a._v("cluster-admin "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("\\")]),a._v("\n--serviceaccount"),s("span",{pre:!0,attrs:{class:"token operator"}},[a._v("=")]),a._v("kube-system:tiller\n")])])]),s("p",[a._v("Deploy Tiller in the "),s("code",[a._v("kube-system")]),a._v(" namespace:")]),a._v(" "),s("div",{staticClass:"language-bash extra-class"},[s("pre",{pre:!0,attrs:{class:"language-bash"}},[s("code",[a._v("helm init --service-account tiller\n")])])]),s("p",[a._v("You should consider using SSL between Helm and Tiller, for more information on securing your Helm installation see "),s("a",{attrs:{href:"https://docs.helm.sh/using_helm/#securing-your-helm-installation",target:"_blank",rel:"noopener noreferrer"}},[a._v("docs.helm.sh"),s("OutboundLink")],1),a._v(".")]),a._v(" "),s("h2",{attrs:{id:"enable-horizontal-pod-auto-scaling"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#enable-horizontal-pod-auto-scaling","aria-hidden":"true"}},[a._v("#")]),a._v(" Enable horizontal pod auto-scaling")]),a._v(" "),s("p",[a._v("Install the Horizontal Pod Autoscaler (HPA) metrics provider:")]),a._v(" "),s("div",{staticClass:"language-bash extra-class"},[s("pre",{pre:!0,attrs:{class:"language-bash"}},[s("code",[a._v("helm upgrade -i metrics-server stable/metrics-server "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("\\")]),a._v("\n--namespace kube-system "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("\\")]),a._v("\n--set args"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("[")]),s("span",{pre:!0,attrs:{class:"token number"}},[a._v("0")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("]")]),s("span",{pre:!0,attrs:{class:"token operator"}},[a._v("=")]),a._v("--kubelet-preferred-address-types"),s("span",{pre:!0,attrs:{class:"token operator"}},[a._v("=")]),a._v("InternalIP\n")])])]),s("p",[a._v("After a minute, the metrics API should report CPU and memory usage for pods. You can very the metrics API with:")]),a._v(" "),s("div",{staticClass:"language-bash extra-class"},[s("pre",{pre:!0,attrs:{class:"language-bash"}},[s("code",[a._v("kubectl -n kube-system "),s("span",{pre:!0,attrs:{class:"token function"}},[a._v("top")]),a._v(" pods\n")])])]),s("h2",{attrs:{id:"install-the-app-mesh-components"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#install-the-app-mesh-components","aria-hidden":"true"}},[a._v("#")]),a._v(" Install the App Mesh components")]),a._v(" "),s("p",[a._v("Create the "),s("code",[a._v("appmesh-system")]),a._v(" namespace:")]),a._v(" "),s("div",{staticClass:"language-bash extra-class"},[s("pre",{pre:!0,attrs:{class:"language-bash"}},[s("code",[a._v("kubectl create ns appmesh-system\n")])])]),s("p",[a._v("Apply the App Mesh CRDs:")]),a._v(" "),s("div",{staticClass:"language-bash extra-class"},[s("pre",{pre:!0,attrs:{class:"language-bash"}},[s("code",[a._v("kubectl apply -k github.com/aws/eks-charts/stable/appmesh-controller//crds\n")])])]),s("p",[a._v("Add the EKS repository to Helm:")]),a._v(" "),s("div",{staticClass:"language-bash extra-class"},[s("pre",{pre:!0,attrs:{class:"language-bash"}},[s("code",[a._v("helm repo "),s("span",{pre:!0,attrs:{class:"token function"}},[a._v("add")]),a._v(" eks https://aws.github.io/eks-charts\n")])])]),s("p",[a._v("Install the App Mesh CRD controller:")]),a._v(" "),s("div",{staticClass:"language-bash extra-class"},[s("pre",{pre:!0,attrs:{class:"language-bash"}},[s("code",[a._v("helm upgrade -i appmesh-controller eks/appmesh-controller "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("\\")]),a._v("\n--wait --namespace appmesh-system\n")])])]),s("p",[a._v("Install the App Mesh admission controller and create a mesh called "),s("code",[a._v("global")]),a._v(":")]),a._v(" "),s("div",{staticClass:"language-bash extra-class"},[s("pre",{pre:!0,attrs:{class:"language-bash"}},[s("code",[a._v("helm upgrade -i appmesh-inject eks/appmesh-inject "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("\\")]),a._v("\n--wait --namespace appmesh-system "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("\\")]),a._v("\n--set mesh.create"),s("span",{pre:!0,attrs:{class:"token operator"}},[a._v("=")]),a._v("true "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("\\")]),a._v("\n--set mesh.name"),s("span",{pre:!0,attrs:{class:"token operator"}},[a._v("=")]),a._v("global\n")])])]),s("p",[a._v("Verify that the global mesh is active:")]),a._v(" "),s("div",{staticClass:"language-bash extra-class"},[s("pre",{pre:!0,attrs:{class:"language-bash"}},[s("code",[a._v("kubectl describe mesh\n\nStatus:\n Mesh Condition:\n Status: True\n Type: MeshActive\n")])])]),s("p",[a._v("In order to collect the App Mesh metrics that Flagger needs to run the canary analysis, you'll need to setup a Prometheus instance to scrape the Envoy sidecars.")]),a._v(" "),s("p",[a._v("Install the App Mesh Prometheus:")]),a._v(" "),s("div",{staticClass:"language-bash extra-class"},[s("pre",{pre:!0,attrs:{class:"language-bash"}},[s("code",[a._v("helm upgrade -i appmesh-prometheus eks/appmesh-prometheus "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("\\")]),a._v("\n--wait --namespace appmesh-system\n")])])]),s("h2",{attrs:{id:"install-flagger-and-grafana"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#install-flagger-and-grafana","aria-hidden":"true"}},[a._v("#")]),a._v(" Install Flagger and Grafana")]),a._v(" "),s("p",[a._v("Add Flagger Helm repository:")]),a._v(" "),s("div",{staticClass:"language-bash extra-class"},[s("pre",{pre:!0,attrs:{class:"language-bash"}},[s("code",[a._v("helm repo "),s("span",{pre:!0,attrs:{class:"token function"}},[a._v("add")]),a._v(" flagger https://flagger.app\n")])])]),s("p",[a._v("Install Flagger's Canary CRD:")]),a._v(" "),s("div",{staticClass:"language-yaml extra-class"},[s("pre",{pre:!0,attrs:{class:"language-yaml"}},[s("code",[a._v("kubectl apply "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("-")]),a._v("f https"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(":")]),a._v("//raw.githubusercontent.com/weaveworks/flagger/master/artifacts/flagger/crd.yaml\n")])])]),s("p",[a._v("Deploy Flagger in the "),s("em",[s("strong",[a._v("appmesh-system")])]),a._v(" namespace:")]),a._v(" "),s("div",{staticClass:"language-bash extra-class"},[s("pre",{pre:!0,attrs:{class:"language-bash"}},[s("code",[a._v("helm upgrade -i flagger flagger/flagger "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("\\")]),a._v("\n--namespace"),s("span",{pre:!0,attrs:{class:"token operator"}},[a._v("=")]),a._v("appmesh-system "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("\\")]),a._v("\n--set crd.create"),s("span",{pre:!0,attrs:{class:"token operator"}},[a._v("=")]),a._v("false "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("\\")]),a._v("\n--set "),s("span",{pre:!0,attrs:{class:"token assign-left variable"}},[a._v("meshProvider")]),s("span",{pre:!0,attrs:{class:"token operator"}},[a._v("=")]),a._v("appmesh "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("\\")]),a._v("\n--set "),s("span",{pre:!0,attrs:{class:"token assign-left variable"}},[a._v("metricsServer")]),s("span",{pre:!0,attrs:{class:"token operator"}},[a._v("=")]),a._v("http://appmesh-prometheus:9090\n")])])]),s("p",[a._v("You can enable Slack or MS Teams notifications with:")]),a._v(" "),s("div",{staticClass:"language-bash extra-class"},[s("pre",{pre:!0,attrs:{class:"language-bash"}},[s("code",[a._v("helm upgrade -i flagger flagger/flagger "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("\\")]),a._v("\n--reuse-values "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("\\")]),a._v("\n--namespace"),s("span",{pre:!0,attrs:{class:"token operator"}},[a._v("=")]),a._v("appmesh-system "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("\\")]),a._v("\n--set slack.url"),s("span",{pre:!0,attrs:{class:"token operator"}},[a._v("=")]),a._v("https://hooks.slack.com/services/YOUR/SLACK/WEBHOOK "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("\\")]),a._v("\n--set slack.channel"),s("span",{pre:!0,attrs:{class:"token operator"}},[a._v("=")]),a._v("general "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("\\")]),a._v("\n--set slack.user"),s("span",{pre:!0,attrs:{class:"token operator"}},[a._v("=")]),a._v("flagger\n")])])]),s("p",[a._v("Flagger comes with a Grafana dashboard made for monitoring the canary analysis. Deploy Grafana in the "),s("em",[s("strong",[a._v("appmesh-system")])]),a._v(" namespace:")]),a._v(" "),s("div",{staticClass:"language-bash extra-class"},[s("pre",{pre:!0,attrs:{class:"language-bash"}},[s("code",[a._v("helm upgrade -i flagger-grafana flagger/grafana "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("\\")]),a._v("\n--namespace"),s("span",{pre:!0,attrs:{class:"token operator"}},[a._v("=")]),a._v("appmesh-system "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("\\")]),a._v("\n--set "),s("span",{pre:!0,attrs:{class:"token assign-left variable"}},[a._v("url")]),s("span",{pre:!0,attrs:{class:"token operator"}},[a._v("=")]),a._v("http://appmesh-prometheus:9090\n")])])]),s("p",[a._v("You can access Grafana using port forwarding:")]),a._v(" "),s("div",{staticClass:"language-bash extra-class"},[s("pre",{pre:!0,attrs:{class:"language-bash"}},[s("code",[a._v("kubectl -n appmesh-system port-forward svc/flagger-grafana "),s("span",{pre:!0,attrs:{class:"token number"}},[a._v("3000")]),a._v(":80\n")])])]),s("p",[a._v("Now that you have Flagger running you can try the "),s("a",{attrs:{href:"https://docs.flagger.app/usage/appmesh-progressive-delivery",target:"_blank",rel:"noopener noreferrer"}},[a._v("App Mesh canary deployments tutorial"),s("OutboundLink")],1),a._v(".")])])},[],!1,null,null,null);e.default=r.exports}}]); \ No newline at end of file +(window.webpackJsonp=window.webpackJsonp||[]).push([[11],{270:function(a,e,s){"use strict";s.r(e);var t=s(37),r=Object(t.a)({},function(){var a=this,e=a.$createElement,s=a._self._c||e;return s("ContentSlotsDistributor",{attrs:{"slot-key":a.$parent.slotKey}},[s("h1",{attrs:{id:"flagger-install-on-eks-app-mesh"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#flagger-install-on-eks-app-mesh","aria-hidden":"true"}},[a._v("#")]),a._v(" Flagger Install on EKS App Mesh")]),a._v(" "),s("p",[a._v("This guide walks you through setting up Flagger and AWS App Mesh on EKS.")]),a._v(" "),s("h2",{attrs:{id:"app-mesh"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#app-mesh","aria-hidden":"true"}},[a._v("#")]),a._v(" App Mesh")]),a._v(" "),s("p",[a._v("The App Mesh integration with EKS is made out of the following components:")]),a._v(" "),s("ul",[s("li",[a._v("Kubernetes custom resources\n"),s("ul",[s("li",[s("code",[a._v("mesh.appmesh.k8s.aws")]),a._v(" defines a logical boundary for network traffic between the services")]),a._v(" "),s("li",[s("code",[a._v("virtualnode.appmesh.k8s.aws")]),a._v(" defines a logical pointer to a Kubernetes workload")]),a._v(" "),s("li",[s("code",[a._v("virtualservice.appmesh.k8s.aws")]),a._v(" defines the routing rules for a workload inside the mesh")])])]),a._v(" "),s("li",[a._v("CRD controller - keeps the custom resources in sync with the App Mesh control plane")]),a._v(" "),s("li",[a._v("Admission controller - injects the Envoy sidecar and assigns Kubernetes pods to App Mesh virtual nodes")]),a._v(" "),s("li",[a._v("Telemetry service - Prometheus instance that collects and stores Envoy's metrics")])]),a._v(" "),s("h2",{attrs:{id:"create-a-kubernetes-cluster"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#create-a-kubernetes-cluster","aria-hidden":"true"}},[a._v("#")]),a._v(" Create a Kubernetes cluster")]),a._v(" "),s("p",[a._v("In order to create an EKS cluster you can use "),s("a",{attrs:{href:"https://eksctl.io",target:"_blank",rel:"noopener noreferrer"}},[a._v("eksctl"),s("OutboundLink")],1),a._v(". Eksctl is an open source command-line utility made by Weaveworks in collaboration with Amazon.")]),a._v(" "),s("p",[a._v("On MacOS you can install eksctl with Homebrew:")]),a._v(" "),s("div",{staticClass:"language-bash extra-class"},[s("pre",{pre:!0,attrs:{class:"language-bash"}},[s("code",[a._v("brew tap weaveworks/tap\nbrew "),s("span",{pre:!0,attrs:{class:"token function"}},[a._v("install")]),a._v(" weaveworks/tap/eksctl\n")])])]),s("p",[a._v("Create an EKS cluster:")]),a._v(" "),s("div",{staticClass:"language-bash extra-class"},[s("pre",{pre:!0,attrs:{class:"language-bash"}},[s("code",[a._v("eksctl create cluster --name"),s("span",{pre:!0,attrs:{class:"token operator"}},[a._v("=")]),a._v("appmesh "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("\\")]),a._v("\n--region"),s("span",{pre:!0,attrs:{class:"token operator"}},[a._v("=")]),a._v("us-west-2 "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("\\")]),a._v("\n--nodes "),s("span",{pre:!0,attrs:{class:"token number"}},[a._v("3")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("\\")]),a._v("\n--node-volume-size"),s("span",{pre:!0,attrs:{class:"token operator"}},[a._v("=")]),s("span",{pre:!0,attrs:{class:"token number"}},[a._v("120")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("\\")]),a._v("\n--appmesh-access\n")])])]),s("p",[a._v("The above command will create a two nodes cluster with App Mesh "),s("a",{attrs:{href:"https://docs.aws.amazon.com/app-mesh/latest/userguide/MESH_IAM_user_policies.html",target:"_blank",rel:"noopener noreferrer"}},[a._v("IAM policy"),s("OutboundLink")],1),a._v(" attached to the EKS node instance role.")]),a._v(" "),s("p",[a._v("Verify the install with:")]),a._v(" "),s("div",{staticClass:"language-bash extra-class"},[s("pre",{pre:!0,attrs:{class:"language-bash"}},[s("code",[a._v("kubectl get nodes\n")])])]),s("h2",{attrs:{id:"install-helm"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#install-helm","aria-hidden":"true"}},[a._v("#")]),a._v(" Install Helm")]),a._v(" "),s("p",[a._v("Install the "),s("a",{attrs:{href:"https://docs.helm.sh/using_helm/#installing-helm",target:"_blank",rel:"noopener noreferrer"}},[a._v("Helm"),s("OutboundLink")],1),a._v(" command-line tool:")]),a._v(" "),s("div",{staticClass:"language-text extra-class"},[s("pre",{pre:!0,attrs:{class:"language-text"}},[s("code",[a._v("brew install kubernetes-helm\n")])])]),s("p",[a._v("Create a service account and a cluster role binding for Tiller:")]),a._v(" "),s("div",{staticClass:"language-bash extra-class"},[s("pre",{pre:!0,attrs:{class:"language-bash"}},[s("code",[a._v("kubectl -n kube-system create sa tiller\n\nkubectl create clusterrolebinding tiller-cluster-rule "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("\\")]),a._v("\n--clusterrole"),s("span",{pre:!0,attrs:{class:"token operator"}},[a._v("=")]),a._v("cluster-admin "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("\\")]),a._v("\n--serviceaccount"),s("span",{pre:!0,attrs:{class:"token operator"}},[a._v("=")]),a._v("kube-system:tiller\n")])])]),s("p",[a._v("Deploy Tiller in the "),s("code",[a._v("kube-system")]),a._v(" namespace:")]),a._v(" "),s("div",{staticClass:"language-bash extra-class"},[s("pre",{pre:!0,attrs:{class:"language-bash"}},[s("code",[a._v("helm init --service-account tiller\n")])])]),s("p",[a._v("You should consider using SSL between Helm and Tiller, for more information on securing your Helm installation see "),s("a",{attrs:{href:"https://docs.helm.sh/using_helm/#securing-your-helm-installation",target:"_blank",rel:"noopener noreferrer"}},[a._v("docs.helm.sh"),s("OutboundLink")],1),a._v(".")]),a._v(" "),s("h2",{attrs:{id:"enable-horizontal-pod-auto-scaling"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#enable-horizontal-pod-auto-scaling","aria-hidden":"true"}},[a._v("#")]),a._v(" Enable horizontal pod auto-scaling")]),a._v(" "),s("p",[a._v("Install the Horizontal Pod Autoscaler (HPA) metrics provider:")]),a._v(" "),s("div",{staticClass:"language-bash extra-class"},[s("pre",{pre:!0,attrs:{class:"language-bash"}},[s("code",[a._v("helm upgrade -i metrics-server stable/metrics-server "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("\\")]),a._v("\n--namespace kube-system "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("\\")]),a._v("\n--set args"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("[")]),s("span",{pre:!0,attrs:{class:"token number"}},[a._v("0")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("]")]),s("span",{pre:!0,attrs:{class:"token operator"}},[a._v("=")]),a._v("--kubelet-preferred-address-types"),s("span",{pre:!0,attrs:{class:"token operator"}},[a._v("=")]),a._v("InternalIP\n")])])]),s("p",[a._v("After a minute, the metrics API should report CPU and memory usage for pods. You can very the metrics API with:")]),a._v(" "),s("div",{staticClass:"language-bash extra-class"},[s("pre",{pre:!0,attrs:{class:"language-bash"}},[s("code",[a._v("kubectl -n kube-system "),s("span",{pre:!0,attrs:{class:"token function"}},[a._v("top")]),a._v(" pods\n")])])]),s("h2",{attrs:{id:"install-the-app-mesh-components"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#install-the-app-mesh-components","aria-hidden":"true"}},[a._v("#")]),a._v(" Install the App Mesh components")]),a._v(" "),s("p",[a._v("Create the "),s("code",[a._v("appmesh-system")]),a._v(" namespace:")]),a._v(" "),s("div",{staticClass:"language-bash extra-class"},[s("pre",{pre:!0,attrs:{class:"language-bash"}},[s("code",[a._v("kubectl create ns appmesh-system\n")])])]),s("p",[a._v("Apply the App Mesh CRDs:")]),a._v(" "),s("div",{staticClass:"language-bash extra-class"},[s("pre",{pre:!0,attrs:{class:"language-bash"}},[s("code",[a._v("kubectl apply -k github.com/aws/eks-charts/stable/appmesh-controller//crds\n")])])]),s("p",[a._v("Add the EKS repository to Helm:")]),a._v(" "),s("div",{staticClass:"language-bash extra-class"},[s("pre",{pre:!0,attrs:{class:"language-bash"}},[s("code",[a._v("helm repo "),s("span",{pre:!0,attrs:{class:"token function"}},[a._v("add")]),a._v(" eks https://aws.github.io/eks-charts\n")])])]),s("p",[a._v("Install the App Mesh CRD controller:")]),a._v(" "),s("div",{staticClass:"language-bash extra-class"},[s("pre",{pre:!0,attrs:{class:"language-bash"}},[s("code",[a._v("helm upgrade -i appmesh-controller eks/appmesh-controller "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("\\")]),a._v("\n--wait --namespace appmesh-system\n")])])]),s("p",[a._v("Install the App Mesh admission controller and create a mesh called "),s("code",[a._v("global")]),a._v(":")]),a._v(" "),s("div",{staticClass:"language-bash extra-class"},[s("pre",{pre:!0,attrs:{class:"language-bash"}},[s("code",[a._v("helm upgrade -i appmesh-inject eks/appmesh-inject "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("\\")]),a._v("\n--wait --namespace appmesh-system "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("\\")]),a._v("\n--set mesh.create"),s("span",{pre:!0,attrs:{class:"token operator"}},[a._v("=")]),a._v("true "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("\\")]),a._v("\n--set mesh.name"),s("span",{pre:!0,attrs:{class:"token operator"}},[a._v("=")]),a._v("global\n")])])]),s("p",[a._v("Verify that the global mesh is active:")]),a._v(" "),s("div",{staticClass:"language-bash extra-class"},[s("pre",{pre:!0,attrs:{class:"language-bash"}},[s("code",[a._v("kubectl describe mesh\n\nStatus:\n Mesh Condition:\n Status: True\n Type: MeshActive\n")])])]),s("p",[a._v("In order to collect the App Mesh metrics that Flagger needs to run the canary analysis, you'll need to setup a Prometheus instance to scrape the Envoy sidecars.")]),a._v(" "),s("p",[a._v("Install the App Mesh Prometheus:")]),a._v(" "),s("div",{staticClass:"language-bash extra-class"},[s("pre",{pre:!0,attrs:{class:"language-bash"}},[s("code",[a._v("helm upgrade -i appmesh-prometheus eks/appmesh-prometheus "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("\\")]),a._v("\n--wait --namespace appmesh-system\n")])])]),s("h2",{attrs:{id:"install-flagger-and-grafana"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#install-flagger-and-grafana","aria-hidden":"true"}},[a._v("#")]),a._v(" Install Flagger and Grafana")]),a._v(" "),s("p",[a._v("Add Flagger Helm repository:")]),a._v(" "),s("div",{staticClass:"language-bash extra-class"},[s("pre",{pre:!0,attrs:{class:"language-bash"}},[s("code",[a._v("helm repo "),s("span",{pre:!0,attrs:{class:"token function"}},[a._v("add")]),a._v(" flagger https://flagger.app\n")])])]),s("p",[a._v("Install Flagger's Canary CRD:")]),a._v(" "),s("div",{staticClass:"language-yaml extra-class"},[s("pre",{pre:!0,attrs:{class:"language-yaml"}},[s("code",[a._v("kubectl apply "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("-")]),a._v("f https"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(":")]),a._v("//raw.githubusercontent.com/weaveworks/flagger/master/artifacts/flagger/crd.yaml\n")])])]),s("p",[a._v("Deploy Flagger in the "),s("em",[s("strong",[a._v("appmesh-system")])]),a._v(" namespace:")]),a._v(" "),s("div",{staticClass:"language-bash extra-class"},[s("pre",{pre:!0,attrs:{class:"language-bash"}},[s("code",[a._v("helm upgrade -i flagger flagger/flagger "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("\\")]),a._v("\n--namespace"),s("span",{pre:!0,attrs:{class:"token operator"}},[a._v("=")]),a._v("appmesh-system "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("\\")]),a._v("\n--set crd.create"),s("span",{pre:!0,attrs:{class:"token operator"}},[a._v("=")]),a._v("false "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("\\")]),a._v("\n--set "),s("span",{pre:!0,attrs:{class:"token assign-left variable"}},[a._v("meshProvider")]),s("span",{pre:!0,attrs:{class:"token operator"}},[a._v("=")]),a._v("appmesh "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("\\")]),a._v("\n--set "),s("span",{pre:!0,attrs:{class:"token assign-left variable"}},[a._v("metricsServer")]),s("span",{pre:!0,attrs:{class:"token operator"}},[a._v("=")]),a._v("http://appmesh-prometheus:9090\n")])])]),s("p",[a._v("You can enable Slack or MS Teams notifications with:")]),a._v(" "),s("div",{staticClass:"language-bash extra-class"},[s("pre",{pre:!0,attrs:{class:"language-bash"}},[s("code",[a._v("helm upgrade -i flagger flagger/flagger "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("\\")]),a._v("\n--reuse-values "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("\\")]),a._v("\n--namespace"),s("span",{pre:!0,attrs:{class:"token operator"}},[a._v("=")]),a._v("appmesh-system "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("\\")]),a._v("\n--set slack.url"),s("span",{pre:!0,attrs:{class:"token operator"}},[a._v("=")]),a._v("https://hooks.slack.com/services/YOUR/SLACK/WEBHOOK "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("\\")]),a._v("\n--set slack.channel"),s("span",{pre:!0,attrs:{class:"token operator"}},[a._v("=")]),a._v("general "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("\\")]),a._v("\n--set slack.user"),s("span",{pre:!0,attrs:{class:"token operator"}},[a._v("=")]),a._v("flagger\n")])])]),s("p",[a._v("Flagger comes with a Grafana dashboard made for monitoring the canary analysis. Deploy Grafana in the "),s("em",[s("strong",[a._v("appmesh-system")])]),a._v(" namespace:")]),a._v(" "),s("div",{staticClass:"language-bash extra-class"},[s("pre",{pre:!0,attrs:{class:"language-bash"}},[s("code",[a._v("helm upgrade -i flagger-grafana flagger/grafana "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("\\")]),a._v("\n--namespace"),s("span",{pre:!0,attrs:{class:"token operator"}},[a._v("=")]),a._v("appmesh-system "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("\\")]),a._v("\n--set "),s("span",{pre:!0,attrs:{class:"token assign-left variable"}},[a._v("url")]),s("span",{pre:!0,attrs:{class:"token operator"}},[a._v("=")]),a._v("http://appmesh-prometheus:9090\n")])])]),s("p",[a._v("You can access Grafana using port forwarding:")]),a._v(" "),s("div",{staticClass:"language-bash extra-class"},[s("pre",{pre:!0,attrs:{class:"language-bash"}},[s("code",[a._v("kubectl -n appmesh-system port-forward svc/flagger-grafana "),s("span",{pre:!0,attrs:{class:"token number"}},[a._v("3000")]),a._v(":80\n")])])]),s("p",[a._v("Now that you have Flagger running you can try the "),s("a",{attrs:{href:"https://docs.flagger.app/usage/appmesh-progressive-delivery",target:"_blank",rel:"noopener noreferrer"}},[a._v("App Mesh canary deployments tutorial"),s("OutboundLink")],1),a._v(".")])])},[],!1,null,null,null);e.default=r.exports}}]); \ No newline at end of file diff --git a/assets/js/13.9104349a.js b/assets/js/13.6b55cb59.js similarity index 99% rename from assets/js/13.9104349a.js rename to assets/js/13.6b55cb59.js index e3f22559..553f44ec 100644 --- a/assets/js/13.9104349a.js +++ b/assets/js/13.6b55cb59.js @@ -1 +1 @@ -(window.webpackJsonp=window.webpackJsonp||[]).push([[13],{273:function(a,e,t){"use strict";t.r(e);var s=t(37),r=Object(s.a)({},function(){var a=this,e=a.$createElement,t=a._self._c||e;return t("ContentSlotsDistributor",{attrs:{"slot-key":a.$parent.slotKey}},[t("h1",{attrs:{id:"flagger-install-on-kubernetes"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#flagger-install-on-kubernetes","aria-hidden":"true"}},[a._v("#")]),a._v(" Flagger Install on Kubernetes")]),a._v(" "),t("p",[a._v("This guide walks you through setting up Flagger on a Kubernetes cluster with Helm v3 or Kustomize.")]),a._v(" "),t("h2",{attrs:{id:"prerequisites"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#prerequisites","aria-hidden":"true"}},[a._v("#")]),a._v(" Prerequisites")]),a._v(" "),t("p",[a._v("Flagger requires a Kubernetes cluster "),t("strong",[a._v("v1.11")]),a._v(" or newer.")]),a._v(" "),t("h2",{attrs:{id:"install-flagger-with-helm"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#install-flagger-with-helm","aria-hidden":"true"}},[a._v("#")]),a._v(" Install Flagger with Helm")]),a._v(" "),t("p",[a._v("Add Flagger Helm repository:")]),a._v(" "),t("div",{staticClass:"language-bash extra-class"},[t("pre",{pre:!0,attrs:{class:"language-bash"}},[t("code",[a._v("helm repo "),t("span",{pre:!0,attrs:{class:"token function"}},[a._v("add")]),a._v(" flagger https://flagger.app\n")])])]),t("p",[a._v("Install Flagger's Canary CRD:")]),a._v(" "),t("div",{staticClass:"language-yaml extra-class"},[t("pre",{pre:!0,attrs:{class:"language-yaml"}},[t("code",[a._v("kubectl apply "),t("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("-")]),a._v("f https"),t("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(":")]),a._v("//raw.githubusercontent.com/weaveworks/flagger/master/artifacts/flagger/crd.yaml\n")])])]),t("p",[a._v("Deploy Flagger for Istio:")]),a._v(" "),t("div",{staticClass:"language-bash extra-class"},[t("pre",{pre:!0,attrs:{class:"language-bash"}},[t("code",[a._v("helm upgrade -i flagger flagger/flagger "),t("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("\\")]),a._v("\n--namespace"),t("span",{pre:!0,attrs:{class:"token operator"}},[a._v("=")]),a._v("istio-system "),t("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("\\")]),a._v("\n--set crd.create"),t("span",{pre:!0,attrs:{class:"token operator"}},[a._v("=")]),a._v("false "),t("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("\\")]),a._v("\n--set "),t("span",{pre:!0,attrs:{class:"token assign-left variable"}},[a._v("meshProvider")]),t("span",{pre:!0,attrs:{class:"token operator"}},[a._v("=")]),a._v("istio "),t("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("\\")]),a._v("\n--set "),t("span",{pre:!0,attrs:{class:"token assign-left variable"}},[a._v("metricsServer")]),t("span",{pre:!0,attrs:{class:"token operator"}},[a._v("=")]),a._v("http://prometheus:9090\n")])])]),t("p",[a._v("Note that Flagger depends on Istio telemetry and Prometheus, if you're installing Istio with istioctl\nthen you should be using the "),t("a",{attrs:{href:"https://istio.io/docs/setup/additional-setup/config-profiles/",target:"_blank",rel:"noopener noreferrer"}},[a._v("default profile"),t("OutboundLink")],1),a._v(".")]),a._v(" "),t("p",[a._v("For Istio multi-cluster shared control plane you can install Flagger\non each remote cluster and set the Istio control plane host cluster kubeconfig:")]),a._v(" "),t("div",{staticClass:"language-bash extra-class"},[t("pre",{pre:!0,attrs:{class:"language-bash"}},[t("code",[a._v("helm upgrade -i flagger flagger/flagger "),t("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("\\")]),a._v("\n--namespace"),t("span",{pre:!0,attrs:{class:"token operator"}},[a._v("=")]),a._v("istio-system "),t("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("\\")]),a._v("\n--set crd.create"),t("span",{pre:!0,attrs:{class:"token operator"}},[a._v("=")]),a._v("false "),t("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("\\")]),a._v("\n--set "),t("span",{pre:!0,attrs:{class:"token assign-left variable"}},[a._v("meshProvider")]),t("span",{pre:!0,attrs:{class:"token operator"}},[a._v("=")]),a._v("istio "),t("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("\\")]),a._v("\n--set "),t("span",{pre:!0,attrs:{class:"token assign-left variable"}},[a._v("metricsServer")]),t("span",{pre:!0,attrs:{class:"token operator"}},[a._v("=")]),a._v("http://istio-cluster-prometheus:9090 "),t("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("\\")]),a._v("\n--set istio.kubeconfig.secretName"),t("span",{pre:!0,attrs:{class:"token operator"}},[a._v("=")]),a._v("istio-kubeconfig "),t("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("\\")]),a._v("\n--set istio.kubeconfig.key"),t("span",{pre:!0,attrs:{class:"token operator"}},[a._v("=")]),a._v("kubeconfig\n")])])]),t("p",[a._v("Note that the Istio kubeconfig must be stored in a Kubernetes secret with a data key named "),t("code",[a._v("kubeconfig")]),a._v(".\nFor more details on how to configure Istio multi-cluster credentials\nread the "),t("a",{attrs:{href:"https://istio.io/docs/setup/install/multicluster/shared-vpn/#credentials",target:"_blank",rel:"noopener noreferrer"}},[a._v("Istio docs"),t("OutboundLink")],1),a._v(".")]),a._v(" "),t("p",[a._v("Deploy Flagger for Linkerd:")]),a._v(" "),t("div",{staticClass:"language-bash extra-class"},[t("pre",{pre:!0,attrs:{class:"language-bash"}},[t("code",[a._v("helm upgrade -i flagger flagger/flagger "),t("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("\\")]),a._v("\n--namespace"),t("span",{pre:!0,attrs:{class:"token operator"}},[a._v("=")]),a._v("linkerd "),t("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("\\")]),a._v("\n--set crd.create"),t("span",{pre:!0,attrs:{class:"token operator"}},[a._v("=")]),a._v("false "),t("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("\\")]),a._v("\n--set "),t("span",{pre:!0,attrs:{class:"token assign-left variable"}},[a._v("meshProvider")]),t("span",{pre:!0,attrs:{class:"token operator"}},[a._v("=")]),a._v("linkerd "),t("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("\\")]),a._v("\n--set "),t("span",{pre:!0,attrs:{class:"token assign-left variable"}},[a._v("metricsServer")]),t("span",{pre:!0,attrs:{class:"token operator"}},[a._v("=")]),a._v("http://linkerd-prometheus:9090\n")])])]),t("p",[a._v("Deploy Flagger for App Mesh:")]),a._v(" "),t("div",{staticClass:"language-bash extra-class"},[t("pre",{pre:!0,attrs:{class:"language-bash"}},[t("code",[a._v("helm upgrade -i flagger flagger/flagger "),t("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("\\")]),a._v("\n--namespace"),t("span",{pre:!0,attrs:{class:"token operator"}},[a._v("=")]),a._v("appmesh-system "),t("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("\\")]),a._v("\n--set crd.create"),t("span",{pre:!0,attrs:{class:"token operator"}},[a._v("=")]),a._v("false "),t("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("\\")]),a._v("\n--set "),t("span",{pre:!0,attrs:{class:"token assign-left variable"}},[a._v("meshProvider")]),t("span",{pre:!0,attrs:{class:"token operator"}},[a._v("=")]),a._v("appmesh "),t("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("\\")]),a._v("\n--set "),t("span",{pre:!0,attrs:{class:"token assign-left variable"}},[a._v("metricsServer")]),t("span",{pre:!0,attrs:{class:"token operator"}},[a._v("=")]),a._v("http://appmesh-prometheus:9090\n")])])]),t("p",[a._v("You can install Flagger in any namespace as long as it can talk to the Prometheus service on port 9090.")]),a._v(" "),t("p",[a._v("For ingress controllers, the install instructions are:")]),a._v(" "),t("ul",[t("li",[t("a",{attrs:{href:"https://docs.flagger.app/tutorials/contour-progressive-delivery",target:"_blank",rel:"noopener noreferrer"}},[a._v("Contour"),t("OutboundLink")],1)]),a._v(" "),t("li",[t("a",{attrs:{href:"https://docs.flagger.app/tutorials/gloo-progressive-delivery",target:"_blank",rel:"noopener noreferrer"}},[a._v("Gloo"),t("OutboundLink")],1)]),a._v(" "),t("li",[t("a",{attrs:{href:"https://docs.flagger.app/tutorials/nginx-progressive-delivery",target:"_blank",rel:"noopener noreferrer"}},[a._v("NGINX"),t("OutboundLink")],1)])]),a._v(" "),t("p",[a._v("Enable "),t("strong",[a._v("Slack")]),a._v(" notifications:")]),a._v(" "),t("div",{staticClass:"language-bash extra-class"},[t("pre",{pre:!0,attrs:{class:"language-bash"}},[t("code",[a._v("helm upgrade -i flagger flagger/flagger "),t("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("\\")]),a._v("\n--namespace"),t("span",{pre:!0,attrs:{class:"token operator"}},[a._v("=")]),a._v("istio-system "),t("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("\\")]),a._v("\n--set crd.create"),t("span",{pre:!0,attrs:{class:"token operator"}},[a._v("=")]),a._v("false "),t("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("\\")]),a._v("\n--set slack.url"),t("span",{pre:!0,attrs:{class:"token operator"}},[a._v("=")]),a._v("https://hooks.slack.com/services/YOUR/SLACK/WEBHOOK "),t("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("\\")]),a._v("\n--set slack.channel"),t("span",{pre:!0,attrs:{class:"token operator"}},[a._v("=")]),a._v("general "),t("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("\\")]),a._v("\n--set slack.user"),t("span",{pre:!0,attrs:{class:"token operator"}},[a._v("=")]),a._v("flagger\n")])])]),t("p",[a._v("Enable "),t("strong",[a._v("Microsoft Teams")]),a._v(" notifications:")]),a._v(" "),t("div",{staticClass:"language-bash extra-class"},[t("pre",{pre:!0,attrs:{class:"language-bash"}},[t("code",[a._v("helm upgrade -i flagger flagger/flagger "),t("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("\\")]),a._v("\n--namespace"),t("span",{pre:!0,attrs:{class:"token operator"}},[a._v("=")]),a._v("istio-system "),t("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("\\")]),a._v("\n--set crd.create"),t("span",{pre:!0,attrs:{class:"token operator"}},[a._v("=")]),a._v("false "),t("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("\\")]),a._v("\n--set msteams.url"),t("span",{pre:!0,attrs:{class:"token operator"}},[a._v("=")]),a._v("https://outlook.office.com/webhook/YOUR/TEAMS/WEBHOOK\n")])])]),t("p",[a._v("You can use the helm template command and apply the generated yaml with kubectl:")]),a._v(" "),t("div",{staticClass:"language-bash extra-class"},[t("pre",{pre:!0,attrs:{class:"language-bash"}},[t("code",[t("span",{pre:!0,attrs:{class:"token comment"}},[a._v("# generate")]),a._v("\nhelm fetch --untar --untardir "),t("span",{pre:!0,attrs:{class:"token builtin class-name"}},[a._v(".")]),a._v(" flagger/flagger "),t("span",{pre:!0,attrs:{class:"token operator"}},[a._v("&&")]),a._v("\nhelm template flagger ./flagger "),t("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("\\")]),a._v("\n--namespace"),t("span",{pre:!0,attrs:{class:"token operator"}},[a._v("=")]),a._v("istio-system "),t("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("\\")]),a._v("\n--set "),t("span",{pre:!0,attrs:{class:"token assign-left variable"}},[a._v("metricsServer")]),t("span",{pre:!0,attrs:{class:"token operator"}},[a._v("=")]),a._v("http://prometheus.istio-system:9090 "),t("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("\\")]),a._v("\n"),t("span",{pre:!0,attrs:{class:"token operator"}},[a._v(">")]),a._v(" flagger.yaml\n\n"),t("span",{pre:!0,attrs:{class:"token comment"}},[a._v("# apply")]),a._v("\nkubectl apply -f flagger.yaml\n")])])]),t("p",[a._v("To uninstall the Flagger release with Helm run:")]),a._v(" "),t("div",{staticClass:"language-text extra-class"},[t("pre",{pre:!0,attrs:{class:"language-text"}},[t("code",[a._v("helm delete flagger\n")])])]),t("p",[a._v("The command removes all the Kubernetes components associated with the chart and deletes the release.")]),a._v(" "),t("blockquote",[t("p",[t("strong",[a._v("Note")]),a._v(" that on uninstall the Canary CRD will not be removed. Deleting the CRD will make Kubernetes\nremove all the objects owned by Flagger like Istio virtual services, Kubernetes deployments and ClusterIP services.")])]),a._v(" "),t("p",[a._v("If you want to remove all the objects created by Flagger you have delete the Canary CRD with kubectl:")]),a._v(" "),t("div",{staticClass:"language-text extra-class"},[t("pre",{pre:!0,attrs:{class:"language-text"}},[t("code",[a._v("kubectl delete crd canaries.flagger.app\n")])])]),t("h2",{attrs:{id:"install-grafana-with-helm"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#install-grafana-with-helm","aria-hidden":"true"}},[a._v("#")]),a._v(" Install Grafana with Helm")]),a._v(" "),t("p",[a._v("Flagger comes with a Grafana dashboard made for monitoring the canary analysis.")]),a._v(" "),t("p",[a._v("Deploy Grafana in the "),t("em",[t("strong",[a._v("istio-system")])]),a._v(" namespace:")]),a._v(" "),t("div",{staticClass:"language-bash extra-class"},[t("pre",{pre:!0,attrs:{class:"language-bash"}},[t("code",[a._v("helm upgrade -i flagger-grafana flagger/grafana "),t("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("\\")]),a._v("\n--namespace"),t("span",{pre:!0,attrs:{class:"token operator"}},[a._v("=")]),a._v("istio-system "),t("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("\\")]),a._v("\n--set "),t("span",{pre:!0,attrs:{class:"token assign-left variable"}},[a._v("url")]),t("span",{pre:!0,attrs:{class:"token operator"}},[a._v("=")]),a._v("http://prometheus.istio-system:9090 "),t("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("\\")]),a._v("\n--set "),t("span",{pre:!0,attrs:{class:"token assign-left variable"}},[a._v("user")]),t("span",{pre:!0,attrs:{class:"token operator"}},[a._v("=")]),a._v("admin "),t("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("\\")]),a._v("\n--set "),t("span",{pre:!0,attrs:{class:"token assign-left variable"}},[a._v("password")]),t("span",{pre:!0,attrs:{class:"token operator"}},[a._v("=")]),a._v("change-me\n")])])]),t("p",[a._v("Or use helm template command and apply the generated yaml with kubectl:")]),a._v(" "),t("div",{staticClass:"language-bash extra-class"},[t("pre",{pre:!0,attrs:{class:"language-bash"}},[t("code",[t("span",{pre:!0,attrs:{class:"token comment"}},[a._v("# generate")]),a._v("\nhelm fetch --untar --untardir "),t("span",{pre:!0,attrs:{class:"token builtin class-name"}},[a._v(".")]),a._v(" flagger/grafana "),t("span",{pre:!0,attrs:{class:"token operator"}},[a._v("&&")]),a._v("\nhelm template flagger-grafana ./grafana "),t("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("\\")]),a._v("\n--namespace"),t("span",{pre:!0,attrs:{class:"token operator"}},[a._v("=")]),a._v("istio-system "),t("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("\\")]),a._v("\n"),t("span",{pre:!0,attrs:{class:"token operator"}},[a._v(">")]),a._v(" flagger-grafana.yaml\n\n"),t("span",{pre:!0,attrs:{class:"token comment"}},[a._v("# apply")]),a._v("\nkubectl apply -f flagger-grafana.yaml\n")])])]),t("p",[a._v("You can access Grafana using port forwarding:")]),a._v(" "),t("div",{staticClass:"language-bash extra-class"},[t("pre",{pre:!0,attrs:{class:"language-bash"}},[t("code",[a._v("kubectl -n istio-system port-forward svc/flagger-grafana "),t("span",{pre:!0,attrs:{class:"token number"}},[a._v("3000")]),a._v(":80\n")])])]),t("h2",{attrs:{id:"install-flagger-with-kustomize"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#install-flagger-with-kustomize","aria-hidden":"true"}},[a._v("#")]),a._v(" Install Flagger with Kustomize")]),a._v(" "),t("p",[a._v("As an alternative to Helm, Flagger can be installed with Kustomize.")]),a._v(" "),t("p",[t("strong",[a._v("Service mesh specific installers")])]),a._v(" "),t("p",[a._v("Install Flagger for Istio:")]),a._v(" "),t("div",{staticClass:"language-bash extra-class"},[t("pre",{pre:!0,attrs:{class:"language-bash"}},[t("code",[a._v("kubectl apply -k github.com/weaveworks/flagger//kustomize/istio\n")])])]),t("p",[a._v("This deploys Flagger in the "),t("code",[a._v("istio-system")]),a._v(" namespace and sets the metrics server URL to Istio's Prometheus instance.")]),a._v(" "),t("p",[a._v("Note that you'll need kubectl 1.14 to run the above the command or you can download\nthe "),t("a",{attrs:{href:"https://github.com/kubernetes-sigs/kustomize/releases",target:"_blank",rel:"noopener noreferrer"}},[a._v("kustomize binary"),t("OutboundLink")],1),a._v(" and run:")]),a._v(" "),t("div",{staticClass:"language-bash extra-class"},[t("pre",{pre:!0,attrs:{class:"language-bash"}},[t("code",[a._v("kustomize build github.com/weaveworks/flagger//kustomize/istio "),t("span",{pre:!0,attrs:{class:"token operator"}},[a._v("|")]),a._v(" kubectl apply -f -\n")])])]),t("p",[a._v("Install Flagger for AWS App Mesh:")]),a._v(" "),t("div",{staticClass:"language-bash extra-class"},[t("pre",{pre:!0,attrs:{class:"language-bash"}},[t("code",[a._v("kubectl apply -k github.com/weaveworks/flagger//kustomize/appmesh\n")])])]),t("p",[a._v("This deploys Flagger and sets the metrics server URL to App Mesh's Prometheus instance.")]),a._v(" "),t("p",[a._v("Install Flagger for Linkerd:")]),a._v(" "),t("div",{staticClass:"language-bash extra-class"},[t("pre",{pre:!0,attrs:{class:"language-bash"}},[t("code",[a._v("kubectl apply -k github.com/weaveworks/flagger//kustomize/linkerd\n")])])]),t("p",[a._v("This deploys Flagger in the "),t("code",[a._v("linkerd")]),a._v(" namespace and sets the metrics server URL to Linkerd's Prometheus instance.")]),a._v(" "),t("p",[a._v("If you want to install a specific Flagger release, add the version number to the URL:")]),a._v(" "),t("div",{staticClass:"language-bash extra-class"},[t("pre",{pre:!0,attrs:{class:"language-bash"}},[t("code",[a._v("kubectl apply -k github.com/weaveworks/flagger//kustomize/linkerd?ref"),t("span",{pre:!0,attrs:{class:"token operator"}},[a._v("=")]),t("span",{pre:!0,attrs:{class:"token number"}},[a._v("0.18")]),a._v(".0\n")])])]),t("p",[t("strong",[a._v("Generic installer")])]),a._v(" "),t("p",[a._v("Install Flagger and Prometheus:")]),a._v(" "),t("div",{staticClass:"language-bash extra-class"},[t("pre",{pre:!0,attrs:{class:"language-bash"}},[t("code",[a._v("kubectl apply -k github.com/weaveworks/flagger//kustomize/kubernetes\n")])])]),t("p",[a._v("This deploys Flagger and Prometheus in the "),t("code",[a._v("flagger-system")]),a._v(" namespace, sets the metrics server URL\nto "),t("code",[a._v("http://flagger-prometheus.flagger-system:9090")]),a._v(" and the mesh provider to "),t("code",[a._v("kubernetes")]),a._v(".")]),a._v(" "),t("p",[a._v("The Prometheus instance has a two hours data retention and is configured to scrape all pods in your cluster\nthat have the "),t("code",[a._v('prometheus.io/scrape: "true"')]),a._v(" annotation.")]),a._v(" "),t("p",[a._v("To target a different provider you can specify it in the canary custom resource:")]),a._v(" "),t("div",{staticClass:"language-yaml extra-class"},[t("pre",{pre:!0,attrs:{class:"language-yaml"}},[t("code",[t("span",{pre:!0,attrs:{class:"token key atrule"}},[a._v("apiVersion")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(":")]),a._v(" flagger.app/v1beta1\n"),t("span",{pre:!0,attrs:{class:"token key atrule"}},[a._v("kind")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(":")]),a._v(" Canary\n"),t("span",{pre:!0,attrs:{class:"token key atrule"}},[a._v("metadata")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(":")]),a._v("\n "),t("span",{pre:!0,attrs:{class:"token key atrule"}},[a._v("name")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(":")]),a._v(" app\n "),t("span",{pre:!0,attrs:{class:"token key atrule"}},[a._v("namespace")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(":")]),a._v(" test\n"),t("span",{pre:!0,attrs:{class:"token key atrule"}},[a._v("spec")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(":")]),a._v("\n "),t("span",{pre:!0,attrs:{class:"token comment"}},[a._v("# can be: kubernetes, istio, linkerd, appmesh, nginx, gloo")]),a._v("\n "),t("span",{pre:!0,attrs:{class:"token comment"}},[a._v("# use the kubernetes provider for Blue/Green style deployments")]),a._v("\n "),t("span",{pre:!0,attrs:{class:"token key atrule"}},[a._v("provider")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(":")]),a._v(" nginx\n")])])]),t("p",[t("strong",[a._v("Customized installer")])]),a._v(" "),t("p",[a._v("Create a kustomization file using flagger as base:")]),a._v(" "),t("div",{staticClass:"language-bash extra-class"},[t("pre",{pre:!0,attrs:{class:"language-bash"}},[t("code",[t("span",{pre:!0,attrs:{class:"token function"}},[a._v("cat")]),a._v(" "),t("span",{pre:!0,attrs:{class:"token operator"}},[a._v(">")]),a._v(" kustomization.yaml "),t("span",{pre:!0,attrs:{class:"token operator"}},[a._v("<<")]),t("span",{pre:!0,attrs:{class:"token string"}},[a._v("EOF\nnamespace: istio-system\nbases:\n - github.com/weaveworks/flagger/kustomize/base/flagger\npatchesStrategicMerge:\n - patch.yaml\nEOF")]),a._v("\n")])])]),t("p",[a._v("Create a patch and enable Slack notifications by setting the slack channel and hook URL:")]),a._v(" "),t("div",{staticClass:"language-bash extra-class"},[t("pre",{pre:!0,attrs:{class:"language-bash"}},[t("code",[t("span",{pre:!0,attrs:{class:"token function"}},[a._v("cat")]),a._v(" "),t("span",{pre:!0,attrs:{class:"token operator"}},[a._v(">")]),a._v(" patch.yaml "),t("span",{pre:!0,attrs:{class:"token operator"}},[a._v("<<")]),t("span",{pre:!0,attrs:{class:"token string"}},[a._v("EOF\napiVersion: apps/v1\nkind: Deployment\nmetadata:\n name: flagger\nspec:\n template:\n spec:\n containers:\n - name: flagger\n args:\n - -mesh-provider=istio\n - -metrics-server=http://prometheus.istio-system:9090\n - -slack-user=flagger\n - -slack-channel=alerts\n - -slack-url=https://hooks.slack.com/services/YOUR/SLACK/WEBHOOK\nEOF")]),a._v("\n")])])]),t("p",[a._v("Install Flagger with Slack:")]),a._v(" "),t("div",{staticClass:"language-bash extra-class"},[t("pre",{pre:!0,attrs:{class:"language-bash"}},[t("code",[a._v("kubectl apply -k "),t("span",{pre:!0,attrs:{class:"token builtin class-name"}},[a._v(".")]),a._v("\n")])])]),t("p",[a._v("If you want to use MS Teams instead of Slack, replace "),t("code",[a._v("-slack-url")]),a._v(" with "),t("code",[a._v("-msteams-url")]),a._v(" and set the webhook address\nto "),t("code",[a._v("https://outlook.office.com/webhook/YOUR/TEAMS/WEBHOOK")]),a._v(".")])])},[],!1,null,null,null);e.default=r.exports}}]); \ No newline at end of file +(window.webpackJsonp=window.webpackJsonp||[]).push([[13],{274:function(a,e,t){"use strict";t.r(e);var s=t(37),r=Object(s.a)({},function(){var a=this,e=a.$createElement,t=a._self._c||e;return t("ContentSlotsDistributor",{attrs:{"slot-key":a.$parent.slotKey}},[t("h1",{attrs:{id:"flagger-install-on-kubernetes"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#flagger-install-on-kubernetes","aria-hidden":"true"}},[a._v("#")]),a._v(" Flagger Install on Kubernetes")]),a._v(" "),t("p",[a._v("This guide walks you through setting up Flagger on a Kubernetes cluster with Helm v3 or Kustomize.")]),a._v(" "),t("h2",{attrs:{id:"prerequisites"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#prerequisites","aria-hidden":"true"}},[a._v("#")]),a._v(" Prerequisites")]),a._v(" "),t("p",[a._v("Flagger requires a Kubernetes cluster "),t("strong",[a._v("v1.11")]),a._v(" or newer.")]),a._v(" "),t("h2",{attrs:{id:"install-flagger-with-helm"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#install-flagger-with-helm","aria-hidden":"true"}},[a._v("#")]),a._v(" Install Flagger with Helm")]),a._v(" "),t("p",[a._v("Add Flagger Helm repository:")]),a._v(" "),t("div",{staticClass:"language-bash extra-class"},[t("pre",{pre:!0,attrs:{class:"language-bash"}},[t("code",[a._v("helm repo "),t("span",{pre:!0,attrs:{class:"token function"}},[a._v("add")]),a._v(" flagger https://flagger.app\n")])])]),t("p",[a._v("Install Flagger's Canary CRD:")]),a._v(" "),t("div",{staticClass:"language-yaml extra-class"},[t("pre",{pre:!0,attrs:{class:"language-yaml"}},[t("code",[a._v("kubectl apply "),t("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("-")]),a._v("f https"),t("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(":")]),a._v("//raw.githubusercontent.com/weaveworks/flagger/master/artifacts/flagger/crd.yaml\n")])])]),t("p",[a._v("Deploy Flagger for Istio:")]),a._v(" "),t("div",{staticClass:"language-bash extra-class"},[t("pre",{pre:!0,attrs:{class:"language-bash"}},[t("code",[a._v("helm upgrade -i flagger flagger/flagger "),t("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("\\")]),a._v("\n--namespace"),t("span",{pre:!0,attrs:{class:"token operator"}},[a._v("=")]),a._v("istio-system "),t("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("\\")]),a._v("\n--set crd.create"),t("span",{pre:!0,attrs:{class:"token operator"}},[a._v("=")]),a._v("false "),t("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("\\")]),a._v("\n--set "),t("span",{pre:!0,attrs:{class:"token assign-left variable"}},[a._v("meshProvider")]),t("span",{pre:!0,attrs:{class:"token operator"}},[a._v("=")]),a._v("istio "),t("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("\\")]),a._v("\n--set "),t("span",{pre:!0,attrs:{class:"token assign-left variable"}},[a._v("metricsServer")]),t("span",{pre:!0,attrs:{class:"token operator"}},[a._v("=")]),a._v("http://prometheus:9090\n")])])]),t("p",[a._v("Note that Flagger depends on Istio telemetry and Prometheus, if you're installing Istio with istioctl\nthen you should be using the "),t("a",{attrs:{href:"https://istio.io/docs/setup/additional-setup/config-profiles/",target:"_blank",rel:"noopener noreferrer"}},[a._v("default profile"),t("OutboundLink")],1),a._v(".")]),a._v(" "),t("p",[a._v("For Istio multi-cluster shared control plane you can install Flagger\non each remote cluster and set the Istio control plane host cluster kubeconfig:")]),a._v(" "),t("div",{staticClass:"language-bash extra-class"},[t("pre",{pre:!0,attrs:{class:"language-bash"}},[t("code",[a._v("helm upgrade -i flagger flagger/flagger "),t("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("\\")]),a._v("\n--namespace"),t("span",{pre:!0,attrs:{class:"token operator"}},[a._v("=")]),a._v("istio-system "),t("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("\\")]),a._v("\n--set crd.create"),t("span",{pre:!0,attrs:{class:"token operator"}},[a._v("=")]),a._v("false "),t("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("\\")]),a._v("\n--set "),t("span",{pre:!0,attrs:{class:"token assign-left variable"}},[a._v("meshProvider")]),t("span",{pre:!0,attrs:{class:"token operator"}},[a._v("=")]),a._v("istio "),t("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("\\")]),a._v("\n--set "),t("span",{pre:!0,attrs:{class:"token assign-left variable"}},[a._v("metricsServer")]),t("span",{pre:!0,attrs:{class:"token operator"}},[a._v("=")]),a._v("http://istio-cluster-prometheus:9090 "),t("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("\\")]),a._v("\n--set istio.kubeconfig.secretName"),t("span",{pre:!0,attrs:{class:"token operator"}},[a._v("=")]),a._v("istio-kubeconfig "),t("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("\\")]),a._v("\n--set istio.kubeconfig.key"),t("span",{pre:!0,attrs:{class:"token operator"}},[a._v("=")]),a._v("kubeconfig\n")])])]),t("p",[a._v("Note that the Istio kubeconfig must be stored in a Kubernetes secret with a data key named "),t("code",[a._v("kubeconfig")]),a._v(".\nFor more details on how to configure Istio multi-cluster credentials\nread the "),t("a",{attrs:{href:"https://istio.io/docs/setup/install/multicluster/shared-vpn/#credentials",target:"_blank",rel:"noopener noreferrer"}},[a._v("Istio docs"),t("OutboundLink")],1),a._v(".")]),a._v(" "),t("p",[a._v("Deploy Flagger for Linkerd:")]),a._v(" "),t("div",{staticClass:"language-bash extra-class"},[t("pre",{pre:!0,attrs:{class:"language-bash"}},[t("code",[a._v("helm upgrade -i flagger flagger/flagger "),t("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("\\")]),a._v("\n--namespace"),t("span",{pre:!0,attrs:{class:"token operator"}},[a._v("=")]),a._v("linkerd "),t("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("\\")]),a._v("\n--set crd.create"),t("span",{pre:!0,attrs:{class:"token operator"}},[a._v("=")]),a._v("false "),t("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("\\")]),a._v("\n--set "),t("span",{pre:!0,attrs:{class:"token assign-left variable"}},[a._v("meshProvider")]),t("span",{pre:!0,attrs:{class:"token operator"}},[a._v("=")]),a._v("linkerd "),t("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("\\")]),a._v("\n--set "),t("span",{pre:!0,attrs:{class:"token assign-left variable"}},[a._v("metricsServer")]),t("span",{pre:!0,attrs:{class:"token operator"}},[a._v("=")]),a._v("http://linkerd-prometheus:9090\n")])])]),t("p",[a._v("Deploy Flagger for App Mesh:")]),a._v(" "),t("div",{staticClass:"language-bash extra-class"},[t("pre",{pre:!0,attrs:{class:"language-bash"}},[t("code",[a._v("helm upgrade -i flagger flagger/flagger "),t("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("\\")]),a._v("\n--namespace"),t("span",{pre:!0,attrs:{class:"token operator"}},[a._v("=")]),a._v("appmesh-system "),t("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("\\")]),a._v("\n--set crd.create"),t("span",{pre:!0,attrs:{class:"token operator"}},[a._v("=")]),a._v("false "),t("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("\\")]),a._v("\n--set "),t("span",{pre:!0,attrs:{class:"token assign-left variable"}},[a._v("meshProvider")]),t("span",{pre:!0,attrs:{class:"token operator"}},[a._v("=")]),a._v("appmesh "),t("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("\\")]),a._v("\n--set "),t("span",{pre:!0,attrs:{class:"token assign-left variable"}},[a._v("metricsServer")]),t("span",{pre:!0,attrs:{class:"token operator"}},[a._v("=")]),a._v("http://appmesh-prometheus:9090\n")])])]),t("p",[a._v("You can install Flagger in any namespace as long as it can talk to the Prometheus service on port 9090.")]),a._v(" "),t("p",[a._v("For ingress controllers, the install instructions are:")]),a._v(" "),t("ul",[t("li",[t("a",{attrs:{href:"https://docs.flagger.app/tutorials/contour-progressive-delivery",target:"_blank",rel:"noopener noreferrer"}},[a._v("Contour"),t("OutboundLink")],1)]),a._v(" "),t("li",[t("a",{attrs:{href:"https://docs.flagger.app/tutorials/gloo-progressive-delivery",target:"_blank",rel:"noopener noreferrer"}},[a._v("Gloo"),t("OutboundLink")],1)]),a._v(" "),t("li",[t("a",{attrs:{href:"https://docs.flagger.app/tutorials/nginx-progressive-delivery",target:"_blank",rel:"noopener noreferrer"}},[a._v("NGINX"),t("OutboundLink")],1)])]),a._v(" "),t("p",[a._v("Enable "),t("strong",[a._v("Slack")]),a._v(" notifications:")]),a._v(" "),t("div",{staticClass:"language-bash extra-class"},[t("pre",{pre:!0,attrs:{class:"language-bash"}},[t("code",[a._v("helm upgrade -i flagger flagger/flagger "),t("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("\\")]),a._v("\n--namespace"),t("span",{pre:!0,attrs:{class:"token operator"}},[a._v("=")]),a._v("istio-system "),t("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("\\")]),a._v("\n--set crd.create"),t("span",{pre:!0,attrs:{class:"token operator"}},[a._v("=")]),a._v("false "),t("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("\\")]),a._v("\n--set slack.url"),t("span",{pre:!0,attrs:{class:"token operator"}},[a._v("=")]),a._v("https://hooks.slack.com/services/YOUR/SLACK/WEBHOOK "),t("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("\\")]),a._v("\n--set slack.channel"),t("span",{pre:!0,attrs:{class:"token operator"}},[a._v("=")]),a._v("general "),t("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("\\")]),a._v("\n--set slack.user"),t("span",{pre:!0,attrs:{class:"token operator"}},[a._v("=")]),a._v("flagger\n")])])]),t("p",[a._v("Enable "),t("strong",[a._v("Microsoft Teams")]),a._v(" notifications:")]),a._v(" "),t("div",{staticClass:"language-bash extra-class"},[t("pre",{pre:!0,attrs:{class:"language-bash"}},[t("code",[a._v("helm upgrade -i flagger flagger/flagger "),t("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("\\")]),a._v("\n--namespace"),t("span",{pre:!0,attrs:{class:"token operator"}},[a._v("=")]),a._v("istio-system "),t("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("\\")]),a._v("\n--set crd.create"),t("span",{pre:!0,attrs:{class:"token operator"}},[a._v("=")]),a._v("false "),t("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("\\")]),a._v("\n--set msteams.url"),t("span",{pre:!0,attrs:{class:"token operator"}},[a._v("=")]),a._v("https://outlook.office.com/webhook/YOUR/TEAMS/WEBHOOK\n")])])]),t("p",[a._v("You can use the helm template command and apply the generated yaml with kubectl:")]),a._v(" "),t("div",{staticClass:"language-bash extra-class"},[t("pre",{pre:!0,attrs:{class:"language-bash"}},[t("code",[t("span",{pre:!0,attrs:{class:"token comment"}},[a._v("# generate")]),a._v("\nhelm fetch --untar --untardir "),t("span",{pre:!0,attrs:{class:"token builtin class-name"}},[a._v(".")]),a._v(" flagger/flagger "),t("span",{pre:!0,attrs:{class:"token operator"}},[a._v("&&")]),a._v("\nhelm template flagger ./flagger "),t("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("\\")]),a._v("\n--namespace"),t("span",{pre:!0,attrs:{class:"token operator"}},[a._v("=")]),a._v("istio-system "),t("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("\\")]),a._v("\n--set "),t("span",{pre:!0,attrs:{class:"token assign-left variable"}},[a._v("metricsServer")]),t("span",{pre:!0,attrs:{class:"token operator"}},[a._v("=")]),a._v("http://prometheus.istio-system:9090 "),t("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("\\")]),a._v("\n"),t("span",{pre:!0,attrs:{class:"token operator"}},[a._v(">")]),a._v(" flagger.yaml\n\n"),t("span",{pre:!0,attrs:{class:"token comment"}},[a._v("# apply")]),a._v("\nkubectl apply -f flagger.yaml\n")])])]),t("p",[a._v("To uninstall the Flagger release with Helm run:")]),a._v(" "),t("div",{staticClass:"language-text extra-class"},[t("pre",{pre:!0,attrs:{class:"language-text"}},[t("code",[a._v("helm delete flagger\n")])])]),t("p",[a._v("The command removes all the Kubernetes components associated with the chart and deletes the release.")]),a._v(" "),t("blockquote",[t("p",[t("strong",[a._v("Note")]),a._v(" that on uninstall the Canary CRD will not be removed. Deleting the CRD will make Kubernetes\nremove all the objects owned by Flagger like Istio virtual services, Kubernetes deployments and ClusterIP services.")])]),a._v(" "),t("p",[a._v("If you want to remove all the objects created by Flagger you have delete the Canary CRD with kubectl:")]),a._v(" "),t("div",{staticClass:"language-text extra-class"},[t("pre",{pre:!0,attrs:{class:"language-text"}},[t("code",[a._v("kubectl delete crd canaries.flagger.app\n")])])]),t("h2",{attrs:{id:"install-grafana-with-helm"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#install-grafana-with-helm","aria-hidden":"true"}},[a._v("#")]),a._v(" Install Grafana with Helm")]),a._v(" "),t("p",[a._v("Flagger comes with a Grafana dashboard made for monitoring the canary analysis.")]),a._v(" "),t("p",[a._v("Deploy Grafana in the "),t("em",[t("strong",[a._v("istio-system")])]),a._v(" namespace:")]),a._v(" "),t("div",{staticClass:"language-bash extra-class"},[t("pre",{pre:!0,attrs:{class:"language-bash"}},[t("code",[a._v("helm upgrade -i flagger-grafana flagger/grafana "),t("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("\\")]),a._v("\n--namespace"),t("span",{pre:!0,attrs:{class:"token operator"}},[a._v("=")]),a._v("istio-system "),t("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("\\")]),a._v("\n--set "),t("span",{pre:!0,attrs:{class:"token assign-left variable"}},[a._v("url")]),t("span",{pre:!0,attrs:{class:"token operator"}},[a._v("=")]),a._v("http://prometheus.istio-system:9090 "),t("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("\\")]),a._v("\n--set "),t("span",{pre:!0,attrs:{class:"token assign-left variable"}},[a._v("user")]),t("span",{pre:!0,attrs:{class:"token operator"}},[a._v("=")]),a._v("admin "),t("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("\\")]),a._v("\n--set "),t("span",{pre:!0,attrs:{class:"token assign-left variable"}},[a._v("password")]),t("span",{pre:!0,attrs:{class:"token operator"}},[a._v("=")]),a._v("change-me\n")])])]),t("p",[a._v("Or use helm template command and apply the generated yaml with kubectl:")]),a._v(" "),t("div",{staticClass:"language-bash extra-class"},[t("pre",{pre:!0,attrs:{class:"language-bash"}},[t("code",[t("span",{pre:!0,attrs:{class:"token comment"}},[a._v("# generate")]),a._v("\nhelm fetch --untar --untardir "),t("span",{pre:!0,attrs:{class:"token builtin class-name"}},[a._v(".")]),a._v(" flagger/grafana "),t("span",{pre:!0,attrs:{class:"token operator"}},[a._v("&&")]),a._v("\nhelm template flagger-grafana ./grafana "),t("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("\\")]),a._v("\n--namespace"),t("span",{pre:!0,attrs:{class:"token operator"}},[a._v("=")]),a._v("istio-system "),t("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("\\")]),a._v("\n"),t("span",{pre:!0,attrs:{class:"token operator"}},[a._v(">")]),a._v(" flagger-grafana.yaml\n\n"),t("span",{pre:!0,attrs:{class:"token comment"}},[a._v("# apply")]),a._v("\nkubectl apply -f flagger-grafana.yaml\n")])])]),t("p",[a._v("You can access Grafana using port forwarding:")]),a._v(" "),t("div",{staticClass:"language-bash extra-class"},[t("pre",{pre:!0,attrs:{class:"language-bash"}},[t("code",[a._v("kubectl -n istio-system port-forward svc/flagger-grafana "),t("span",{pre:!0,attrs:{class:"token number"}},[a._v("3000")]),a._v(":80\n")])])]),t("h2",{attrs:{id:"install-flagger-with-kustomize"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#install-flagger-with-kustomize","aria-hidden":"true"}},[a._v("#")]),a._v(" Install Flagger with Kustomize")]),a._v(" "),t("p",[a._v("As an alternative to Helm, Flagger can be installed with Kustomize.")]),a._v(" "),t("p",[t("strong",[a._v("Service mesh specific installers")])]),a._v(" "),t("p",[a._v("Install Flagger for Istio:")]),a._v(" "),t("div",{staticClass:"language-bash extra-class"},[t("pre",{pre:!0,attrs:{class:"language-bash"}},[t("code",[a._v("kubectl apply -k github.com/weaveworks/flagger//kustomize/istio\n")])])]),t("p",[a._v("This deploys Flagger in the "),t("code",[a._v("istio-system")]),a._v(" namespace and sets the metrics server URL to Istio's Prometheus instance.")]),a._v(" "),t("p",[a._v("Note that you'll need kubectl 1.14 to run the above the command or you can download\nthe "),t("a",{attrs:{href:"https://github.com/kubernetes-sigs/kustomize/releases",target:"_blank",rel:"noopener noreferrer"}},[a._v("kustomize binary"),t("OutboundLink")],1),a._v(" and run:")]),a._v(" "),t("div",{staticClass:"language-bash extra-class"},[t("pre",{pre:!0,attrs:{class:"language-bash"}},[t("code",[a._v("kustomize build github.com/weaveworks/flagger//kustomize/istio "),t("span",{pre:!0,attrs:{class:"token operator"}},[a._v("|")]),a._v(" kubectl apply -f -\n")])])]),t("p",[a._v("Install Flagger for AWS App Mesh:")]),a._v(" "),t("div",{staticClass:"language-bash extra-class"},[t("pre",{pre:!0,attrs:{class:"language-bash"}},[t("code",[a._v("kubectl apply -k github.com/weaveworks/flagger//kustomize/appmesh\n")])])]),t("p",[a._v("This deploys Flagger and sets the metrics server URL to App Mesh's Prometheus instance.")]),a._v(" "),t("p",[a._v("Install Flagger for Linkerd:")]),a._v(" "),t("div",{staticClass:"language-bash extra-class"},[t("pre",{pre:!0,attrs:{class:"language-bash"}},[t("code",[a._v("kubectl apply -k github.com/weaveworks/flagger//kustomize/linkerd\n")])])]),t("p",[a._v("This deploys Flagger in the "),t("code",[a._v("linkerd")]),a._v(" namespace and sets the metrics server URL to Linkerd's Prometheus instance.")]),a._v(" "),t("p",[a._v("If you want to install a specific Flagger release, add the version number to the URL:")]),a._v(" "),t("div",{staticClass:"language-bash extra-class"},[t("pre",{pre:!0,attrs:{class:"language-bash"}},[t("code",[a._v("kubectl apply -k github.com/weaveworks/flagger//kustomize/linkerd?ref"),t("span",{pre:!0,attrs:{class:"token operator"}},[a._v("=")]),t("span",{pre:!0,attrs:{class:"token number"}},[a._v("0.18")]),a._v(".0\n")])])]),t("p",[t("strong",[a._v("Generic installer")])]),a._v(" "),t("p",[a._v("Install Flagger and Prometheus:")]),a._v(" "),t("div",{staticClass:"language-bash extra-class"},[t("pre",{pre:!0,attrs:{class:"language-bash"}},[t("code",[a._v("kubectl apply -k github.com/weaveworks/flagger//kustomize/kubernetes\n")])])]),t("p",[a._v("This deploys Flagger and Prometheus in the "),t("code",[a._v("flagger-system")]),a._v(" namespace, sets the metrics server URL\nto "),t("code",[a._v("http://flagger-prometheus.flagger-system:9090")]),a._v(" and the mesh provider to "),t("code",[a._v("kubernetes")]),a._v(".")]),a._v(" "),t("p",[a._v("The Prometheus instance has a two hours data retention and is configured to scrape all pods in your cluster\nthat have the "),t("code",[a._v('prometheus.io/scrape: "true"')]),a._v(" annotation.")]),a._v(" "),t("p",[a._v("To target a different provider you can specify it in the canary custom resource:")]),a._v(" "),t("div",{staticClass:"language-yaml extra-class"},[t("pre",{pre:!0,attrs:{class:"language-yaml"}},[t("code",[t("span",{pre:!0,attrs:{class:"token key atrule"}},[a._v("apiVersion")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(":")]),a._v(" flagger.app/v1beta1\n"),t("span",{pre:!0,attrs:{class:"token key atrule"}},[a._v("kind")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(":")]),a._v(" Canary\n"),t("span",{pre:!0,attrs:{class:"token key atrule"}},[a._v("metadata")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(":")]),a._v("\n "),t("span",{pre:!0,attrs:{class:"token key atrule"}},[a._v("name")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(":")]),a._v(" app\n "),t("span",{pre:!0,attrs:{class:"token key atrule"}},[a._v("namespace")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(":")]),a._v(" test\n"),t("span",{pre:!0,attrs:{class:"token key atrule"}},[a._v("spec")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(":")]),a._v("\n "),t("span",{pre:!0,attrs:{class:"token comment"}},[a._v("# can be: kubernetes, istio, linkerd, appmesh, nginx, gloo")]),a._v("\n "),t("span",{pre:!0,attrs:{class:"token comment"}},[a._v("# use the kubernetes provider for Blue/Green style deployments")]),a._v("\n "),t("span",{pre:!0,attrs:{class:"token key atrule"}},[a._v("provider")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(":")]),a._v(" nginx\n")])])]),t("p",[t("strong",[a._v("Customized installer")])]),a._v(" "),t("p",[a._v("Create a kustomization file using flagger as base:")]),a._v(" "),t("div",{staticClass:"language-bash extra-class"},[t("pre",{pre:!0,attrs:{class:"language-bash"}},[t("code",[t("span",{pre:!0,attrs:{class:"token function"}},[a._v("cat")]),a._v(" "),t("span",{pre:!0,attrs:{class:"token operator"}},[a._v(">")]),a._v(" kustomization.yaml "),t("span",{pre:!0,attrs:{class:"token operator"}},[a._v("<<")]),t("span",{pre:!0,attrs:{class:"token string"}},[a._v("EOF\nnamespace: istio-system\nbases:\n - github.com/weaveworks/flagger/kustomize/base/flagger\npatchesStrategicMerge:\n - patch.yaml\nEOF")]),a._v("\n")])])]),t("p",[a._v("Create a patch and enable Slack notifications by setting the slack channel and hook URL:")]),a._v(" "),t("div",{staticClass:"language-bash extra-class"},[t("pre",{pre:!0,attrs:{class:"language-bash"}},[t("code",[t("span",{pre:!0,attrs:{class:"token function"}},[a._v("cat")]),a._v(" "),t("span",{pre:!0,attrs:{class:"token operator"}},[a._v(">")]),a._v(" patch.yaml "),t("span",{pre:!0,attrs:{class:"token operator"}},[a._v("<<")]),t("span",{pre:!0,attrs:{class:"token string"}},[a._v("EOF\napiVersion: apps/v1\nkind: Deployment\nmetadata:\n name: flagger\nspec:\n template:\n spec:\n containers:\n - name: flagger\n args:\n - -mesh-provider=istio\n - -metrics-server=http://prometheus.istio-system:9090\n - -slack-user=flagger\n - -slack-channel=alerts\n - -slack-url=https://hooks.slack.com/services/YOUR/SLACK/WEBHOOK\nEOF")]),a._v("\n")])])]),t("p",[a._v("Install Flagger with Slack:")]),a._v(" "),t("div",{staticClass:"language-bash extra-class"},[t("pre",{pre:!0,attrs:{class:"language-bash"}},[t("code",[a._v("kubectl apply -k "),t("span",{pre:!0,attrs:{class:"token builtin class-name"}},[a._v(".")]),a._v("\n")])])]),t("p",[a._v("If you want to use MS Teams instead of Slack, replace "),t("code",[a._v("-slack-url")]),a._v(" with "),t("code",[a._v("-msteams-url")]),a._v(" and set the webhook address\nto "),t("code",[a._v("https://outlook.office.com/webhook/YOUR/TEAMS/WEBHOOK")]),a._v(".")])])},[],!1,null,null,null);e.default=r.exports}}]); \ No newline at end of file diff --git a/assets/js/14.a4f3d810.js b/assets/js/14.affa49a6.js similarity index 98% rename from assets/js/14.a4f3d810.js rename to assets/js/14.affa49a6.js index 1ba97bcb..fa8f2088 100644 --- a/assets/js/14.a4f3d810.js +++ b/assets/js/14.affa49a6.js @@ -1 +1 @@ -(window.webpackJsonp=window.webpackJsonp||[]).push([[14],{274:function(e,r,t){"use strict";t.r(r);var s=t(37),o=Object(s.a)({},function(){var e=this,r=e.$createElement,t=e._self._c||r;return t("ContentSlotsDistributor",{attrs:{"slot-key":e.$parent.slotKey}},[t("h1",{attrs:{id:"introduction"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#introduction","aria-hidden":"true"}},[e._v("#")]),e._v(" Introduction")]),e._v(" "),t("p",[t("a",{attrs:{href:"https://github.com/weaveworks/flagger",target:"_blank",rel:"noopener noreferrer"}},[e._v("Flagger"),t("OutboundLink")],1),e._v(" is a "),t("strong",[e._v("Kubernetes")]),e._v(" operator that automates the promotion of\ncanary deployments using "),t("strong",[e._v("Istio")]),e._v(", "),t("strong",[e._v("Linkerd")]),e._v(", "),t("strong",[e._v("App Mesh")]),e._v(", "),t("strong",[e._v("NGINX")]),e._v(", "),t("strong",[e._v("Contour")]),e._v(" or "),t("strong",[e._v("Gloo")]),e._v(" routing for\ntraffic shifting and "),t("strong",[e._v("Prometheus")]),e._v(" metrics for canary analysis. The canary analysis can be extended with webhooks for\nrunning system integration/acceptance tests, load tests, or any other custom validation.")]),e._v(" "),t("p",[e._v("Flagger implements a control loop that gradually shifts traffic to the canary while measuring key performance indicators\nlike HTTP requests success rate, requests average duration and pods health.\nBased on analysis of the "),t("strong",[e._v("KPIs")]),e._v(" a canary is promoted or aborted, and the analysis result is published to "),t("strong",[e._v("Slack")]),e._v(" or "),t("strong",[e._v("MS Teams")]),e._v(".")]),e._v(" "),t("p",[t("img",{attrs:{src:"https://raw.githubusercontent.com/weaveworks/flagger/master/docs/diagrams/flagger-canary-overview.png",alt:"Flagger overview diagram"}})]),e._v(" "),t("p",[e._v("Flagger can be configured with Kubernetes custom resources and is compatible with any CI/CD solutions made for Kubernetes.\nSince Flagger is declarative and reacts to Kubernetes events,\nit can be used in "),t("strong",[e._v("GitOps")]),e._v(" pipelines together with Flux CD or JenkinsX.")]),e._v(" "),t("p",[e._v("To get started with Flagger, chose one of the supported routing providers\nand "),t("a",{attrs:{href:"../install/flagger-install-on-kubernetes"}},[e._v("install")]),e._v(" Flagger with Helm or Kustomize.")]),e._v(" "),t("p",[e._v("After install Flagger, you can follow one of the tutorials:")]),e._v(" "),t("p",[t("strong",[e._v("Service mesh tutorials")])]),e._v(" "),t("ul",[t("li",[t("a",{attrs:{href:"../tutorials/istio-progressive-delivery"}},[e._v("Istio")])]),e._v(" "),t("li",[t("a",{attrs:{href:"../tutorials/linkerd-progressive-delivery"}},[e._v("Linkerd")])]),e._v(" "),t("li",[t("a",{attrs:{href:"../tutorials/appmesh-progressive-delivery"}},[e._v("AWS App Mesh")])])]),e._v(" "),t("p",[t("strong",[e._v("Ingress controller tutorials")])]),e._v(" "),t("ul",[t("li",[t("a",{attrs:{href:"../tutorials/contour-progressive-delivery"}},[e._v("Contour")])]),e._v(" "),t("li",[t("a",{attrs:{href:"../tutorials/gloo-progressive-delivery"}},[e._v("Gloo")])]),e._v(" "),t("li",[t("a",{attrs:{href:"../tutorials/nginx-progressive-delivery"}},[e._v("NGINX Ingress")])])]),e._v(" "),t("p",[t("strong",[e._v("Hands-on GitOps workshops")])]),e._v(" "),t("ul",[t("li",[t("a",{attrs:{href:"https://github.com/stefanprodan/gitops-istio",target:"_blank",rel:"noopener noreferrer"}},[e._v("Istio"),t("OutboundLink")],1)]),e._v(" "),t("li",[t("a",{attrs:{href:"https://helm.workshop.flagger.dev",target:"_blank",rel:"noopener noreferrer"}},[e._v("Linkerd"),t("OutboundLink")],1)]),e._v(" "),t("li",[t("a",{attrs:{href:"https://eks.hands-on.flagger.dev",target:"_blank",rel:"noopener noreferrer"}},[e._v("AWS App Mesh"),t("OutboundLink")],1)])])])},[],!1,null,null,null);r.default=o.exports}}]); \ No newline at end of file +(window.webpackJsonp=window.webpackJsonp||[]).push([[14],{273:function(e,r,t){"use strict";t.r(r);var s=t(37),o=Object(s.a)({},function(){var e=this,r=e.$createElement,t=e._self._c||r;return t("ContentSlotsDistributor",{attrs:{"slot-key":e.$parent.slotKey}},[t("h1",{attrs:{id:"introduction"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#introduction","aria-hidden":"true"}},[e._v("#")]),e._v(" Introduction")]),e._v(" "),t("p",[t("a",{attrs:{href:"https://github.com/weaveworks/flagger",target:"_blank",rel:"noopener noreferrer"}},[e._v("Flagger"),t("OutboundLink")],1),e._v(" is a "),t("strong",[e._v("Kubernetes")]),e._v(" operator that automates the promotion of\ncanary deployments using "),t("strong",[e._v("Istio")]),e._v(", "),t("strong",[e._v("Linkerd")]),e._v(", "),t("strong",[e._v("App Mesh")]),e._v(", "),t("strong",[e._v("NGINX")]),e._v(", "),t("strong",[e._v("Contour")]),e._v(" or "),t("strong",[e._v("Gloo")]),e._v(" routing for\ntraffic shifting and "),t("strong",[e._v("Prometheus")]),e._v(" metrics for canary analysis. The canary analysis can be extended with webhooks for\nrunning system integration/acceptance tests, load tests, or any other custom validation.")]),e._v(" "),t("p",[e._v("Flagger implements a control loop that gradually shifts traffic to the canary while measuring key performance indicators\nlike HTTP requests success rate, requests average duration and pods health.\nBased on analysis of the "),t("strong",[e._v("KPIs")]),e._v(" a canary is promoted or aborted, and the analysis result is published to "),t("strong",[e._v("Slack")]),e._v(" or "),t("strong",[e._v("MS Teams")]),e._v(".")]),e._v(" "),t("p",[t("img",{attrs:{src:"https://raw.githubusercontent.com/weaveworks/flagger/master/docs/diagrams/flagger-canary-overview.png",alt:"Flagger overview diagram"}})]),e._v(" "),t("p",[e._v("Flagger can be configured with Kubernetes custom resources and is compatible with any CI/CD solutions made for Kubernetes.\nSince Flagger is declarative and reacts to Kubernetes events,\nit can be used in "),t("strong",[e._v("GitOps")]),e._v(" pipelines together with Flux CD or JenkinsX.")]),e._v(" "),t("p",[e._v("To get started with Flagger, chose one of the supported routing providers\nand "),t("a",{attrs:{href:"../install/flagger-install-on-kubernetes"}},[e._v("install")]),e._v(" Flagger with Helm or Kustomize.")]),e._v(" "),t("p",[e._v("After install Flagger, you can follow one of the tutorials:")]),e._v(" "),t("p",[t("strong",[e._v("Service mesh tutorials")])]),e._v(" "),t("ul",[t("li",[t("a",{attrs:{href:"../tutorials/istio-progressive-delivery"}},[e._v("Istio")])]),e._v(" "),t("li",[t("a",{attrs:{href:"../tutorials/linkerd-progressive-delivery"}},[e._v("Linkerd")])]),e._v(" "),t("li",[t("a",{attrs:{href:"../tutorials/appmesh-progressive-delivery"}},[e._v("AWS App Mesh")])])]),e._v(" "),t("p",[t("strong",[e._v("Ingress controller tutorials")])]),e._v(" "),t("ul",[t("li",[t("a",{attrs:{href:"../tutorials/contour-progressive-delivery"}},[e._v("Contour")])]),e._v(" "),t("li",[t("a",{attrs:{href:"../tutorials/gloo-progressive-delivery"}},[e._v("Gloo")])]),e._v(" "),t("li",[t("a",{attrs:{href:"../tutorials/nginx-progressive-delivery"}},[e._v("NGINX Ingress")])])]),e._v(" "),t("p",[t("strong",[e._v("Hands-on GitOps workshops")])]),e._v(" "),t("ul",[t("li",[t("a",{attrs:{href:"https://github.com/stefanprodan/gitops-istio",target:"_blank",rel:"noopener noreferrer"}},[e._v("Istio"),t("OutboundLink")],1)]),e._v(" "),t("li",[t("a",{attrs:{href:"https://helm.workshop.flagger.dev",target:"_blank",rel:"noopener noreferrer"}},[e._v("Linkerd"),t("OutboundLink")],1)]),e._v(" "),t("li",[t("a",{attrs:{href:"https://eks.hands-on.flagger.dev",target:"_blank",rel:"noopener noreferrer"}},[e._v("AWS App Mesh"),t("OutboundLink")],1)])])])},[],!1,null,null,null);r.default=o.exports}}]); \ No newline at end of file diff --git a/assets/js/20.dce5a04e.js b/assets/js/20.2b1bebf5.js similarity index 99% rename from assets/js/20.dce5a04e.js rename to assets/js/20.2b1bebf5.js index f5694bbb..6c80d3de 100644 --- a/assets/js/20.dce5a04e.js +++ b/assets/js/20.2b1bebf5.js @@ -1 +1 @@ -(window.webpackJsonp=window.webpackJsonp||[]).push([[20],{281:function(a,t,e){"use strict";e.r(t);var s=e(37),n=Object(s.a)({},function(){var a=this,t=a.$createElement,e=a._self._c||t;return e("ContentSlotsDistributor",{attrs:{"slot-key":a.$parent.slotKey}},[e("h1",{attrs:{id:"crossover-canary-deployments"}},[e("a",{staticClass:"header-anchor",attrs:{href:"#crossover-canary-deployments","aria-hidden":"true"}},[a._v("#")]),a._v(" Crossover Canary Deployments")]),a._v(" "),e("p",[a._v("This guide shows you how to use Envoy, "),e("a",{attrs:{href:"https://github.com/mumoshu/crossover",target:"_blank",rel:"noopener noreferrer"}},[a._v("Crossover"),e("OutboundLink")],1),a._v(" and Flagger to automate canary deployments.")]),a._v(" "),e("p",[a._v("Crossover is a minimal Envoy xDS implementation supports "),e("a",{attrs:{href:"https://smi-spec.io/",target:"_blank",rel:"noopener noreferrer"}},[a._v("Service Mesh Interface"),e("OutboundLink")],1),a._v(".")]),a._v(" "),e("h2",{attrs:{id:"prerequisites"}},[e("a",{staticClass:"header-anchor",attrs:{href:"#prerequisites","aria-hidden":"true"}},[a._v("#")]),a._v(" Prerequisites")]),a._v(" "),e("p",[a._v("Flagger requires a Kubernetes cluster "),e("strong",[a._v("v1.11")]),a._v(" or newer and Envoy paired with "),e("a",{attrs:{href:"https://github.com/mumoshu/crossover",target:"_blank",rel:"noopener noreferrer"}},[a._v("Crossover"),e("OutboundLink")],1),a._v(" sidecar.")]),a._v(" "),e("p",[a._v("Create a test namespace:")]),a._v(" "),e("div",{staticClass:"language-bash extra-class"},[e("pre",{pre:!0,attrs:{class:"language-bash"}},[e("code",[a._v("kubectl create ns "),e("span",{pre:!0,attrs:{class:"token builtin class-name"}},[a._v("test")]),a._v("\n")])])]),e("p",[a._v("Install Envoy along with the Crossover sidecar with Helm:")]),a._v(" "),e("div",{staticClass:"language-bash extra-class"},[e("pre",{pre:!0,attrs:{class:"language-bash"}},[e("code",[a._v("helm repo "),e("span",{pre:!0,attrs:{class:"token function"}},[a._v("add")]),a._v(" crossover https://mumoshu.github.io/crossover\n\nhelm upgrade --install envoy crossover/envoy "),e("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("\\")]),a._v("\n --namespace "),e("span",{pre:!0,attrs:{class:"token builtin class-name"}},[a._v("test")]),a._v(" "),e("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("\\")]),a._v("\n -f "),e("span",{pre:!0,attrs:{class:"token operator"}},[a._v("<")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("(")]),e("span",{pre:!0,attrs:{class:"token function"}},[a._v("cat")]),a._v(" "),e("span",{pre:!0,attrs:{class:"token operator"}},[a._v("<<")]),e("span",{pre:!0,attrs:{class:"token string"}},[a._v("EOF\nsmi:\n apiVersions:\n trafficSplits: v1alpha1\nupstreams:\n podinfo:\n smi:\n enabled: true\n backends:\n podinfo-primary:\n port: 9898\n weight: 100\n podinfo-canary:\n port: 9898\n weight: 0\nEOF")]),a._v("\n"),e("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(")")]),a._v("\n")])])]),e("p",[a._v("Install Flagger and the Prometheus add-on in the same namespace as Envoy:")]),a._v(" "),e("div",{staticClass:"language-bash extra-class"},[e("pre",{pre:!0,attrs:{class:"language-bash"}},[e("code",[a._v("helm repo "),e("span",{pre:!0,attrs:{class:"token function"}},[a._v("add")]),a._v(" flagger https://flagger.app\n\nhelm upgrade -i flagger flagger/flagger "),e("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("\\")]),a._v("\n--namespace "),e("span",{pre:!0,attrs:{class:"token builtin class-name"}},[a._v("test")]),a._v(" "),e("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("\\")]),a._v("\n--set prometheus.install"),e("span",{pre:!0,attrs:{class:"token operator"}},[a._v("=")]),a._v("true "),e("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("\\")]),a._v("\n--set "),e("span",{pre:!0,attrs:{class:"token assign-left variable"}},[a._v("meshProvider")]),e("span",{pre:!0,attrs:{class:"token operator"}},[a._v("=")]),a._v("smi:crossover\n")])])]),e("p",[a._v("Optionally you can enable Slack notifications:")]),a._v(" "),e("div",{staticClass:"language-bash extra-class"},[e("pre",{pre:!0,attrs:{class:"language-bash"}},[e("code",[a._v("helm upgrade -i flagger flagger/flagger "),e("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("\\")]),a._v("\n--reuse-values "),e("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("\\")]),a._v("\n--namespace "),e("span",{pre:!0,attrs:{class:"token builtin class-name"}},[a._v("test")]),a._v(" "),e("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("\\")]),a._v("\n--set slack.url"),e("span",{pre:!0,attrs:{class:"token operator"}},[a._v("=")]),a._v("https://hooks.slack.com/services/YOUR/SLACK/WEBHOOK "),e("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("\\")]),a._v("\n--set slack.channel"),e("span",{pre:!0,attrs:{class:"token operator"}},[a._v("=")]),a._v("general "),e("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("\\")]),a._v("\n--set slack.user"),e("span",{pre:!0,attrs:{class:"token operator"}},[a._v("=")]),a._v("flagger\n")])])]),e("h2",{attrs:{id:"bootstrap"}},[e("a",{staticClass:"header-anchor",attrs:{href:"#bootstrap","aria-hidden":"true"}},[a._v("#")]),a._v(" Bootstrap")]),a._v(" "),e("p",[a._v("Flagger takes a Kubernetes deployment and optionally a horizontal pod autoscaler (HPA),\nthen creates a series of objects (Kubernetes deployments, ClusterIP services, SMI traffic splits).\nThese objects expose the application on the mesh and drive the canary analysis and promotion.\nThere's no SMI object you need to create by yourself.")]),a._v(" "),e("p",[a._v("Create a deployment and a horizontal pod autoscaler:")]),a._v(" "),e("div",{staticClass:"language-bash extra-class"},[e("pre",{pre:!0,attrs:{class:"language-bash"}},[e("code",[a._v("kubectl apply -k github.com/weaveworks/flagger//kustomize/podinfo\n")])])]),e("p",[a._v("Deploy the load testing service to generate traffic during the canary analysis:")]),a._v(" "),e("div",{staticClass:"language-bash extra-class"},[e("pre",{pre:!0,attrs:{class:"language-bash"}},[e("code",[a._v("helm upgrade -i flagger-loadtester flagger/loadtester "),e("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("\\")]),a._v("\n--namespace"),e("span",{pre:!0,attrs:{class:"token operator"}},[a._v("=")]),a._v("test\n")])])]),e("p",[a._v("Create a canary custom resource:")]),a._v(" "),e("div",{staticClass:"language-yaml extra-class"},[e("pre",{pre:!0,attrs:{class:"language-yaml"}},[e("code",[e("span",{pre:!0,attrs:{class:"token key atrule"}},[a._v("apiVersion")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(":")]),a._v(" flagger.app/v1beta1\n"),e("span",{pre:!0,attrs:{class:"token key atrule"}},[a._v("kind")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(":")]),a._v(" Canary\n"),e("span",{pre:!0,attrs:{class:"token key atrule"}},[a._v("metadata")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(":")]),a._v("\n "),e("span",{pre:!0,attrs:{class:"token key atrule"}},[a._v("name")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(":")]),a._v(" podinfo\n "),e("span",{pre:!0,attrs:{class:"token key atrule"}},[a._v("namespace")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(":")]),a._v(" test\n"),e("span",{pre:!0,attrs:{class:"token key atrule"}},[a._v("spec")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(":")]),a._v("\n "),e("span",{pre:!0,attrs:{class:"token comment"}},[a._v("# specify mesh provider if it isn't the default one")]),a._v("\n "),e("span",{pre:!0,attrs:{class:"token comment"}},[a._v('# provider: "smi:crossover"')]),a._v("\n "),e("span",{pre:!0,attrs:{class:"token comment"}},[a._v("# deployment reference")]),a._v("\n "),e("span",{pre:!0,attrs:{class:"token key atrule"}},[a._v("targetRef")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(":")]),a._v("\n "),e("span",{pre:!0,attrs:{class:"token key atrule"}},[a._v("apiVersion")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(":")]),a._v(" apps/v1\n "),e("span",{pre:!0,attrs:{class:"token key atrule"}},[a._v("kind")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(":")]),a._v(" Deployment\n "),e("span",{pre:!0,attrs:{class:"token key atrule"}},[a._v("name")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(":")]),a._v(" podinfo\n "),e("span",{pre:!0,attrs:{class:"token comment"}},[a._v("# the maximum time in seconds for the canary deployment")]),a._v("\n "),e("span",{pre:!0,attrs:{class:"token comment"}},[a._v("# to make progress before it is rollback (default 600s)")]),a._v("\n "),e("span",{pre:!0,attrs:{class:"token key atrule"}},[a._v("progressDeadlineSeconds")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(":")]),a._v(" "),e("span",{pre:!0,attrs:{class:"token number"}},[a._v("60")]),a._v("\n "),e("span",{pre:!0,attrs:{class:"token comment"}},[a._v("# HPA reference (optional)")]),a._v("\n "),e("span",{pre:!0,attrs:{class:"token key atrule"}},[a._v("autoscalerRef")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(":")]),a._v("\n "),e("span",{pre:!0,attrs:{class:"token key atrule"}},[a._v("apiVersion")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(":")]),a._v(" autoscaling/v2beta1\n "),e("span",{pre:!0,attrs:{class:"token key atrule"}},[a._v("kind")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(":")]),a._v(" HorizontalPodAutoscaler\n "),e("span",{pre:!0,attrs:{class:"token key atrule"}},[a._v("name")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(":")]),a._v(" podinfo\n "),e("span",{pre:!0,attrs:{class:"token key atrule"}},[a._v("service")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(":")]),a._v("\n "),e("span",{pre:!0,attrs:{class:"token comment"}},[a._v("# ClusterIP port number")]),a._v("\n "),e("span",{pre:!0,attrs:{class:"token key atrule"}},[a._v("port")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(":")]),a._v(" "),e("span",{pre:!0,attrs:{class:"token number"}},[a._v("9898")]),a._v("\n "),e("span",{pre:!0,attrs:{class:"token comment"}},[a._v("# container port number or name (optional)")]),a._v("\n "),e("span",{pre:!0,attrs:{class:"token key atrule"}},[a._v("targetPort")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(":")]),a._v(" "),e("span",{pre:!0,attrs:{class:"token number"}},[a._v("9898")]),a._v("\n "),e("span",{pre:!0,attrs:{class:"token comment"}},[a._v("# define the canary analysis timing and KPIs")]),a._v("\n "),e("span",{pre:!0,attrs:{class:"token key atrule"}},[a._v("analysis")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(":")]),a._v("\n "),e("span",{pre:!0,attrs:{class:"token comment"}},[a._v("# schedule interval (default 60s)")]),a._v("\n "),e("span",{pre:!0,attrs:{class:"token key atrule"}},[a._v("interval")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(":")]),a._v(" 1m\n "),e("span",{pre:!0,attrs:{class:"token comment"}},[a._v("# max number of failed metric checks before rollback")]),a._v("\n "),e("span",{pre:!0,attrs:{class:"token key atrule"}},[a._v("threshold")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(":")]),a._v(" "),e("span",{pre:!0,attrs:{class:"token number"}},[a._v("5")]),a._v("\n "),e("span",{pre:!0,attrs:{class:"token comment"}},[a._v("# max traffic percentage routed to canary")]),a._v("\n "),e("span",{pre:!0,attrs:{class:"token comment"}},[a._v("# percentage (0-100)")]),a._v("\n "),e("span",{pre:!0,attrs:{class:"token key atrule"}},[a._v("maxWeight")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(":")]),a._v(" "),e("span",{pre:!0,attrs:{class:"token number"}},[a._v("50")]),a._v("\n "),e("span",{pre:!0,attrs:{class:"token comment"}},[a._v("# canary increment step")]),a._v("\n "),e("span",{pre:!0,attrs:{class:"token comment"}},[a._v("# percentage (0-100)")]),a._v("\n "),e("span",{pre:!0,attrs:{class:"token key atrule"}},[a._v("stepWeight")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(":")]),a._v(" "),e("span",{pre:!0,attrs:{class:"token number"}},[a._v("5")]),a._v("\n "),e("span",{pre:!0,attrs:{class:"token comment"}},[a._v("# App Mesh Prometheus checks")]),a._v("\n "),e("span",{pre:!0,attrs:{class:"token key atrule"}},[a._v("metrics")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(":")]),a._v("\n "),e("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("-")]),a._v(" "),e("span",{pre:!0,attrs:{class:"token key atrule"}},[a._v("name")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(":")]),a._v(" request"),e("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("-")]),a._v("success"),e("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("-")]),a._v("rate\n "),e("span",{pre:!0,attrs:{class:"token comment"}},[a._v("# minimum req success rate (non 5xx responses)")]),a._v("\n "),e("span",{pre:!0,attrs:{class:"token comment"}},[a._v("# percentage (0-100)")]),a._v("\n "),e("span",{pre:!0,attrs:{class:"token key atrule"}},[a._v("thresholdRange")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(":")]),a._v("\n "),e("span",{pre:!0,attrs:{class:"token key atrule"}},[a._v("min")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(":")]),a._v(" "),e("span",{pre:!0,attrs:{class:"token number"}},[a._v("99")]),a._v("\n "),e("span",{pre:!0,attrs:{class:"token key atrule"}},[a._v("interval")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(":")]),a._v(" 1m\n "),e("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("-")]),a._v(" "),e("span",{pre:!0,attrs:{class:"token key atrule"}},[a._v("name")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(":")]),a._v(" request"),e("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("-")]),a._v("duration\n "),e("span",{pre:!0,attrs:{class:"token comment"}},[a._v("# maximum req duration P99")]),a._v("\n "),e("span",{pre:!0,attrs:{class:"token comment"}},[a._v("# milliseconds")]),a._v("\n "),e("span",{pre:!0,attrs:{class:"token key atrule"}},[a._v("thresholdRange")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(":")]),a._v("\n "),e("span",{pre:!0,attrs:{class:"token key atrule"}},[a._v("max")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(":")]),a._v(" "),e("span",{pre:!0,attrs:{class:"token number"}},[a._v("500")]),a._v("\n "),e("span",{pre:!0,attrs:{class:"token key atrule"}},[a._v("interval")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(":")]),a._v(" 30s\n "),e("span",{pre:!0,attrs:{class:"token comment"}},[a._v("# testing (optional)")]),a._v("\n "),e("span",{pre:!0,attrs:{class:"token key atrule"}},[a._v("webhooks")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(":")]),a._v("\n "),e("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("-")]),a._v(" "),e("span",{pre:!0,attrs:{class:"token key atrule"}},[a._v("name")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(":")]),a._v(" acceptance"),e("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("-")]),a._v("test\n "),e("span",{pre:!0,attrs:{class:"token key atrule"}},[a._v("type")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(":")]),a._v(" pre"),e("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("-")]),a._v("rollout\n "),e("span",{pre:!0,attrs:{class:"token key atrule"}},[a._v("url")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(":")]),a._v(" http"),e("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(":")]),a._v("//flagger"),e("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("-")]),a._v("loadtester.test/\n "),e("span",{pre:!0,attrs:{class:"token key atrule"}},[a._v("timeout")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(":")]),a._v(" 30s\n "),e("span",{pre:!0,attrs:{class:"token key atrule"}},[a._v("metadata")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(":")]),a._v("\n "),e("span",{pre:!0,attrs:{class:"token key atrule"}},[a._v("type")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(":")]),a._v(" bash\n "),e("span",{pre:!0,attrs:{class:"token key atrule"}},[a._v("cmd")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(":")]),a._v(" "),e("span",{pre:!0,attrs:{class:"token string"}},[a._v("\"curl -sd 'test' http://podinfo-canary.test:9898/token | grep token\"")]),a._v("\n "),e("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("-")]),a._v(" "),e("span",{pre:!0,attrs:{class:"token key atrule"}},[a._v("name")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(":")]),a._v(" load"),e("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("-")]),a._v("test\n "),e("span",{pre:!0,attrs:{class:"token key atrule"}},[a._v("url")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(":")]),a._v(" http"),e("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(":")]),a._v("//flagger"),e("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("-")]),a._v("loadtester.test/\n "),e("span",{pre:!0,attrs:{class:"token key atrule"}},[a._v("timeout")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(":")]),a._v(" 5s\n "),e("span",{pre:!0,attrs:{class:"token key atrule"}},[a._v("metadata")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(":")]),a._v("\n "),e("span",{pre:!0,attrs:{class:"token key atrule"}},[a._v("cmd")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(":")]),a._v(" "),e("span",{pre:!0,attrs:{class:"token string"}},[a._v("\"hey -z 1m -q 10 -c 2 -H 'Host: podinfo.test' http://envoy.test:10000/\"")]),a._v("\n")])])]),e("p",[a._v("Save the above resource as podinfo-canary.yaml and then apply it:")]),a._v(" "),e("div",{staticClass:"language-bash extra-class"},[e("pre",{pre:!0,attrs:{class:"language-bash"}},[e("code",[a._v("kubectl apply -f ./podinfo-canary.yaml\n")])])]),e("p",[a._v("After a couple of seconds Flagger will create the canary objects:")]),a._v(" "),e("div",{staticClass:"language-bash extra-class"},[e("pre",{pre:!0,attrs:{class:"language-bash"}},[e("code",[e("span",{pre:!0,attrs:{class:"token comment"}},[a._v("# applied ")]),a._v("\ndeployment.apps/podinfo\nhorizontalpodautoscaler.autoscaling/podinfo\ncanary.flagger.app/podinfo\n\n"),e("span",{pre:!0,attrs:{class:"token comment"}},[a._v("# generated")]),a._v("\ndeployment.apps/podinfo-primary\nhorizontalpodautoscaler.autoscaling/podinfo-primary\nservice/podinfo\nservice/podinfo-canary\nservice/podinfo-primary\ntrafficsplits.split.smi-spec.io/podinfo\n")])])]),e("p",[a._v("After the boostrap, the podinfo deployment will be scaled to zero and the traffic to "),e("code",[a._v("podinfo.test")]),a._v("\nwill be routed to the primary pods. During the canary analysis,\nthe "),e("code",[a._v("podinfo-canary.test")]),a._v(" address can be used to target directly the canary pods.")]),a._v(" "),e("h2",{attrs:{id:"automated-canary-promotion"}},[e("a",{staticClass:"header-anchor",attrs:{href:"#automated-canary-promotion","aria-hidden":"true"}},[a._v("#")]),a._v(" Automated canary promotion")]),a._v(" "),e("p",[a._v("Flagger implements a control loop that gradually shifts traffic to the canary while measuring\nkey performance indicators like HTTP requests success rate, requests average duration and pod health.\nBased on analysis of the KPIs a canary is promoted or aborted, and the analysis result is published to Slack.")]),a._v(" "),e("p",[e("img",{attrs:{src:"https://raw.githubusercontent.com/weaveworks/flagger/master/docs/diagrams/flagger-canary-steps.png",alt:"Flagger Canary Stages"}})]),a._v(" "),e("p",[a._v("A canary deployment is triggered by changes in any of the following objects:")]),a._v(" "),e("ul",[e("li",[a._v("Deployment PodSpec (container image, command, ports, env, resources, etc)")]),a._v(" "),e("li",[a._v("ConfigMaps and Secrets mounted as volumes or mapped to environment variables")])]),a._v(" "),e("p",[a._v("Trigger a canary deployment by updating the container image:")]),a._v(" "),e("div",{staticClass:"language-bash extra-class"},[e("pre",{pre:!0,attrs:{class:"language-bash"}},[e("code",[a._v("kubectl -n "),e("span",{pre:!0,attrs:{class:"token builtin class-name"}},[a._v("test")]),a._v(" "),e("span",{pre:!0,attrs:{class:"token builtin class-name"}},[a._v("set")]),a._v(" image deployment/podinfo "),e("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("\\")]),a._v("\n"),e("span",{pre:!0,attrs:{class:"token assign-left variable"}},[a._v("podinfod")]),e("span",{pre:!0,attrs:{class:"token operator"}},[a._v("=")]),a._v("stefanprodan/podinfo:3.1.5\n")])])]),e("p",[a._v("Flagger detects that the deployment revision changed and starts a new rollout:")]),a._v(" "),e("div",{staticClass:"language-text extra-class"},[e("pre",{pre:!0,attrs:{class:"language-text"}},[e("code",[a._v("kubectl -n test describe canary/podinfo\n\nStatus:\n Canary Weight: 0\n Failed Checks: 0\n Phase: Succeeded\nEvents:\n New revision detected! Scaling up podinfo.test\n Waiting for podinfo.test rollout to finish: 0 of 1 updated replicas are available\n Pre-rollout check acceptance-test passed\n Advance podinfo.test canary weight 5\n Advance podinfo.test canary weight 10\n Advance podinfo.test canary weight 15\n Advance podinfo.test canary weight 20\n Advance podinfo.test canary weight 25\n Advance podinfo.test canary weight 30\n Advance podinfo.test canary weight 35\n Advance podinfo.test canary weight 40\n Advance podinfo.test canary weight 45\n Advance podinfo.test canary weight 50\n Copying podinfo.test template spec to podinfo-primary.test\n Waiting for podinfo-primary.test rollout to finish: 1 of 2 updated replicas are available\n Routing all traffic to primary\n Promotion completed! Scaling down podinfo.test\n")])])]),e("p",[a._v("When the canary analysis starts, Flagger will call the pre-rollout webhooks before routing traffic to the canary.")]),a._v(" "),e("p",[e("strong",[a._v("Note")]),a._v(" that if you apply new changes to the deployment during the canary analysis, Flagger will restart the analysis.")]),a._v(" "),e("p",[a._v("During the analysis the canary’s progress can be monitored with Grafana.")]),a._v(" "),e("p",[a._v("Flagger comes with a Grafana dashboard made for canary analysis. Install Grafana with Helm:")]),a._v(" "),e("div",{staticClass:"language-bash extra-class"},[e("pre",{pre:!0,attrs:{class:"language-bash"}},[e("code",[a._v("helm upgrade -i flagger-grafana flagger/grafana "),e("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("\\")]),a._v("\n--namespace"),e("span",{pre:!0,attrs:{class:"token operator"}},[a._v("=")]),a._v("test "),e("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("\\")]),a._v("\n--set "),e("span",{pre:!0,attrs:{class:"token assign-left variable"}},[a._v("url")]),e("span",{pre:!0,attrs:{class:"token operator"}},[a._v("=")]),a._v("http://flagger-prometheus:9090\n")])])]),e("p",[a._v("Run:")]),a._v(" "),e("div",{staticClass:"language-bash extra-class"},[e("pre",{pre:!0,attrs:{class:"language-bash"}},[e("code",[a._v("kubectl port-forward --namespace "),e("span",{pre:!0,attrs:{class:"token builtin class-name"}},[a._v("test")]),a._v(" svc/flagger-grafana "),e("span",{pre:!0,attrs:{class:"token number"}},[a._v("3000")]),a._v(":80\n")])])]),e("p",[a._v("The Envoy dashboard URL is "),e("a",{attrs:{href:"http://localhost:3000/d/flagger-envoy/envoy-canary?refresh=10s&orgId=1&var-namespace=test&var-target=podinfo",target:"_blank",rel:"noopener noreferrer"}},[a._v("http://localhost:3000/d/flagger-envoy/envoy-canary?refresh=10s&orgId=1&var-namespace=test&var-target=podinfo"),e("OutboundLink")],1)]),a._v(" "),e("p",[e("img",{attrs:{src:"https://raw.githubusercontent.com/weaveworks/flagger/master/docs/screens/flagger-grafana-appmesh.png",alt:"Envoy Canary Dashboard"}})]),a._v(" "),e("p",[a._v("You can monitor all canaries with:")]),a._v(" "),e("div",{staticClass:"language-bash extra-class"},[e("pre",{pre:!0,attrs:{class:"language-bash"}},[e("code",[e("span",{pre:!0,attrs:{class:"token function"}},[a._v("watch")]),a._v(" kubectl get canaries --all-namespaces\n\nNAMESPACE NAME STATUS WEIGHT LASTTRANSITIONTIME\n"),e("span",{pre:!0,attrs:{class:"token builtin class-name"}},[a._v("test")]),a._v(" podinfo Progressing "),e("span",{pre:!0,attrs:{class:"token number"}},[a._v("15")]),a._v(" "),e("span",{pre:!0,attrs:{class:"token number"}},[a._v("2019")]),a._v("-10-02T14:05:07Z\nprod frontend Succeeded "),e("span",{pre:!0,attrs:{class:"token number"}},[a._v("0")]),a._v(" "),e("span",{pre:!0,attrs:{class:"token number"}},[a._v("2019")]),a._v("-10-02T16:15:07Z\nprod backend Failed "),e("span",{pre:!0,attrs:{class:"token number"}},[a._v("0")]),a._v(" "),e("span",{pre:!0,attrs:{class:"token number"}},[a._v("2019")]),a._v("-10-02T17:05:07Z\n")])])]),e("p",[a._v("If you’ve enabled the Slack notifications, you should receive the following messages:")]),a._v(" "),e("p",[e("img",{attrs:{src:"https://raw.githubusercontent.com/weaveworks/flagger/master/docs/screens/slack-canary-notifications.png",alt:"Flagger Slack Notifications"}})]),a._v(" "),e("h2",{attrs:{id:"automated-rollback"}},[e("a",{staticClass:"header-anchor",attrs:{href:"#automated-rollback","aria-hidden":"true"}},[a._v("#")]),a._v(" Automated rollback")]),a._v(" "),e("p",[a._v("During the canary analysis you can generate HTTP 500 errors or high latency to test if Flagger pauses the rollout.")]),a._v(" "),e("p",[a._v("Trigger a canary deployment:")]),a._v(" "),e("div",{staticClass:"language-bash extra-class"},[e("pre",{pre:!0,attrs:{class:"language-bash"}},[e("code",[a._v("kubectl -n "),e("span",{pre:!0,attrs:{class:"token builtin class-name"}},[a._v("test")]),a._v(" "),e("span",{pre:!0,attrs:{class:"token builtin class-name"}},[a._v("set")]),a._v(" image deployment/podinfo "),e("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("\\")]),a._v("\n"),e("span",{pre:!0,attrs:{class:"token assign-left variable"}},[a._v("podinfod")]),e("span",{pre:!0,attrs:{class:"token operator"}},[a._v("=")]),a._v("stefanprodan/podinfo:3.1.2\n")])])]),e("p",[a._v("Exec into the load tester pod with:")]),a._v(" "),e("div",{staticClass:"language-bash extra-class"},[e("pre",{pre:!0,attrs:{class:"language-bash"}},[e("code",[a._v("kubectl -n "),e("span",{pre:!0,attrs:{class:"token builtin class-name"}},[a._v("test")]),a._v(" "),e("span",{pre:!0,attrs:{class:"token builtin class-name"}},[a._v("exec")]),a._v(" -it deploy/flagger-loadtester "),e("span",{pre:!0,attrs:{class:"token function"}},[a._v("bash")]),a._v("\n")])])]),e("p",[a._v("Generate HTTP 500 errors:")]),a._v(" "),e("div",{staticClass:"language-bash extra-class"},[e("pre",{pre:!0,attrs:{class:"language-bash"}},[e("code",[a._v("hey -z 1m -c "),e("span",{pre:!0,attrs:{class:"token number"}},[a._v("5")]),a._v(" -q "),e("span",{pre:!0,attrs:{class:"token number"}},[a._v("5")]),a._v(" -H "),e("span",{pre:!0,attrs:{class:"token string"}},[a._v("'Host: podinfo.test'")]),a._v(" http://envoy.test:10000/status/500\n")])])]),e("p",[a._v("Generate latency:")]),a._v(" "),e("div",{staticClass:"language-bash extra-class"},[e("pre",{pre:!0,attrs:{class:"language-bash"}},[e("code",[e("span",{pre:!0,attrs:{class:"token function"}},[a._v("watch")]),a._v(" -n "),e("span",{pre:!0,attrs:{class:"token number"}},[a._v("1")]),a._v(" "),e("span",{pre:!0,attrs:{class:"token function"}},[a._v("curl")]),a._v(" -H "),e("span",{pre:!0,attrs:{class:"token string"}},[a._v("'Host: podinfo.test'")]),a._v(" http://envoy.test:10000/delay/1\n")])])]),e("p",[a._v("When the number of failed checks reaches the canary analysis threshold, the traffic is routed back to the primary,\nthe canary is scaled to zero and the rollout is marked as failed.")]),a._v(" "),e("div",{staticClass:"language-text extra-class"},[e("pre",{pre:!0,attrs:{class:"language-text"}},[e("code",[a._v("kubectl -n test logs deploy/flagger -f | jq .msg\n\nNew revision detected! Starting canary analysis for podinfo.test\nPre-rollout check acceptance-test passed\nAdvance podinfo.test canary weight 5\nAdvance podinfo.test canary weight 10\nAdvance podinfo.test canary weight 15\nHalt podinfo.test advancement success rate 69.17% < 99%\nHalt podinfo.test advancement success rate 61.39% < 99%\nHalt podinfo.test advancement success rate 55.06% < 99%\nHalt podinfo.test advancement request duration 1.20s > 0.5s\nHalt podinfo.test advancement request duration 1.45s > 0.5s\nRolling back podinfo.test failed checks threshold reached 5\nCanary failed! Scaling down podinfo.test\n")])])]),e("p",[a._v("If you’ve enabled the Slack notifications, you’ll receive a message if the progress deadline is exceeded,\nor if the analysis reached the maximum number of failed checks:")]),a._v(" "),e("p",[e("img",{attrs:{src:"https://raw.githubusercontent.com/weaveworks/flagger/master/docs/screens/slack-canary-failed.png",alt:"Flagger Slack Notifications"}})])])},[],!1,null,null,null);t.default=n.exports}}]); \ No newline at end of file +(window.webpackJsonp=window.webpackJsonp||[]).push([[20],{280:function(a,t,e){"use strict";e.r(t);var s=e(37),n=Object(s.a)({},function(){var a=this,t=a.$createElement,e=a._self._c||t;return e("ContentSlotsDistributor",{attrs:{"slot-key":a.$parent.slotKey}},[e("h1",{attrs:{id:"crossover-canary-deployments"}},[e("a",{staticClass:"header-anchor",attrs:{href:"#crossover-canary-deployments","aria-hidden":"true"}},[a._v("#")]),a._v(" Crossover Canary Deployments")]),a._v(" "),e("p",[a._v("This guide shows you how to use Envoy, "),e("a",{attrs:{href:"https://github.com/mumoshu/crossover",target:"_blank",rel:"noopener noreferrer"}},[a._v("Crossover"),e("OutboundLink")],1),a._v(" and Flagger to automate canary deployments.")]),a._v(" "),e("p",[a._v("Crossover is a minimal Envoy xDS implementation supports "),e("a",{attrs:{href:"https://smi-spec.io/",target:"_blank",rel:"noopener noreferrer"}},[a._v("Service Mesh Interface"),e("OutboundLink")],1),a._v(".")]),a._v(" "),e("h2",{attrs:{id:"prerequisites"}},[e("a",{staticClass:"header-anchor",attrs:{href:"#prerequisites","aria-hidden":"true"}},[a._v("#")]),a._v(" Prerequisites")]),a._v(" "),e("p",[a._v("Flagger requires a Kubernetes cluster "),e("strong",[a._v("v1.11")]),a._v(" or newer and Envoy paired with "),e("a",{attrs:{href:"https://github.com/mumoshu/crossover",target:"_blank",rel:"noopener noreferrer"}},[a._v("Crossover"),e("OutboundLink")],1),a._v(" sidecar.")]),a._v(" "),e("p",[a._v("Create a test namespace:")]),a._v(" "),e("div",{staticClass:"language-bash extra-class"},[e("pre",{pre:!0,attrs:{class:"language-bash"}},[e("code",[a._v("kubectl create ns "),e("span",{pre:!0,attrs:{class:"token builtin class-name"}},[a._v("test")]),a._v("\n")])])]),e("p",[a._v("Install Envoy along with the Crossover sidecar with Helm:")]),a._v(" "),e("div",{staticClass:"language-bash extra-class"},[e("pre",{pre:!0,attrs:{class:"language-bash"}},[e("code",[a._v("helm repo "),e("span",{pre:!0,attrs:{class:"token function"}},[a._v("add")]),a._v(" crossover https://mumoshu.github.io/crossover\n\nhelm upgrade --install envoy crossover/envoy "),e("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("\\")]),a._v("\n --namespace "),e("span",{pre:!0,attrs:{class:"token builtin class-name"}},[a._v("test")]),a._v(" "),e("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("\\")]),a._v("\n -f "),e("span",{pre:!0,attrs:{class:"token operator"}},[a._v("<")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("(")]),e("span",{pre:!0,attrs:{class:"token function"}},[a._v("cat")]),a._v(" "),e("span",{pre:!0,attrs:{class:"token operator"}},[a._v("<<")]),e("span",{pre:!0,attrs:{class:"token string"}},[a._v("EOF\nsmi:\n apiVersions:\n trafficSplits: v1alpha1\nupstreams:\n podinfo:\n smi:\n enabled: true\n backends:\n podinfo-primary:\n port: 9898\n weight: 100\n podinfo-canary:\n port: 9898\n weight: 0\nEOF")]),a._v("\n"),e("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(")")]),a._v("\n")])])]),e("p",[a._v("Install Flagger and the Prometheus add-on in the same namespace as Envoy:")]),a._v(" "),e("div",{staticClass:"language-bash extra-class"},[e("pre",{pre:!0,attrs:{class:"language-bash"}},[e("code",[a._v("helm repo "),e("span",{pre:!0,attrs:{class:"token function"}},[a._v("add")]),a._v(" flagger https://flagger.app\n\nhelm upgrade -i flagger flagger/flagger "),e("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("\\")]),a._v("\n--namespace "),e("span",{pre:!0,attrs:{class:"token builtin class-name"}},[a._v("test")]),a._v(" "),e("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("\\")]),a._v("\n--set prometheus.install"),e("span",{pre:!0,attrs:{class:"token operator"}},[a._v("=")]),a._v("true "),e("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("\\")]),a._v("\n--set "),e("span",{pre:!0,attrs:{class:"token assign-left variable"}},[a._v("meshProvider")]),e("span",{pre:!0,attrs:{class:"token operator"}},[a._v("=")]),a._v("smi:crossover\n")])])]),e("p",[a._v("Optionally you can enable Slack notifications:")]),a._v(" "),e("div",{staticClass:"language-bash extra-class"},[e("pre",{pre:!0,attrs:{class:"language-bash"}},[e("code",[a._v("helm upgrade -i flagger flagger/flagger "),e("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("\\")]),a._v("\n--reuse-values "),e("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("\\")]),a._v("\n--namespace "),e("span",{pre:!0,attrs:{class:"token builtin class-name"}},[a._v("test")]),a._v(" "),e("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("\\")]),a._v("\n--set slack.url"),e("span",{pre:!0,attrs:{class:"token operator"}},[a._v("=")]),a._v("https://hooks.slack.com/services/YOUR/SLACK/WEBHOOK "),e("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("\\")]),a._v("\n--set slack.channel"),e("span",{pre:!0,attrs:{class:"token operator"}},[a._v("=")]),a._v("general "),e("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("\\")]),a._v("\n--set slack.user"),e("span",{pre:!0,attrs:{class:"token operator"}},[a._v("=")]),a._v("flagger\n")])])]),e("h2",{attrs:{id:"bootstrap"}},[e("a",{staticClass:"header-anchor",attrs:{href:"#bootstrap","aria-hidden":"true"}},[a._v("#")]),a._v(" Bootstrap")]),a._v(" "),e("p",[a._v("Flagger takes a Kubernetes deployment and optionally a horizontal pod autoscaler (HPA),\nthen creates a series of objects (Kubernetes deployments, ClusterIP services, SMI traffic splits).\nThese objects expose the application on the mesh and drive the canary analysis and promotion.\nThere's no SMI object you need to create by yourself.")]),a._v(" "),e("p",[a._v("Create a deployment and a horizontal pod autoscaler:")]),a._v(" "),e("div",{staticClass:"language-bash extra-class"},[e("pre",{pre:!0,attrs:{class:"language-bash"}},[e("code",[a._v("kubectl apply -k github.com/weaveworks/flagger//kustomize/podinfo\n")])])]),e("p",[a._v("Deploy the load testing service to generate traffic during the canary analysis:")]),a._v(" "),e("div",{staticClass:"language-bash extra-class"},[e("pre",{pre:!0,attrs:{class:"language-bash"}},[e("code",[a._v("helm upgrade -i flagger-loadtester flagger/loadtester "),e("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("\\")]),a._v("\n--namespace"),e("span",{pre:!0,attrs:{class:"token operator"}},[a._v("=")]),a._v("test\n")])])]),e("p",[a._v("Create a canary custom resource:")]),a._v(" "),e("div",{staticClass:"language-yaml extra-class"},[e("pre",{pre:!0,attrs:{class:"language-yaml"}},[e("code",[e("span",{pre:!0,attrs:{class:"token key atrule"}},[a._v("apiVersion")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(":")]),a._v(" flagger.app/v1beta1\n"),e("span",{pre:!0,attrs:{class:"token key atrule"}},[a._v("kind")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(":")]),a._v(" Canary\n"),e("span",{pre:!0,attrs:{class:"token key atrule"}},[a._v("metadata")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(":")]),a._v("\n "),e("span",{pre:!0,attrs:{class:"token key atrule"}},[a._v("name")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(":")]),a._v(" podinfo\n "),e("span",{pre:!0,attrs:{class:"token key atrule"}},[a._v("namespace")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(":")]),a._v(" test\n"),e("span",{pre:!0,attrs:{class:"token key atrule"}},[a._v("spec")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(":")]),a._v("\n "),e("span",{pre:!0,attrs:{class:"token comment"}},[a._v("# specify mesh provider if it isn't the default one")]),a._v("\n "),e("span",{pre:!0,attrs:{class:"token comment"}},[a._v('# provider: "smi:crossover"')]),a._v("\n "),e("span",{pre:!0,attrs:{class:"token comment"}},[a._v("# deployment reference")]),a._v("\n "),e("span",{pre:!0,attrs:{class:"token key atrule"}},[a._v("targetRef")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(":")]),a._v("\n "),e("span",{pre:!0,attrs:{class:"token key atrule"}},[a._v("apiVersion")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(":")]),a._v(" apps/v1\n "),e("span",{pre:!0,attrs:{class:"token key atrule"}},[a._v("kind")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(":")]),a._v(" Deployment\n "),e("span",{pre:!0,attrs:{class:"token key atrule"}},[a._v("name")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(":")]),a._v(" podinfo\n "),e("span",{pre:!0,attrs:{class:"token comment"}},[a._v("# the maximum time in seconds for the canary deployment")]),a._v("\n "),e("span",{pre:!0,attrs:{class:"token comment"}},[a._v("# to make progress before it is rollback (default 600s)")]),a._v("\n "),e("span",{pre:!0,attrs:{class:"token key atrule"}},[a._v("progressDeadlineSeconds")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(":")]),a._v(" "),e("span",{pre:!0,attrs:{class:"token number"}},[a._v("60")]),a._v("\n "),e("span",{pre:!0,attrs:{class:"token comment"}},[a._v("# HPA reference (optional)")]),a._v("\n "),e("span",{pre:!0,attrs:{class:"token key atrule"}},[a._v("autoscalerRef")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(":")]),a._v("\n "),e("span",{pre:!0,attrs:{class:"token key atrule"}},[a._v("apiVersion")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(":")]),a._v(" autoscaling/v2beta1\n "),e("span",{pre:!0,attrs:{class:"token key atrule"}},[a._v("kind")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(":")]),a._v(" HorizontalPodAutoscaler\n "),e("span",{pre:!0,attrs:{class:"token key atrule"}},[a._v("name")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(":")]),a._v(" podinfo\n "),e("span",{pre:!0,attrs:{class:"token key atrule"}},[a._v("service")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(":")]),a._v("\n "),e("span",{pre:!0,attrs:{class:"token comment"}},[a._v("# ClusterIP port number")]),a._v("\n "),e("span",{pre:!0,attrs:{class:"token key atrule"}},[a._v("port")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(":")]),a._v(" "),e("span",{pre:!0,attrs:{class:"token number"}},[a._v("9898")]),a._v("\n "),e("span",{pre:!0,attrs:{class:"token comment"}},[a._v("# container port number or name (optional)")]),a._v("\n "),e("span",{pre:!0,attrs:{class:"token key atrule"}},[a._v("targetPort")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(":")]),a._v(" "),e("span",{pre:!0,attrs:{class:"token number"}},[a._v("9898")]),a._v("\n "),e("span",{pre:!0,attrs:{class:"token comment"}},[a._v("# define the canary analysis timing and KPIs")]),a._v("\n "),e("span",{pre:!0,attrs:{class:"token key atrule"}},[a._v("analysis")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(":")]),a._v("\n "),e("span",{pre:!0,attrs:{class:"token comment"}},[a._v("# schedule interval (default 60s)")]),a._v("\n "),e("span",{pre:!0,attrs:{class:"token key atrule"}},[a._v("interval")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(":")]),a._v(" 1m\n "),e("span",{pre:!0,attrs:{class:"token comment"}},[a._v("# max number of failed metric checks before rollback")]),a._v("\n "),e("span",{pre:!0,attrs:{class:"token key atrule"}},[a._v("threshold")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(":")]),a._v(" "),e("span",{pre:!0,attrs:{class:"token number"}},[a._v("5")]),a._v("\n "),e("span",{pre:!0,attrs:{class:"token comment"}},[a._v("# max traffic percentage routed to canary")]),a._v("\n "),e("span",{pre:!0,attrs:{class:"token comment"}},[a._v("# percentage (0-100)")]),a._v("\n "),e("span",{pre:!0,attrs:{class:"token key atrule"}},[a._v("maxWeight")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(":")]),a._v(" "),e("span",{pre:!0,attrs:{class:"token number"}},[a._v("50")]),a._v("\n "),e("span",{pre:!0,attrs:{class:"token comment"}},[a._v("# canary increment step")]),a._v("\n "),e("span",{pre:!0,attrs:{class:"token comment"}},[a._v("# percentage (0-100)")]),a._v("\n "),e("span",{pre:!0,attrs:{class:"token key atrule"}},[a._v("stepWeight")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(":")]),a._v(" "),e("span",{pre:!0,attrs:{class:"token number"}},[a._v("5")]),a._v("\n "),e("span",{pre:!0,attrs:{class:"token comment"}},[a._v("# App Mesh Prometheus checks")]),a._v("\n "),e("span",{pre:!0,attrs:{class:"token key atrule"}},[a._v("metrics")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(":")]),a._v("\n "),e("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("-")]),a._v(" "),e("span",{pre:!0,attrs:{class:"token key atrule"}},[a._v("name")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(":")]),a._v(" request"),e("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("-")]),a._v("success"),e("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("-")]),a._v("rate\n "),e("span",{pre:!0,attrs:{class:"token comment"}},[a._v("# minimum req success rate (non 5xx responses)")]),a._v("\n "),e("span",{pre:!0,attrs:{class:"token comment"}},[a._v("# percentage (0-100)")]),a._v("\n "),e("span",{pre:!0,attrs:{class:"token key atrule"}},[a._v("thresholdRange")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(":")]),a._v("\n "),e("span",{pre:!0,attrs:{class:"token key atrule"}},[a._v("min")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(":")]),a._v(" "),e("span",{pre:!0,attrs:{class:"token number"}},[a._v("99")]),a._v("\n "),e("span",{pre:!0,attrs:{class:"token key atrule"}},[a._v("interval")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(":")]),a._v(" 1m\n "),e("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("-")]),a._v(" "),e("span",{pre:!0,attrs:{class:"token key atrule"}},[a._v("name")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(":")]),a._v(" request"),e("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("-")]),a._v("duration\n "),e("span",{pre:!0,attrs:{class:"token comment"}},[a._v("# maximum req duration P99")]),a._v("\n "),e("span",{pre:!0,attrs:{class:"token comment"}},[a._v("# milliseconds")]),a._v("\n "),e("span",{pre:!0,attrs:{class:"token key atrule"}},[a._v("thresholdRange")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(":")]),a._v("\n "),e("span",{pre:!0,attrs:{class:"token key atrule"}},[a._v("max")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(":")]),a._v(" "),e("span",{pre:!0,attrs:{class:"token number"}},[a._v("500")]),a._v("\n "),e("span",{pre:!0,attrs:{class:"token key atrule"}},[a._v("interval")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(":")]),a._v(" 30s\n "),e("span",{pre:!0,attrs:{class:"token comment"}},[a._v("# testing (optional)")]),a._v("\n "),e("span",{pre:!0,attrs:{class:"token key atrule"}},[a._v("webhooks")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(":")]),a._v("\n "),e("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("-")]),a._v(" "),e("span",{pre:!0,attrs:{class:"token key atrule"}},[a._v("name")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(":")]),a._v(" acceptance"),e("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("-")]),a._v("test\n "),e("span",{pre:!0,attrs:{class:"token key atrule"}},[a._v("type")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(":")]),a._v(" pre"),e("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("-")]),a._v("rollout\n "),e("span",{pre:!0,attrs:{class:"token key atrule"}},[a._v("url")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(":")]),a._v(" http"),e("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(":")]),a._v("//flagger"),e("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("-")]),a._v("loadtester.test/\n "),e("span",{pre:!0,attrs:{class:"token key atrule"}},[a._v("timeout")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(":")]),a._v(" 30s\n "),e("span",{pre:!0,attrs:{class:"token key atrule"}},[a._v("metadata")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(":")]),a._v("\n "),e("span",{pre:!0,attrs:{class:"token key atrule"}},[a._v("type")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(":")]),a._v(" bash\n "),e("span",{pre:!0,attrs:{class:"token key atrule"}},[a._v("cmd")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(":")]),a._v(" "),e("span",{pre:!0,attrs:{class:"token string"}},[a._v("\"curl -sd 'test' http://podinfo-canary.test:9898/token | grep token\"")]),a._v("\n "),e("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("-")]),a._v(" "),e("span",{pre:!0,attrs:{class:"token key atrule"}},[a._v("name")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(":")]),a._v(" load"),e("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("-")]),a._v("test\n "),e("span",{pre:!0,attrs:{class:"token key atrule"}},[a._v("url")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(":")]),a._v(" http"),e("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(":")]),a._v("//flagger"),e("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("-")]),a._v("loadtester.test/\n "),e("span",{pre:!0,attrs:{class:"token key atrule"}},[a._v("timeout")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(":")]),a._v(" 5s\n "),e("span",{pre:!0,attrs:{class:"token key atrule"}},[a._v("metadata")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(":")]),a._v("\n "),e("span",{pre:!0,attrs:{class:"token key atrule"}},[a._v("cmd")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(":")]),a._v(" "),e("span",{pre:!0,attrs:{class:"token string"}},[a._v("\"hey -z 1m -q 10 -c 2 -H 'Host: podinfo.test' http://envoy.test:10000/\"")]),a._v("\n")])])]),e("p",[a._v("Save the above resource as podinfo-canary.yaml and then apply it:")]),a._v(" "),e("div",{staticClass:"language-bash extra-class"},[e("pre",{pre:!0,attrs:{class:"language-bash"}},[e("code",[a._v("kubectl apply -f ./podinfo-canary.yaml\n")])])]),e("p",[a._v("After a couple of seconds Flagger will create the canary objects:")]),a._v(" "),e("div",{staticClass:"language-bash extra-class"},[e("pre",{pre:!0,attrs:{class:"language-bash"}},[e("code",[e("span",{pre:!0,attrs:{class:"token comment"}},[a._v("# applied ")]),a._v("\ndeployment.apps/podinfo\nhorizontalpodautoscaler.autoscaling/podinfo\ncanary.flagger.app/podinfo\n\n"),e("span",{pre:!0,attrs:{class:"token comment"}},[a._v("# generated")]),a._v("\ndeployment.apps/podinfo-primary\nhorizontalpodautoscaler.autoscaling/podinfo-primary\nservice/podinfo\nservice/podinfo-canary\nservice/podinfo-primary\ntrafficsplits.split.smi-spec.io/podinfo\n")])])]),e("p",[a._v("After the boostrap, the podinfo deployment will be scaled to zero and the traffic to "),e("code",[a._v("podinfo.test")]),a._v("\nwill be routed to the primary pods. During the canary analysis,\nthe "),e("code",[a._v("podinfo-canary.test")]),a._v(" address can be used to target directly the canary pods.")]),a._v(" "),e("h2",{attrs:{id:"automated-canary-promotion"}},[e("a",{staticClass:"header-anchor",attrs:{href:"#automated-canary-promotion","aria-hidden":"true"}},[a._v("#")]),a._v(" Automated canary promotion")]),a._v(" "),e("p",[a._v("Flagger implements a control loop that gradually shifts traffic to the canary while measuring\nkey performance indicators like HTTP requests success rate, requests average duration and pod health.\nBased on analysis of the KPIs a canary is promoted or aborted, and the analysis result is published to Slack.")]),a._v(" "),e("p",[e("img",{attrs:{src:"https://raw.githubusercontent.com/weaveworks/flagger/master/docs/diagrams/flagger-canary-steps.png",alt:"Flagger Canary Stages"}})]),a._v(" "),e("p",[a._v("A canary deployment is triggered by changes in any of the following objects:")]),a._v(" "),e("ul",[e("li",[a._v("Deployment PodSpec (container image, command, ports, env, resources, etc)")]),a._v(" "),e("li",[a._v("ConfigMaps and Secrets mounted as volumes or mapped to environment variables")])]),a._v(" "),e("p",[a._v("Trigger a canary deployment by updating the container image:")]),a._v(" "),e("div",{staticClass:"language-bash extra-class"},[e("pre",{pre:!0,attrs:{class:"language-bash"}},[e("code",[a._v("kubectl -n "),e("span",{pre:!0,attrs:{class:"token builtin class-name"}},[a._v("test")]),a._v(" "),e("span",{pre:!0,attrs:{class:"token builtin class-name"}},[a._v("set")]),a._v(" image deployment/podinfo "),e("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("\\")]),a._v("\n"),e("span",{pre:!0,attrs:{class:"token assign-left variable"}},[a._v("podinfod")]),e("span",{pre:!0,attrs:{class:"token operator"}},[a._v("=")]),a._v("stefanprodan/podinfo:3.1.5\n")])])]),e("p",[a._v("Flagger detects that the deployment revision changed and starts a new rollout:")]),a._v(" "),e("div",{staticClass:"language-text extra-class"},[e("pre",{pre:!0,attrs:{class:"language-text"}},[e("code",[a._v("kubectl -n test describe canary/podinfo\n\nStatus:\n Canary Weight: 0\n Failed Checks: 0\n Phase: Succeeded\nEvents:\n New revision detected! Scaling up podinfo.test\n Waiting for podinfo.test rollout to finish: 0 of 1 updated replicas are available\n Pre-rollout check acceptance-test passed\n Advance podinfo.test canary weight 5\n Advance podinfo.test canary weight 10\n Advance podinfo.test canary weight 15\n Advance podinfo.test canary weight 20\n Advance podinfo.test canary weight 25\n Advance podinfo.test canary weight 30\n Advance podinfo.test canary weight 35\n Advance podinfo.test canary weight 40\n Advance podinfo.test canary weight 45\n Advance podinfo.test canary weight 50\n Copying podinfo.test template spec to podinfo-primary.test\n Waiting for podinfo-primary.test rollout to finish: 1 of 2 updated replicas are available\n Routing all traffic to primary\n Promotion completed! Scaling down podinfo.test\n")])])]),e("p",[a._v("When the canary analysis starts, Flagger will call the pre-rollout webhooks before routing traffic to the canary.")]),a._v(" "),e("p",[e("strong",[a._v("Note")]),a._v(" that if you apply new changes to the deployment during the canary analysis, Flagger will restart the analysis.")]),a._v(" "),e("p",[a._v("During the analysis the canary’s progress can be monitored with Grafana.")]),a._v(" "),e("p",[a._v("Flagger comes with a Grafana dashboard made for canary analysis. Install Grafana with Helm:")]),a._v(" "),e("div",{staticClass:"language-bash extra-class"},[e("pre",{pre:!0,attrs:{class:"language-bash"}},[e("code",[a._v("helm upgrade -i flagger-grafana flagger/grafana "),e("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("\\")]),a._v("\n--namespace"),e("span",{pre:!0,attrs:{class:"token operator"}},[a._v("=")]),a._v("test "),e("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("\\")]),a._v("\n--set "),e("span",{pre:!0,attrs:{class:"token assign-left variable"}},[a._v("url")]),e("span",{pre:!0,attrs:{class:"token operator"}},[a._v("=")]),a._v("http://flagger-prometheus:9090\n")])])]),e("p",[a._v("Run:")]),a._v(" "),e("div",{staticClass:"language-bash extra-class"},[e("pre",{pre:!0,attrs:{class:"language-bash"}},[e("code",[a._v("kubectl port-forward --namespace "),e("span",{pre:!0,attrs:{class:"token builtin class-name"}},[a._v("test")]),a._v(" svc/flagger-grafana "),e("span",{pre:!0,attrs:{class:"token number"}},[a._v("3000")]),a._v(":80\n")])])]),e("p",[a._v("The Envoy dashboard URL is "),e("a",{attrs:{href:"http://localhost:3000/d/flagger-envoy/envoy-canary?refresh=10s&orgId=1&var-namespace=test&var-target=podinfo",target:"_blank",rel:"noopener noreferrer"}},[a._v("http://localhost:3000/d/flagger-envoy/envoy-canary?refresh=10s&orgId=1&var-namespace=test&var-target=podinfo"),e("OutboundLink")],1)]),a._v(" "),e("p",[e("img",{attrs:{src:"https://raw.githubusercontent.com/weaveworks/flagger/master/docs/screens/flagger-grafana-appmesh.png",alt:"Envoy Canary Dashboard"}})]),a._v(" "),e("p",[a._v("You can monitor all canaries with:")]),a._v(" "),e("div",{staticClass:"language-bash extra-class"},[e("pre",{pre:!0,attrs:{class:"language-bash"}},[e("code",[e("span",{pre:!0,attrs:{class:"token function"}},[a._v("watch")]),a._v(" kubectl get canaries --all-namespaces\n\nNAMESPACE NAME STATUS WEIGHT LASTTRANSITIONTIME\n"),e("span",{pre:!0,attrs:{class:"token builtin class-name"}},[a._v("test")]),a._v(" podinfo Progressing "),e("span",{pre:!0,attrs:{class:"token number"}},[a._v("15")]),a._v(" "),e("span",{pre:!0,attrs:{class:"token number"}},[a._v("2019")]),a._v("-10-02T14:05:07Z\nprod frontend Succeeded "),e("span",{pre:!0,attrs:{class:"token number"}},[a._v("0")]),a._v(" "),e("span",{pre:!0,attrs:{class:"token number"}},[a._v("2019")]),a._v("-10-02T16:15:07Z\nprod backend Failed "),e("span",{pre:!0,attrs:{class:"token number"}},[a._v("0")]),a._v(" "),e("span",{pre:!0,attrs:{class:"token number"}},[a._v("2019")]),a._v("-10-02T17:05:07Z\n")])])]),e("p",[a._v("If you’ve enabled the Slack notifications, you should receive the following messages:")]),a._v(" "),e("p",[e("img",{attrs:{src:"https://raw.githubusercontent.com/weaveworks/flagger/master/docs/screens/slack-canary-notifications.png",alt:"Flagger Slack Notifications"}})]),a._v(" "),e("h2",{attrs:{id:"automated-rollback"}},[e("a",{staticClass:"header-anchor",attrs:{href:"#automated-rollback","aria-hidden":"true"}},[a._v("#")]),a._v(" Automated rollback")]),a._v(" "),e("p",[a._v("During the canary analysis you can generate HTTP 500 errors or high latency to test if Flagger pauses the rollout.")]),a._v(" "),e("p",[a._v("Trigger a canary deployment:")]),a._v(" "),e("div",{staticClass:"language-bash extra-class"},[e("pre",{pre:!0,attrs:{class:"language-bash"}},[e("code",[a._v("kubectl -n "),e("span",{pre:!0,attrs:{class:"token builtin class-name"}},[a._v("test")]),a._v(" "),e("span",{pre:!0,attrs:{class:"token builtin class-name"}},[a._v("set")]),a._v(" image deployment/podinfo "),e("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("\\")]),a._v("\n"),e("span",{pre:!0,attrs:{class:"token assign-left variable"}},[a._v("podinfod")]),e("span",{pre:!0,attrs:{class:"token operator"}},[a._v("=")]),a._v("stefanprodan/podinfo:3.1.2\n")])])]),e("p",[a._v("Exec into the load tester pod with:")]),a._v(" "),e("div",{staticClass:"language-bash extra-class"},[e("pre",{pre:!0,attrs:{class:"language-bash"}},[e("code",[a._v("kubectl -n "),e("span",{pre:!0,attrs:{class:"token builtin class-name"}},[a._v("test")]),a._v(" "),e("span",{pre:!0,attrs:{class:"token builtin class-name"}},[a._v("exec")]),a._v(" -it deploy/flagger-loadtester "),e("span",{pre:!0,attrs:{class:"token function"}},[a._v("bash")]),a._v("\n")])])]),e("p",[a._v("Generate HTTP 500 errors:")]),a._v(" "),e("div",{staticClass:"language-bash extra-class"},[e("pre",{pre:!0,attrs:{class:"language-bash"}},[e("code",[a._v("hey -z 1m -c "),e("span",{pre:!0,attrs:{class:"token number"}},[a._v("5")]),a._v(" -q "),e("span",{pre:!0,attrs:{class:"token number"}},[a._v("5")]),a._v(" -H "),e("span",{pre:!0,attrs:{class:"token string"}},[a._v("'Host: podinfo.test'")]),a._v(" http://envoy.test:10000/status/500\n")])])]),e("p",[a._v("Generate latency:")]),a._v(" "),e("div",{staticClass:"language-bash extra-class"},[e("pre",{pre:!0,attrs:{class:"language-bash"}},[e("code",[e("span",{pre:!0,attrs:{class:"token function"}},[a._v("watch")]),a._v(" -n "),e("span",{pre:!0,attrs:{class:"token number"}},[a._v("1")]),a._v(" "),e("span",{pre:!0,attrs:{class:"token function"}},[a._v("curl")]),a._v(" -H "),e("span",{pre:!0,attrs:{class:"token string"}},[a._v("'Host: podinfo.test'")]),a._v(" http://envoy.test:10000/delay/1\n")])])]),e("p",[a._v("When the number of failed checks reaches the canary analysis threshold, the traffic is routed back to the primary,\nthe canary is scaled to zero and the rollout is marked as failed.")]),a._v(" "),e("div",{staticClass:"language-text extra-class"},[e("pre",{pre:!0,attrs:{class:"language-text"}},[e("code",[a._v("kubectl -n test logs deploy/flagger -f | jq .msg\n\nNew revision detected! Starting canary analysis for podinfo.test\nPre-rollout check acceptance-test passed\nAdvance podinfo.test canary weight 5\nAdvance podinfo.test canary weight 10\nAdvance podinfo.test canary weight 15\nHalt podinfo.test advancement success rate 69.17% < 99%\nHalt podinfo.test advancement success rate 61.39% < 99%\nHalt podinfo.test advancement success rate 55.06% < 99%\nHalt podinfo.test advancement request duration 1.20s > 0.5s\nHalt podinfo.test advancement request duration 1.45s > 0.5s\nRolling back podinfo.test failed checks threshold reached 5\nCanary failed! Scaling down podinfo.test\n")])])]),e("p",[a._v("If you’ve enabled the Slack notifications, you’ll receive a message if the progress deadline is exceeded,\nor if the analysis reached the maximum number of failed checks:")]),a._v(" "),e("p",[e("img",{attrs:{src:"https://raw.githubusercontent.com/weaveworks/flagger/master/docs/screens/slack-canary-failed.png",alt:"Flagger Slack Notifications"}})])])},[],!1,null,null,null);t.default=n.exports}}]); \ No newline at end of file diff --git a/assets/js/21.df66561d.js b/assets/js/21.e1068843.js similarity index 99% rename from assets/js/21.df66561d.js rename to assets/js/21.e1068843.js index d96d19b1..1be8c67b 100644 --- a/assets/js/21.df66561d.js +++ b/assets/js/21.e1068843.js @@ -1 +1 @@ -(window.webpackJsonp=window.webpackJsonp||[]).push([[21],{280:function(a,t,s){"use strict";s.r(t);var e=s(37),n=Object(e.a)({},function(){var a=this,t=a.$createElement,s=a._self._c||t;return s("ContentSlotsDistributor",{attrs:{"slot-key":a.$parent.slotKey}},[s("h1",{attrs:{id:"smi-istio-canary-deployments"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#smi-istio-canary-deployments","aria-hidden":"true"}},[a._v("#")]),a._v(" SMI Istio Canary Deployments")]),a._v(" "),s("p",[a._v("This guide shows you how to use the SMI Istio adapter and Flagger to automate canary deployments.")]),a._v(" "),s("h2",{attrs:{id:"prerequisites"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#prerequisites","aria-hidden":"true"}},[a._v("#")]),a._v(" Prerequisites")]),a._v(" "),s("ul",[s("li",[a._v("Kubernetes > 1.13")]),a._v(" "),s("li",[a._v("Istio > 1.0")])]),a._v(" "),s("h2",{attrs:{id:"install-istio-smi-adapter"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#install-istio-smi-adapter","aria-hidden":"true"}},[a._v("#")]),a._v(" Install Istio SMI adapter")]),a._v(" "),s("p",[a._v("Install the SMI adapter:")]),a._v(" "),s("div",{staticClass:"language-bash extra-class"},[s("pre",{pre:!0,attrs:{class:"language-bash"}},[s("code",[a._v("kubectl apply -f https://raw.githubusercontent.com/deislabs/smi-adapter-istio/master/deploy/crds/crds.yaml\nkubectl apply -f https://raw.githubusercontent.com/deislabs/smi-adapter-istio/master/deploy/operator-and-rbac.yaml\n")])])]),s("p",[a._v("Create a generic Istio gateway to expose services outside the mesh on HTTP:")]),a._v(" "),s("div",{staticClass:"language-yaml extra-class"},[s("pre",{pre:!0,attrs:{class:"language-yaml"}},[s("code",[s("span",{pre:!0,attrs:{class:"token key atrule"}},[a._v("apiVersion")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(":")]),a._v(" networking.istio.io/v1alpha3\n"),s("span",{pre:!0,attrs:{class:"token key atrule"}},[a._v("kind")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(":")]),a._v(" Gateway\n"),s("span",{pre:!0,attrs:{class:"token key atrule"}},[a._v("metadata")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(":")]),a._v("\n "),s("span",{pre:!0,attrs:{class:"token key atrule"}},[a._v("name")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(":")]),a._v(" public"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("-")]),a._v("gateway\n "),s("span",{pre:!0,attrs:{class:"token key atrule"}},[a._v("namespace")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(":")]),a._v(" istio"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("-")]),a._v("system\n"),s("span",{pre:!0,attrs:{class:"token key atrule"}},[a._v("spec")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(":")]),a._v("\n "),s("span",{pre:!0,attrs:{class:"token key atrule"}},[a._v("selector")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(":")]),a._v("\n "),s("span",{pre:!0,attrs:{class:"token key atrule"}},[a._v("istio")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(":")]),a._v(" ingressgateway\n "),s("span",{pre:!0,attrs:{class:"token key atrule"}},[a._v("servers")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(":")]),a._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("-")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token key atrule"}},[a._v("port")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(":")]),a._v("\n "),s("span",{pre:!0,attrs:{class:"token key atrule"}},[a._v("number")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(":")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token number"}},[a._v("80")]),a._v("\n "),s("span",{pre:!0,attrs:{class:"token key atrule"}},[a._v("name")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(":")]),a._v(" http\n "),s("span",{pre:!0,attrs:{class:"token key atrule"}},[a._v("protocol")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(":")]),a._v(" HTTP\n "),s("span",{pre:!0,attrs:{class:"token key atrule"}},[a._v("hosts")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(":")]),a._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("-")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token string"}},[a._v('"*"')]),a._v("\n")])])]),s("p",[a._v("Save the above resource as public-gateway.yaml and then apply it:")]),a._v(" "),s("div",{staticClass:"language-bash extra-class"},[s("pre",{pre:!0,attrs:{class:"language-bash"}},[s("code",[a._v("kubectl apply -f ./public-gateway.yaml\n")])])]),s("p",[a._v("Find the Gateway load balancer IP and add a DNS record for it:")]),a._v(" "),s("div",{staticClass:"language-bash extra-class"},[s("pre",{pre:!0,attrs:{class:"language-bash"}},[s("code",[a._v("kubectl -n istio-system get svc/istio-ingressgateway -ojson "),s("span",{pre:!0,attrs:{class:"token operator"}},[a._v("|")]),a._v(" jq -r .status.loadBalancer.ingress"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("[")]),s("span",{pre:!0,attrs:{class:"token number"}},[a._v("0")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("]")]),a._v(".ip\n")])])]),s("h2",{attrs:{id:"install-flagger-and-grafana"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#install-flagger-and-grafana","aria-hidden":"true"}},[a._v("#")]),a._v(" Install Flagger and Grafana")]),a._v(" "),s("p",[a._v("Add Flagger Helm repository:")]),a._v(" "),s("div",{staticClass:"language-bash extra-class"},[s("pre",{pre:!0,attrs:{class:"language-bash"}},[s("code",[a._v("helm repo "),s("span",{pre:!0,attrs:{class:"token function"}},[a._v("add")]),a._v(" flagger https://flagger.app\n")])])]),s("p",[a._v("Deploy Flagger in the "),s("em",[s("strong",[a._v("istio-system")])]),a._v(" namespace:")]),a._v(" "),s("div",{staticClass:"language-bash extra-class"},[s("pre",{pre:!0,attrs:{class:"language-bash"}},[s("code",[a._v("helm upgrade -i flagger flagger/flagger "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("\\")]),a._v("\n--namespace"),s("span",{pre:!0,attrs:{class:"token operator"}},[a._v("=")]),a._v("istio-system "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("\\")]),a._v("\n--set "),s("span",{pre:!0,attrs:{class:"token assign-left variable"}},[a._v("meshProvider")]),s("span",{pre:!0,attrs:{class:"token operator"}},[a._v("=")]),a._v("smi:istio\n")])])]),s("p",[a._v("Flagger comes with a Grafana dashboard made for monitoring the canary deployments.")]),a._v(" "),s("p",[a._v("Deploy Grafana in the "),s("em",[s("strong",[a._v("istio-system")])]),a._v(" namespace:")]),a._v(" "),s("div",{staticClass:"language-bash extra-class"},[s("pre",{pre:!0,attrs:{class:"language-bash"}},[s("code",[a._v("helm upgrade -i flagger-grafana flagger/grafana "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("\\")]),a._v("\n--namespace"),s("span",{pre:!0,attrs:{class:"token operator"}},[a._v("=")]),a._v("istio-system "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("\\")]),a._v("\n--set "),s("span",{pre:!0,attrs:{class:"token assign-left variable"}},[a._v("url")]),s("span",{pre:!0,attrs:{class:"token operator"}},[a._v("=")]),a._v("http://prometheus.istio-system:9090\n")])])]),s("p",[a._v("You can access Grafana using port forwarding:")]),a._v(" "),s("div",{staticClass:"language-bash extra-class"},[s("pre",{pre:!0,attrs:{class:"language-bash"}},[s("code",[a._v("kubectl -n istio-system port-forward svc/flagger-grafana "),s("span",{pre:!0,attrs:{class:"token number"}},[a._v("3000")]),a._v(":80\n")])])]),s("h2",{attrs:{id:"workloads-bootstrap"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#workloads-bootstrap","aria-hidden":"true"}},[a._v("#")]),a._v(" Workloads bootstrap")]),a._v(" "),s("p",[a._v("Create a test namespace with Istio sidecar injection enabled:")]),a._v(" "),s("p",[a._v("Create a test namespace and enable Linkerd proxy injection:")]),a._v(" "),s("div",{staticClass:"language-bash extra-class"},[s("pre",{pre:!0,attrs:{class:"language-bash"}},[s("code",[a._v("kubectl create ns "),s("span",{pre:!0,attrs:{class:"token builtin class-name"}},[a._v("test")]),a._v("\nkubectl label namespace "),s("span",{pre:!0,attrs:{class:"token builtin class-name"}},[a._v("test")]),a._v(" istio-injection"),s("span",{pre:!0,attrs:{class:"token operator"}},[a._v("=")]),a._v("enabled\n")])])]),s("p",[a._v("Create a deployment and a horizontal pod autoscaler:")]),a._v(" "),s("div",{staticClass:"language-bash extra-class"},[s("pre",{pre:!0,attrs:{class:"language-bash"}},[s("code",[a._v("kubectl apply -k github.com/weaveworks/flagger//kustomize/podinfo\n")])])]),s("p",[a._v("Deploy the load testing service to generate traffic during the canary analysis:")]),a._v(" "),s("div",{staticClass:"language-bash extra-class"},[s("pre",{pre:!0,attrs:{class:"language-bash"}},[s("code",[a._v("kubectl apply -k github.com/weaveworks/flagger//kustomize/tester\n")])])]),s("p",[a._v("Create a canary custom resource (replace example.com with your own domain):")]),a._v(" "),s("div",{staticClass:"language-yaml extra-class"},[s("pre",{pre:!0,attrs:{class:"language-yaml"}},[s("code",[s("span",{pre:!0,attrs:{class:"token key atrule"}},[a._v("apiVersion")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(":")]),a._v(" flagger.app/v1beta1\n"),s("span",{pre:!0,attrs:{class:"token key atrule"}},[a._v("kind")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(":")]),a._v(" Canary\n"),s("span",{pre:!0,attrs:{class:"token key atrule"}},[a._v("metadata")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(":")]),a._v("\n "),s("span",{pre:!0,attrs:{class:"token key atrule"}},[a._v("name")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(":")]),a._v(" podinfo\n "),s("span",{pre:!0,attrs:{class:"token key atrule"}},[a._v("namespace")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(":")]),a._v(" test\n"),s("span",{pre:!0,attrs:{class:"token key atrule"}},[a._v("spec")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(":")]),a._v("\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[a._v("# deployment reference")]),a._v("\n "),s("span",{pre:!0,attrs:{class:"token key atrule"}},[a._v("targetRef")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(":")]),a._v("\n "),s("span",{pre:!0,attrs:{class:"token key atrule"}},[a._v("apiVersion")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(":")]),a._v(" apps/v1\n "),s("span",{pre:!0,attrs:{class:"token key atrule"}},[a._v("kind")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(":")]),a._v(" Deployment\n "),s("span",{pre:!0,attrs:{class:"token key atrule"}},[a._v("name")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(":")]),a._v(" podinfo\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[a._v("# the maximum time in seconds for the canary deployment")]),a._v("\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[a._v("# to make progress before it is rollback (default 600s)")]),a._v("\n "),s("span",{pre:!0,attrs:{class:"token key atrule"}},[a._v("progressDeadlineSeconds")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(":")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token number"}},[a._v("60")]),a._v("\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[a._v("# HPA reference (optional)")]),a._v("\n "),s("span",{pre:!0,attrs:{class:"token key atrule"}},[a._v("autoscalerRef")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(":")]),a._v("\n "),s("span",{pre:!0,attrs:{class:"token key atrule"}},[a._v("apiVersion")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(":")]),a._v(" autoscaling/v2beta1\n "),s("span",{pre:!0,attrs:{class:"token key atrule"}},[a._v("kind")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(":")]),a._v(" HorizontalPodAutoscaler\n "),s("span",{pre:!0,attrs:{class:"token key atrule"}},[a._v("name")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(":")]),a._v(" podinfo\n "),s("span",{pre:!0,attrs:{class:"token key atrule"}},[a._v("service")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(":")]),a._v("\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[a._v("# container port")]),a._v("\n "),s("span",{pre:!0,attrs:{class:"token key atrule"}},[a._v("port")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(":")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token number"}},[a._v("9898")]),a._v("\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[a._v("# Istio gateways (optional)")]),a._v("\n "),s("span",{pre:!0,attrs:{class:"token key atrule"}},[a._v("gateways")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(":")]),a._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("-")]),a._v(" public"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("-")]),a._v("gateway.istio"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("-")]),a._v("system.svc.cluster.local\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[a._v("# Istio virtual service host names (optional)")]),a._v("\n "),s("span",{pre:!0,attrs:{class:"token key atrule"}},[a._v("hosts")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(":")]),a._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("-")]),a._v(" app.example.com\n "),s("span",{pre:!0,attrs:{class:"token key atrule"}},[a._v("analysis")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(":")]),a._v("\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[a._v("# schedule interval (default 60s)")]),a._v("\n "),s("span",{pre:!0,attrs:{class:"token key atrule"}},[a._v("interval")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(":")]),a._v(" 10s\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[a._v("# max number of failed metric checks before rollback")]),a._v("\n "),s("span",{pre:!0,attrs:{class:"token key atrule"}},[a._v("threshold")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(":")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token number"}},[a._v("5")]),a._v("\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[a._v("# max traffic percentage routed to canary")]),a._v("\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[a._v("# percentage (0-100)")]),a._v("\n "),s("span",{pre:!0,attrs:{class:"token key atrule"}},[a._v("maxWeight")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(":")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token number"}},[a._v("50")]),a._v("\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[a._v("# canary increment step")]),a._v("\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[a._v("# percentage (0-100)")]),a._v("\n "),s("span",{pre:!0,attrs:{class:"token key atrule"}},[a._v("stepWeight")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(":")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token number"}},[a._v("10")]),a._v("\n "),s("span",{pre:!0,attrs:{class:"token key atrule"}},[a._v("metrics")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(":")]),a._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("-")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token key atrule"}},[a._v("name")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(":")]),a._v(" request"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("-")]),a._v("success"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("-")]),a._v("rate\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[a._v("# minimum req success rate (non 5xx responses)")]),a._v("\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[a._v("# percentage (0-100)")]),a._v("\n "),s("span",{pre:!0,attrs:{class:"token key atrule"}},[a._v("thresholdRange")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(":")]),a._v("\n "),s("span",{pre:!0,attrs:{class:"token key atrule"}},[a._v("min")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(":")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token number"}},[a._v("99")]),a._v("\n "),s("span",{pre:!0,attrs:{class:"token key atrule"}},[a._v("interval")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(":")]),a._v(" 1m\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("-")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token key atrule"}},[a._v("name")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(":")]),a._v(" request"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("-")]),a._v("duration\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[a._v("# maximum req duration P99")]),a._v("\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[a._v("# milliseconds")]),a._v("\n "),s("span",{pre:!0,attrs:{class:"token key atrule"}},[a._v("thresholdRange")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(":")]),a._v("\n "),s("span",{pre:!0,attrs:{class:"token key atrule"}},[a._v("max")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(":")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token number"}},[a._v("500")]),a._v("\n "),s("span",{pre:!0,attrs:{class:"token key atrule"}},[a._v("interval")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(":")]),a._v(" 30s\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[a._v("# generate traffic during analysis")]),a._v("\n "),s("span",{pre:!0,attrs:{class:"token key atrule"}},[a._v("webhooks")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(":")]),a._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("-")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token key atrule"}},[a._v("name")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(":")]),a._v(" load"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("-")]),a._v("test\n "),s("span",{pre:!0,attrs:{class:"token key atrule"}},[a._v("url")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(":")]),a._v(" http"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(":")]),a._v("//flagger"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("-")]),a._v("loadtester.test/\n "),s("span",{pre:!0,attrs:{class:"token key atrule"}},[a._v("timeout")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(":")]),a._v(" 5s\n "),s("span",{pre:!0,attrs:{class:"token key atrule"}},[a._v("metadata")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(":")]),a._v("\n "),s("span",{pre:!0,attrs:{class:"token key atrule"}},[a._v("cmd")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(":")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token string"}},[a._v('"hey -z 1m -q 10 -c 2 http://podinfo.test:9898/"')]),a._v("\n")])])]),s("p",[a._v("Save the above resource as podinfo-canary.yaml and then apply it:")]),a._v(" "),s("div",{staticClass:"language-bash extra-class"},[s("pre",{pre:!0,attrs:{class:"language-bash"}},[s("code",[a._v("kubectl apply -f ./podinfo-canary.yaml\n")])])]),s("p",[a._v("After a couple of seconds Flagger will create the canary objects:")]),a._v(" "),s("div",{staticClass:"language-bash extra-class"},[s("pre",{pre:!0,attrs:{class:"language-bash"}},[s("code",[s("span",{pre:!0,attrs:{class:"token comment"}},[a._v("# applied ")]),a._v("\ndeployment.apps/podinfo\nhorizontalpodautoscaler.autoscaling/podinfo\ncanary.flagger.app/podinfo\n\n"),s("span",{pre:!0,attrs:{class:"token comment"}},[a._v("# generated ")]),a._v("\ndeployment.apps/podinfo-primary\nhorizontalpodautoscaler.autoscaling/podinfo-primary\nservice/podinfo\nservice/podinfo-canary\nservice/podinfo-primary\ntrafficsplits.split.smi-spec.io/podinfo\n")])])]),s("h2",{attrs:{id:"automated-canary-promotion"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#automated-canary-promotion","aria-hidden":"true"}},[a._v("#")]),a._v(" Automated canary promotion")]),a._v(" "),s("p",[a._v("Flagger implements a control loop that gradually shifts traffic to the canary while measuring key performance indicators like HTTP requests success rate, requests average duration and pod health. Based on analysis of the KPIs a canary is promoted or aborted, and the analysis result is published to Slack.")]),a._v(" "),s("p",[s("img",{attrs:{src:"https://raw.githubusercontent.com/weaveworks/flagger/master/docs/diagrams/flagger-canary-steps.png",alt:"Flagger Canary Stages"}})]),a._v(" "),s("p",[a._v("Trigger a canary deployment by updating the container image:")]),a._v(" "),s("div",{staticClass:"language-bash extra-class"},[s("pre",{pre:!0,attrs:{class:"language-bash"}},[s("code",[a._v("kubectl -n "),s("span",{pre:!0,attrs:{class:"token builtin class-name"}},[a._v("test")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token builtin class-name"}},[a._v("set")]),a._v(" image deployment/podinfo "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("\\")]),a._v("\n"),s("span",{pre:!0,attrs:{class:"token assign-left variable"}},[a._v("podinfod")]),s("span",{pre:!0,attrs:{class:"token operator"}},[a._v("=")]),a._v("quay.io/stefanprodan/podinfo:3.1.1\n")])])]),s("p",[a._v("Flagger detects that the deployment revision changed and starts a new rollout:")]),a._v(" "),s("div",{staticClass:"language-text extra-class"},[s("pre",{pre:!0,attrs:{class:"language-text"}},[s("code",[a._v("kubectl -n istio-system logs deployment/flagger -f | jq .msg\n\n\nNew revision detected podinfo.test\nScaling up podinfo.test\nWaiting for podinfo.test rollout to finish: 0 of 1 updated replicas are available\nAdvance podinfo.test canary weight 5\nAdvance podinfo.test canary weight 10\nAdvance podinfo.test canary weight 15\nAdvance podinfo.test canary weight 20\nAdvance podinfo.test canary weight 25\nAdvance podinfo.test canary weight 30\nAdvance podinfo.test canary weight 35\nAdvance podinfo.test canary weight 40\nAdvance podinfo.test canary weight 45\nAdvance podinfo.test canary weight 50\nCopying podinfo.test template spec to podinfo-primary.test\nWaiting for podinfo-primary.test rollout to finish: 1 of 2 updated replicas are available\nPromotion completed! Scaling down podinfo.test\n")])])]),s("p",[s("strong",[a._v("Note")]),a._v(" that if you apply new changes to the deployment during the canary analysis, Flagger will restart the analysis.")]),a._v(" "),s("p",[a._v("During the analysis the canary’s progress can be monitored with Grafana. The Istio dashboard URL is "),s("a",{attrs:{href:"http://localhost:3000/d/flagger-istio/istio-canary?refresh=10s&orgId=1&var-namespace=test&var-primary=podinfo-primary&var-canary=podinfo",target:"_blank",rel:"noopener noreferrer"}},[a._v("http://localhost:3000/d/flagger-istio/istio-canary?refresh=10s&orgId=1&var-namespace=test&var-primary=podinfo-primary&var-canary=podinfo"),s("OutboundLink")],1)]),a._v(" "),s("p",[a._v("You can monitor all canaries with:")]),a._v(" "),s("div",{staticClass:"language-bash extra-class"},[s("pre",{pre:!0,attrs:{class:"language-bash"}},[s("code",[s("span",{pre:!0,attrs:{class:"token function"}},[a._v("watch")]),a._v(" kubectl get canaries --all-namespaces\n\nNAMESPACE NAME STATUS WEIGHT LASTTRANSITIONTIME\n"),s("span",{pre:!0,attrs:{class:"token builtin class-name"}},[a._v("test")]),a._v(" podinfo Progressing "),s("span",{pre:!0,attrs:{class:"token number"}},[a._v("15")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token number"}},[a._v("2019")]),a._v("-05-16T14:05:07Z\nprod frontend Succeeded "),s("span",{pre:!0,attrs:{class:"token number"}},[a._v("0")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token number"}},[a._v("2019")]),a._v("-05-15T16:15:07Z\nprod backend Failed "),s("span",{pre:!0,attrs:{class:"token number"}},[a._v("0")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token number"}},[a._v("2019")]),a._v("-05-14T17:05:07Z\n")])])]),s("h2",{attrs:{id:"automated-rollback"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#automated-rollback","aria-hidden":"true"}},[a._v("#")]),a._v(" Automated rollback")]),a._v(" "),s("p",[a._v("During the canary analysis you can generate HTTP 500 errors and high latency to test if Flagger pauses the rollout.")]),a._v(" "),s("p",[a._v("Create a tester pod and exec into it:")]),a._v(" "),s("div",{staticClass:"language-bash extra-class"},[s("pre",{pre:!0,attrs:{class:"language-bash"}},[s("code",[a._v("kubectl -n "),s("span",{pre:!0,attrs:{class:"token builtin class-name"}},[a._v("test")]),a._v(" run tester "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("\\")]),a._v("\n--image"),s("span",{pre:!0,attrs:{class:"token operator"}},[a._v("=")]),a._v("quay.io/stefanprodan/podinfo:3.1.2 "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("\\")]),a._v("\n-- ./podinfo --port"),s("span",{pre:!0,attrs:{class:"token operator"}},[a._v("=")]),s("span",{pre:!0,attrs:{class:"token number"}},[a._v("9898")]),a._v("\n\nkubectl -n "),s("span",{pre:!0,attrs:{class:"token builtin class-name"}},[a._v("test")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token builtin class-name"}},[a._v("exec")]),a._v(" -it tester-xx-xx "),s("span",{pre:!0,attrs:{class:"token function"}},[a._v("sh")]),a._v("\n")])])]),s("p",[a._v("Generate HTTP 500 errors:")]),a._v(" "),s("div",{staticClass:"language-bash extra-class"},[s("pre",{pre:!0,attrs:{class:"language-bash"}},[s("code",[s("span",{pre:!0,attrs:{class:"token function"}},[a._v("watch")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token function"}},[a._v("curl")]),a._v(" http://podinfo-canary:9898/status/500\n")])])]),s("p",[a._v("Generate latency:")]),a._v(" "),s("div",{staticClass:"language-bash extra-class"},[s("pre",{pre:!0,attrs:{class:"language-bash"}},[s("code",[s("span",{pre:!0,attrs:{class:"token function"}},[a._v("watch")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token function"}},[a._v("curl")]),a._v(" http://podinfo-canary:9898/delay/1\n")])])]),s("p",[a._v("When the number of failed checks reaches the canary analysis threshold, the traffic is routed back to the primary, the canary is scaled to zero and the rollout is marked as failed.")]),a._v(" "),s("div",{staticClass:"language-text extra-class"},[s("pre",{pre:!0,attrs:{class:"language-text"}},[s("code",[a._v("kubectl -n test describe canary/podinfo\n\nStatus:\n Canary Weight: 0\n Failed Checks: 10\n Phase: Failed\nEvents:\n Type Reason Age From Message\n ---- ------ ---- ---- -------\n Normal Synced 3m flagger Starting canary deployment for podinfo.test\n Normal Synced 3m flagger Advance podinfo.test canary weight 5\n Normal Synced 3m flagger Advance podinfo.test canary weight 10\n Normal Synced 3m flagger Advance podinfo.test canary weight 15\n Normal Synced 3m flagger Halt podinfo.test advancement success rate 69.17% < 99%\n Normal Synced 2m flagger Halt podinfo.test advancement success rate 61.39% < 99%\n Normal Synced 2m flagger Halt podinfo.test advancement success rate 55.06% < 99%\n Normal Synced 2m flagger Halt podinfo.test advancement success rate 47.00% < 99%\n Normal Synced 2m flagger (combined from similar events): Halt podinfo.test advancement success rate 38.08% < 99%\n Warning Synced 1m flagger Rolling back podinfo.test failed checks threshold reached 10\n Warning Synced 1m flagger Canary failed! Scaling down podinfo.test\n")])])])])},[],!1,null,null,null);t.default=n.exports}}]); \ No newline at end of file +(window.webpackJsonp=window.webpackJsonp||[]).push([[21],{281:function(a,t,s){"use strict";s.r(t);var e=s(37),n=Object(e.a)({},function(){var a=this,t=a.$createElement,s=a._self._c||t;return s("ContentSlotsDistributor",{attrs:{"slot-key":a.$parent.slotKey}},[s("h1",{attrs:{id:"smi-istio-canary-deployments"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#smi-istio-canary-deployments","aria-hidden":"true"}},[a._v("#")]),a._v(" SMI Istio Canary Deployments")]),a._v(" "),s("p",[a._v("This guide shows you how to use the SMI Istio adapter and Flagger to automate canary deployments.")]),a._v(" "),s("h2",{attrs:{id:"prerequisites"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#prerequisites","aria-hidden":"true"}},[a._v("#")]),a._v(" Prerequisites")]),a._v(" "),s("ul",[s("li",[a._v("Kubernetes > 1.13")]),a._v(" "),s("li",[a._v("Istio > 1.0")])]),a._v(" "),s("h2",{attrs:{id:"install-istio-smi-adapter"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#install-istio-smi-adapter","aria-hidden":"true"}},[a._v("#")]),a._v(" Install Istio SMI adapter")]),a._v(" "),s("p",[a._v("Install the SMI adapter:")]),a._v(" "),s("div",{staticClass:"language-bash extra-class"},[s("pre",{pre:!0,attrs:{class:"language-bash"}},[s("code",[a._v("kubectl apply -f https://raw.githubusercontent.com/deislabs/smi-adapter-istio/master/deploy/crds/crds.yaml\nkubectl apply -f https://raw.githubusercontent.com/deislabs/smi-adapter-istio/master/deploy/operator-and-rbac.yaml\n")])])]),s("p",[a._v("Create a generic Istio gateway to expose services outside the mesh on HTTP:")]),a._v(" "),s("div",{staticClass:"language-yaml extra-class"},[s("pre",{pre:!0,attrs:{class:"language-yaml"}},[s("code",[s("span",{pre:!0,attrs:{class:"token key atrule"}},[a._v("apiVersion")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(":")]),a._v(" networking.istio.io/v1alpha3\n"),s("span",{pre:!0,attrs:{class:"token key atrule"}},[a._v("kind")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(":")]),a._v(" Gateway\n"),s("span",{pre:!0,attrs:{class:"token key atrule"}},[a._v("metadata")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(":")]),a._v("\n "),s("span",{pre:!0,attrs:{class:"token key atrule"}},[a._v("name")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(":")]),a._v(" public"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("-")]),a._v("gateway\n "),s("span",{pre:!0,attrs:{class:"token key atrule"}},[a._v("namespace")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(":")]),a._v(" istio"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("-")]),a._v("system\n"),s("span",{pre:!0,attrs:{class:"token key atrule"}},[a._v("spec")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(":")]),a._v("\n "),s("span",{pre:!0,attrs:{class:"token key atrule"}},[a._v("selector")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(":")]),a._v("\n "),s("span",{pre:!0,attrs:{class:"token key atrule"}},[a._v("istio")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(":")]),a._v(" ingressgateway\n "),s("span",{pre:!0,attrs:{class:"token key atrule"}},[a._v("servers")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(":")]),a._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("-")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token key atrule"}},[a._v("port")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(":")]),a._v("\n "),s("span",{pre:!0,attrs:{class:"token key atrule"}},[a._v("number")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(":")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token number"}},[a._v("80")]),a._v("\n "),s("span",{pre:!0,attrs:{class:"token key atrule"}},[a._v("name")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(":")]),a._v(" http\n "),s("span",{pre:!0,attrs:{class:"token key atrule"}},[a._v("protocol")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(":")]),a._v(" HTTP\n "),s("span",{pre:!0,attrs:{class:"token key atrule"}},[a._v("hosts")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(":")]),a._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("-")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token string"}},[a._v('"*"')]),a._v("\n")])])]),s("p",[a._v("Save the above resource as public-gateway.yaml and then apply it:")]),a._v(" "),s("div",{staticClass:"language-bash extra-class"},[s("pre",{pre:!0,attrs:{class:"language-bash"}},[s("code",[a._v("kubectl apply -f ./public-gateway.yaml\n")])])]),s("p",[a._v("Find the Gateway load balancer IP and add a DNS record for it:")]),a._v(" "),s("div",{staticClass:"language-bash extra-class"},[s("pre",{pre:!0,attrs:{class:"language-bash"}},[s("code",[a._v("kubectl -n istio-system get svc/istio-ingressgateway -ojson "),s("span",{pre:!0,attrs:{class:"token operator"}},[a._v("|")]),a._v(" jq -r .status.loadBalancer.ingress"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("[")]),s("span",{pre:!0,attrs:{class:"token number"}},[a._v("0")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("]")]),a._v(".ip\n")])])]),s("h2",{attrs:{id:"install-flagger-and-grafana"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#install-flagger-and-grafana","aria-hidden":"true"}},[a._v("#")]),a._v(" Install Flagger and Grafana")]),a._v(" "),s("p",[a._v("Add Flagger Helm repository:")]),a._v(" "),s("div",{staticClass:"language-bash extra-class"},[s("pre",{pre:!0,attrs:{class:"language-bash"}},[s("code",[a._v("helm repo "),s("span",{pre:!0,attrs:{class:"token function"}},[a._v("add")]),a._v(" flagger https://flagger.app\n")])])]),s("p",[a._v("Deploy Flagger in the "),s("em",[s("strong",[a._v("istio-system")])]),a._v(" namespace:")]),a._v(" "),s("div",{staticClass:"language-bash extra-class"},[s("pre",{pre:!0,attrs:{class:"language-bash"}},[s("code",[a._v("helm upgrade -i flagger flagger/flagger "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("\\")]),a._v("\n--namespace"),s("span",{pre:!0,attrs:{class:"token operator"}},[a._v("=")]),a._v("istio-system "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("\\")]),a._v("\n--set "),s("span",{pre:!0,attrs:{class:"token assign-left variable"}},[a._v("meshProvider")]),s("span",{pre:!0,attrs:{class:"token operator"}},[a._v("=")]),a._v("smi:istio\n")])])]),s("p",[a._v("Flagger comes with a Grafana dashboard made for monitoring the canary deployments.")]),a._v(" "),s("p",[a._v("Deploy Grafana in the "),s("em",[s("strong",[a._v("istio-system")])]),a._v(" namespace:")]),a._v(" "),s("div",{staticClass:"language-bash extra-class"},[s("pre",{pre:!0,attrs:{class:"language-bash"}},[s("code",[a._v("helm upgrade -i flagger-grafana flagger/grafana "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("\\")]),a._v("\n--namespace"),s("span",{pre:!0,attrs:{class:"token operator"}},[a._v("=")]),a._v("istio-system "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("\\")]),a._v("\n--set "),s("span",{pre:!0,attrs:{class:"token assign-left variable"}},[a._v("url")]),s("span",{pre:!0,attrs:{class:"token operator"}},[a._v("=")]),a._v("http://prometheus.istio-system:9090\n")])])]),s("p",[a._v("You can access Grafana using port forwarding:")]),a._v(" "),s("div",{staticClass:"language-bash extra-class"},[s("pre",{pre:!0,attrs:{class:"language-bash"}},[s("code",[a._v("kubectl -n istio-system port-forward svc/flagger-grafana "),s("span",{pre:!0,attrs:{class:"token number"}},[a._v("3000")]),a._v(":80\n")])])]),s("h2",{attrs:{id:"workloads-bootstrap"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#workloads-bootstrap","aria-hidden":"true"}},[a._v("#")]),a._v(" Workloads bootstrap")]),a._v(" "),s("p",[a._v("Create a test namespace with Istio sidecar injection enabled:")]),a._v(" "),s("p",[a._v("Create a test namespace and enable Linkerd proxy injection:")]),a._v(" "),s("div",{staticClass:"language-bash extra-class"},[s("pre",{pre:!0,attrs:{class:"language-bash"}},[s("code",[a._v("kubectl create ns "),s("span",{pre:!0,attrs:{class:"token builtin class-name"}},[a._v("test")]),a._v("\nkubectl label namespace "),s("span",{pre:!0,attrs:{class:"token builtin class-name"}},[a._v("test")]),a._v(" istio-injection"),s("span",{pre:!0,attrs:{class:"token operator"}},[a._v("=")]),a._v("enabled\n")])])]),s("p",[a._v("Create a deployment and a horizontal pod autoscaler:")]),a._v(" "),s("div",{staticClass:"language-bash extra-class"},[s("pre",{pre:!0,attrs:{class:"language-bash"}},[s("code",[a._v("kubectl apply -k github.com/weaveworks/flagger//kustomize/podinfo\n")])])]),s("p",[a._v("Deploy the load testing service to generate traffic during the canary analysis:")]),a._v(" "),s("div",{staticClass:"language-bash extra-class"},[s("pre",{pre:!0,attrs:{class:"language-bash"}},[s("code",[a._v("kubectl apply -k github.com/weaveworks/flagger//kustomize/tester\n")])])]),s("p",[a._v("Create a canary custom resource (replace example.com with your own domain):")]),a._v(" "),s("div",{staticClass:"language-yaml extra-class"},[s("pre",{pre:!0,attrs:{class:"language-yaml"}},[s("code",[s("span",{pre:!0,attrs:{class:"token key atrule"}},[a._v("apiVersion")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(":")]),a._v(" flagger.app/v1beta1\n"),s("span",{pre:!0,attrs:{class:"token key atrule"}},[a._v("kind")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(":")]),a._v(" Canary\n"),s("span",{pre:!0,attrs:{class:"token key atrule"}},[a._v("metadata")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(":")]),a._v("\n "),s("span",{pre:!0,attrs:{class:"token key atrule"}},[a._v("name")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(":")]),a._v(" podinfo\n "),s("span",{pre:!0,attrs:{class:"token key atrule"}},[a._v("namespace")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(":")]),a._v(" test\n"),s("span",{pre:!0,attrs:{class:"token key atrule"}},[a._v("spec")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(":")]),a._v("\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[a._v("# deployment reference")]),a._v("\n "),s("span",{pre:!0,attrs:{class:"token key atrule"}},[a._v("targetRef")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(":")]),a._v("\n "),s("span",{pre:!0,attrs:{class:"token key atrule"}},[a._v("apiVersion")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(":")]),a._v(" apps/v1\n "),s("span",{pre:!0,attrs:{class:"token key atrule"}},[a._v("kind")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(":")]),a._v(" Deployment\n "),s("span",{pre:!0,attrs:{class:"token key atrule"}},[a._v("name")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(":")]),a._v(" podinfo\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[a._v("# the maximum time in seconds for the canary deployment")]),a._v("\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[a._v("# to make progress before it is rollback (default 600s)")]),a._v("\n "),s("span",{pre:!0,attrs:{class:"token key atrule"}},[a._v("progressDeadlineSeconds")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(":")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token number"}},[a._v("60")]),a._v("\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[a._v("# HPA reference (optional)")]),a._v("\n "),s("span",{pre:!0,attrs:{class:"token key atrule"}},[a._v("autoscalerRef")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(":")]),a._v("\n "),s("span",{pre:!0,attrs:{class:"token key atrule"}},[a._v("apiVersion")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(":")]),a._v(" autoscaling/v2beta1\n "),s("span",{pre:!0,attrs:{class:"token key atrule"}},[a._v("kind")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(":")]),a._v(" HorizontalPodAutoscaler\n "),s("span",{pre:!0,attrs:{class:"token key atrule"}},[a._v("name")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(":")]),a._v(" podinfo\n "),s("span",{pre:!0,attrs:{class:"token key atrule"}},[a._v("service")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(":")]),a._v("\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[a._v("# container port")]),a._v("\n "),s("span",{pre:!0,attrs:{class:"token key atrule"}},[a._v("port")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(":")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token number"}},[a._v("9898")]),a._v("\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[a._v("# Istio gateways (optional)")]),a._v("\n "),s("span",{pre:!0,attrs:{class:"token key atrule"}},[a._v("gateways")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(":")]),a._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("-")]),a._v(" public"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("-")]),a._v("gateway.istio"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("-")]),a._v("system.svc.cluster.local\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[a._v("# Istio virtual service host names (optional)")]),a._v("\n "),s("span",{pre:!0,attrs:{class:"token key atrule"}},[a._v("hosts")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(":")]),a._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("-")]),a._v(" app.example.com\n "),s("span",{pre:!0,attrs:{class:"token key atrule"}},[a._v("analysis")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(":")]),a._v("\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[a._v("# schedule interval (default 60s)")]),a._v("\n "),s("span",{pre:!0,attrs:{class:"token key atrule"}},[a._v("interval")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(":")]),a._v(" 10s\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[a._v("# max number of failed metric checks before rollback")]),a._v("\n "),s("span",{pre:!0,attrs:{class:"token key atrule"}},[a._v("threshold")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(":")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token number"}},[a._v("5")]),a._v("\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[a._v("# max traffic percentage routed to canary")]),a._v("\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[a._v("# percentage (0-100)")]),a._v("\n "),s("span",{pre:!0,attrs:{class:"token key atrule"}},[a._v("maxWeight")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(":")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token number"}},[a._v("50")]),a._v("\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[a._v("# canary increment step")]),a._v("\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[a._v("# percentage (0-100)")]),a._v("\n "),s("span",{pre:!0,attrs:{class:"token key atrule"}},[a._v("stepWeight")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(":")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token number"}},[a._v("10")]),a._v("\n "),s("span",{pre:!0,attrs:{class:"token key atrule"}},[a._v("metrics")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(":")]),a._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("-")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token key atrule"}},[a._v("name")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(":")]),a._v(" request"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("-")]),a._v("success"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("-")]),a._v("rate\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[a._v("# minimum req success rate (non 5xx responses)")]),a._v("\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[a._v("# percentage (0-100)")]),a._v("\n "),s("span",{pre:!0,attrs:{class:"token key atrule"}},[a._v("thresholdRange")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(":")]),a._v("\n "),s("span",{pre:!0,attrs:{class:"token key atrule"}},[a._v("min")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(":")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token number"}},[a._v("99")]),a._v("\n "),s("span",{pre:!0,attrs:{class:"token key atrule"}},[a._v("interval")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(":")]),a._v(" 1m\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("-")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token key atrule"}},[a._v("name")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(":")]),a._v(" request"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("-")]),a._v("duration\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[a._v("# maximum req duration P99")]),a._v("\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[a._v("# milliseconds")]),a._v("\n "),s("span",{pre:!0,attrs:{class:"token key atrule"}},[a._v("thresholdRange")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(":")]),a._v("\n "),s("span",{pre:!0,attrs:{class:"token key atrule"}},[a._v("max")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(":")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token number"}},[a._v("500")]),a._v("\n "),s("span",{pre:!0,attrs:{class:"token key atrule"}},[a._v("interval")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(":")]),a._v(" 30s\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[a._v("# generate traffic during analysis")]),a._v("\n "),s("span",{pre:!0,attrs:{class:"token key atrule"}},[a._v("webhooks")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(":")]),a._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("-")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token key atrule"}},[a._v("name")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(":")]),a._v(" load"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("-")]),a._v("test\n "),s("span",{pre:!0,attrs:{class:"token key atrule"}},[a._v("url")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(":")]),a._v(" http"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(":")]),a._v("//flagger"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("-")]),a._v("loadtester.test/\n "),s("span",{pre:!0,attrs:{class:"token key atrule"}},[a._v("timeout")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(":")]),a._v(" 5s\n "),s("span",{pre:!0,attrs:{class:"token key atrule"}},[a._v("metadata")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(":")]),a._v("\n "),s("span",{pre:!0,attrs:{class:"token key atrule"}},[a._v("cmd")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(":")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token string"}},[a._v('"hey -z 1m -q 10 -c 2 http://podinfo.test:9898/"')]),a._v("\n")])])]),s("p",[a._v("Save the above resource as podinfo-canary.yaml and then apply it:")]),a._v(" "),s("div",{staticClass:"language-bash extra-class"},[s("pre",{pre:!0,attrs:{class:"language-bash"}},[s("code",[a._v("kubectl apply -f ./podinfo-canary.yaml\n")])])]),s("p",[a._v("After a couple of seconds Flagger will create the canary objects:")]),a._v(" "),s("div",{staticClass:"language-bash extra-class"},[s("pre",{pre:!0,attrs:{class:"language-bash"}},[s("code",[s("span",{pre:!0,attrs:{class:"token comment"}},[a._v("# applied ")]),a._v("\ndeployment.apps/podinfo\nhorizontalpodautoscaler.autoscaling/podinfo\ncanary.flagger.app/podinfo\n\n"),s("span",{pre:!0,attrs:{class:"token comment"}},[a._v("# generated ")]),a._v("\ndeployment.apps/podinfo-primary\nhorizontalpodautoscaler.autoscaling/podinfo-primary\nservice/podinfo\nservice/podinfo-canary\nservice/podinfo-primary\ntrafficsplits.split.smi-spec.io/podinfo\n")])])]),s("h2",{attrs:{id:"automated-canary-promotion"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#automated-canary-promotion","aria-hidden":"true"}},[a._v("#")]),a._v(" Automated canary promotion")]),a._v(" "),s("p",[a._v("Flagger implements a control loop that gradually shifts traffic to the canary while measuring key performance indicators like HTTP requests success rate, requests average duration and pod health. Based on analysis of the KPIs a canary is promoted or aborted, and the analysis result is published to Slack.")]),a._v(" "),s("p",[s("img",{attrs:{src:"https://raw.githubusercontent.com/weaveworks/flagger/master/docs/diagrams/flagger-canary-steps.png",alt:"Flagger Canary Stages"}})]),a._v(" "),s("p",[a._v("Trigger a canary deployment by updating the container image:")]),a._v(" "),s("div",{staticClass:"language-bash extra-class"},[s("pre",{pre:!0,attrs:{class:"language-bash"}},[s("code",[a._v("kubectl -n "),s("span",{pre:!0,attrs:{class:"token builtin class-name"}},[a._v("test")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token builtin class-name"}},[a._v("set")]),a._v(" image deployment/podinfo "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("\\")]),a._v("\n"),s("span",{pre:!0,attrs:{class:"token assign-left variable"}},[a._v("podinfod")]),s("span",{pre:!0,attrs:{class:"token operator"}},[a._v("=")]),a._v("quay.io/stefanprodan/podinfo:3.1.1\n")])])]),s("p",[a._v("Flagger detects that the deployment revision changed and starts a new rollout:")]),a._v(" "),s("div",{staticClass:"language-text extra-class"},[s("pre",{pre:!0,attrs:{class:"language-text"}},[s("code",[a._v("kubectl -n istio-system logs deployment/flagger -f | jq .msg\n\n\nNew revision detected podinfo.test\nScaling up podinfo.test\nWaiting for podinfo.test rollout to finish: 0 of 1 updated replicas are available\nAdvance podinfo.test canary weight 5\nAdvance podinfo.test canary weight 10\nAdvance podinfo.test canary weight 15\nAdvance podinfo.test canary weight 20\nAdvance podinfo.test canary weight 25\nAdvance podinfo.test canary weight 30\nAdvance podinfo.test canary weight 35\nAdvance podinfo.test canary weight 40\nAdvance podinfo.test canary weight 45\nAdvance podinfo.test canary weight 50\nCopying podinfo.test template spec to podinfo-primary.test\nWaiting for podinfo-primary.test rollout to finish: 1 of 2 updated replicas are available\nPromotion completed! Scaling down podinfo.test\n")])])]),s("p",[s("strong",[a._v("Note")]),a._v(" that if you apply new changes to the deployment during the canary analysis, Flagger will restart the analysis.")]),a._v(" "),s("p",[a._v("During the analysis the canary’s progress can be monitored with Grafana. The Istio dashboard URL is "),s("a",{attrs:{href:"http://localhost:3000/d/flagger-istio/istio-canary?refresh=10s&orgId=1&var-namespace=test&var-primary=podinfo-primary&var-canary=podinfo",target:"_blank",rel:"noopener noreferrer"}},[a._v("http://localhost:3000/d/flagger-istio/istio-canary?refresh=10s&orgId=1&var-namespace=test&var-primary=podinfo-primary&var-canary=podinfo"),s("OutboundLink")],1)]),a._v(" "),s("p",[a._v("You can monitor all canaries with:")]),a._v(" "),s("div",{staticClass:"language-bash extra-class"},[s("pre",{pre:!0,attrs:{class:"language-bash"}},[s("code",[s("span",{pre:!0,attrs:{class:"token function"}},[a._v("watch")]),a._v(" kubectl get canaries --all-namespaces\n\nNAMESPACE NAME STATUS WEIGHT LASTTRANSITIONTIME\n"),s("span",{pre:!0,attrs:{class:"token builtin class-name"}},[a._v("test")]),a._v(" podinfo Progressing "),s("span",{pre:!0,attrs:{class:"token number"}},[a._v("15")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token number"}},[a._v("2019")]),a._v("-05-16T14:05:07Z\nprod frontend Succeeded "),s("span",{pre:!0,attrs:{class:"token number"}},[a._v("0")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token number"}},[a._v("2019")]),a._v("-05-15T16:15:07Z\nprod backend Failed "),s("span",{pre:!0,attrs:{class:"token number"}},[a._v("0")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token number"}},[a._v("2019")]),a._v("-05-14T17:05:07Z\n")])])]),s("h2",{attrs:{id:"automated-rollback"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#automated-rollback","aria-hidden":"true"}},[a._v("#")]),a._v(" Automated rollback")]),a._v(" "),s("p",[a._v("During the canary analysis you can generate HTTP 500 errors and high latency to test if Flagger pauses the rollout.")]),a._v(" "),s("p",[a._v("Create a tester pod and exec into it:")]),a._v(" "),s("div",{staticClass:"language-bash extra-class"},[s("pre",{pre:!0,attrs:{class:"language-bash"}},[s("code",[a._v("kubectl -n "),s("span",{pre:!0,attrs:{class:"token builtin class-name"}},[a._v("test")]),a._v(" run tester "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("\\")]),a._v("\n--image"),s("span",{pre:!0,attrs:{class:"token operator"}},[a._v("=")]),a._v("quay.io/stefanprodan/podinfo:3.1.2 "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("\\")]),a._v("\n-- ./podinfo --port"),s("span",{pre:!0,attrs:{class:"token operator"}},[a._v("=")]),s("span",{pre:!0,attrs:{class:"token number"}},[a._v("9898")]),a._v("\n\nkubectl -n "),s("span",{pre:!0,attrs:{class:"token builtin class-name"}},[a._v("test")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token builtin class-name"}},[a._v("exec")]),a._v(" -it tester-xx-xx "),s("span",{pre:!0,attrs:{class:"token function"}},[a._v("sh")]),a._v("\n")])])]),s("p",[a._v("Generate HTTP 500 errors:")]),a._v(" "),s("div",{staticClass:"language-bash extra-class"},[s("pre",{pre:!0,attrs:{class:"language-bash"}},[s("code",[s("span",{pre:!0,attrs:{class:"token function"}},[a._v("watch")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token function"}},[a._v("curl")]),a._v(" http://podinfo-canary:9898/status/500\n")])])]),s("p",[a._v("Generate latency:")]),a._v(" "),s("div",{staticClass:"language-bash extra-class"},[s("pre",{pre:!0,attrs:{class:"language-bash"}},[s("code",[s("span",{pre:!0,attrs:{class:"token function"}},[a._v("watch")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token function"}},[a._v("curl")]),a._v(" http://podinfo-canary:9898/delay/1\n")])])]),s("p",[a._v("When the number of failed checks reaches the canary analysis threshold, the traffic is routed back to the primary, the canary is scaled to zero and the rollout is marked as failed.")]),a._v(" "),s("div",{staticClass:"language-text extra-class"},[s("pre",{pre:!0,attrs:{class:"language-text"}},[s("code",[a._v("kubectl -n test describe canary/podinfo\n\nStatus:\n Canary Weight: 0\n Failed Checks: 10\n Phase: Failed\nEvents:\n Type Reason Age From Message\n ---- ------ ---- ---- -------\n Normal Synced 3m flagger Starting canary deployment for podinfo.test\n Normal Synced 3m flagger Advance podinfo.test canary weight 5\n Normal Synced 3m flagger Advance podinfo.test canary weight 10\n Normal Synced 3m flagger Advance podinfo.test canary weight 15\n Normal Synced 3m flagger Halt podinfo.test advancement success rate 69.17% < 99%\n Normal Synced 2m flagger Halt podinfo.test advancement success rate 61.39% < 99%\n Normal Synced 2m flagger Halt podinfo.test advancement success rate 55.06% < 99%\n Normal Synced 2m flagger Halt podinfo.test advancement success rate 47.00% < 99%\n Normal Synced 2m flagger (combined from similar events): Halt podinfo.test advancement success rate 38.08% < 99%\n Warning Synced 1m flagger Rolling back podinfo.test failed checks threshold reached 10\n Warning Synced 1m flagger Canary failed! Scaling down podinfo.test\n")])])])])},[],!1,null,null,null);t.default=n.exports}}]); \ No newline at end of file diff --git a/assets/js/23.b3dcc355.js b/assets/js/23.ec1dec63.js similarity index 99% rename from assets/js/23.b3dcc355.js rename to assets/js/23.ec1dec63.js index ea5f9616..36281afc 100644 --- a/assets/js/23.b3dcc355.js +++ b/assets/js/23.ec1dec63.js @@ -1 +1 @@ -(window.webpackJsonp=window.webpackJsonp||[]).push([[23],{283:function(a,t,e){"use strict";e.r(t);var s=e(37),n=Object(s.a)({},function(){var a=this,t=a.$createElement,e=a._self._c||t;return e("ContentSlotsDistributor",{attrs:{"slot-key":a.$parent.slotKey}},[e("h1",{attrs:{id:"istio-a-b-testing"}},[e("a",{staticClass:"header-anchor",attrs:{href:"#istio-a-b-testing","aria-hidden":"true"}},[a._v("#")]),a._v(" Istio A/B Testing")]),a._v(" "),e("p",[a._v("This guide shows you how to automate A/B testing with Istio and Flagger.")]),a._v(" "),e("p",[a._v("Besides weighted routing, Flagger can be configured to route traffic to the canary based on HTTP match conditions.\nIn an A/B testing scenario, you'll be using HTTP headers or cookies to target a certain segment of your users.\nThis is particularly useful for frontend applications that require session affinity.")]),a._v(" "),e("p",[e("img",{attrs:{src:"https://raw.githubusercontent.com/weaveworks/flagger/master/docs/diagrams/flagger-abtest-steps.png",alt:"Flagger A/B Testing Stages"}})]),a._v(" "),e("h2",{attrs:{id:"prerequisites"}},[e("a",{staticClass:"header-anchor",attrs:{href:"#prerequisites","aria-hidden":"true"}},[a._v("#")]),a._v(" Prerequisites")]),a._v(" "),e("p",[a._v("Flagger requires a Kubernetes cluster "),e("strong",[a._v("v1.11")]),a._v(" or newer and Istio "),e("strong",[a._v("v1.0")]),a._v(" or newer.")]),a._v(" "),e("p",[a._v("Install Istio with telemetry support and Prometheus:")]),a._v(" "),e("div",{staticClass:"language-bash extra-class"},[e("pre",{pre:!0,attrs:{class:"language-bash"}},[e("code",[a._v("istioctl manifest apply --set "),e("span",{pre:!0,attrs:{class:"token assign-left variable"}},[a._v("profile")]),e("span",{pre:!0,attrs:{class:"token operator"}},[a._v("=")]),a._v("default\n")])])]),e("p",[a._v("Install Flagger using Kustomize (kubectl 1.14) in the "),e("code",[a._v("istio-system")]),a._v(" namespace:")]),a._v(" "),e("div",{staticClass:"language-bash extra-class"},[e("pre",{pre:!0,attrs:{class:"language-bash"}},[e("code",[a._v("kubectl apply -k github.com/weaveworks/flagger//kustomize/istio\n")])])]),e("p",[a._v("Create an ingress gateway to expose the demo app outside of the mesh:")]),a._v(" "),e("div",{staticClass:"language-yaml extra-class"},[e("pre",{pre:!0,attrs:{class:"language-yaml"}},[e("code",[e("span",{pre:!0,attrs:{class:"token key atrule"}},[a._v("apiVersion")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(":")]),a._v(" networking.istio.io/v1alpha3\n"),e("span",{pre:!0,attrs:{class:"token key atrule"}},[a._v("kind")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(":")]),a._v(" Gateway\n"),e("span",{pre:!0,attrs:{class:"token key atrule"}},[a._v("metadata")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(":")]),a._v("\n "),e("span",{pre:!0,attrs:{class:"token key atrule"}},[a._v("name")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(":")]),a._v(" public"),e("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("-")]),a._v("gateway\n "),e("span",{pre:!0,attrs:{class:"token key atrule"}},[a._v("namespace")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(":")]),a._v(" istio"),e("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("-")]),a._v("system\n"),e("span",{pre:!0,attrs:{class:"token key atrule"}},[a._v("spec")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(":")]),a._v("\n "),e("span",{pre:!0,attrs:{class:"token key atrule"}},[a._v("selector")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(":")]),a._v("\n "),e("span",{pre:!0,attrs:{class:"token key atrule"}},[a._v("istio")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(":")]),a._v(" ingressgateway\n "),e("span",{pre:!0,attrs:{class:"token key atrule"}},[a._v("servers")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(":")]),a._v("\n "),e("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("-")]),a._v(" "),e("span",{pre:!0,attrs:{class:"token key atrule"}},[a._v("port")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(":")]),a._v("\n "),e("span",{pre:!0,attrs:{class:"token key atrule"}},[a._v("number")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(":")]),a._v(" "),e("span",{pre:!0,attrs:{class:"token number"}},[a._v("80")]),a._v("\n "),e("span",{pre:!0,attrs:{class:"token key atrule"}},[a._v("name")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(":")]),a._v(" http\n "),e("span",{pre:!0,attrs:{class:"token key atrule"}},[a._v("protocol")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(":")]),a._v(" HTTP\n "),e("span",{pre:!0,attrs:{class:"token key atrule"}},[a._v("hosts")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(":")]),a._v("\n "),e("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("-")]),a._v(" "),e("span",{pre:!0,attrs:{class:"token string"}},[a._v('"*"')]),a._v("\n")])])]),e("h2",{attrs:{id:"bootstrap"}},[e("a",{staticClass:"header-anchor",attrs:{href:"#bootstrap","aria-hidden":"true"}},[a._v("#")]),a._v(" Bootstrap")]),a._v(" "),e("p",[a._v("Create a test namespace with Istio sidecar injection enabled:")]),a._v(" "),e("div",{staticClass:"language-bash extra-class"},[e("pre",{pre:!0,attrs:{class:"language-bash"}},[e("code",[a._v("kubectl create ns "),e("span",{pre:!0,attrs:{class:"token builtin class-name"}},[a._v("test")]),a._v("\nkubectl label namespace "),e("span",{pre:!0,attrs:{class:"token builtin class-name"}},[a._v("test")]),a._v(" istio-injection"),e("span",{pre:!0,attrs:{class:"token operator"}},[a._v("=")]),a._v("enabled\n")])])]),e("p",[a._v("Create a deployment and a horizontal pod autoscaler:")]),a._v(" "),e("div",{staticClass:"language-bash extra-class"},[e("pre",{pre:!0,attrs:{class:"language-bash"}},[e("code",[a._v("kubectl apply -k github.com/weaveworks/flagger//kustomize/podinfo\n")])])]),e("p",[a._v("Deploy the load testing service to generate traffic during the canary analysis:")]),a._v(" "),e("div",{staticClass:"language-bash extra-class"},[e("pre",{pre:!0,attrs:{class:"language-bash"}},[e("code",[a._v("kubectl apply -k github.com/weaveworks/flagger//kustomize/tester\n")])])]),e("p",[a._v("Create a canary custom resource (replace example.com with your own domain):")]),a._v(" "),e("div",{staticClass:"language-yaml extra-class"},[e("pre",{pre:!0,attrs:{class:"language-yaml"}},[e("code",[e("span",{pre:!0,attrs:{class:"token key atrule"}},[a._v("apiVersion")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(":")]),a._v(" flagger.app/v1beta1\n"),e("span",{pre:!0,attrs:{class:"token key atrule"}},[a._v("kind")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(":")]),a._v(" Canary\n"),e("span",{pre:!0,attrs:{class:"token key atrule"}},[a._v("metadata")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(":")]),a._v("\n "),e("span",{pre:!0,attrs:{class:"token key atrule"}},[a._v("name")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(":")]),a._v(" podinfo\n "),e("span",{pre:!0,attrs:{class:"token key atrule"}},[a._v("namespace")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(":")]),a._v(" test\n"),e("span",{pre:!0,attrs:{class:"token key atrule"}},[a._v("spec")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(":")]),a._v("\n "),e("span",{pre:!0,attrs:{class:"token comment"}},[a._v("# deployment reference")]),a._v("\n "),e("span",{pre:!0,attrs:{class:"token key atrule"}},[a._v("targetRef")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(":")]),a._v("\n "),e("span",{pre:!0,attrs:{class:"token key atrule"}},[a._v("apiVersion")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(":")]),a._v(" apps/v1\n "),e("span",{pre:!0,attrs:{class:"token key atrule"}},[a._v("kind")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(":")]),a._v(" Deployment\n "),e("span",{pre:!0,attrs:{class:"token key atrule"}},[a._v("name")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(":")]),a._v(" podinfo\n "),e("span",{pre:!0,attrs:{class:"token comment"}},[a._v("# the maximum time in seconds for the canary deployment")]),a._v("\n "),e("span",{pre:!0,attrs:{class:"token comment"}},[a._v("# to make progress before it is rollback (default 600s)")]),a._v("\n "),e("span",{pre:!0,attrs:{class:"token key atrule"}},[a._v("progressDeadlineSeconds")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(":")]),a._v(" "),e("span",{pre:!0,attrs:{class:"token number"}},[a._v("60")]),a._v("\n "),e("span",{pre:!0,attrs:{class:"token comment"}},[a._v("# HPA reference (optional)")]),a._v("\n "),e("span",{pre:!0,attrs:{class:"token key atrule"}},[a._v("autoscalerRef")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(":")]),a._v("\n "),e("span",{pre:!0,attrs:{class:"token key atrule"}},[a._v("apiVersion")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(":")]),a._v(" autoscaling/v2beta1\n "),e("span",{pre:!0,attrs:{class:"token key atrule"}},[a._v("kind")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(":")]),a._v(" HorizontalPodAutoscaler\n "),e("span",{pre:!0,attrs:{class:"token key atrule"}},[a._v("name")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(":")]),a._v(" podinfo\n "),e("span",{pre:!0,attrs:{class:"token key atrule"}},[a._v("service")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(":")]),a._v("\n "),e("span",{pre:!0,attrs:{class:"token comment"}},[a._v("# container port")]),a._v("\n "),e("span",{pre:!0,attrs:{class:"token key atrule"}},[a._v("port")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(":")]),a._v(" "),e("span",{pre:!0,attrs:{class:"token number"}},[a._v("9898")]),a._v("\n "),e("span",{pre:!0,attrs:{class:"token comment"}},[a._v("# Istio gateways (optional)")]),a._v("\n "),e("span",{pre:!0,attrs:{class:"token key atrule"}},[a._v("gateways")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(":")]),a._v("\n "),e("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("-")]),a._v(" public"),e("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("-")]),a._v("gateway.istio"),e("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("-")]),a._v("system.svc.cluster.local\n "),e("span",{pre:!0,attrs:{class:"token comment"}},[a._v("# Istio virtual service host names (optional)")]),a._v("\n "),e("span",{pre:!0,attrs:{class:"token key atrule"}},[a._v("hosts")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(":")]),a._v("\n "),e("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("-")]),a._v(" app.example.com\n "),e("span",{pre:!0,attrs:{class:"token comment"}},[a._v("# Istio traffic policy (optional)")]),a._v("\n "),e("span",{pre:!0,attrs:{class:"token key atrule"}},[a._v("trafficPolicy")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(":")]),a._v("\n "),e("span",{pre:!0,attrs:{class:"token key atrule"}},[a._v("tls")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(":")]),a._v("\n "),e("span",{pre:!0,attrs:{class:"token comment"}},[a._v("# use ISTIO_MUTUAL when mTLS is enabled")]),a._v("\n "),e("span",{pre:!0,attrs:{class:"token key atrule"}},[a._v("mode")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(":")]),a._v(" DISABLE\n "),e("span",{pre:!0,attrs:{class:"token key atrule"}},[a._v("analysis")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(":")]),a._v("\n "),e("span",{pre:!0,attrs:{class:"token comment"}},[a._v("# schedule interval (default 60s)")]),a._v("\n "),e("span",{pre:!0,attrs:{class:"token key atrule"}},[a._v("interval")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(":")]),a._v(" 1m\n "),e("span",{pre:!0,attrs:{class:"token comment"}},[a._v("# total number of iterations")]),a._v("\n "),e("span",{pre:!0,attrs:{class:"token key atrule"}},[a._v("iterations")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(":")]),a._v(" "),e("span",{pre:!0,attrs:{class:"token number"}},[a._v("10")]),a._v("\n "),e("span",{pre:!0,attrs:{class:"token comment"}},[a._v("# max number of failed iterations before rollback")]),a._v("\n "),e("span",{pre:!0,attrs:{class:"token key atrule"}},[a._v("threshold")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(":")]),a._v(" "),e("span",{pre:!0,attrs:{class:"token number"}},[a._v("2")]),a._v("\n "),e("span",{pre:!0,attrs:{class:"token comment"}},[a._v("# canary match condition")]),a._v("\n "),e("span",{pre:!0,attrs:{class:"token key atrule"}},[a._v("match")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(":")]),a._v("\n "),e("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("-")]),a._v(" "),e("span",{pre:!0,attrs:{class:"token key atrule"}},[a._v("headers")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(":")]),a._v("\n "),e("span",{pre:!0,attrs:{class:"token key atrule"}},[a._v("user-agent")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(":")]),a._v("\n "),e("span",{pre:!0,attrs:{class:"token key atrule"}},[a._v("regex")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(":")]),a._v(" "),e("span",{pre:!0,attrs:{class:"token string"}},[a._v('"^(?!.*Chrome).*Safari.*"')]),a._v("\n "),e("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("-")]),a._v(" "),e("span",{pre:!0,attrs:{class:"token key atrule"}},[a._v("headers")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(":")]),a._v("\n "),e("span",{pre:!0,attrs:{class:"token key atrule"}},[a._v("cookie")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(":")]),a._v("\n "),e("span",{pre:!0,attrs:{class:"token key atrule"}},[a._v("regex")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(":")]),a._v(" "),e("span",{pre:!0,attrs:{class:"token string"}},[a._v('"^(.*?;)?(type=insider)(;.*)?$"')]),a._v("\n "),e("span",{pre:!0,attrs:{class:"token key atrule"}},[a._v("metrics")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(":")]),a._v("\n "),e("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("-")]),a._v(" "),e("span",{pre:!0,attrs:{class:"token key atrule"}},[a._v("name")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(":")]),a._v(" request"),e("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("-")]),a._v("success"),e("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("-")]),a._v("rate\n "),e("span",{pre:!0,attrs:{class:"token comment"}},[a._v("# minimum req success rate (non 5xx responses)")]),a._v("\n "),e("span",{pre:!0,attrs:{class:"token comment"}},[a._v("# percentage (0-100)")]),a._v("\n "),e("span",{pre:!0,attrs:{class:"token key atrule"}},[a._v("thresholdRange")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(":")]),a._v("\n "),e("span",{pre:!0,attrs:{class:"token key atrule"}},[a._v("min")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(":")]),a._v(" "),e("span",{pre:!0,attrs:{class:"token number"}},[a._v("99")]),a._v("\n "),e("span",{pre:!0,attrs:{class:"token key atrule"}},[a._v("interval")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(":")]),a._v(" 1m\n "),e("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("-")]),a._v(" "),e("span",{pre:!0,attrs:{class:"token key atrule"}},[a._v("name")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(":")]),a._v(" request"),e("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("-")]),a._v("duration\n "),e("span",{pre:!0,attrs:{class:"token comment"}},[a._v("# maximum req duration P99")]),a._v("\n "),e("span",{pre:!0,attrs:{class:"token comment"}},[a._v("# milliseconds")]),a._v("\n "),e("span",{pre:!0,attrs:{class:"token key atrule"}},[a._v("thresholdRange")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(":")]),a._v("\n "),e("span",{pre:!0,attrs:{class:"token key atrule"}},[a._v("max")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(":")]),a._v(" "),e("span",{pre:!0,attrs:{class:"token number"}},[a._v("500")]),a._v("\n "),e("span",{pre:!0,attrs:{class:"token key atrule"}},[a._v("interval")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(":")]),a._v(" 30s\n "),e("span",{pre:!0,attrs:{class:"token comment"}},[a._v("# generate traffic during analysis")]),a._v("\n "),e("span",{pre:!0,attrs:{class:"token key atrule"}},[a._v("webhooks")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(":")]),a._v("\n "),e("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("-")]),a._v(" "),e("span",{pre:!0,attrs:{class:"token key atrule"}},[a._v("name")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(":")]),a._v(" load"),e("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("-")]),a._v("test\n "),e("span",{pre:!0,attrs:{class:"token key atrule"}},[a._v("url")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(":")]),a._v(" http"),e("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(":")]),a._v("//flagger"),e("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("-")]),a._v("loadtester.test/\n "),e("span",{pre:!0,attrs:{class:"token key atrule"}},[a._v("timeout")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(":")]),a._v(" 5s\n "),e("span",{pre:!0,attrs:{class:"token key atrule"}},[a._v("metadata")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(":")]),a._v("\n "),e("span",{pre:!0,attrs:{class:"token key atrule"}},[a._v("cmd")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(":")]),a._v(" "),e("span",{pre:!0,attrs:{class:"token string"}},[a._v("\"hey -z 1m -q 10 -c 2 -H 'Cookie: type=insider' http://podinfo.test:9898/\"")]),a._v("\n")])])]),e("p",[a._v("The above configuration will run an analysis for ten minutes targeting Safari users and those that have an insider cookie.")]),a._v(" "),e("p",[a._v("Save the above resource as podinfo-abtest.yaml and then apply it:")]),a._v(" "),e("div",{staticClass:"language-bash extra-class"},[e("pre",{pre:!0,attrs:{class:"language-bash"}},[e("code",[a._v("kubectl apply -f ./podinfo-abtest.yaml\n")])])]),e("p",[a._v("After a couple of seconds Flagger will create the canary objects:")]),a._v(" "),e("div",{staticClass:"language-bash extra-class"},[e("pre",{pre:!0,attrs:{class:"language-bash"}},[e("code",[e("span",{pre:!0,attrs:{class:"token comment"}},[a._v("# applied ")]),a._v("\ndeployment.apps/podinfo\nhorizontalpodautoscaler.autoscaling/podinfo\ncanary.flagger.app/podinfo\n\n"),e("span",{pre:!0,attrs:{class:"token comment"}},[a._v("# generated ")]),a._v("\ndeployment.apps/podinfo-primary\nhorizontalpodautoscaler.autoscaling/podinfo-primary\nservice/podinfo\nservice/podinfo-canary\nservice/podinfo-primary\ndestinationrule.networking.istio.io/podinfo-canary\ndestinationrule.networking.istio.io/podinfo-primary\nvirtualservice.networking.istio.io/podinfo\n")])])]),e("h2",{attrs:{id:"automated-canary-promotion"}},[e("a",{staticClass:"header-anchor",attrs:{href:"#automated-canary-promotion","aria-hidden":"true"}},[a._v("#")]),a._v(" Automated canary promotion")]),a._v(" "),e("p",[a._v("Trigger a canary deployment by updating the container image:")]),a._v(" "),e("div",{staticClass:"language-bash extra-class"},[e("pre",{pre:!0,attrs:{class:"language-bash"}},[e("code",[a._v("kubectl -n "),e("span",{pre:!0,attrs:{class:"token builtin class-name"}},[a._v("test")]),a._v(" "),e("span",{pre:!0,attrs:{class:"token builtin class-name"}},[a._v("set")]),a._v(" image deployment/podinfo "),e("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("\\")]),a._v("\n"),e("span",{pre:!0,attrs:{class:"token assign-left variable"}},[a._v("podinfod")]),e("span",{pre:!0,attrs:{class:"token operator"}},[a._v("=")]),a._v("stefanprodan/podinfo:3.1.1\n")])])]),e("p",[a._v("Flagger detects that the deployment revision changed and starts a new rollout:")]),a._v(" "),e("div",{staticClass:"language-text extra-class"},[e("pre",{pre:!0,attrs:{class:"language-text"}},[e("code",[a._v("kubectl -n test describe canary/abtest\n\nStatus:\n Failed Checks: 0\n Phase: Succeeded\nEvents:\n Type Reason Age From Message\n ---- ------ ---- ---- -------\n Normal Synced 3m flagger New revision detected podinfo.test\n Normal Synced 3m flagger Scaling up podinfo.test\n Warning Synced 3m flagger Waiting for podinfo.test rollout to finish: 0 of 1 updated replicas are available\n Normal Synced 3m flagger Advance podinfo.test canary iteration 1/10\n Normal Synced 3m flagger Advance podinfo.test canary iteration 2/10\n Normal Synced 3m flagger Advance podinfo.test canary iteration 3/10\n Normal Synced 2m flagger Advance podinfo.test canary iteration 4/10\n Normal Synced 2m flagger Advance podinfo.test canary iteration 5/10\n Normal Synced 1m flagger Advance podinfo.test canary iteration 6/10\n Normal Synced 1m flagger Advance podinfo.test canary iteration 7/10\n Normal Synced 55s flagger Advance podinfo.test canary iteration 8/10\n Normal Synced 45s flagger Advance podinfo.test canary iteration 9/10\n Normal Synced 35s flagger Advance podinfo.test canary iteration 10/10\n Normal Synced 25s flagger Copying podinfo.test template spec to podinfo-primary.test\n Warning Synced 15s flagger Waiting for podinfo-primary.test rollout to finish: 1 of 2 updated replicas are available\n Normal Synced 5s flagger Promotion completed! Scaling down podinfo.test\n")])])]),e("p",[e("strong",[a._v("Note")]),a._v(" that if you apply new changes to the deployment during the canary analysis, Flagger will restart the analysis.")]),a._v(" "),e("p",[a._v("You can monitor all canaries with:")]),a._v(" "),e("div",{staticClass:"language-bash extra-class"},[e("pre",{pre:!0,attrs:{class:"language-bash"}},[e("code",[e("span",{pre:!0,attrs:{class:"token function"}},[a._v("watch")]),a._v(" kubectl get canaries --all-namespaces\n\nNAMESPACE NAME STATUS WEIGHT LASTTRANSITIONTIME\n"),e("span",{pre:!0,attrs:{class:"token builtin class-name"}},[a._v("test")]),a._v(" podinfo Progressing "),e("span",{pre:!0,attrs:{class:"token number"}},[a._v("100")]),a._v(" "),e("span",{pre:!0,attrs:{class:"token number"}},[a._v("2019")]),a._v("-03-16T14:05:07Z\nprod frontend Succeeded "),e("span",{pre:!0,attrs:{class:"token number"}},[a._v("0")]),a._v(" "),e("span",{pre:!0,attrs:{class:"token number"}},[a._v("2019")]),a._v("-03-15T16:15:07Z\nprod backend Failed "),e("span",{pre:!0,attrs:{class:"token number"}},[a._v("0")]),a._v(" "),e("span",{pre:!0,attrs:{class:"token number"}},[a._v("2019")]),a._v("-03-14T17:05:07Z\n")])])]),e("h2",{attrs:{id:"automated-rollback"}},[e("a",{staticClass:"header-anchor",attrs:{href:"#automated-rollback","aria-hidden":"true"}},[a._v("#")]),a._v(" Automated rollback")]),a._v(" "),e("p",[a._v("During the canary analysis you can generate HTTP 500 errors and high latency to test Flagger's rollback.")]),a._v(" "),e("p",[a._v("Generate HTTP 500 errors:")]),a._v(" "),e("div",{staticClass:"language-bash extra-class"},[e("pre",{pre:!0,attrs:{class:"language-bash"}},[e("code",[e("span",{pre:!0,attrs:{class:"token function"}},[a._v("watch")]),a._v(" "),e("span",{pre:!0,attrs:{class:"token function"}},[a._v("curl")]),a._v(" -b "),e("span",{pre:!0,attrs:{class:"token string"}},[a._v("'type=insider'")]),a._v(" http://app.example.com/status/500\n")])])]),e("p",[a._v("Generate latency:")]),a._v(" "),e("div",{staticClass:"language-bash extra-class"},[e("pre",{pre:!0,attrs:{class:"language-bash"}},[e("code",[e("span",{pre:!0,attrs:{class:"token function"}},[a._v("watch")]),a._v(" "),e("span",{pre:!0,attrs:{class:"token function"}},[a._v("curl")]),a._v(" -b "),e("span",{pre:!0,attrs:{class:"token string"}},[a._v("'type=insider'")]),a._v(" http://app.example.com/delay/1\n")])])]),e("p",[a._v("When the number of failed checks reaches the canary analysis threshold, the traffic is routed back to the primary,\nthe canary is scaled to zero and the rollout is marked as failed.")]),a._v(" "),e("div",{staticClass:"language-text extra-class"},[e("pre",{pre:!0,attrs:{class:"language-text"}},[e("code",[a._v("kubectl -n test describe canary/podinfo\n\nStatus:\n Failed Checks: 2\n Phase: Failed\nEvents:\n Type Reason Age From Message\n ---- ------ ---- ---- -------\n Normal Synced 3m flagger Starting canary deployment for podinfo.test\n Normal Synced 3m flagger Advance podinfo.test canary iteration 1/10\n Normal Synced 3m flagger Advance podinfo.test canary iteration 2/10\n Normal Synced 3m flagger Advance podinfo.test canary iteration 3/10\n Normal Synced 3m flagger Halt podinfo.test advancement success rate 69.17% < 99%\n Normal Synced 2m flagger Halt podinfo.test advancement success rate 61.39% < 99%\n Warning Synced 2m flagger Rolling back podinfo.test failed checks threshold reached 2\n Warning Synced 1m flagger Canary failed! Scaling down podinfo.test\n")])])]),e("p",[a._v("The above procedure can be extended with "),e("router-link",{attrs:{to:"/usage/metrics.html"}},[a._v("custom metrics")]),a._v(" checks,\n"),e("router-link",{attrs:{to:"/usage/webhooks.html"}},[a._v("webhooks")]),a._v(",\n"),e("router-link",{attrs:{to:"/usage/webhooks.html#manual-gating"}},[a._v("manual promotion")]),a._v(" approval and\n"),e("router-link",{attrs:{to:"/usage/alerting.html"}},[a._v("Slack or MS Teams")]),a._v(" notifications.")],1)])},[],!1,null,null,null);t.default=n.exports}}]); \ No newline at end of file +(window.webpackJsonp=window.webpackJsonp||[]).push([[23],{284:function(a,t,e){"use strict";e.r(t);var s=e(37),n=Object(s.a)({},function(){var a=this,t=a.$createElement,e=a._self._c||t;return e("ContentSlotsDistributor",{attrs:{"slot-key":a.$parent.slotKey}},[e("h1",{attrs:{id:"istio-a-b-testing"}},[e("a",{staticClass:"header-anchor",attrs:{href:"#istio-a-b-testing","aria-hidden":"true"}},[a._v("#")]),a._v(" Istio A/B Testing")]),a._v(" "),e("p",[a._v("This guide shows you how to automate A/B testing with Istio and Flagger.")]),a._v(" "),e("p",[a._v("Besides weighted routing, Flagger can be configured to route traffic to the canary based on HTTP match conditions.\nIn an A/B testing scenario, you'll be using HTTP headers or cookies to target a certain segment of your users.\nThis is particularly useful for frontend applications that require session affinity.")]),a._v(" "),e("p",[e("img",{attrs:{src:"https://raw.githubusercontent.com/weaveworks/flagger/master/docs/diagrams/flagger-abtest-steps.png",alt:"Flagger A/B Testing Stages"}})]),a._v(" "),e("h2",{attrs:{id:"prerequisites"}},[e("a",{staticClass:"header-anchor",attrs:{href:"#prerequisites","aria-hidden":"true"}},[a._v("#")]),a._v(" Prerequisites")]),a._v(" "),e("p",[a._v("Flagger requires a Kubernetes cluster "),e("strong",[a._v("v1.11")]),a._v(" or newer and Istio "),e("strong",[a._v("v1.0")]),a._v(" or newer.")]),a._v(" "),e("p",[a._v("Install Istio with telemetry support and Prometheus:")]),a._v(" "),e("div",{staticClass:"language-bash extra-class"},[e("pre",{pre:!0,attrs:{class:"language-bash"}},[e("code",[a._v("istioctl manifest apply --set "),e("span",{pre:!0,attrs:{class:"token assign-left variable"}},[a._v("profile")]),e("span",{pre:!0,attrs:{class:"token operator"}},[a._v("=")]),a._v("default\n")])])]),e("p",[a._v("Install Flagger using Kustomize (kubectl 1.14) in the "),e("code",[a._v("istio-system")]),a._v(" namespace:")]),a._v(" "),e("div",{staticClass:"language-bash extra-class"},[e("pre",{pre:!0,attrs:{class:"language-bash"}},[e("code",[a._v("kubectl apply -k github.com/weaveworks/flagger//kustomize/istio\n")])])]),e("p",[a._v("Create an ingress gateway to expose the demo app outside of the mesh:")]),a._v(" "),e("div",{staticClass:"language-yaml extra-class"},[e("pre",{pre:!0,attrs:{class:"language-yaml"}},[e("code",[e("span",{pre:!0,attrs:{class:"token key atrule"}},[a._v("apiVersion")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(":")]),a._v(" networking.istio.io/v1alpha3\n"),e("span",{pre:!0,attrs:{class:"token key atrule"}},[a._v("kind")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(":")]),a._v(" Gateway\n"),e("span",{pre:!0,attrs:{class:"token key atrule"}},[a._v("metadata")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(":")]),a._v("\n "),e("span",{pre:!0,attrs:{class:"token key atrule"}},[a._v("name")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(":")]),a._v(" public"),e("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("-")]),a._v("gateway\n "),e("span",{pre:!0,attrs:{class:"token key atrule"}},[a._v("namespace")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(":")]),a._v(" istio"),e("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("-")]),a._v("system\n"),e("span",{pre:!0,attrs:{class:"token key atrule"}},[a._v("spec")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(":")]),a._v("\n "),e("span",{pre:!0,attrs:{class:"token key atrule"}},[a._v("selector")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(":")]),a._v("\n "),e("span",{pre:!0,attrs:{class:"token key atrule"}},[a._v("istio")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(":")]),a._v(" ingressgateway\n "),e("span",{pre:!0,attrs:{class:"token key atrule"}},[a._v("servers")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(":")]),a._v("\n "),e("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("-")]),a._v(" "),e("span",{pre:!0,attrs:{class:"token key atrule"}},[a._v("port")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(":")]),a._v("\n "),e("span",{pre:!0,attrs:{class:"token key atrule"}},[a._v("number")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(":")]),a._v(" "),e("span",{pre:!0,attrs:{class:"token number"}},[a._v("80")]),a._v("\n "),e("span",{pre:!0,attrs:{class:"token key atrule"}},[a._v("name")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(":")]),a._v(" http\n "),e("span",{pre:!0,attrs:{class:"token key atrule"}},[a._v("protocol")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(":")]),a._v(" HTTP\n "),e("span",{pre:!0,attrs:{class:"token key atrule"}},[a._v("hosts")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(":")]),a._v("\n "),e("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("-")]),a._v(" "),e("span",{pre:!0,attrs:{class:"token string"}},[a._v('"*"')]),a._v("\n")])])]),e("h2",{attrs:{id:"bootstrap"}},[e("a",{staticClass:"header-anchor",attrs:{href:"#bootstrap","aria-hidden":"true"}},[a._v("#")]),a._v(" Bootstrap")]),a._v(" "),e("p",[a._v("Create a test namespace with Istio sidecar injection enabled:")]),a._v(" "),e("div",{staticClass:"language-bash extra-class"},[e("pre",{pre:!0,attrs:{class:"language-bash"}},[e("code",[a._v("kubectl create ns "),e("span",{pre:!0,attrs:{class:"token builtin class-name"}},[a._v("test")]),a._v("\nkubectl label namespace "),e("span",{pre:!0,attrs:{class:"token builtin class-name"}},[a._v("test")]),a._v(" istio-injection"),e("span",{pre:!0,attrs:{class:"token operator"}},[a._v("=")]),a._v("enabled\n")])])]),e("p",[a._v("Create a deployment and a horizontal pod autoscaler:")]),a._v(" "),e("div",{staticClass:"language-bash extra-class"},[e("pre",{pre:!0,attrs:{class:"language-bash"}},[e("code",[a._v("kubectl apply -k github.com/weaveworks/flagger//kustomize/podinfo\n")])])]),e("p",[a._v("Deploy the load testing service to generate traffic during the canary analysis:")]),a._v(" "),e("div",{staticClass:"language-bash extra-class"},[e("pre",{pre:!0,attrs:{class:"language-bash"}},[e("code",[a._v("kubectl apply -k github.com/weaveworks/flagger//kustomize/tester\n")])])]),e("p",[a._v("Create a canary custom resource (replace example.com with your own domain):")]),a._v(" "),e("div",{staticClass:"language-yaml extra-class"},[e("pre",{pre:!0,attrs:{class:"language-yaml"}},[e("code",[e("span",{pre:!0,attrs:{class:"token key atrule"}},[a._v("apiVersion")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(":")]),a._v(" flagger.app/v1beta1\n"),e("span",{pre:!0,attrs:{class:"token key atrule"}},[a._v("kind")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(":")]),a._v(" Canary\n"),e("span",{pre:!0,attrs:{class:"token key atrule"}},[a._v("metadata")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(":")]),a._v("\n "),e("span",{pre:!0,attrs:{class:"token key atrule"}},[a._v("name")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(":")]),a._v(" podinfo\n "),e("span",{pre:!0,attrs:{class:"token key atrule"}},[a._v("namespace")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(":")]),a._v(" test\n"),e("span",{pre:!0,attrs:{class:"token key atrule"}},[a._v("spec")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(":")]),a._v("\n "),e("span",{pre:!0,attrs:{class:"token comment"}},[a._v("# deployment reference")]),a._v("\n "),e("span",{pre:!0,attrs:{class:"token key atrule"}},[a._v("targetRef")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(":")]),a._v("\n "),e("span",{pre:!0,attrs:{class:"token key atrule"}},[a._v("apiVersion")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(":")]),a._v(" apps/v1\n "),e("span",{pre:!0,attrs:{class:"token key atrule"}},[a._v("kind")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(":")]),a._v(" Deployment\n "),e("span",{pre:!0,attrs:{class:"token key atrule"}},[a._v("name")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(":")]),a._v(" podinfo\n "),e("span",{pre:!0,attrs:{class:"token comment"}},[a._v("# the maximum time in seconds for the canary deployment")]),a._v("\n "),e("span",{pre:!0,attrs:{class:"token comment"}},[a._v("# to make progress before it is rollback (default 600s)")]),a._v("\n "),e("span",{pre:!0,attrs:{class:"token key atrule"}},[a._v("progressDeadlineSeconds")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(":")]),a._v(" "),e("span",{pre:!0,attrs:{class:"token number"}},[a._v("60")]),a._v("\n "),e("span",{pre:!0,attrs:{class:"token comment"}},[a._v("# HPA reference (optional)")]),a._v("\n "),e("span",{pre:!0,attrs:{class:"token key atrule"}},[a._v("autoscalerRef")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(":")]),a._v("\n "),e("span",{pre:!0,attrs:{class:"token key atrule"}},[a._v("apiVersion")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(":")]),a._v(" autoscaling/v2beta1\n "),e("span",{pre:!0,attrs:{class:"token key atrule"}},[a._v("kind")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(":")]),a._v(" HorizontalPodAutoscaler\n "),e("span",{pre:!0,attrs:{class:"token key atrule"}},[a._v("name")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(":")]),a._v(" podinfo\n "),e("span",{pre:!0,attrs:{class:"token key atrule"}},[a._v("service")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(":")]),a._v("\n "),e("span",{pre:!0,attrs:{class:"token comment"}},[a._v("# container port")]),a._v("\n "),e("span",{pre:!0,attrs:{class:"token key atrule"}},[a._v("port")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(":")]),a._v(" "),e("span",{pre:!0,attrs:{class:"token number"}},[a._v("9898")]),a._v("\n "),e("span",{pre:!0,attrs:{class:"token comment"}},[a._v("# Istio gateways (optional)")]),a._v("\n "),e("span",{pre:!0,attrs:{class:"token key atrule"}},[a._v("gateways")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(":")]),a._v("\n "),e("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("-")]),a._v(" public"),e("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("-")]),a._v("gateway.istio"),e("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("-")]),a._v("system.svc.cluster.local\n "),e("span",{pre:!0,attrs:{class:"token comment"}},[a._v("# Istio virtual service host names (optional)")]),a._v("\n "),e("span",{pre:!0,attrs:{class:"token key atrule"}},[a._v("hosts")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(":")]),a._v("\n "),e("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("-")]),a._v(" app.example.com\n "),e("span",{pre:!0,attrs:{class:"token comment"}},[a._v("# Istio traffic policy (optional)")]),a._v("\n "),e("span",{pre:!0,attrs:{class:"token key atrule"}},[a._v("trafficPolicy")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(":")]),a._v("\n "),e("span",{pre:!0,attrs:{class:"token key atrule"}},[a._v("tls")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(":")]),a._v("\n "),e("span",{pre:!0,attrs:{class:"token comment"}},[a._v("# use ISTIO_MUTUAL when mTLS is enabled")]),a._v("\n "),e("span",{pre:!0,attrs:{class:"token key atrule"}},[a._v("mode")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(":")]),a._v(" DISABLE\n "),e("span",{pre:!0,attrs:{class:"token key atrule"}},[a._v("analysis")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(":")]),a._v("\n "),e("span",{pre:!0,attrs:{class:"token comment"}},[a._v("# schedule interval (default 60s)")]),a._v("\n "),e("span",{pre:!0,attrs:{class:"token key atrule"}},[a._v("interval")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(":")]),a._v(" 1m\n "),e("span",{pre:!0,attrs:{class:"token comment"}},[a._v("# total number of iterations")]),a._v("\n "),e("span",{pre:!0,attrs:{class:"token key atrule"}},[a._v("iterations")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(":")]),a._v(" "),e("span",{pre:!0,attrs:{class:"token number"}},[a._v("10")]),a._v("\n "),e("span",{pre:!0,attrs:{class:"token comment"}},[a._v("# max number of failed iterations before rollback")]),a._v("\n "),e("span",{pre:!0,attrs:{class:"token key atrule"}},[a._v("threshold")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(":")]),a._v(" "),e("span",{pre:!0,attrs:{class:"token number"}},[a._v("2")]),a._v("\n "),e("span",{pre:!0,attrs:{class:"token comment"}},[a._v("# canary match condition")]),a._v("\n "),e("span",{pre:!0,attrs:{class:"token key atrule"}},[a._v("match")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(":")]),a._v("\n "),e("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("-")]),a._v(" "),e("span",{pre:!0,attrs:{class:"token key atrule"}},[a._v("headers")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(":")]),a._v("\n "),e("span",{pre:!0,attrs:{class:"token key atrule"}},[a._v("user-agent")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(":")]),a._v("\n "),e("span",{pre:!0,attrs:{class:"token key atrule"}},[a._v("regex")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(":")]),a._v(" "),e("span",{pre:!0,attrs:{class:"token string"}},[a._v('"^(?!.*Chrome).*Safari.*"')]),a._v("\n "),e("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("-")]),a._v(" "),e("span",{pre:!0,attrs:{class:"token key atrule"}},[a._v("headers")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(":")]),a._v("\n "),e("span",{pre:!0,attrs:{class:"token key atrule"}},[a._v("cookie")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(":")]),a._v("\n "),e("span",{pre:!0,attrs:{class:"token key atrule"}},[a._v("regex")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(":")]),a._v(" "),e("span",{pre:!0,attrs:{class:"token string"}},[a._v('"^(.*?;)?(type=insider)(;.*)?$"')]),a._v("\n "),e("span",{pre:!0,attrs:{class:"token key atrule"}},[a._v("metrics")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(":")]),a._v("\n "),e("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("-")]),a._v(" "),e("span",{pre:!0,attrs:{class:"token key atrule"}},[a._v("name")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(":")]),a._v(" request"),e("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("-")]),a._v("success"),e("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("-")]),a._v("rate\n "),e("span",{pre:!0,attrs:{class:"token comment"}},[a._v("# minimum req success rate (non 5xx responses)")]),a._v("\n "),e("span",{pre:!0,attrs:{class:"token comment"}},[a._v("# percentage (0-100)")]),a._v("\n "),e("span",{pre:!0,attrs:{class:"token key atrule"}},[a._v("thresholdRange")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(":")]),a._v("\n "),e("span",{pre:!0,attrs:{class:"token key atrule"}},[a._v("min")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(":")]),a._v(" "),e("span",{pre:!0,attrs:{class:"token number"}},[a._v("99")]),a._v("\n "),e("span",{pre:!0,attrs:{class:"token key atrule"}},[a._v("interval")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(":")]),a._v(" 1m\n "),e("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("-")]),a._v(" "),e("span",{pre:!0,attrs:{class:"token key atrule"}},[a._v("name")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(":")]),a._v(" request"),e("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("-")]),a._v("duration\n "),e("span",{pre:!0,attrs:{class:"token comment"}},[a._v("# maximum req duration P99")]),a._v("\n "),e("span",{pre:!0,attrs:{class:"token comment"}},[a._v("# milliseconds")]),a._v("\n "),e("span",{pre:!0,attrs:{class:"token key atrule"}},[a._v("thresholdRange")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(":")]),a._v("\n "),e("span",{pre:!0,attrs:{class:"token key atrule"}},[a._v("max")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(":")]),a._v(" "),e("span",{pre:!0,attrs:{class:"token number"}},[a._v("500")]),a._v("\n "),e("span",{pre:!0,attrs:{class:"token key atrule"}},[a._v("interval")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(":")]),a._v(" 30s\n "),e("span",{pre:!0,attrs:{class:"token comment"}},[a._v("# generate traffic during analysis")]),a._v("\n "),e("span",{pre:!0,attrs:{class:"token key atrule"}},[a._v("webhooks")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(":")]),a._v("\n "),e("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("-")]),a._v(" "),e("span",{pre:!0,attrs:{class:"token key atrule"}},[a._v("name")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(":")]),a._v(" load"),e("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("-")]),a._v("test\n "),e("span",{pre:!0,attrs:{class:"token key atrule"}},[a._v("url")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(":")]),a._v(" http"),e("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(":")]),a._v("//flagger"),e("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("-")]),a._v("loadtester.test/\n "),e("span",{pre:!0,attrs:{class:"token key atrule"}},[a._v("timeout")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(":")]),a._v(" 5s\n "),e("span",{pre:!0,attrs:{class:"token key atrule"}},[a._v("metadata")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(":")]),a._v("\n "),e("span",{pre:!0,attrs:{class:"token key atrule"}},[a._v("cmd")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(":")]),a._v(" "),e("span",{pre:!0,attrs:{class:"token string"}},[a._v("\"hey -z 1m -q 10 -c 2 -H 'Cookie: type=insider' http://podinfo.test:9898/\"")]),a._v("\n")])])]),e("p",[a._v("The above configuration will run an analysis for ten minutes targeting Safari users and those that have an insider cookie.")]),a._v(" "),e("p",[a._v("Save the above resource as podinfo-abtest.yaml and then apply it:")]),a._v(" "),e("div",{staticClass:"language-bash extra-class"},[e("pre",{pre:!0,attrs:{class:"language-bash"}},[e("code",[a._v("kubectl apply -f ./podinfo-abtest.yaml\n")])])]),e("p",[a._v("After a couple of seconds Flagger will create the canary objects:")]),a._v(" "),e("div",{staticClass:"language-bash extra-class"},[e("pre",{pre:!0,attrs:{class:"language-bash"}},[e("code",[e("span",{pre:!0,attrs:{class:"token comment"}},[a._v("# applied ")]),a._v("\ndeployment.apps/podinfo\nhorizontalpodautoscaler.autoscaling/podinfo\ncanary.flagger.app/podinfo\n\n"),e("span",{pre:!0,attrs:{class:"token comment"}},[a._v("# generated ")]),a._v("\ndeployment.apps/podinfo-primary\nhorizontalpodautoscaler.autoscaling/podinfo-primary\nservice/podinfo\nservice/podinfo-canary\nservice/podinfo-primary\ndestinationrule.networking.istio.io/podinfo-canary\ndestinationrule.networking.istio.io/podinfo-primary\nvirtualservice.networking.istio.io/podinfo\n")])])]),e("h2",{attrs:{id:"automated-canary-promotion"}},[e("a",{staticClass:"header-anchor",attrs:{href:"#automated-canary-promotion","aria-hidden":"true"}},[a._v("#")]),a._v(" Automated canary promotion")]),a._v(" "),e("p",[a._v("Trigger a canary deployment by updating the container image:")]),a._v(" "),e("div",{staticClass:"language-bash extra-class"},[e("pre",{pre:!0,attrs:{class:"language-bash"}},[e("code",[a._v("kubectl -n "),e("span",{pre:!0,attrs:{class:"token builtin class-name"}},[a._v("test")]),a._v(" "),e("span",{pre:!0,attrs:{class:"token builtin class-name"}},[a._v("set")]),a._v(" image deployment/podinfo "),e("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("\\")]),a._v("\n"),e("span",{pre:!0,attrs:{class:"token assign-left variable"}},[a._v("podinfod")]),e("span",{pre:!0,attrs:{class:"token operator"}},[a._v("=")]),a._v("stefanprodan/podinfo:3.1.1\n")])])]),e("p",[a._v("Flagger detects that the deployment revision changed and starts a new rollout:")]),a._v(" "),e("div",{staticClass:"language-text extra-class"},[e("pre",{pre:!0,attrs:{class:"language-text"}},[e("code",[a._v("kubectl -n test describe canary/abtest\n\nStatus:\n Failed Checks: 0\n Phase: Succeeded\nEvents:\n Type Reason Age From Message\n ---- ------ ---- ---- -------\n Normal Synced 3m flagger New revision detected podinfo.test\n Normal Synced 3m flagger Scaling up podinfo.test\n Warning Synced 3m flagger Waiting for podinfo.test rollout to finish: 0 of 1 updated replicas are available\n Normal Synced 3m flagger Advance podinfo.test canary iteration 1/10\n Normal Synced 3m flagger Advance podinfo.test canary iteration 2/10\n Normal Synced 3m flagger Advance podinfo.test canary iteration 3/10\n Normal Synced 2m flagger Advance podinfo.test canary iteration 4/10\n Normal Synced 2m flagger Advance podinfo.test canary iteration 5/10\n Normal Synced 1m flagger Advance podinfo.test canary iteration 6/10\n Normal Synced 1m flagger Advance podinfo.test canary iteration 7/10\n Normal Synced 55s flagger Advance podinfo.test canary iteration 8/10\n Normal Synced 45s flagger Advance podinfo.test canary iteration 9/10\n Normal Synced 35s flagger Advance podinfo.test canary iteration 10/10\n Normal Synced 25s flagger Copying podinfo.test template spec to podinfo-primary.test\n Warning Synced 15s flagger Waiting for podinfo-primary.test rollout to finish: 1 of 2 updated replicas are available\n Normal Synced 5s flagger Promotion completed! Scaling down podinfo.test\n")])])]),e("p",[e("strong",[a._v("Note")]),a._v(" that if you apply new changes to the deployment during the canary analysis, Flagger will restart the analysis.")]),a._v(" "),e("p",[a._v("You can monitor all canaries with:")]),a._v(" "),e("div",{staticClass:"language-bash extra-class"},[e("pre",{pre:!0,attrs:{class:"language-bash"}},[e("code",[e("span",{pre:!0,attrs:{class:"token function"}},[a._v("watch")]),a._v(" kubectl get canaries --all-namespaces\n\nNAMESPACE NAME STATUS WEIGHT LASTTRANSITIONTIME\n"),e("span",{pre:!0,attrs:{class:"token builtin class-name"}},[a._v("test")]),a._v(" podinfo Progressing "),e("span",{pre:!0,attrs:{class:"token number"}},[a._v("100")]),a._v(" "),e("span",{pre:!0,attrs:{class:"token number"}},[a._v("2019")]),a._v("-03-16T14:05:07Z\nprod frontend Succeeded "),e("span",{pre:!0,attrs:{class:"token number"}},[a._v("0")]),a._v(" "),e("span",{pre:!0,attrs:{class:"token number"}},[a._v("2019")]),a._v("-03-15T16:15:07Z\nprod backend Failed "),e("span",{pre:!0,attrs:{class:"token number"}},[a._v("0")]),a._v(" "),e("span",{pre:!0,attrs:{class:"token number"}},[a._v("2019")]),a._v("-03-14T17:05:07Z\n")])])]),e("h2",{attrs:{id:"automated-rollback"}},[e("a",{staticClass:"header-anchor",attrs:{href:"#automated-rollback","aria-hidden":"true"}},[a._v("#")]),a._v(" Automated rollback")]),a._v(" "),e("p",[a._v("During the canary analysis you can generate HTTP 500 errors and high latency to test Flagger's rollback.")]),a._v(" "),e("p",[a._v("Generate HTTP 500 errors:")]),a._v(" "),e("div",{staticClass:"language-bash extra-class"},[e("pre",{pre:!0,attrs:{class:"language-bash"}},[e("code",[e("span",{pre:!0,attrs:{class:"token function"}},[a._v("watch")]),a._v(" "),e("span",{pre:!0,attrs:{class:"token function"}},[a._v("curl")]),a._v(" -b "),e("span",{pre:!0,attrs:{class:"token string"}},[a._v("'type=insider'")]),a._v(" http://app.example.com/status/500\n")])])]),e("p",[a._v("Generate latency:")]),a._v(" "),e("div",{staticClass:"language-bash extra-class"},[e("pre",{pre:!0,attrs:{class:"language-bash"}},[e("code",[e("span",{pre:!0,attrs:{class:"token function"}},[a._v("watch")]),a._v(" "),e("span",{pre:!0,attrs:{class:"token function"}},[a._v("curl")]),a._v(" -b "),e("span",{pre:!0,attrs:{class:"token string"}},[a._v("'type=insider'")]),a._v(" http://app.example.com/delay/1\n")])])]),e("p",[a._v("When the number of failed checks reaches the canary analysis threshold, the traffic is routed back to the primary,\nthe canary is scaled to zero and the rollout is marked as failed.")]),a._v(" "),e("div",{staticClass:"language-text extra-class"},[e("pre",{pre:!0,attrs:{class:"language-text"}},[e("code",[a._v("kubectl -n test describe canary/podinfo\n\nStatus:\n Failed Checks: 2\n Phase: Failed\nEvents:\n Type Reason Age From Message\n ---- ------ ---- ---- -------\n Normal Synced 3m flagger Starting canary deployment for podinfo.test\n Normal Synced 3m flagger Advance podinfo.test canary iteration 1/10\n Normal Synced 3m flagger Advance podinfo.test canary iteration 2/10\n Normal Synced 3m flagger Advance podinfo.test canary iteration 3/10\n Normal Synced 3m flagger Halt podinfo.test advancement success rate 69.17% < 99%\n Normal Synced 2m flagger Halt podinfo.test advancement success rate 61.39% < 99%\n Warning Synced 2m flagger Rolling back podinfo.test failed checks threshold reached 2\n Warning Synced 1m flagger Canary failed! Scaling down podinfo.test\n")])])]),e("p",[a._v("The above procedure can be extended with "),e("router-link",{attrs:{to:"/usage/metrics.html"}},[a._v("custom metrics")]),a._v(" checks,\n"),e("router-link",{attrs:{to:"/usage/webhooks.html"}},[a._v("webhooks")]),a._v(",\n"),e("router-link",{attrs:{to:"/usage/webhooks.html#manual-gating"}},[a._v("manual promotion")]),a._v(" approval and\n"),e("router-link",{attrs:{to:"/usage/alerting.html"}},[a._v("Slack or MS Teams")]),a._v(" notifications.")],1)])},[],!1,null,null,null);t.default=n.exports}}]); \ No newline at end of file diff --git a/assets/js/24.4f54d289.js b/assets/js/24.721d8c4e.js similarity index 99% rename from assets/js/24.4f54d289.js rename to assets/js/24.721d8c4e.js index 29b683e8..95450031 100644 --- a/assets/js/24.4f54d289.js +++ b/assets/js/24.721d8c4e.js @@ -1 +1 @@ -(window.webpackJsonp=window.webpackJsonp||[]).push([[24],{284:function(t,a,e){"use strict";e.r(a);var s=e(37),n=Object(s.a)({},function(){var t=this,a=t.$createElement,e=t._self._c||a;return e("ContentSlotsDistributor",{attrs:{"slot-key":t.$parent.slotKey}},[e("h1",{attrs:{id:"istio-canary-deployments"}},[e("a",{staticClass:"header-anchor",attrs:{href:"#istio-canary-deployments","aria-hidden":"true"}},[t._v("#")]),t._v(" Istio Canary Deployments")]),t._v(" "),e("p",[t._v("This guide shows you how to use Istio and Flagger to automate canary deployments.")]),t._v(" "),e("p",[e("img",{attrs:{src:"https://raw.githubusercontent.com/weaveworks/flagger/master/docs/diagrams/flagger-canary-steps.png",alt:"Flagger Canary Stages"}})]),t._v(" "),e("h2",{attrs:{id:"prerequisites"}},[e("a",{staticClass:"header-anchor",attrs:{href:"#prerequisites","aria-hidden":"true"}},[t._v("#")]),t._v(" Prerequisites")]),t._v(" "),e("p",[t._v("Flagger requires a Kubernetes cluster "),e("strong",[t._v("v1.11")]),t._v(" or newer and Istio "),e("strong",[t._v("v1.0")]),t._v(" or newer.")]),t._v(" "),e("p",[t._v("Install Istio with telemetry support and Prometheus:")]),t._v(" "),e("div",{staticClass:"language-bash extra-class"},[e("pre",{pre:!0,attrs:{class:"language-bash"}},[e("code",[t._v("istioctl manifest apply --set "),e("span",{pre:!0,attrs:{class:"token assign-left variable"}},[t._v("profile")]),e("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v("default\n")])])]),e("p",[t._v("Install Flagger using Kustomize (kubectl 1.14) in the "),e("code",[t._v("istio-system")]),t._v(" namespace:")]),t._v(" "),e("div",{staticClass:"language-bash extra-class"},[e("pre",{pre:!0,attrs:{class:"language-bash"}},[e("code",[t._v("kubectl apply -k github.com/weaveworks/flagger//kustomize/istio\n")])])]),e("p",[t._v("Create an ingress gateway to expose the demo app outside of the mesh:")]),t._v(" "),e("div",{staticClass:"language-yaml extra-class"},[e("pre",{pre:!0,attrs:{class:"language-yaml"}},[e("code",[e("span",{pre:!0,attrs:{class:"token key atrule"}},[t._v("apiVersion")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" networking.istio.io/v1alpha3\n"),e("span",{pre:!0,attrs:{class:"token key atrule"}},[t._v("kind")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" Gateway\n"),e("span",{pre:!0,attrs:{class:"token key atrule"}},[t._v("metadata")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v("\n "),e("span",{pre:!0,attrs:{class:"token key atrule"}},[t._v("name")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" public"),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("-")]),t._v("gateway\n "),e("span",{pre:!0,attrs:{class:"token key atrule"}},[t._v("namespace")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" istio"),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("-")]),t._v("system\n"),e("span",{pre:!0,attrs:{class:"token key atrule"}},[t._v("spec")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v("\n "),e("span",{pre:!0,attrs:{class:"token key atrule"}},[t._v("selector")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v("\n "),e("span",{pre:!0,attrs:{class:"token key atrule"}},[t._v("istio")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" ingressgateway\n "),e("span",{pre:!0,attrs:{class:"token key atrule"}},[t._v("servers")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v("\n "),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("-")]),t._v(" "),e("span",{pre:!0,attrs:{class:"token key atrule"}},[t._v("port")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v("\n "),e("span",{pre:!0,attrs:{class:"token key atrule"}},[t._v("number")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),e("span",{pre:!0,attrs:{class:"token number"}},[t._v("80")]),t._v("\n "),e("span",{pre:!0,attrs:{class:"token key atrule"}},[t._v("name")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" http\n "),e("span",{pre:!0,attrs:{class:"token key atrule"}},[t._v("protocol")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" HTTP\n "),e("span",{pre:!0,attrs:{class:"token key atrule"}},[t._v("hosts")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v("\n "),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("-")]),t._v(" "),e("span",{pre:!0,attrs:{class:"token string"}},[t._v('"*"')]),t._v("\n")])])]),e("h2",{attrs:{id:"bootstrap"}},[e("a",{staticClass:"header-anchor",attrs:{href:"#bootstrap","aria-hidden":"true"}},[t._v("#")]),t._v(" Bootstrap")]),t._v(" "),e("p",[t._v("Flagger takes a Kubernetes deployment and optionally a horizontal pod autoscaler (HPA),\nthen creates a series of objects (Kubernetes deployments, ClusterIP services,\nIstio destination rules and virtual services).\nThese objects expose the application inside the mesh and drive the canary analysis and promotion.")]),t._v(" "),e("p",[t._v("Create a test namespace with Istio sidecar injection enabled:")]),t._v(" "),e("div",{staticClass:"language-bash extra-class"},[e("pre",{pre:!0,attrs:{class:"language-bash"}},[e("code",[t._v("kubectl create ns "),e("span",{pre:!0,attrs:{class:"token builtin class-name"}},[t._v("test")]),t._v("\nkubectl label namespace "),e("span",{pre:!0,attrs:{class:"token builtin class-name"}},[t._v("test")]),t._v(" istio-injection"),e("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v("enabled\n")])])]),e("p",[t._v("Create a deployment and a horizontal pod autoscaler:")]),t._v(" "),e("div",{staticClass:"language-bash extra-class"},[e("pre",{pre:!0,attrs:{class:"language-bash"}},[e("code",[t._v("kubectl apply -k github.com/weaveworks/flagger//kustomize/podinfo\n")])])]),e("p",[t._v("Deploy the load testing service to generate traffic during the canary analysis:")]),t._v(" "),e("div",{staticClass:"language-bash extra-class"},[e("pre",{pre:!0,attrs:{class:"language-bash"}},[e("code",[t._v("kubectl apply -k github.com/weaveworks/flagger//kustomize/tester\n")])])]),e("p",[t._v("Create a canary custom resource (replace example.com with your own domain):")]),t._v(" "),e("div",{staticClass:"language-yaml extra-class"},[e("pre",{pre:!0,attrs:{class:"language-yaml"}},[e("code",[e("span",{pre:!0,attrs:{class:"token key atrule"}},[t._v("apiVersion")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" flagger.app/v1beta1\n"),e("span",{pre:!0,attrs:{class:"token key atrule"}},[t._v("kind")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" Canary\n"),e("span",{pre:!0,attrs:{class:"token key atrule"}},[t._v("metadata")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v("\n "),e("span",{pre:!0,attrs:{class:"token key atrule"}},[t._v("name")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" podinfo\n "),e("span",{pre:!0,attrs:{class:"token key atrule"}},[t._v("namespace")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" test\n"),e("span",{pre:!0,attrs:{class:"token key atrule"}},[t._v("spec")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v("\n "),e("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# deployment reference")]),t._v("\n "),e("span",{pre:!0,attrs:{class:"token key atrule"}},[t._v("targetRef")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v("\n "),e("span",{pre:!0,attrs:{class:"token key atrule"}},[t._v("apiVersion")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" apps/v1\n "),e("span",{pre:!0,attrs:{class:"token key atrule"}},[t._v("kind")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" Deployment\n "),e("span",{pre:!0,attrs:{class:"token key atrule"}},[t._v("name")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" podinfo\n "),e("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# the maximum time in seconds for the canary deployment")]),t._v("\n "),e("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# to make progress before it is rollback (default 600s)")]),t._v("\n "),e("span",{pre:!0,attrs:{class:"token key atrule"}},[t._v("progressDeadlineSeconds")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),e("span",{pre:!0,attrs:{class:"token number"}},[t._v("60")]),t._v("\n "),e("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# HPA reference (optional)")]),t._v("\n "),e("span",{pre:!0,attrs:{class:"token key atrule"}},[t._v("autoscalerRef")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v("\n "),e("span",{pre:!0,attrs:{class:"token key atrule"}},[t._v("apiVersion")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" autoscaling/v2beta1\n "),e("span",{pre:!0,attrs:{class:"token key atrule"}},[t._v("kind")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" HorizontalPodAutoscaler\n "),e("span",{pre:!0,attrs:{class:"token key atrule"}},[t._v("name")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" podinfo\n "),e("span",{pre:!0,attrs:{class:"token key atrule"}},[t._v("service")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v("\n "),e("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# service port number")]),t._v("\n "),e("span",{pre:!0,attrs:{class:"token key atrule"}},[t._v("port")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),e("span",{pre:!0,attrs:{class:"token number"}},[t._v("9898")]),t._v("\n "),e("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# container port number or name (optional)")]),t._v("\n "),e("span",{pre:!0,attrs:{class:"token key atrule"}},[t._v("targetPort")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),e("span",{pre:!0,attrs:{class:"token number"}},[t._v("9898")]),t._v("\n "),e("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# Istio gateways (optional)")]),t._v("\n "),e("span",{pre:!0,attrs:{class:"token key atrule"}},[t._v("gateways")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v("\n "),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("-")]),t._v(" public"),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("-")]),t._v("gateway.istio"),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("-")]),t._v("system.svc.cluster.local\n "),e("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# Istio virtual service host names (optional)")]),t._v("\n "),e("span",{pre:!0,attrs:{class:"token key atrule"}},[t._v("hosts")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v("\n "),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("-")]),t._v(" app.example.com\n "),e("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# Istio traffic policy (optional)")]),t._v("\n "),e("span",{pre:!0,attrs:{class:"token key atrule"}},[t._v("trafficPolicy")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v("\n "),e("span",{pre:!0,attrs:{class:"token key atrule"}},[t._v("tls")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v("\n "),e("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# use ISTIO_MUTUAL when mTLS is enabled")]),t._v("\n "),e("span",{pre:!0,attrs:{class:"token key atrule"}},[t._v("mode")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" DISABLE\n "),e("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# Istio retry policy (optional)")]),t._v("\n "),e("span",{pre:!0,attrs:{class:"token key atrule"}},[t._v("retries")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v("\n "),e("span",{pre:!0,attrs:{class:"token key atrule"}},[t._v("attempts")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),e("span",{pre:!0,attrs:{class:"token number"}},[t._v("3")]),t._v("\n "),e("span",{pre:!0,attrs:{class:"token key atrule"}},[t._v("perTryTimeout")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" 1s\n "),e("span",{pre:!0,attrs:{class:"token key atrule"}},[t._v("retryOn")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),e("span",{pre:!0,attrs:{class:"token string"}},[t._v('"gateway-error,connect-failure,refused-stream"')]),t._v("\n "),e("span",{pre:!0,attrs:{class:"token key atrule"}},[t._v("analysis")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v("\n "),e("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# schedule interval (default 60s)")]),t._v("\n "),e("span",{pre:!0,attrs:{class:"token key atrule"}},[t._v("interval")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" 1m\n "),e("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# max number of failed metric checks before rollback")]),t._v("\n "),e("span",{pre:!0,attrs:{class:"token key atrule"}},[t._v("threshold")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),e("span",{pre:!0,attrs:{class:"token number"}},[t._v("5")]),t._v("\n "),e("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# max traffic percentage routed to canary")]),t._v("\n "),e("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# percentage (0-100)")]),t._v("\n "),e("span",{pre:!0,attrs:{class:"token key atrule"}},[t._v("maxWeight")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),e("span",{pre:!0,attrs:{class:"token number"}},[t._v("50")]),t._v("\n "),e("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# canary increment step")]),t._v("\n "),e("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# percentage (0-100)")]),t._v("\n "),e("span",{pre:!0,attrs:{class:"token key atrule"}},[t._v("stepWeight")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),e("span",{pre:!0,attrs:{class:"token number"}},[t._v("10")]),t._v("\n "),e("span",{pre:!0,attrs:{class:"token key atrule"}},[t._v("metrics")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v("\n "),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("-")]),t._v(" "),e("span",{pre:!0,attrs:{class:"token key atrule"}},[t._v("name")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" request"),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("-")]),t._v("success"),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("-")]),t._v("rate\n "),e("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# minimum req success rate (non 5xx responses)")]),t._v("\n "),e("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# percentage (0-100)")]),t._v("\n "),e("span",{pre:!0,attrs:{class:"token key atrule"}},[t._v("thresholdRange")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v("\n "),e("span",{pre:!0,attrs:{class:"token key atrule"}},[t._v("min")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),e("span",{pre:!0,attrs:{class:"token number"}},[t._v("99")]),t._v("\n "),e("span",{pre:!0,attrs:{class:"token key atrule"}},[t._v("interval")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" 1m\n "),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("-")]),t._v(" "),e("span",{pre:!0,attrs:{class:"token key atrule"}},[t._v("name")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" request"),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("-")]),t._v("duration\n "),e("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# maximum req duration P99")]),t._v("\n "),e("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# milliseconds")]),t._v("\n "),e("span",{pre:!0,attrs:{class:"token key atrule"}},[t._v("thresholdRange")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v("\n "),e("span",{pre:!0,attrs:{class:"token key atrule"}},[t._v("max")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),e("span",{pre:!0,attrs:{class:"token number"}},[t._v("500")]),t._v("\n "),e("span",{pre:!0,attrs:{class:"token key atrule"}},[t._v("interval")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" 30s\n "),e("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# testing (optional)")]),t._v("\n "),e("span",{pre:!0,attrs:{class:"token key atrule"}},[t._v("webhooks")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v("\n "),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("-")]),t._v(" "),e("span",{pre:!0,attrs:{class:"token key atrule"}},[t._v("name")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" acceptance"),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("-")]),t._v("test\n "),e("span",{pre:!0,attrs:{class:"token key atrule"}},[t._v("type")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" pre"),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("-")]),t._v("rollout\n "),e("span",{pre:!0,attrs:{class:"token key atrule"}},[t._v("url")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" http"),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v("//flagger"),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("-")]),t._v("loadtester.test/\n "),e("span",{pre:!0,attrs:{class:"token key atrule"}},[t._v("timeout")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" 30s\n "),e("span",{pre:!0,attrs:{class:"token key atrule"}},[t._v("metadata")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v("\n "),e("span",{pre:!0,attrs:{class:"token key atrule"}},[t._v("type")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" bash\n "),e("span",{pre:!0,attrs:{class:"token key atrule"}},[t._v("cmd")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),e("span",{pre:!0,attrs:{class:"token string"}},[t._v("\"curl -sd 'test' http://podinfo-canary:9898/token | grep token\"")]),t._v("\n "),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("-")]),t._v(" "),e("span",{pre:!0,attrs:{class:"token key atrule"}},[t._v("name")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" load"),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("-")]),t._v("test\n "),e("span",{pre:!0,attrs:{class:"token key atrule"}},[t._v("url")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" http"),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v("//flagger"),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("-")]),t._v("loadtester.test/\n "),e("span",{pre:!0,attrs:{class:"token key atrule"}},[t._v("timeout")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" 5s\n "),e("span",{pre:!0,attrs:{class:"token key atrule"}},[t._v("metadata")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v("\n "),e("span",{pre:!0,attrs:{class:"token key atrule"}},[t._v("cmd")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),e("span",{pre:!0,attrs:{class:"token string"}},[t._v('"hey -z 1m -q 10 -c 2 http://podinfo-canary.test:9898/"')]),t._v("\n")])])]),e("p",[t._v("Save the above resource as podinfo-canary.yaml and then apply it:")]),t._v(" "),e("div",{staticClass:"language-bash extra-class"},[e("pre",{pre:!0,attrs:{class:"language-bash"}},[e("code",[t._v("kubectl apply -f ./podinfo-canary.yaml\n")])])]),e("p",[t._v("When the canary analysis starts, Flagger will call the pre-rollout webhooks before routing traffic to the canary.\nThe canary analysis will run for five minutes while validating the HTTP metrics and rollout hooks every minute.")]),t._v(" "),e("p",[e("img",{attrs:{src:"https://raw.githubusercontent.com/weaveworks/flagger/master/docs/diagrams/flagger-canary-hpa.png",alt:"Flagger Canary Process"}})]),t._v(" "),e("p",[t._v("After a couple of seconds Flagger will create the canary objects:")]),t._v(" "),e("div",{staticClass:"language-bash extra-class"},[e("pre",{pre:!0,attrs:{class:"language-bash"}},[e("code",[e("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# applied ")]),t._v("\ndeployment.apps/podinfo\nhorizontalpodautoscaler.autoscaling/podinfo\ncanary.flagger.app/podinfo\n\n"),e("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# generated ")]),t._v("\ndeployment.apps/podinfo-primary\nhorizontalpodautoscaler.autoscaling/podinfo-primary\nservice/podinfo\nservice/podinfo-canary\nservice/podinfo-primary\ndestinationrule.networking.istio.io/podinfo-canary\ndestinationrule.networking.istio.io/podinfo-primary\nvirtualservice.networking.istio.io/podinfo\n")])])]),e("h2",{attrs:{id:"automated-canary-promotion"}},[e("a",{staticClass:"header-anchor",attrs:{href:"#automated-canary-promotion","aria-hidden":"true"}},[t._v("#")]),t._v(" Automated canary promotion")]),t._v(" "),e("p",[t._v("Trigger a canary deployment by updating the container image:")]),t._v(" "),e("div",{staticClass:"language-bash extra-class"},[e("pre",{pre:!0,attrs:{class:"language-bash"}},[e("code",[t._v("kubectl -n "),e("span",{pre:!0,attrs:{class:"token builtin class-name"}},[t._v("test")]),t._v(" "),e("span",{pre:!0,attrs:{class:"token builtin class-name"}},[t._v("set")]),t._v(" image deployment/podinfo "),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("\\")]),t._v("\n"),e("span",{pre:!0,attrs:{class:"token assign-left variable"}},[t._v("podinfod")]),e("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v("stefanprodan/podinfo:3.1.1\n")])])]),e("p",[t._v("Flagger detects that the deployment revision changed and starts a new rollout:")]),t._v(" "),e("div",{staticClass:"language-text extra-class"},[e("pre",{pre:!0,attrs:{class:"language-text"}},[e("code",[t._v("kubectl -n test describe canary/podinfo\n\nStatus:\n Canary Weight: 0\n Failed Checks: 0\n Phase: Succeeded\nEvents:\n Type Reason Age From Message\n ---- ------ ---- ---- -------\n Normal Synced 3m flagger New revision detected podinfo.test\n Normal Synced 3m flagger Scaling up podinfo.test\n Warning Synced 3m flagger Waiting for podinfo.test rollout to finish: 0 of 1 updated replicas are available\n Normal Synced 3m flagger Advance podinfo.test canary weight 5\n Normal Synced 3m flagger Advance podinfo.test canary weight 10\n Normal Synced 3m flagger Advance podinfo.test canary weight 15\n Normal Synced 2m flagger Advance podinfo.test canary weight 20\n Normal Synced 2m flagger Advance podinfo.test canary weight 25\n Normal Synced 1m flagger Advance podinfo.test canary weight 30\n Normal Synced 1m flagger Advance podinfo.test canary weight 35\n Normal Synced 55s flagger Advance podinfo.test canary weight 40\n Normal Synced 45s flagger Advance podinfo.test canary weight 45\n Normal Synced 35s flagger Advance podinfo.test canary weight 50\n Normal Synced 25s flagger Copying podinfo.test template spec to podinfo-primary.test\n Warning Synced 15s flagger Waiting for podinfo-primary.test rollout to finish: 1 of 2 updated replicas are available\n Normal Synced 5s flagger Promotion completed! Scaling down podinfo.test\n")])])]),e("p",[e("strong",[t._v("Note")]),t._v(" that if you apply new changes to the deployment during the canary analysis, Flagger will restart the analysis.")]),t._v(" "),e("p",[t._v("A canary deployment is triggered by changes in any of the following objects:")]),t._v(" "),e("ul",[e("li",[t._v("Deployment PodSpec (container image, command, ports, env, resources, etc)")]),t._v(" "),e("li",[t._v("ConfigMaps mounted as volumes or mapped to environment variables")]),t._v(" "),e("li",[t._v("Secrets mounted as volumes or mapped to environment variables")])]),t._v(" "),e("p",[t._v("You can monitor all canaries with:")]),t._v(" "),e("div",{staticClass:"language-bash extra-class"},[e("pre",{pre:!0,attrs:{class:"language-bash"}},[e("code",[e("span",{pre:!0,attrs:{class:"token function"}},[t._v("watch")]),t._v(" kubectl get canaries --all-namespaces\n\nNAMESPACE NAME STATUS WEIGHT LASTTRANSITIONTIME\n"),e("span",{pre:!0,attrs:{class:"token builtin class-name"}},[t._v("test")]),t._v(" podinfo Progressing "),e("span",{pre:!0,attrs:{class:"token number"}},[t._v("15")]),t._v(" "),e("span",{pre:!0,attrs:{class:"token number"}},[t._v("2019")]),t._v("-01-16T14:05:07Z\nprod frontend Succeeded "),e("span",{pre:!0,attrs:{class:"token number"}},[t._v("0")]),t._v(" "),e("span",{pre:!0,attrs:{class:"token number"}},[t._v("2019")]),t._v("-01-15T16:15:07Z\nprod backend Failed "),e("span",{pre:!0,attrs:{class:"token number"}},[t._v("0")]),t._v(" "),e("span",{pre:!0,attrs:{class:"token number"}},[t._v("2019")]),t._v("-01-14T17:05:07Z\n")])])]),e("h2",{attrs:{id:"automated-rollback"}},[e("a",{staticClass:"header-anchor",attrs:{href:"#automated-rollback","aria-hidden":"true"}},[t._v("#")]),t._v(" Automated rollback")]),t._v(" "),e("p",[t._v("During the canary analysis you can generate HTTP 500 errors and high latency to test if Flagger pauses the rollout.")]),t._v(" "),e("p",[t._v("Trigger another canary deployment:")]),t._v(" "),e("div",{staticClass:"language-bash extra-class"},[e("pre",{pre:!0,attrs:{class:"language-bash"}},[e("code",[t._v("kubectl -n "),e("span",{pre:!0,attrs:{class:"token builtin class-name"}},[t._v("test")]),t._v(" "),e("span",{pre:!0,attrs:{class:"token builtin class-name"}},[t._v("set")]),t._v(" image deployment/podinfo "),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("\\")]),t._v("\n"),e("span",{pre:!0,attrs:{class:"token assign-left variable"}},[t._v("podinfod")]),e("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v("stefanprodan/podinfo:3.1.2\n")])])]),e("p",[t._v("Exec into the load tester pod with:")]),t._v(" "),e("div",{staticClass:"language-bash extra-class"},[e("pre",{pre:!0,attrs:{class:"language-bash"}},[e("code",[t._v("kubectl -n "),e("span",{pre:!0,attrs:{class:"token builtin class-name"}},[t._v("test")]),t._v(" "),e("span",{pre:!0,attrs:{class:"token builtin class-name"}},[t._v("exec")]),t._v(" -it flagger-loadtester-xx-xx "),e("span",{pre:!0,attrs:{class:"token function"}},[t._v("sh")]),t._v("\n")])])]),e("p",[t._v("Generate HTTP 500 errors:")]),t._v(" "),e("div",{staticClass:"language-bash extra-class"},[e("pre",{pre:!0,attrs:{class:"language-bash"}},[e("code",[e("span",{pre:!0,attrs:{class:"token function"}},[t._v("watch")]),t._v(" "),e("span",{pre:!0,attrs:{class:"token function"}},[t._v("curl")]),t._v(" http://podinfo-canary:9898/status/500\n")])])]),e("p",[t._v("Generate latency:")]),t._v(" "),e("div",{staticClass:"language-bash extra-class"},[e("pre",{pre:!0,attrs:{class:"language-bash"}},[e("code",[e("span",{pre:!0,attrs:{class:"token function"}},[t._v("watch")]),t._v(" "),e("span",{pre:!0,attrs:{class:"token function"}},[t._v("curl")]),t._v(" http://podinfo-canary:9898/delay/1\n")])])]),e("p",[t._v("When the number of failed checks reaches the canary analysis threshold, the traffic is routed back to the primary,\nthe canary is scaled to zero and the rollout is marked as failed.")]),t._v(" "),e("div",{staticClass:"language-text extra-class"},[e("pre",{pre:!0,attrs:{class:"language-text"}},[e("code",[t._v("kubectl -n test describe canary/podinfo\n\nStatus:\n Canary Weight: 0\n Failed Checks: 10\n Phase: Failed\nEvents:\n Type Reason Age From Message\n ---- ------ ---- ---- -------\n Normal Synced 3m flagger Starting canary deployment for podinfo.test\n Normal Synced 3m flagger Advance podinfo.test canary weight 5\n Normal Synced 3m flagger Advance podinfo.test canary weight 10\n Normal Synced 3m flagger Advance podinfo.test canary weight 15\n Normal Synced 3m flagger Halt podinfo.test advancement success rate 69.17% < 99%\n Normal Synced 2m flagger Halt podinfo.test advancement success rate 61.39% < 99%\n Normal Synced 2m flagger Halt podinfo.test advancement success rate 55.06% < 99%\n Normal Synced 2m flagger Halt podinfo.test advancement success rate 47.00% < 99%\n Normal Synced 2m flagger (combined from similar events): Halt podinfo.test advancement success rate 38.08% < 99%\n Warning Synced 1m flagger Rolling back podinfo.test failed checks threshold reached 10\n Warning Synced 1m flagger Canary failed! Scaling down podinfo.test\n")])])]),e("h2",{attrs:{id:"traffic-mirroring"}},[e("a",{staticClass:"header-anchor",attrs:{href:"#traffic-mirroring","aria-hidden":"true"}},[t._v("#")]),t._v(" Traffic mirroring")]),t._v(" "),e("p",[e("img",{attrs:{src:"https://raw.githubusercontent.com/weaveworks/flagger/master/docs/diagrams/flagger-canary-traffic-mirroring.png",alt:"Flagger Canary Traffic Shadowing"}})]),t._v(" "),e("p",[t._v("For applications that perform read operations, Flagger can be configured to drive canary releases with traffic mirroring.\nIstio traffic mirroring will copy each incoming request, sending one request to the primary and one to the canary service.\nThe response from the primary is sent back to the user and the response from the canary is discarded.\nMetrics are collected on both requests so that the deployment will only proceed if the canary metrics are within the threshold values.")]),t._v(" "),e("p",[t._v("Note that mirroring should be used for requests that are "),e("strong",[t._v("idempotent")]),t._v(" or capable of being processed twice (once by the primary and once by the canary).")]),t._v(" "),e("p",[t._v("You can enable mirroring by replacing "),e("code",[t._v("stepWeight/maxWeight")]),t._v(" with "),e("code",[t._v("iterations")]),t._v(" and by setting "),e("code",[t._v("analysis.mirror")]),t._v(" to "),e("code",[t._v("true")]),t._v(":")]),t._v(" "),e("div",{staticClass:"language-yaml extra-class"},[e("pre",{pre:!0,attrs:{class:"language-yaml"}},[e("code",[e("span",{pre:!0,attrs:{class:"token key atrule"}},[t._v("apiVersion")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" flagger.app/v1beta1\n"),e("span",{pre:!0,attrs:{class:"token key atrule"}},[t._v("kind")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" Canary\n"),e("span",{pre:!0,attrs:{class:"token key atrule"}},[t._v("metadata")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v("\n "),e("span",{pre:!0,attrs:{class:"token key atrule"}},[t._v("name")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" podinfo\n "),e("span",{pre:!0,attrs:{class:"token key atrule"}},[t._v("namespace")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" test\n"),e("span",{pre:!0,attrs:{class:"token key atrule"}},[t._v("spec")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v("\n "),e("span",{pre:!0,attrs:{class:"token key atrule"}},[t._v("analysis")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v("\n "),e("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# schedule interval")]),t._v("\n "),e("span",{pre:!0,attrs:{class:"token key atrule"}},[t._v("interval")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" 1m\n "),e("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# max number of failed metric checks before rollback")]),t._v("\n "),e("span",{pre:!0,attrs:{class:"token key atrule"}},[t._v("threshold")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),e("span",{pre:!0,attrs:{class:"token number"}},[t._v("5")]),t._v("\n "),e("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# total number of iterations")]),t._v("\n "),e("span",{pre:!0,attrs:{class:"token key atrule"}},[t._v("iterations")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),e("span",{pre:!0,attrs:{class:"token number"}},[t._v("10")]),t._v("\n "),e("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# enable traffic shadowing ")]),t._v("\n "),e("span",{pre:!0,attrs:{class:"token key atrule"}},[t._v("mirror")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),e("span",{pre:!0,attrs:{class:"token boolean important"}},[t._v("true")]),t._v("\n "),e("span",{pre:!0,attrs:{class:"token key atrule"}},[t._v("metrics")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v("\n "),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("-")]),t._v(" "),e("span",{pre:!0,attrs:{class:"token key atrule"}},[t._v("name")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" request"),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("-")]),t._v("success"),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("-")]),t._v("rate\n "),e("span",{pre:!0,attrs:{class:"token key atrule"}},[t._v("thresholdRange")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v("\n "),e("span",{pre:!0,attrs:{class:"token key atrule"}},[t._v("min")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),e("span",{pre:!0,attrs:{class:"token number"}},[t._v("99")]),t._v("\n "),e("span",{pre:!0,attrs:{class:"token key atrule"}},[t._v("interval")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" 1m\n "),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("-")]),t._v(" "),e("span",{pre:!0,attrs:{class:"token key atrule"}},[t._v("name")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" request"),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("-")]),t._v("duration\n "),e("span",{pre:!0,attrs:{class:"token key atrule"}},[t._v("thresholdRange")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v("\n "),e("span",{pre:!0,attrs:{class:"token key atrule"}},[t._v("max")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),e("span",{pre:!0,attrs:{class:"token number"}},[t._v("500")]),t._v("\n "),e("span",{pre:!0,attrs:{class:"token key atrule"}},[t._v("interval")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" 1m\n "),e("span",{pre:!0,attrs:{class:"token key atrule"}},[t._v("webhooks")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v("\n "),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("-")]),t._v(" "),e("span",{pre:!0,attrs:{class:"token key atrule"}},[t._v("name")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" acceptance"),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("-")]),t._v("test\n "),e("span",{pre:!0,attrs:{class:"token key atrule"}},[t._v("type")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" pre"),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("-")]),t._v("rollout\n "),e("span",{pre:!0,attrs:{class:"token key atrule"}},[t._v("url")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" http"),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v("//flagger"),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("-")]),t._v("loadtester.test/\n "),e("span",{pre:!0,attrs:{class:"token key atrule"}},[t._v("timeout")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" 30s\n "),e("span",{pre:!0,attrs:{class:"token key atrule"}},[t._v("metadata")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v("\n "),e("span",{pre:!0,attrs:{class:"token key atrule"}},[t._v("type")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" bash\n "),e("span",{pre:!0,attrs:{class:"token key atrule"}},[t._v("cmd")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),e("span",{pre:!0,attrs:{class:"token string"}},[t._v("\"curl -sd 'test' http://podinfo-canary:9898/token | grep token\"")]),t._v("\n "),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("-")]),t._v(" "),e("span",{pre:!0,attrs:{class:"token key atrule"}},[t._v("name")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" load"),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("-")]),t._v("test\n "),e("span",{pre:!0,attrs:{class:"token key atrule"}},[t._v("url")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" http"),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v("//flagger"),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("-")]),t._v("loadtester.test/\n "),e("span",{pre:!0,attrs:{class:"token key atrule"}},[t._v("timeout")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" 5s\n "),e("span",{pre:!0,attrs:{class:"token key atrule"}},[t._v("metadata")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v("\n "),e("span",{pre:!0,attrs:{class:"token key atrule"}},[t._v("cmd")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),e("span",{pre:!0,attrs:{class:"token string"}},[t._v('"hey -z 1m -q 10 -c 2 http://podinfo.test:9898/"')]),t._v("\n")])])]),e("p",[t._v("With the above configuration, Flagger will run a canary release with the following steps:")]),t._v(" "),e("ul",[e("li",[t._v("detect new revision (deployment spec, secrets or configmaps changes)")]),t._v(" "),e("li",[t._v("scale from zero the canary deployment")]),t._v(" "),e("li",[t._v("wait for the HPA to set the canary minimum replicas")]),t._v(" "),e("li",[t._v("check canary pods health")]),t._v(" "),e("li",[t._v("run the acceptance tests")]),t._v(" "),e("li",[t._v("abort the canary release if tests fail")]),t._v(" "),e("li",[t._v("start the load tests")]),t._v(" "),e("li",[t._v("mirror traffic from primary to canary")]),t._v(" "),e("li",[t._v("check request success rate and request duration every minute")]),t._v(" "),e("li",[t._v("abort the canary release if the metrics check failure threshold is reached")]),t._v(" "),e("li",[t._v("stop traffic mirroring after the number of iterations is reached")]),t._v(" "),e("li",[t._v("route live traffic to the canary pods")]),t._v(" "),e("li",[t._v("promote the canary (update the primary secrets, configmaps and deployment spec)")]),t._v(" "),e("li",[t._v("wait for the primary deployment rollout to finish")]),t._v(" "),e("li",[t._v("wait for the HPA to set the primary minimum replicas")]),t._v(" "),e("li",[t._v("check primary pods health")]),t._v(" "),e("li",[t._v("switch live traffic back to primary")]),t._v(" "),e("li",[t._v("scale to zero the canary")]),t._v(" "),e("li",[t._v("send notification with the canary analysis result")])]),t._v(" "),e("p",[t._v("The above procedure can be extended with "),e("router-link",{attrs:{to:"/usage/metrics.html"}},[t._v("custom metrics")]),t._v(" checks,\n"),e("router-link",{attrs:{to:"/usage/webhooks.html"}},[t._v("webhooks")]),t._v(",\n"),e("router-link",{attrs:{to:"/usage/webhooks.html#manual-gating"}},[t._v("manual promotion")]),t._v(" approval and\n"),e("router-link",{attrs:{to:"/usage/alerting.html"}},[t._v("Slack or MS Teams")]),t._v(" notifications.")],1)])},[],!1,null,null,null);a.default=n.exports}}]); \ No newline at end of file +(window.webpackJsonp=window.webpackJsonp||[]).push([[24],{283:function(t,a,e){"use strict";e.r(a);var s=e(37),n=Object(s.a)({},function(){var t=this,a=t.$createElement,e=t._self._c||a;return e("ContentSlotsDistributor",{attrs:{"slot-key":t.$parent.slotKey}},[e("h1",{attrs:{id:"istio-canary-deployments"}},[e("a",{staticClass:"header-anchor",attrs:{href:"#istio-canary-deployments","aria-hidden":"true"}},[t._v("#")]),t._v(" Istio Canary Deployments")]),t._v(" "),e("p",[t._v("This guide shows you how to use Istio and Flagger to automate canary deployments.")]),t._v(" "),e("p",[e("img",{attrs:{src:"https://raw.githubusercontent.com/weaveworks/flagger/master/docs/diagrams/flagger-canary-steps.png",alt:"Flagger Canary Stages"}})]),t._v(" "),e("h2",{attrs:{id:"prerequisites"}},[e("a",{staticClass:"header-anchor",attrs:{href:"#prerequisites","aria-hidden":"true"}},[t._v("#")]),t._v(" Prerequisites")]),t._v(" "),e("p",[t._v("Flagger requires a Kubernetes cluster "),e("strong",[t._v("v1.11")]),t._v(" or newer and Istio "),e("strong",[t._v("v1.0")]),t._v(" or newer.")]),t._v(" "),e("p",[t._v("Install Istio with telemetry support and Prometheus:")]),t._v(" "),e("div",{staticClass:"language-bash extra-class"},[e("pre",{pre:!0,attrs:{class:"language-bash"}},[e("code",[t._v("istioctl manifest apply --set "),e("span",{pre:!0,attrs:{class:"token assign-left variable"}},[t._v("profile")]),e("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v("default\n")])])]),e("p",[t._v("Install Flagger using Kustomize (kubectl 1.14) in the "),e("code",[t._v("istio-system")]),t._v(" namespace:")]),t._v(" "),e("div",{staticClass:"language-bash extra-class"},[e("pre",{pre:!0,attrs:{class:"language-bash"}},[e("code",[t._v("kubectl apply -k github.com/weaveworks/flagger//kustomize/istio\n")])])]),e("p",[t._v("Create an ingress gateway to expose the demo app outside of the mesh:")]),t._v(" "),e("div",{staticClass:"language-yaml extra-class"},[e("pre",{pre:!0,attrs:{class:"language-yaml"}},[e("code",[e("span",{pre:!0,attrs:{class:"token key atrule"}},[t._v("apiVersion")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" networking.istio.io/v1alpha3\n"),e("span",{pre:!0,attrs:{class:"token key atrule"}},[t._v("kind")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" Gateway\n"),e("span",{pre:!0,attrs:{class:"token key atrule"}},[t._v("metadata")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v("\n "),e("span",{pre:!0,attrs:{class:"token key atrule"}},[t._v("name")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" public"),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("-")]),t._v("gateway\n "),e("span",{pre:!0,attrs:{class:"token key atrule"}},[t._v("namespace")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" istio"),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("-")]),t._v("system\n"),e("span",{pre:!0,attrs:{class:"token key atrule"}},[t._v("spec")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v("\n "),e("span",{pre:!0,attrs:{class:"token key atrule"}},[t._v("selector")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v("\n "),e("span",{pre:!0,attrs:{class:"token key atrule"}},[t._v("istio")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" ingressgateway\n "),e("span",{pre:!0,attrs:{class:"token key atrule"}},[t._v("servers")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v("\n "),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("-")]),t._v(" "),e("span",{pre:!0,attrs:{class:"token key atrule"}},[t._v("port")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v("\n "),e("span",{pre:!0,attrs:{class:"token key atrule"}},[t._v("number")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),e("span",{pre:!0,attrs:{class:"token number"}},[t._v("80")]),t._v("\n "),e("span",{pre:!0,attrs:{class:"token key atrule"}},[t._v("name")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" http\n "),e("span",{pre:!0,attrs:{class:"token key atrule"}},[t._v("protocol")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" HTTP\n "),e("span",{pre:!0,attrs:{class:"token key atrule"}},[t._v("hosts")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v("\n "),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("-")]),t._v(" "),e("span",{pre:!0,attrs:{class:"token string"}},[t._v('"*"')]),t._v("\n")])])]),e("h2",{attrs:{id:"bootstrap"}},[e("a",{staticClass:"header-anchor",attrs:{href:"#bootstrap","aria-hidden":"true"}},[t._v("#")]),t._v(" Bootstrap")]),t._v(" "),e("p",[t._v("Flagger takes a Kubernetes deployment and optionally a horizontal pod autoscaler (HPA),\nthen creates a series of objects (Kubernetes deployments, ClusterIP services,\nIstio destination rules and virtual services).\nThese objects expose the application inside the mesh and drive the canary analysis and promotion.")]),t._v(" "),e("p",[t._v("Create a test namespace with Istio sidecar injection enabled:")]),t._v(" "),e("div",{staticClass:"language-bash extra-class"},[e("pre",{pre:!0,attrs:{class:"language-bash"}},[e("code",[t._v("kubectl create ns "),e("span",{pre:!0,attrs:{class:"token builtin class-name"}},[t._v("test")]),t._v("\nkubectl label namespace "),e("span",{pre:!0,attrs:{class:"token builtin class-name"}},[t._v("test")]),t._v(" istio-injection"),e("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v("enabled\n")])])]),e("p",[t._v("Create a deployment and a horizontal pod autoscaler:")]),t._v(" "),e("div",{staticClass:"language-bash extra-class"},[e("pre",{pre:!0,attrs:{class:"language-bash"}},[e("code",[t._v("kubectl apply -k github.com/weaveworks/flagger//kustomize/podinfo\n")])])]),e("p",[t._v("Deploy the load testing service to generate traffic during the canary analysis:")]),t._v(" "),e("div",{staticClass:"language-bash extra-class"},[e("pre",{pre:!0,attrs:{class:"language-bash"}},[e("code",[t._v("kubectl apply -k github.com/weaveworks/flagger//kustomize/tester\n")])])]),e("p",[t._v("Create a canary custom resource (replace example.com with your own domain):")]),t._v(" "),e("div",{staticClass:"language-yaml extra-class"},[e("pre",{pre:!0,attrs:{class:"language-yaml"}},[e("code",[e("span",{pre:!0,attrs:{class:"token key atrule"}},[t._v("apiVersion")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" flagger.app/v1beta1\n"),e("span",{pre:!0,attrs:{class:"token key atrule"}},[t._v("kind")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" Canary\n"),e("span",{pre:!0,attrs:{class:"token key atrule"}},[t._v("metadata")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v("\n "),e("span",{pre:!0,attrs:{class:"token key atrule"}},[t._v("name")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" podinfo\n "),e("span",{pre:!0,attrs:{class:"token key atrule"}},[t._v("namespace")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" test\n"),e("span",{pre:!0,attrs:{class:"token key atrule"}},[t._v("spec")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v("\n "),e("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# deployment reference")]),t._v("\n "),e("span",{pre:!0,attrs:{class:"token key atrule"}},[t._v("targetRef")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v("\n "),e("span",{pre:!0,attrs:{class:"token key atrule"}},[t._v("apiVersion")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" apps/v1\n "),e("span",{pre:!0,attrs:{class:"token key atrule"}},[t._v("kind")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" Deployment\n "),e("span",{pre:!0,attrs:{class:"token key atrule"}},[t._v("name")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" podinfo\n "),e("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# the maximum time in seconds for the canary deployment")]),t._v("\n "),e("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# to make progress before it is rollback (default 600s)")]),t._v("\n "),e("span",{pre:!0,attrs:{class:"token key atrule"}},[t._v("progressDeadlineSeconds")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),e("span",{pre:!0,attrs:{class:"token number"}},[t._v("60")]),t._v("\n "),e("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# HPA reference (optional)")]),t._v("\n "),e("span",{pre:!0,attrs:{class:"token key atrule"}},[t._v("autoscalerRef")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v("\n "),e("span",{pre:!0,attrs:{class:"token key atrule"}},[t._v("apiVersion")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" autoscaling/v2beta1\n "),e("span",{pre:!0,attrs:{class:"token key atrule"}},[t._v("kind")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" HorizontalPodAutoscaler\n "),e("span",{pre:!0,attrs:{class:"token key atrule"}},[t._v("name")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" podinfo\n "),e("span",{pre:!0,attrs:{class:"token key atrule"}},[t._v("service")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v("\n "),e("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# service port number")]),t._v("\n "),e("span",{pre:!0,attrs:{class:"token key atrule"}},[t._v("port")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),e("span",{pre:!0,attrs:{class:"token number"}},[t._v("9898")]),t._v("\n "),e("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# container port number or name (optional)")]),t._v("\n "),e("span",{pre:!0,attrs:{class:"token key atrule"}},[t._v("targetPort")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),e("span",{pre:!0,attrs:{class:"token number"}},[t._v("9898")]),t._v("\n "),e("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# Istio gateways (optional)")]),t._v("\n "),e("span",{pre:!0,attrs:{class:"token key atrule"}},[t._v("gateways")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v("\n "),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("-")]),t._v(" public"),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("-")]),t._v("gateway.istio"),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("-")]),t._v("system.svc.cluster.local\n "),e("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# Istio virtual service host names (optional)")]),t._v("\n "),e("span",{pre:!0,attrs:{class:"token key atrule"}},[t._v("hosts")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v("\n "),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("-")]),t._v(" app.example.com\n "),e("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# Istio traffic policy (optional)")]),t._v("\n "),e("span",{pre:!0,attrs:{class:"token key atrule"}},[t._v("trafficPolicy")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v("\n "),e("span",{pre:!0,attrs:{class:"token key atrule"}},[t._v("tls")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v("\n "),e("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# use ISTIO_MUTUAL when mTLS is enabled")]),t._v("\n "),e("span",{pre:!0,attrs:{class:"token key atrule"}},[t._v("mode")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" DISABLE\n "),e("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# Istio retry policy (optional)")]),t._v("\n "),e("span",{pre:!0,attrs:{class:"token key atrule"}},[t._v("retries")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v("\n "),e("span",{pre:!0,attrs:{class:"token key atrule"}},[t._v("attempts")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),e("span",{pre:!0,attrs:{class:"token number"}},[t._v("3")]),t._v("\n "),e("span",{pre:!0,attrs:{class:"token key atrule"}},[t._v("perTryTimeout")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" 1s\n "),e("span",{pre:!0,attrs:{class:"token key atrule"}},[t._v("retryOn")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),e("span",{pre:!0,attrs:{class:"token string"}},[t._v('"gateway-error,connect-failure,refused-stream"')]),t._v("\n "),e("span",{pre:!0,attrs:{class:"token key atrule"}},[t._v("analysis")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v("\n "),e("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# schedule interval (default 60s)")]),t._v("\n "),e("span",{pre:!0,attrs:{class:"token key atrule"}},[t._v("interval")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" 1m\n "),e("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# max number of failed metric checks before rollback")]),t._v("\n "),e("span",{pre:!0,attrs:{class:"token key atrule"}},[t._v("threshold")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),e("span",{pre:!0,attrs:{class:"token number"}},[t._v("5")]),t._v("\n "),e("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# max traffic percentage routed to canary")]),t._v("\n "),e("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# percentage (0-100)")]),t._v("\n "),e("span",{pre:!0,attrs:{class:"token key atrule"}},[t._v("maxWeight")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),e("span",{pre:!0,attrs:{class:"token number"}},[t._v("50")]),t._v("\n "),e("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# canary increment step")]),t._v("\n "),e("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# percentage (0-100)")]),t._v("\n "),e("span",{pre:!0,attrs:{class:"token key atrule"}},[t._v("stepWeight")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),e("span",{pre:!0,attrs:{class:"token number"}},[t._v("10")]),t._v("\n "),e("span",{pre:!0,attrs:{class:"token key atrule"}},[t._v("metrics")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v("\n "),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("-")]),t._v(" "),e("span",{pre:!0,attrs:{class:"token key atrule"}},[t._v("name")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" request"),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("-")]),t._v("success"),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("-")]),t._v("rate\n "),e("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# minimum req success rate (non 5xx responses)")]),t._v("\n "),e("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# percentage (0-100)")]),t._v("\n "),e("span",{pre:!0,attrs:{class:"token key atrule"}},[t._v("thresholdRange")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v("\n "),e("span",{pre:!0,attrs:{class:"token key atrule"}},[t._v("min")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),e("span",{pre:!0,attrs:{class:"token number"}},[t._v("99")]),t._v("\n "),e("span",{pre:!0,attrs:{class:"token key atrule"}},[t._v("interval")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" 1m\n "),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("-")]),t._v(" "),e("span",{pre:!0,attrs:{class:"token key atrule"}},[t._v("name")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" request"),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("-")]),t._v("duration\n "),e("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# maximum req duration P99")]),t._v("\n "),e("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# milliseconds")]),t._v("\n "),e("span",{pre:!0,attrs:{class:"token key atrule"}},[t._v("thresholdRange")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v("\n "),e("span",{pre:!0,attrs:{class:"token key atrule"}},[t._v("max")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),e("span",{pre:!0,attrs:{class:"token number"}},[t._v("500")]),t._v("\n "),e("span",{pre:!0,attrs:{class:"token key atrule"}},[t._v("interval")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" 30s\n "),e("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# testing (optional)")]),t._v("\n "),e("span",{pre:!0,attrs:{class:"token key atrule"}},[t._v("webhooks")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v("\n "),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("-")]),t._v(" "),e("span",{pre:!0,attrs:{class:"token key atrule"}},[t._v("name")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" acceptance"),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("-")]),t._v("test\n "),e("span",{pre:!0,attrs:{class:"token key atrule"}},[t._v("type")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" pre"),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("-")]),t._v("rollout\n "),e("span",{pre:!0,attrs:{class:"token key atrule"}},[t._v("url")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" http"),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v("//flagger"),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("-")]),t._v("loadtester.test/\n "),e("span",{pre:!0,attrs:{class:"token key atrule"}},[t._v("timeout")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" 30s\n "),e("span",{pre:!0,attrs:{class:"token key atrule"}},[t._v("metadata")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v("\n "),e("span",{pre:!0,attrs:{class:"token key atrule"}},[t._v("type")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" bash\n "),e("span",{pre:!0,attrs:{class:"token key atrule"}},[t._v("cmd")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),e("span",{pre:!0,attrs:{class:"token string"}},[t._v("\"curl -sd 'test' http://podinfo-canary:9898/token | grep token\"")]),t._v("\n "),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("-")]),t._v(" "),e("span",{pre:!0,attrs:{class:"token key atrule"}},[t._v("name")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" load"),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("-")]),t._v("test\n "),e("span",{pre:!0,attrs:{class:"token key atrule"}},[t._v("url")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" http"),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v("//flagger"),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("-")]),t._v("loadtester.test/\n "),e("span",{pre:!0,attrs:{class:"token key atrule"}},[t._v("timeout")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" 5s\n "),e("span",{pre:!0,attrs:{class:"token key atrule"}},[t._v("metadata")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v("\n "),e("span",{pre:!0,attrs:{class:"token key atrule"}},[t._v("cmd")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),e("span",{pre:!0,attrs:{class:"token string"}},[t._v('"hey -z 1m -q 10 -c 2 http://podinfo-canary.test:9898/"')]),t._v("\n")])])]),e("p",[t._v("Save the above resource as podinfo-canary.yaml and then apply it:")]),t._v(" "),e("div",{staticClass:"language-bash extra-class"},[e("pre",{pre:!0,attrs:{class:"language-bash"}},[e("code",[t._v("kubectl apply -f ./podinfo-canary.yaml\n")])])]),e("p",[t._v("When the canary analysis starts, Flagger will call the pre-rollout webhooks before routing traffic to the canary.\nThe canary analysis will run for five minutes while validating the HTTP metrics and rollout hooks every minute.")]),t._v(" "),e("p",[e("img",{attrs:{src:"https://raw.githubusercontent.com/weaveworks/flagger/master/docs/diagrams/flagger-canary-hpa.png",alt:"Flagger Canary Process"}})]),t._v(" "),e("p",[t._v("After a couple of seconds Flagger will create the canary objects:")]),t._v(" "),e("div",{staticClass:"language-bash extra-class"},[e("pre",{pre:!0,attrs:{class:"language-bash"}},[e("code",[e("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# applied ")]),t._v("\ndeployment.apps/podinfo\nhorizontalpodautoscaler.autoscaling/podinfo\ncanary.flagger.app/podinfo\n\n"),e("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# generated ")]),t._v("\ndeployment.apps/podinfo-primary\nhorizontalpodautoscaler.autoscaling/podinfo-primary\nservice/podinfo\nservice/podinfo-canary\nservice/podinfo-primary\ndestinationrule.networking.istio.io/podinfo-canary\ndestinationrule.networking.istio.io/podinfo-primary\nvirtualservice.networking.istio.io/podinfo\n")])])]),e("h2",{attrs:{id:"automated-canary-promotion"}},[e("a",{staticClass:"header-anchor",attrs:{href:"#automated-canary-promotion","aria-hidden":"true"}},[t._v("#")]),t._v(" Automated canary promotion")]),t._v(" "),e("p",[t._v("Trigger a canary deployment by updating the container image:")]),t._v(" "),e("div",{staticClass:"language-bash extra-class"},[e("pre",{pre:!0,attrs:{class:"language-bash"}},[e("code",[t._v("kubectl -n "),e("span",{pre:!0,attrs:{class:"token builtin class-name"}},[t._v("test")]),t._v(" "),e("span",{pre:!0,attrs:{class:"token builtin class-name"}},[t._v("set")]),t._v(" image deployment/podinfo "),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("\\")]),t._v("\n"),e("span",{pre:!0,attrs:{class:"token assign-left variable"}},[t._v("podinfod")]),e("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v("stefanprodan/podinfo:3.1.1\n")])])]),e("p",[t._v("Flagger detects that the deployment revision changed and starts a new rollout:")]),t._v(" "),e("div",{staticClass:"language-text extra-class"},[e("pre",{pre:!0,attrs:{class:"language-text"}},[e("code",[t._v("kubectl -n test describe canary/podinfo\n\nStatus:\n Canary Weight: 0\n Failed Checks: 0\n Phase: Succeeded\nEvents:\n Type Reason Age From Message\n ---- ------ ---- ---- -------\n Normal Synced 3m flagger New revision detected podinfo.test\n Normal Synced 3m flagger Scaling up podinfo.test\n Warning Synced 3m flagger Waiting for podinfo.test rollout to finish: 0 of 1 updated replicas are available\n Normal Synced 3m flagger Advance podinfo.test canary weight 5\n Normal Synced 3m flagger Advance podinfo.test canary weight 10\n Normal Synced 3m flagger Advance podinfo.test canary weight 15\n Normal Synced 2m flagger Advance podinfo.test canary weight 20\n Normal Synced 2m flagger Advance podinfo.test canary weight 25\n Normal Synced 1m flagger Advance podinfo.test canary weight 30\n Normal Synced 1m flagger Advance podinfo.test canary weight 35\n Normal Synced 55s flagger Advance podinfo.test canary weight 40\n Normal Synced 45s flagger Advance podinfo.test canary weight 45\n Normal Synced 35s flagger Advance podinfo.test canary weight 50\n Normal Synced 25s flagger Copying podinfo.test template spec to podinfo-primary.test\n Warning Synced 15s flagger Waiting for podinfo-primary.test rollout to finish: 1 of 2 updated replicas are available\n Normal Synced 5s flagger Promotion completed! Scaling down podinfo.test\n")])])]),e("p",[e("strong",[t._v("Note")]),t._v(" that if you apply new changes to the deployment during the canary analysis, Flagger will restart the analysis.")]),t._v(" "),e("p",[t._v("A canary deployment is triggered by changes in any of the following objects:")]),t._v(" "),e("ul",[e("li",[t._v("Deployment PodSpec (container image, command, ports, env, resources, etc)")]),t._v(" "),e("li",[t._v("ConfigMaps mounted as volumes or mapped to environment variables")]),t._v(" "),e("li",[t._v("Secrets mounted as volumes or mapped to environment variables")])]),t._v(" "),e("p",[t._v("You can monitor all canaries with:")]),t._v(" "),e("div",{staticClass:"language-bash extra-class"},[e("pre",{pre:!0,attrs:{class:"language-bash"}},[e("code",[e("span",{pre:!0,attrs:{class:"token function"}},[t._v("watch")]),t._v(" kubectl get canaries --all-namespaces\n\nNAMESPACE NAME STATUS WEIGHT LASTTRANSITIONTIME\n"),e("span",{pre:!0,attrs:{class:"token builtin class-name"}},[t._v("test")]),t._v(" podinfo Progressing "),e("span",{pre:!0,attrs:{class:"token number"}},[t._v("15")]),t._v(" "),e("span",{pre:!0,attrs:{class:"token number"}},[t._v("2019")]),t._v("-01-16T14:05:07Z\nprod frontend Succeeded "),e("span",{pre:!0,attrs:{class:"token number"}},[t._v("0")]),t._v(" "),e("span",{pre:!0,attrs:{class:"token number"}},[t._v("2019")]),t._v("-01-15T16:15:07Z\nprod backend Failed "),e("span",{pre:!0,attrs:{class:"token number"}},[t._v("0")]),t._v(" "),e("span",{pre:!0,attrs:{class:"token number"}},[t._v("2019")]),t._v("-01-14T17:05:07Z\n")])])]),e("h2",{attrs:{id:"automated-rollback"}},[e("a",{staticClass:"header-anchor",attrs:{href:"#automated-rollback","aria-hidden":"true"}},[t._v("#")]),t._v(" Automated rollback")]),t._v(" "),e("p",[t._v("During the canary analysis you can generate HTTP 500 errors and high latency to test if Flagger pauses the rollout.")]),t._v(" "),e("p",[t._v("Trigger another canary deployment:")]),t._v(" "),e("div",{staticClass:"language-bash extra-class"},[e("pre",{pre:!0,attrs:{class:"language-bash"}},[e("code",[t._v("kubectl -n "),e("span",{pre:!0,attrs:{class:"token builtin class-name"}},[t._v("test")]),t._v(" "),e("span",{pre:!0,attrs:{class:"token builtin class-name"}},[t._v("set")]),t._v(" image deployment/podinfo "),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("\\")]),t._v("\n"),e("span",{pre:!0,attrs:{class:"token assign-left variable"}},[t._v("podinfod")]),e("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v("stefanprodan/podinfo:3.1.2\n")])])]),e("p",[t._v("Exec into the load tester pod with:")]),t._v(" "),e("div",{staticClass:"language-bash extra-class"},[e("pre",{pre:!0,attrs:{class:"language-bash"}},[e("code",[t._v("kubectl -n "),e("span",{pre:!0,attrs:{class:"token builtin class-name"}},[t._v("test")]),t._v(" "),e("span",{pre:!0,attrs:{class:"token builtin class-name"}},[t._v("exec")]),t._v(" -it flagger-loadtester-xx-xx "),e("span",{pre:!0,attrs:{class:"token function"}},[t._v("sh")]),t._v("\n")])])]),e("p",[t._v("Generate HTTP 500 errors:")]),t._v(" "),e("div",{staticClass:"language-bash extra-class"},[e("pre",{pre:!0,attrs:{class:"language-bash"}},[e("code",[e("span",{pre:!0,attrs:{class:"token function"}},[t._v("watch")]),t._v(" "),e("span",{pre:!0,attrs:{class:"token function"}},[t._v("curl")]),t._v(" http://podinfo-canary:9898/status/500\n")])])]),e("p",[t._v("Generate latency:")]),t._v(" "),e("div",{staticClass:"language-bash extra-class"},[e("pre",{pre:!0,attrs:{class:"language-bash"}},[e("code",[e("span",{pre:!0,attrs:{class:"token function"}},[t._v("watch")]),t._v(" "),e("span",{pre:!0,attrs:{class:"token function"}},[t._v("curl")]),t._v(" http://podinfo-canary:9898/delay/1\n")])])]),e("p",[t._v("When the number of failed checks reaches the canary analysis threshold, the traffic is routed back to the primary,\nthe canary is scaled to zero and the rollout is marked as failed.")]),t._v(" "),e("div",{staticClass:"language-text extra-class"},[e("pre",{pre:!0,attrs:{class:"language-text"}},[e("code",[t._v("kubectl -n test describe canary/podinfo\n\nStatus:\n Canary Weight: 0\n Failed Checks: 10\n Phase: Failed\nEvents:\n Type Reason Age From Message\n ---- ------ ---- ---- -------\n Normal Synced 3m flagger Starting canary deployment for podinfo.test\n Normal Synced 3m flagger Advance podinfo.test canary weight 5\n Normal Synced 3m flagger Advance podinfo.test canary weight 10\n Normal Synced 3m flagger Advance podinfo.test canary weight 15\n Normal Synced 3m flagger Halt podinfo.test advancement success rate 69.17% < 99%\n Normal Synced 2m flagger Halt podinfo.test advancement success rate 61.39% < 99%\n Normal Synced 2m flagger Halt podinfo.test advancement success rate 55.06% < 99%\n Normal Synced 2m flagger Halt podinfo.test advancement success rate 47.00% < 99%\n Normal Synced 2m flagger (combined from similar events): Halt podinfo.test advancement success rate 38.08% < 99%\n Warning Synced 1m flagger Rolling back podinfo.test failed checks threshold reached 10\n Warning Synced 1m flagger Canary failed! Scaling down podinfo.test\n")])])]),e("h2",{attrs:{id:"traffic-mirroring"}},[e("a",{staticClass:"header-anchor",attrs:{href:"#traffic-mirroring","aria-hidden":"true"}},[t._v("#")]),t._v(" Traffic mirroring")]),t._v(" "),e("p",[e("img",{attrs:{src:"https://raw.githubusercontent.com/weaveworks/flagger/master/docs/diagrams/flagger-canary-traffic-mirroring.png",alt:"Flagger Canary Traffic Shadowing"}})]),t._v(" "),e("p",[t._v("For applications that perform read operations, Flagger can be configured to drive canary releases with traffic mirroring.\nIstio traffic mirroring will copy each incoming request, sending one request to the primary and one to the canary service.\nThe response from the primary is sent back to the user and the response from the canary is discarded.\nMetrics are collected on both requests so that the deployment will only proceed if the canary metrics are within the threshold values.")]),t._v(" "),e("p",[t._v("Note that mirroring should be used for requests that are "),e("strong",[t._v("idempotent")]),t._v(" or capable of being processed twice (once by the primary and once by the canary).")]),t._v(" "),e("p",[t._v("You can enable mirroring by replacing "),e("code",[t._v("stepWeight/maxWeight")]),t._v(" with "),e("code",[t._v("iterations")]),t._v(" and by setting "),e("code",[t._v("analysis.mirror")]),t._v(" to "),e("code",[t._v("true")]),t._v(":")]),t._v(" "),e("div",{staticClass:"language-yaml extra-class"},[e("pre",{pre:!0,attrs:{class:"language-yaml"}},[e("code",[e("span",{pre:!0,attrs:{class:"token key atrule"}},[t._v("apiVersion")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" flagger.app/v1beta1\n"),e("span",{pre:!0,attrs:{class:"token key atrule"}},[t._v("kind")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" Canary\n"),e("span",{pre:!0,attrs:{class:"token key atrule"}},[t._v("metadata")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v("\n "),e("span",{pre:!0,attrs:{class:"token key atrule"}},[t._v("name")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" podinfo\n "),e("span",{pre:!0,attrs:{class:"token key atrule"}},[t._v("namespace")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" test\n"),e("span",{pre:!0,attrs:{class:"token key atrule"}},[t._v("spec")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v("\n "),e("span",{pre:!0,attrs:{class:"token key atrule"}},[t._v("analysis")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v("\n "),e("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# schedule interval")]),t._v("\n "),e("span",{pre:!0,attrs:{class:"token key atrule"}},[t._v("interval")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" 1m\n "),e("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# max number of failed metric checks before rollback")]),t._v("\n "),e("span",{pre:!0,attrs:{class:"token key atrule"}},[t._v("threshold")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),e("span",{pre:!0,attrs:{class:"token number"}},[t._v("5")]),t._v("\n "),e("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# total number of iterations")]),t._v("\n "),e("span",{pre:!0,attrs:{class:"token key atrule"}},[t._v("iterations")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),e("span",{pre:!0,attrs:{class:"token number"}},[t._v("10")]),t._v("\n "),e("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# enable traffic shadowing ")]),t._v("\n "),e("span",{pre:!0,attrs:{class:"token key atrule"}},[t._v("mirror")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),e("span",{pre:!0,attrs:{class:"token boolean important"}},[t._v("true")]),t._v("\n "),e("span",{pre:!0,attrs:{class:"token key atrule"}},[t._v("metrics")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v("\n "),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("-")]),t._v(" "),e("span",{pre:!0,attrs:{class:"token key atrule"}},[t._v("name")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" request"),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("-")]),t._v("success"),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("-")]),t._v("rate\n "),e("span",{pre:!0,attrs:{class:"token key atrule"}},[t._v("thresholdRange")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v("\n "),e("span",{pre:!0,attrs:{class:"token key atrule"}},[t._v("min")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),e("span",{pre:!0,attrs:{class:"token number"}},[t._v("99")]),t._v("\n "),e("span",{pre:!0,attrs:{class:"token key atrule"}},[t._v("interval")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" 1m\n "),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("-")]),t._v(" "),e("span",{pre:!0,attrs:{class:"token key atrule"}},[t._v("name")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" request"),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("-")]),t._v("duration\n "),e("span",{pre:!0,attrs:{class:"token key atrule"}},[t._v("thresholdRange")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v("\n "),e("span",{pre:!0,attrs:{class:"token key atrule"}},[t._v("max")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),e("span",{pre:!0,attrs:{class:"token number"}},[t._v("500")]),t._v("\n "),e("span",{pre:!0,attrs:{class:"token key atrule"}},[t._v("interval")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" 1m\n "),e("span",{pre:!0,attrs:{class:"token key atrule"}},[t._v("webhooks")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v("\n "),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("-")]),t._v(" "),e("span",{pre:!0,attrs:{class:"token key atrule"}},[t._v("name")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" acceptance"),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("-")]),t._v("test\n "),e("span",{pre:!0,attrs:{class:"token key atrule"}},[t._v("type")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" pre"),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("-")]),t._v("rollout\n "),e("span",{pre:!0,attrs:{class:"token key atrule"}},[t._v("url")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" http"),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v("//flagger"),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("-")]),t._v("loadtester.test/\n "),e("span",{pre:!0,attrs:{class:"token key atrule"}},[t._v("timeout")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" 30s\n "),e("span",{pre:!0,attrs:{class:"token key atrule"}},[t._v("metadata")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v("\n "),e("span",{pre:!0,attrs:{class:"token key atrule"}},[t._v("type")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" bash\n "),e("span",{pre:!0,attrs:{class:"token key atrule"}},[t._v("cmd")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),e("span",{pre:!0,attrs:{class:"token string"}},[t._v("\"curl -sd 'test' http://podinfo-canary:9898/token | grep token\"")]),t._v("\n "),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("-")]),t._v(" "),e("span",{pre:!0,attrs:{class:"token key atrule"}},[t._v("name")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" load"),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("-")]),t._v("test\n "),e("span",{pre:!0,attrs:{class:"token key atrule"}},[t._v("url")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" http"),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v("//flagger"),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("-")]),t._v("loadtester.test/\n "),e("span",{pre:!0,attrs:{class:"token key atrule"}},[t._v("timeout")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" 5s\n "),e("span",{pre:!0,attrs:{class:"token key atrule"}},[t._v("metadata")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v("\n "),e("span",{pre:!0,attrs:{class:"token key atrule"}},[t._v("cmd")]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(":")]),t._v(" "),e("span",{pre:!0,attrs:{class:"token string"}},[t._v('"hey -z 1m -q 10 -c 2 http://podinfo.test:9898/"')]),t._v("\n")])])]),e("p",[t._v("With the above configuration, Flagger will run a canary release with the following steps:")]),t._v(" "),e("ul",[e("li",[t._v("detect new revision (deployment spec, secrets or configmaps changes)")]),t._v(" "),e("li",[t._v("scale from zero the canary deployment")]),t._v(" "),e("li",[t._v("wait for the HPA to set the canary minimum replicas")]),t._v(" "),e("li",[t._v("check canary pods health")]),t._v(" "),e("li",[t._v("run the acceptance tests")]),t._v(" "),e("li",[t._v("abort the canary release if tests fail")]),t._v(" "),e("li",[t._v("start the load tests")]),t._v(" "),e("li",[t._v("mirror traffic from primary to canary")]),t._v(" "),e("li",[t._v("check request success rate and request duration every minute")]),t._v(" "),e("li",[t._v("abort the canary release if the metrics check failure threshold is reached")]),t._v(" "),e("li",[t._v("stop traffic mirroring after the number of iterations is reached")]),t._v(" "),e("li",[t._v("route live traffic to the canary pods")]),t._v(" "),e("li",[t._v("promote the canary (update the primary secrets, configmaps and deployment spec)")]),t._v(" "),e("li",[t._v("wait for the primary deployment rollout to finish")]),t._v(" "),e("li",[t._v("wait for the HPA to set the primary minimum replicas")]),t._v(" "),e("li",[t._v("check primary pods health")]),t._v(" "),e("li",[t._v("switch live traffic back to primary")]),t._v(" "),e("li",[t._v("scale to zero the canary")]),t._v(" "),e("li",[t._v("send notification with the canary analysis result")])]),t._v(" "),e("p",[t._v("The above procedure can be extended with "),e("router-link",{attrs:{to:"/usage/metrics.html"}},[t._v("custom metrics")]),t._v(" checks,\n"),e("router-link",{attrs:{to:"/usage/webhooks.html"}},[t._v("webhooks")]),t._v(",\n"),e("router-link",{attrs:{to:"/usage/webhooks.html#manual-gating"}},[t._v("manual promotion")]),t._v(" approval and\n"),e("router-link",{attrs:{to:"/usage/alerting.html"}},[t._v("Slack or MS Teams")]),t._v(" notifications.")],1)])},[],!1,null,null,null);a.default=n.exports}}]); \ No newline at end of file diff --git a/assets/js/5.f0e04ff6.js b/assets/js/5.f0e04ff6.js new file mode 100644 index 00000000..cba88192 --- /dev/null +++ b/assets/js/5.f0e04ff6.js @@ -0,0 +1 @@ +(window.webpackJsonp=window.webpackJsonp||[]).push([[5],{265:function(e,r,t){"use strict";t.r(r);var a=t(37),n=Object(a.a)({},function(){var e=this,r=e.$createElement,t=e._self._c||r;return t("ContentSlotsDistributor",{attrs:{"slot-key":e.$parent.slotKey}},[t("h2",{attrs:{id:"progressive-delivery"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#progressive-delivery","aria-hidden":"true"}},[e._v("#")]),e._v(" Progressive Delivery")]),e._v(" "),t("p",[e._v("Flagger was designed to give developers confidence in automating production releases with progressive delivery techniques.")]),e._v(" "),t("div",{staticClass:"tip custom-block"},[t("p",{staticClass:"custom-block-title"},[e._v("Canary release")]),e._v(" "),t("p",[e._v("A benefit of using canary releases is the ability to do capacity testing of the new version in a production environment\nwith a safe rollback strategy if issues are found. By slowly ramping up the load, you can monitor and capture metrics\nabout how the new version impacts the production environment.")]),e._v(" "),t("p",[t("a",{attrs:{href:"https://martinfowler.com/bliki/CanaryRelease.html",target:"_blank",rel:"noopener noreferrer"}},[e._v("Martin Fowler"),t("OutboundLink")],1)])]),e._v(" "),t("p",[e._v("Flagger can run automated application analysis, testing, promotion and rollback for the following deployment strategies:")]),e._v(" "),t("ul",[t("li",[t("p",[t("strong",[e._v("Canary")]),e._v(" (progressive traffic shifting)")]),e._v(" "),t("ul",[t("li",[t("a",{attrs:{href:"https://docs.flagger.app/tutorials/istio-progressive-delivery",target:"_blank",rel:"noopener noreferrer"}},[e._v("Istio"),t("OutboundLink")],1),e._v(",\n"),t("a",{attrs:{href:"https://docs.flagger.app/tutorials/linkerd-progressive-delivery",target:"_blank",rel:"noopener noreferrer"}},[e._v("Linkerd"),t("OutboundLink")],1),e._v(",\n"),t("a",{attrs:{href:"https://docs.flagger.app/tutorials/appmesh-progressive-delivery",target:"_blank",rel:"noopener noreferrer"}},[e._v("App Mesh"),t("OutboundLink")],1),e._v(",\n"),t("a",{attrs:{href:"https://docs.flagger.app/tutorials/contour-progressive-delivery",target:"_blank",rel:"noopener noreferrer"}},[e._v("Contour"),t("OutboundLink")],1),e._v(",\n"),t("a",{attrs:{href:"https://docs.flagger.app/tutorials/gloo-progressive-delivery",target:"_blank",rel:"noopener noreferrer"}},[e._v("Gloo"),t("OutboundLink")],1),e._v(",\n"),t("a",{attrs:{href:"https://docs.flagger.app/tutorials/nginx-progressive-delivery",target:"_blank",rel:"noopener noreferrer"}},[e._v("NGINX"),t("OutboundLink")],1)])])]),e._v(" "),t("li",[t("p",[t("strong",[e._v("A/B Testing")]),e._v(" (HTTP headers and cookies traffic routing)")]),e._v(" "),t("ul",[t("li",[t("a",{attrs:{href:"https://docs.flagger.app/tutorials/istio-ab-testing",target:"_blank",rel:"noopener noreferrer"}},[e._v("Istio"),t("OutboundLink")],1),e._v(",\n"),t("a",{attrs:{href:"https://docs.flagger.app/tutorials/appmesh-progressive-delivery#a-b-testing",target:"_blank",rel:"noopener noreferrer"}},[e._v("App Mesh"),t("OutboundLink")],1),e._v(",\n"),t("a",{attrs:{href:"https://docs.flagger.app/tutorials/contour-progressive-delivery#a-b-testing",target:"_blank",rel:"noopener noreferrer"}},[e._v("Contour"),t("OutboundLink")],1),e._v(",\n"),t("a",{attrs:{href:"https://docs.flagger.app/tutorials/nginx-progressive-delivery#a-b-testing",target:"_blank",rel:"noopener noreferrer"}},[e._v("NGINX"),t("OutboundLink")],1)])])]),e._v(" "),t("li",[t("p",[t("strong",[e._v("Blue/Green")]),e._v(" (traffic switching and mirroring)")]),e._v(" "),t("ul",[t("li",[t("a",{attrs:{href:"https://docs.flagger.app/tutorials/kubernetes-blue-green",target:"_blank",rel:"noopener noreferrer"}},[e._v("Kubernetes CNI"),t("OutboundLink")],1),e._v(",\n"),t("a",{attrs:{href:"https://docs.flagger.app/tutorials/istio-progressive-delivery#traffic-mirroring",target:"_blank",rel:"noopener noreferrer"}},[e._v("Istio"),t("OutboundLink")],1),e._v(",\nLinkerd, App Mesh, Contour, Gloo, NGINX")])])])]),e._v(" "),t("p",[e._v("Flagger can be configured to "),t("a",{attrs:{href:"https://docs.flagger.app/usage/alerting",target:"_blank",rel:"noopener noreferrer"}},[e._v("send notifications"),t("OutboundLink")],1),e._v(" to\nSlack, Microsoft Teams, Discord or Rocket.\nIt will post messages when a deployment has been initialised,\nwhen a new revision has been detected and if the canary analysis failed or succeeded.")]),e._v(" "),t("h2",{attrs:{id:"gitops"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#gitops","aria-hidden":"true"}},[e._v("#")]),e._v(" GitOps")]),e._v(" "),t("p",[t("img",{attrs:{src:"/flagger-gitops.png",alt:"GtiOps with Flagger and FluxCD"}})]),e._v(" "),t("p",[e._v("You can build fully automated GitOps pipelines for canary deployments with Flagger and\n"),t("a",{attrs:{href:"https://github.com/fluxcd/flux",target:"_blank",rel:"noopener noreferrer"}},[e._v("FluxCD"),t("OutboundLink")],1),e._v(" (CNCF sandbox project).")]),e._v(" "),t("div",{staticClass:"tip custom-block"},[t("p",{staticClass:"custom-block-title"},[e._v("GitOps")]),e._v(" "),t("p",[e._v("GitOps is a way to do Kubernetes cluster management and application delivery.\nIt works by using Git as a single source of truth for declarative infrastructure and applications.\nWith Git at the center of your delivery pipelines, developers can make pull requests\nto accelerate and simplify application deployments and operations tasks to Kubernetes.")]),e._v(" "),t("p",[t("a",{attrs:{href:"https://www.weave.works/technologies/gitops/",target:"_blank",rel:"noopener noreferrer"}},[e._v("Weaveworks"),t("OutboundLink")],1)])]),e._v(" "),t("p",[e._v("GitOps tutorials:")]),e._v(" "),t("ul",[t("li",[t("a",{attrs:{href:"https://github.com/stefanprodan/gitops-istio",target:"_blank",rel:"noopener noreferrer"}},[e._v("Progressive Delivery for Istio with Flagger and FluxCD"),t("OutboundLink")],1)]),e._v(" "),t("li",[t("a",{attrs:{href:"https://eks.handson.flagger.dev",target:"_blank",rel:"noopener noreferrer"}},[e._v("Progressive Delivery for AWS App Mesh with Flagger and FluxCD"),t("OutboundLink")],1)]),e._v(" "),t("li",[t("a",{attrs:{href:"https://helm.workshop.flagger.dev",target:"_blank",rel:"noopener noreferrer"}},[e._v("Progressive Delivery for Linkerd with Flagger, FluxCD and Helm v3"),t("OutboundLink")],1)])]),e._v(" "),t("h2",{attrs:{id:"getting-help"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#getting-help","aria-hidden":"true"}},[e._v("#")]),e._v(" Getting Help")]),e._v(" "),t("p",[e._v("If you have any questions about Flagger and progressive delivery:")]),e._v(" "),t("ul",[t("li",[e._v("Read the Flagger "),t("a",{attrs:{href:"https://docs.flagger.app",target:"_blank",rel:"noopener noreferrer"}},[e._v("docs"),t("OutboundLink")],1),e._v(".")]),e._v(" "),t("li",[e._v("Invite yourself to the "),t("a",{attrs:{href:"https://slack.weave.works/",target:"_blank",rel:"noopener noreferrer"}},[e._v("Weave community slack"),t("OutboundLink")],1),e._v("\nand join the "),t("a",{attrs:{href:"https://weave-community.slack.com/messages/flagger/",target:"_blank",rel:"noopener noreferrer"}},[e._v("#flagger"),t("OutboundLink")],1),e._v(" channel.")]),e._v(" "),t("li",[e._v("Join the "),t("a",{attrs:{href:"https://www.meetup.com/pro/Weave/",target:"_blank",rel:"noopener noreferrer"}},[e._v("Weave User Group"),t("OutboundLink")],1),e._v(" and get invited to online talks,\nhands-on training and meetups in your area.")]),e._v(" "),t("li",[e._v("File an "),t("a",{attrs:{href:"https://github.com/weaveworks/flagger/issues/new",target:"_blank",rel:"noopener noreferrer"}},[e._v("issue"),t("OutboundLink")],1),e._v(".")])]),e._v(" "),t("p",[e._v("Your feedback is always welcome!")])])},[],!1,null,null,null);r.default=n.exports}}]); \ No newline at end of file diff --git a/assets/js/5.f92a6aca.js b/assets/js/5.f92a6aca.js deleted file mode 100644 index c92b9214..00000000 --- a/assets/js/5.f92a6aca.js +++ /dev/null @@ -1 +0,0 @@ -(window.webpackJsonp=window.webpackJsonp||[]).push([[5],{265:function(e,r,t){"use strict";t.r(r);var a=t(37),n=Object(a.a)({},function(){var e=this,r=e.$createElement,t=e._self._c||r;return t("ContentSlotsDistributor",{attrs:{"slot-key":e.$parent.slotKey}},[t("h2",{attrs:{id:"progressive-delivery"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#progressive-delivery","aria-hidden":"true"}},[e._v("#")]),e._v(" Progressive Delivery")]),e._v(" "),t("p",[e._v("Flagger was designed to give developers confidence in automating production releases with progressive delivery techniques.")]),e._v(" "),t("div",{staticClass:"tip custom-block"},[t("p",{staticClass:"custom-block-title"},[e._v("Canary release")]),e._v(" "),t("p",[e._v("A benefit of using canary releases is the ability to do capacity testing of the new version in a production environment\nwith a safe rollback strategy if issues are found. By slowly ramping up the load, you can monitor and capture metrics\nabout how the new version impacts the production environment.")]),e._v(" "),t("p",[t("a",{attrs:{href:"https://martinfowler.com/bliki/CanaryRelease.html",target:"_blank",rel:"noopener noreferrer"}},[e._v("Martin Fowler"),t("OutboundLink")],1)])]),e._v(" "),t("p",[e._v("Flagger can run automated application analysis, testing, promotion and rollback for the following deployment strategies:")]),e._v(" "),t("ul",[t("li",[t("p",[t("strong",[e._v("Canary")]),e._v(" (progressive traffic shifting)")]),e._v(" "),t("ul",[t("li",[t("a",{attrs:{href:"https://docs.flagger.app/tutorials/istio-progressive-delivery",target:"_blank",rel:"noopener noreferrer"}},[e._v("Istio"),t("OutboundLink")],1),e._v(",\n"),t("a",{attrs:{href:"https://docs.flagger.app/tutorials/linkerd-progressive-delivery",target:"_blank",rel:"noopener noreferrer"}},[e._v("Linkerd"),t("OutboundLink")],1),e._v(",\n"),t("a",{attrs:{href:"https://docs.flagger.app/tutorials/appmesh-progressive-delivery",target:"_blank",rel:"noopener noreferrer"}},[e._v("App Mesh"),t("OutboundLink")],1),e._v(",\n"),t("a",{attrs:{href:"https://docs.flagger.app/tutorials/contour-progressive-delivery",target:"_blank",rel:"noopener noreferrer"}},[e._v("Contour"),t("OutboundLink")],1),e._v(",\n"),t("a",{attrs:{href:"https://docs.flagger.app/tutorials/gloo-progressive-delivery",target:"_blank",rel:"noopener noreferrer"}},[e._v("Gloo"),t("OutboundLink")],1),e._v(",\n"),t("a",{attrs:{href:"https://docs.flagger.app/tutorials/nginx-progressive-delivery",target:"_blank",rel:"noopener noreferrer"}},[e._v("NGINX"),t("OutboundLink")],1)])])]),e._v(" "),t("li",[t("p",[t("strong",[e._v("A/B Testing")]),e._v(" (HTTP headers and cookies traffic routing)")]),e._v(" "),t("ul",[t("li",[t("a",{attrs:{href:"https://docs.flagger.app/tutorials/istio-ab-testing",target:"_blank",rel:"noopener noreferrer"}},[e._v("Istio"),t("OutboundLink")],1),e._v(",\n"),t("a",{attrs:{href:"hhttps://docs.flagger.app/tutorials/appmesh-progressive-delivery#a-b-testing"}},[e._v("App Mesh")]),e._v(",\n"),t("a",{attrs:{href:"https://docs.flagger.app/tutorials/contour-progressive-delivery#a-b-testing",target:"_blank",rel:"noopener noreferrer"}},[e._v("Contour"),t("OutboundLink")],1),e._v(",\n"),t("a",{attrs:{href:"https://docs.flagger.app/tutorials/nginx-progressive-delivery#a-b-testing",target:"_blank",rel:"noopener noreferrer"}},[e._v("NGINX"),t("OutboundLink")],1)])])]),e._v(" "),t("li",[t("p",[t("strong",[e._v("Blue/Green")]),e._v(" (traffic switching and mirroring)")]),e._v(" "),t("ul",[t("li",[t("a",{attrs:{href:"https://docs.flagger.app/tutorials/kubernetes-blue-green",target:"_blank",rel:"noopener noreferrer"}},[e._v("Kubernetes CNI"),t("OutboundLink")],1),e._v(",\n"),t("a",{attrs:{href:"https://docs.flagger.app/tutorials/istio-progressive-delivery#traffic-mirroring",target:"_blank",rel:"noopener noreferrer"}},[e._v("Istio"),t("OutboundLink")],1),e._v(",\nLinkerd, App Mesh, Contour, Gloo, NGINX")])])])]),e._v(" "),t("p",[e._v("Flagger can be configured to "),t("a",{attrs:{href:"https://docs.flagger.app/usage/alerting",target:"_blank",rel:"noopener noreferrer"}},[e._v("send notifications"),t("OutboundLink")],1),e._v(" to\nSlack, Microsoft Teams, Discord or Rocket.\nIt will post messages when a deployment has been initialised,\nwhen a new revision has been detected and if the canary analysis failed or succeeded.")]),e._v(" "),t("h2",{attrs:{id:"gitops"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#gitops","aria-hidden":"true"}},[e._v("#")]),e._v(" GitOps")]),e._v(" "),t("p",[t("img",{attrs:{src:"/flagger-gitops.png",alt:"GtiOps with Flagger and FluxCD"}})]),e._v(" "),t("p",[e._v("You can build fully automated GitOps pipelines for canary deployments with Flagger and\n"),t("a",{attrs:{href:"https://github.com/fluxcd/flux",target:"_blank",rel:"noopener noreferrer"}},[e._v("FluxCD"),t("OutboundLink")],1),e._v(" (CNCF sandbox project).")]),e._v(" "),t("div",{staticClass:"tip custom-block"},[t("p",{staticClass:"custom-block-title"},[e._v("GitOps")]),e._v(" "),t("p",[e._v("GitOps is a way to do Kubernetes cluster management and application delivery.\nIt works by using Git as a single source of truth for declarative infrastructure and applications.\nWith Git at the center of your delivery pipelines, developers can make pull requests\nto accelerate and simplify application deployments and operations tasks to Kubernetes.")]),e._v(" "),t("p",[t("a",{attrs:{href:"https://www.weave.works/technologies/gitops/",target:"_blank",rel:"noopener noreferrer"}},[e._v("Weaveworks"),t("OutboundLink")],1)])]),e._v(" "),t("p",[e._v("GitOps tutorials:")]),e._v(" "),t("ul",[t("li",[t("a",{attrs:{href:"https://github.com/stefanprodan/gitops-istio",target:"_blank",rel:"noopener noreferrer"}},[e._v("Progressive Delivery for Istio with Flagger and FluxCD"),t("OutboundLink")],1)]),e._v(" "),t("li",[t("a",{attrs:{href:"https://eks.hands-on.flagger.dev",target:"_blank",rel:"noopener noreferrer"}},[e._v("Progressive Delivery for AWS App Mesh with Flagger and FluxCD"),t("OutboundLink")],1)]),e._v(" "),t("li",[t("a",{attrs:{href:"https://helm.workshop.flagger.dev",target:"_blank",rel:"noopener noreferrer"}},[e._v("Progressive Delivery for Linkerd with Flagger, FluxCD and Helm v3"),t("OutboundLink")],1)])]),e._v(" "),t("h2",{attrs:{id:"getting-help"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#getting-help","aria-hidden":"true"}},[e._v("#")]),e._v(" Getting Help")]),e._v(" "),t("p",[e._v("If you have any questions about Flagger and progressive delivery:")]),e._v(" "),t("ul",[t("li",[e._v("Read the Flagger "),t("a",{attrs:{href:"https://docs.flagger.app",target:"_blank",rel:"noopener noreferrer"}},[e._v("docs"),t("OutboundLink")],1),e._v(".")]),e._v(" "),t("li",[e._v("Invite yourself to the "),t("a",{attrs:{href:"https://slack.weave.works/",target:"_blank",rel:"noopener noreferrer"}},[e._v("Weave community slack"),t("OutboundLink")],1),e._v("\nand join the "),t("a",{attrs:{href:"https://weave-community.slack.com/messages/flagger/",target:"_blank",rel:"noopener noreferrer"}},[e._v("#flagger"),t("OutboundLink")],1),e._v(" channel.")]),e._v(" "),t("li",[e._v("Join the "),t("a",{attrs:{href:"https://www.meetup.com/pro/Weave/",target:"_blank",rel:"noopener noreferrer"}},[e._v("Weave User Group"),t("OutboundLink")],1),e._v(" and get invited to online talks,\nhands-on training and meetups in your area.")]),e._v(" "),t("li",[e._v("File an "),t("a",{attrs:{href:"https://github.com/weaveworks/flagger/issues/new",target:"_blank",rel:"noopener noreferrer"}},[e._v("issue"),t("OutboundLink")],1),e._v(".")])]),e._v(" "),t("p",[e._v("Your feedback is always welcome!")])])},[],!1,null,null,null);r.default=n.exports}}]); \ No newline at end of file diff --git a/assets/js/app.b4b27991.js b/assets/js/app.67d16e10.js similarity index 96% rename from assets/js/app.b4b27991.js rename to assets/js/app.67d16e10.js index 13af667f..a0e1e10e 100644 --- a/assets/js/app.b4b27991.js +++ b/assets/js/app.67d16e10.js @@ -1,8 +1,8 @@ -(window.webpackJsonp=window.webpackJsonp||[]).push([[0],[]]);!function(t){function e(e){for(var r,a,s=e[0],u=e[1],c=e[2],f=0,p=[];f0?o(r(t),9007199254740991):0}},function(t,e,n){var r=n(7),o=n(17),i=n(22),a=n(41)("src"),s=n(143),u=(""+s).split("toString");n(28).inspectSource=function(t){return s.call(t)},(t.exports=function(t,e,n,s){var c="function"==typeof n;c&&(i(n,"name")||o(n,"name",e)),t[e]!==n&&(c&&(i(n,a)||o(n,a,t[e]?""+t[e]:u.join(String(e)))),t===r?t[e]=n:s?t[e]?t[e]=n:o(t,e,n):(delete t[e],o(t,e,n)))})(Function.prototype,"toString",function(){return"function"==typeof this&&this[a]||s.call(this)})},function(t,e){var n={}.hasOwnProperty;t.exports=function(t,e){return n.call(t,e)}},function(t,e,n){var r=n(45);t.exports=function(t,e,n){if(r(t),void 0===e)return t;switch(n){case 1:return function(n){return t.call(e,n)};case 2:return function(n,r){return t.call(e,n,r)};case 3:return function(n,r,o){return t.call(e,n,r,o)}}return function(){return t.apply(e,arguments)}}},function(t,e){t.exports={}},function(t,e,n){var r=n(165),o=n(68);t.exports=function(t){return r(o(t))}},function(t,e){t.exports=function(t){if(null==t)throw TypeError("Can't call method on "+t);return t}},function(t,e,n){"use strict";var r=n(16);t.exports=function(t,e){return!!t&&r(function(){e?t.call(null,function(){},1):t.call(null)})}},function(t,e){var n=t.exports={version:"2.6.9"};"number"==typeof __e&&(__e=n)},function(t,e,n){var r=n(88);t.exports=function(t,e,n){if(r(t),void 0===e)return t;switch(n){case 1:return function(n){return t.call(e,n)};case 2:return function(n,r){return t.call(e,n,r)};case 3:return function(n,r,o){return t.call(e,n,r,o)}}return function(){return t.apply(e,arguments)}}},function(t,e,n){var r=n(26);t.exports=function(t){return Object(r(t))}},function(t,e){t.exports={}},function(t,e,n){var r=n(58),o=n(26);t.exports=function(t){return r(o(t))}},function(t,e){t.exports=!0},function(t,e){t.exports=function(t){try{return!!t()}catch(t){return!0}}},function(t,e){t.exports=function(t,e){return{enumerable:!(1&t),configurable:!(2&t),writable:!(4&t),value:e}}},function(t,e){var n={}.toString;t.exports=function(t){return n.call(t).slice(8,-1)}},function(t,e,n){"use strict";function r(t,e,n,r,o,i,a,s){var u,c="function"==typeof t?t.options:t;if(e&&(c.render=e,c.staticRenderFns=n,c._compiled=!0),r&&(c.functional=!0),i&&(c._scopeId="data-v-"+i),a?(u=function(t){(t=t||this.$vnode&&this.$vnode.ssrContext||this.parent&&this.parent.$vnode&&this.parent.$vnode.ssrContext)||"undefined"==typeof __VUE_SSR_CONTEXT__||(t=__VUE_SSR_CONTEXT__),o&&o.call(this,t),t&&t._registeredComponents&&t._registeredComponents.add(a)},c._ssrRegister=u):o&&(u=s?function(){o.call(this,this.$root.$options.shadowRoot)}:o),u)if(c.functional){c._injectStyles=u;var l=c.render;c.render=function(t,e){return u.call(e),l(t,e)}}else{var f=c.beforeCreate;c.beforeCreate=f?[].concat(f,u):[u]}return{exports:t,options:c}}n.d(e,"a",function(){return r})},function(t,e,n){for(var r=n(146),o=n(61),i=n(21),a=n(7),s=n(17),u=n(31),c=n(2),l=c("iterator"),f=c("toStringTag"),p=u.Array,h={CSSRuleList:!0,CSSStyleDeclaration:!1,CSSValueList:!1,ClientRectList:!1,DOMRectList:!1,DOMStringList:!1,DOMTokenList:!0,DataTransferItemList:!1,FileList:!1,HTMLAllCollection:!1,HTMLCollection:!1,HTMLFormElement:!1,HTMLSelectElement:!1,MediaList:!0,MimeTypeArray:!1,NamedNodeMap:!1,NodeList:!0,PaintRequestList:!1,Plugin:!1,PluginArray:!1,SVGLengthList:!1,SVGNumberList:!1,SVGPathSegList:!1,SVGPointList:!1,SVGStringList:!1,SVGTransformList:!1,SourceBufferList:!1,StyleSheetList:!0,TextTrackCueList:!1,TextTrackList:!1,TouchList:!1},d=o(h),v=0;v0?r:n)(t)}},function(t,e,n){"use strict";var r=n(162)(!0);n(101)(String,"String",function(t){this._t=String(t),this._i=0},function(){var t,e=this._t,n=this._i;return n>=e.length?{value:void 0,done:!0}:(t=r(e,n),this._i+=t.length,{value:t,done:!1})})},function(t,e){t.exports=function(t){if("function"!=typeof t)throw TypeError(t+" is not a function!");return t}},function(t,e){var n=0,r=Math.random();t.exports=function(t){return"Symbol(".concat(void 0===t?"":t,")_",(++n+r).toString(36))}},function(t,e,n){var r=n(9).f,o=n(19),i=n(4)("toStringTag");t.exports=function(t,e,n){t&&!o(t=n?t:t.prototype,i)&&r(t,i,{configurable:!0,value:e})}},function(t,e,n){var r=n(68);t.exports=function(t){return Object(r(t))}},function(t,e,n){var r=n(12).f,o=Function.prototype,i=/^\s*function ([^ (]*)/;"name"in o||n(13)&&r(o,"name",{configurable:!0,get:function(){try{return(""+this).match(i)[1]}catch(t){return""}}})},function(t,e,n){},function(t,e,n){"use strict";var r=n(127),o=n.n(r);var i=n(128),a=n.n(i),s=n(129),u=n.n(s);function c(t){return function(t){if(o()(t)){for(var e=0,n=new Array(t.length);e0?o(r(t),9007199254740991):0}},function(t,e,n){var r=n(7),o=n(17),i=n(22),a=n(41)("src"),s=n(143),u=(""+s).split("toString");n(28).inspectSource=function(t){return s.call(t)},(t.exports=function(t,e,n,s){var c="function"==typeof n;c&&(i(n,"name")||o(n,"name",e)),t[e]!==n&&(c&&(i(n,a)||o(n,a,t[e]?""+t[e]:u.join(String(e)))),t===r?t[e]=n:s?t[e]?t[e]=n:o(t,e,n):(delete t[e],o(t,e,n)))})(Function.prototype,"toString",function(){return"function"==typeof this&&this[a]||s.call(this)})},function(t,e){var n={}.hasOwnProperty;t.exports=function(t,e){return n.call(t,e)}},function(t,e,n){var r=n(45);t.exports=function(t,e,n){if(r(t),void 0===e)return t;switch(n){case 1:return function(n){return t.call(e,n)};case 2:return function(n,r){return t.call(e,n,r)};case 3:return function(n,r,o){return t.call(e,n,r,o)}}return function(){return t.apply(e,arguments)}}},function(t,e){t.exports={}},function(t,e,n){var r=n(165),o=n(68);t.exports=function(t){return r(o(t))}},function(t,e){t.exports=function(t){if(null==t)throw TypeError("Can't call method on "+t);return t}},function(t,e,n){"use strict";var r=n(16);t.exports=function(t,e){return!!t&&r(function(){e?t.call(null,function(){},1):t.call(null)})}},function(t,e){var n=t.exports={version:"2.6.9"};"number"==typeof __e&&(__e=n)},function(t,e,n){var r=n(88);t.exports=function(t,e,n){if(r(t),void 0===e)return t;switch(n){case 1:return function(n){return t.call(e,n)};case 2:return function(n,r){return t.call(e,n,r)};case 3:return function(n,r,o){return t.call(e,n,r,o)}}return function(){return t.apply(e,arguments)}}},function(t,e,n){var r=n(26);t.exports=function(t){return Object(r(t))}},function(t,e){t.exports={}},function(t,e,n){var r=n(58),o=n(26);t.exports=function(t){return r(o(t))}},function(t,e){t.exports=!0},function(t,e){t.exports=function(t){try{return!!t()}catch(t){return!0}}},function(t,e){t.exports=function(t,e){return{enumerable:!(1&t),configurable:!(2&t),writable:!(4&t),value:e}}},function(t,e){var n={}.toString;t.exports=function(t){return n.call(t).slice(8,-1)}},function(t,e,n){"use strict";function r(t,e,n,r,o,i,a,s){var u,c="function"==typeof t?t.options:t;if(e&&(c.render=e,c.staticRenderFns=n,c._compiled=!0),r&&(c.functional=!0),i&&(c._scopeId="data-v-"+i),a?(u=function(t){(t=t||this.$vnode&&this.$vnode.ssrContext||this.parent&&this.parent.$vnode&&this.parent.$vnode.ssrContext)||"undefined"==typeof __VUE_SSR_CONTEXT__||(t=__VUE_SSR_CONTEXT__),o&&o.call(this,t),t&&t._registeredComponents&&t._registeredComponents.add(a)},c._ssrRegister=u):o&&(u=s?function(){o.call(this,this.$root.$options.shadowRoot)}:o),u)if(c.functional){c._injectStyles=u;var l=c.render;c.render=function(t,e){return u.call(e),l(t,e)}}else{var f=c.beforeCreate;c.beforeCreate=f?[].concat(f,u):[u]}return{exports:t,options:c}}n.d(e,"a",function(){return r})},function(t,e,n){for(var r=n(146),o=n(61),i=n(21),a=n(7),s=n(17),u=n(31),c=n(2),l=c("iterator"),f=c("toStringTag"),p=u.Array,h={CSSRuleList:!0,CSSStyleDeclaration:!1,CSSValueList:!1,ClientRectList:!1,DOMRectList:!1,DOMStringList:!1,DOMTokenList:!0,DataTransferItemList:!1,FileList:!1,HTMLAllCollection:!1,HTMLCollection:!1,HTMLFormElement:!1,HTMLSelectElement:!1,MediaList:!0,MimeTypeArray:!1,NamedNodeMap:!1,NodeList:!0,PaintRequestList:!1,Plugin:!1,PluginArray:!1,SVGLengthList:!1,SVGNumberList:!1,SVGPathSegList:!1,SVGPointList:!1,SVGStringList:!1,SVGTransformList:!1,SourceBufferList:!1,StyleSheetList:!0,TextTrackCueList:!1,TextTrackList:!1,TouchList:!1},d=o(h),v=0;v0?r:n)(t)}},function(t,e,n){"use strict";var r=n(162)(!0);n(101)(String,"String",function(t){this._t=String(t),this._i=0},function(){var t,e=this._t,n=this._i;return n>=e.length?{value:void 0,done:!0}:(t=r(e,n),this._i+=t.length,{value:t,done:!1})})},function(t,e){t.exports=function(t){if("function"!=typeof t)throw TypeError(t+" is not a function!");return t}},function(t,e){var n=0,r=Math.random();t.exports=function(t){return"Symbol(".concat(void 0===t?"":t,")_",(++n+r).toString(36))}},function(t,e,n){var r=n(9).f,o=n(19),i=n(4)("toStringTag");t.exports=function(t,e,n){t&&!o(t=n?t:t.prototype,i)&&r(t,i,{configurable:!0,value:e})}},function(t,e,n){var r=n(68);t.exports=function(t){return Object(r(t))}},function(t,e,n){var r=n(12).f,o=Function.prototype,i=/^\s*function ([^ (]*)/;"name"in o||n(13)&&r(o,"name",{configurable:!0,get:function(){try{return(""+this).match(i)[1]}catch(t){return""}}})},function(t,e,n){},function(t,e,n){"use strict";var r=n(127),o=n.n(r);var i=n(128),a=n.n(i),s=n(129),u=n.n(s);function c(t){return function(t){if(o()(t)){for(var e=0,n=new Array(t.length);e
'};function o(t,e,n){return tn?n:t}function i(t){return 100*(-1+t)}n.configure=function(t){var e,n;for(e in t)void 0!==(n=t[e])&&t.hasOwnProperty(e)&&(r[e]=n);return this},n.status=null,n.set=function(t){var e=n.isStarted();t=o(t,r.minimum,1),n.status=1===t?null:t;var u=n.render(!e),c=u.querySelector(r.barSelector),l=r.speed,f=r.easing;return u.offsetWidth,a(function(e){""===r.positionUsing&&(r.positionUsing=n.getPositioningCSS()),s(c,function(t,e,n){var o;return(o="translate3d"===r.positionUsing?{transform:"translate3d("+i(t)+"%,0,0)"}:"translate"===r.positionUsing?{transform:"translate("+i(t)+"%,0)"}:{"margin-left":i(t)+"%"}).transition="all "+e+"ms "+n,o}(t,l,f)),1===t?(s(u,{transition:"none",opacity:1}),u.offsetWidth,setTimeout(function(){s(u,{transition:"all "+l+"ms linear",opacity:0}),setTimeout(function(){n.remove(),e()},l)},l)):setTimeout(e,l)}),this},n.isStarted=function(){return"number"==typeof n.status},n.start=function(){n.status||n.set(0);var t=function(){setTimeout(function(){n.status&&(n.trickle(),t())},r.trickleSpeed)};return r.trickle&&t(),this},n.done=function(t){return t||n.status?n.inc(.3+.5*Math.random()).set(1):this},n.inc=function(t){var e=n.status;return e?("number"!=typeof t&&(t=(1-e)*o(Math.random()*e,.1,.95)),e=o(e+t,0,.994),n.set(e)):n.start()},n.trickle=function(){return n.inc(Math.random()*r.trickleRate)},t=0,e=0,n.promise=function(r){return r&&"resolved"!==r.state()?(0===e&&n.start(),t++,e++,r.always(function(){0==--e?(t=0,n.done()):n.set((t-e)/t)}),this):this},n.render=function(t){if(n.isRendered())return document.getElementById("nprogress");c(document.documentElement,"nprogress-busy");var e=document.createElement("div");e.id="nprogress",e.innerHTML=r.template;var o,a=e.querySelector(r.barSelector),u=t?"-100":i(n.status||0),l=document.querySelector(r.parent);return s(a,{transition:"all 0 linear",transform:"translate3d("+u+"%,0,0)"}),r.showSpinner||(o=e.querySelector(r.spinnerSelector))&&p(o),l!=document.body&&c(l,"nprogress-custom-parent"),l.appendChild(e),e},n.remove=function(){l(document.documentElement,"nprogress-busy"),l(document.querySelector(r.parent),"nprogress-custom-parent");var t=document.getElementById("nprogress");t&&p(t)},n.isRendered=function(){return!!document.getElementById("nprogress")},n.getPositioningCSS=function(){var t=document.body.style,e="WebkitTransform"in t?"Webkit":"MozTransform"in t?"Moz":"msTransform"in t?"ms":"OTransform"in t?"O":"";return e+"Perspective"in t?"translate3d":e+"Transform"in t?"translate":"margin"};var a=function(){var t=[];function e(){var n=t.shift();n&&n(e)}return function(n){t.push(n),1==t.length&&e()}}(),s=function(){var t=["Webkit","O","Moz","ms"],e={};function n(n){return n=n.replace(/^-ms-/,"ms-").replace(/-([\da-z])/gi,function(t,e){return e.toUpperCase()}),e[n]||(e[n]=function(e){var n=document.body.style;if(e in n)return e;for(var r,o=t.length,i=e.charAt(0).toUpperCase()+e.slice(1);o--;)if((r=t[o]+i)in n)return r;return e}(n))}function r(t,e,r){e=n(e),t.style[e]=r}return function(t,e){var n,o,i=arguments;if(2==i.length)for(n in e)void 0!==(o=e[n])&&e.hasOwnProperty(n)&&r(t,n,o);else r(t,i[1],i[2])}}();function u(t,e){return("string"==typeof t?t:f(t)).indexOf(" "+e+" ")>=0}function c(t,e){var n=f(t),r=n+e;u(n,e)||(t.className=r.substring(1))}function l(t,e){var n,r=f(t);u(t,e)&&(n=r.replace(" "+e+" "," "),t.className=n.substring(1,n.length-1))}function f(t){return(" "+(t.className||"")+" ").replace(/\s+/gi," ")}function p(t){t&&t.parentNode&&t.parentNode.removeChild(t)}return n})?r.call(e,n,e,t):r)||(t.exports=o)},function(t,e,n){"use strict";var r=n(1),o=n(55)(1);r(r.P+r.F*!n(27)([].map,!0),"Array",{map:function(t){return o(this,t,arguments[1])}})},function(t,e,n){var r=n(29),o=n(58),i=n(30),a=n(20),s=n(144);t.exports=function(t,e){var n=1==t,u=2==t,c=3==t,l=4==t,f=6==t,p=5==t||f,h=e||s;return function(e,s,d){for(var v,m,y=i(e),g=o(y),b=r(s,d,3),_=a(g.length),w=0,x=n?h(e,_):u?h(e,0):void 0;_>w;w++)if((p||w in g)&&(m=b(v=g[w],w,y),t))if(n)x[w]=m;else if(m)switch(t){case 3:return!0;case 5:return v;case 6:return w;case 2:x.push(v)}else if(l)return!1;return f?-1:c||l?l:x}}},function(t,e,n){"use strict";var r=n(1),o=n(55)(0),i=n(27)([].forEach,!0);r(r.P+r.F*!i,"Array",{forEach:function(t){return o(this,t,arguments[1])}})},function(t,e,n){var r=n(28),o=n(7),i=o["__core-js_shared__"]||(o["__core-js_shared__"]={});(t.exports=function(t,e){return i[t]||(i[t]=void 0!==e?e:{})})("versions",[]).push({version:r.version,mode:n(94)?"pure":"global",copyright:"© 2019 Denis Pushkarev (zloirock.ru)"})},function(t,e,n){var r=n(42);t.exports=Object("z").propertyIsEnumerable(0)?Object:function(t){return"String"==r(t)?t.split(""):Object(t)}},function(t,e,n){"use strict";var r=n(94),o=n(1),i=n(21),a=n(17),s=n(31),u=n(147),c=n(65),l=n(151),f=n(2)("iterator"),p=!([].keys&&"next"in[].keys()),h=function(){return this};t.exports=function(t,e,n,d,v,m,y){u(n,e,d);var g,b,_,w=function(t){if(!p&&t in S)return S[t];switch(t){case"keys":case"values":return function(){return new n(this,t)}}return function(){return new n(this,t)}},x=e+" Iterator",k="values"==v,O=!1,S=t.prototype,C=S[f]||S["@@iterator"]||v&&S[v],A=C||w(v),E=v?k?w("entries"):A:void 0,$="Array"==e&&S.entries||C;if($&&(_=l($.call(new t)))!==Object.prototype&&_.next&&(c(_,x,!0),r||"function"==typeof _[f]||a(_,f,h)),k&&C&&"values"!==C.name&&(O=!0,A=function(){return C.call(this)}),r&&!y||!p&&!O&&S[f]||a(S,f,A),s[e]=A,s[x]=h,v)if(g={values:k?A:w("values"),keys:m?A:w("keys"),entries:E},y)for(b in g)b in S||i(S,b,g[b]);else o(o.P+o.F*(p||O),e,g);return g}},function(t,e,n){var r=n(8),o=n(148),i=n(64),a=n(63)("IE_PROTO"),s=function(){},u=function(){var t,e=n(92)("iframe"),r=i.length;for(e.style.display="none",n(150).appendChild(e),e.src="javascript:",(t=e.contentWindow.document).open(),t.write(" + diff --git a/dev/index.html b/dev/index.html index d9557640..9d10de91 100644 --- a/dev/index.html +++ b/dev/index.html @@ -13,7 +13,7 @@ - + @@ -30,6 +30,6 @@ GitHub
- + diff --git a/dev/release-guide.html b/dev/release-guide.html index be4f36d5..408200d8 100644 --- a/dev/release-guide.html +++ b/dev/release-guide.html @@ -13,7 +13,7 @@ - + @@ -38,6 +38,6 @@ →

- + diff --git a/dev/upgrade-guide.html b/dev/upgrade-guide.html index 23668aab..a6178d36 100644 --- a/dev/upgrade-guide.html +++ b/dev/upgrade-guide.html @@ -13,7 +13,7 @@ - + @@ -45,6 +45,6 @@ do the upgrade, wait for Flagger to finish the no-op promotions and finally set

- + diff --git a/index.html b/index.html index b3b692e0..aafa1d4a 100644 --- a/index.html +++ b/index.html @@ -13,7 +13,7 @@ - + @@ -41,7 +41,7 @@ about how the new version impacts the production environment.

Contour, Gloo, NGINX

  • A/B Testing (HTTP headers and cookies traffic routing)

  • Blue/Green (traffic switching and mirroring)

    • Kubernetes CNI, Istio, @@ -52,11 +52,11 @@ when a new revision has been detected and if the canary analysis failed or succe FluxCD (CNCF sandbox project).

      GitOps

      GitOps is a way to do Kubernetes cluster management and application delivery. It works by using Git as a single source of truth for declarative infrastructure and applications. With Git at the center of your delivery pipelines, developers can make pull requests -to accelerate and simplify application deployments and operations tasks to Kubernetes.

      Weaveworks

      GitOps tutorials:

      Getting Help

      If you have any questions about Flagger and progressive delivery:

      • Read the Flagger docs.
      • Invite yourself to the Weave community slack +to accelerate and simplify application deployments and operations tasks to Kubernetes.

        Weaveworks

        GitOps tutorials:

        Getting Help

        If you have any questions about Flagger and progressive delivery:

        Your feedback is always welcome!

        - + diff --git a/install/flagger-install-on-eks-appmesh.html b/install/flagger-install-on-eks-appmesh.html index ab5ade52..6ae0a932 100644 --- a/install/flagger-install-on-eks-appmesh.html +++ b/install/flagger-install-on-eks-appmesh.html @@ -13,7 +13,7 @@ - + @@ -92,6 +92,6 @@ Status: →

        - + diff --git a/install/flagger-install-on-google-cloud.html b/install/flagger-install-on-google-cloud.html index 6902ee06..86013398 100644 --- a/install/flagger-install-on-google-cloud.html +++ b/install/flagger-install-on-google-cloud.html @@ -13,7 +13,7 @@ - + @@ -203,6 +203,6 @@ https://storage.googleapis.com/gke-release/istio/release/1.0.6-gke.3/patches/ins →

        - + diff --git a/install/flagger-install-on-kubernetes.html b/install/flagger-install-on-kubernetes.html index 83d7754e..07e01a6d 100644 --- a/install/flagger-install-on-kubernetes.html +++ b/install/flagger-install-on-kubernetes.html @@ -13,7 +13,7 @@ - + @@ -146,6 +146,6 @@ to https://outlook.office.com/webhook/YOUR/TEAMS/WEBHOOK.

        - + diff --git a/install/index.html b/install/index.html index e2541096..a3f89ab3 100644 --- a/install/index.html +++ b/install/index.html @@ -13,7 +13,7 @@ - + @@ -30,6 +30,6 @@ GitHub
        - + diff --git a/intro/faq.html b/intro/faq.html index ad689fe1..a270c1c6 100644 --- a/intro/faq.html +++ b/intro/faq.html @@ -13,7 +13,7 @@ - + @@ -478,6 +478,6 @@ the two services and the website rule will be moved to the end of the list in th →

        - + diff --git a/intro/index.html b/intro/index.html index ea94770a..af551889 100644 --- a/intro/index.html +++ b/intro/index.html @@ -13,7 +13,7 @@ - + @@ -46,6 +46,6 @@ and install Flagger with →

        - + diff --git a/tutorials/appmesh-progressive-delivery.html b/tutorials/appmesh-progressive-delivery.html index 9be64f57..c109a4ac 100644 --- a/tutorials/appmesh-progressive-delivery.html +++ b/tutorials/appmesh-progressive-delivery.html @@ -13,7 +13,7 @@ - + @@ -263,6 +263,6 @@ Promotion completed! Scaling down podinfo.test →

        - + diff --git a/tutorials/canary-helm-gitops.html b/tutorials/canary-helm-gitops.html index 1cbd0d63..1ed6c278 100644 --- a/tutorials/canary-helm-gitops.html +++ b/tutorials/canary-helm-gitops.html @@ -13,7 +13,7 @@ - + @@ -216,6 +216,6 @@ and - + diff --git a/tutorials/contour-progressive-delivery.html b/tutorials/contour-progressive-delivery.html index 44775882..cc82a3b0 100644 --- a/tutorials/contour-progressive-delivery.html +++ b/tutorials/contour-progressive-delivery.html @@ -13,7 +13,7 @@ - + @@ -268,6 +268,6 @@ Promotion completed! Scaling down podinfo.test

        - + diff --git a/tutorials/crossover-progressive-delivery.html b/tutorials/crossover-progressive-delivery.html index f7de19a7..159ef2ce 100644 --- a/tutorials/crossover-progressive-delivery.html +++ b/tutorials/crossover-progressive-delivery.html @@ -13,7 +13,7 @@ - + @@ -210,6 +210,6 @@ Rolling back podinfo.test failed checks threshold reached 5 Canary failed! Scaling down podinfo.test

        If you’ve enabled the Slack notifications, you’ll receive a message if the progress deadline is exceeded, or if the analysis reached the maximum number of failed checks:

        Flagger Slack Notifications

        - + diff --git a/tutorials/flagger-smi-istio.html b/tutorials/flagger-smi-istio.html index 0c25b20e..a8f0eb98 100644 --- a/tutorials/flagger-smi-istio.html +++ b/tutorials/flagger-smi-istio.html @@ -13,7 +13,7 @@ - + @@ -187,6 +187,6 @@ Events: Warning Synced 1m flagger Rolling back podinfo.test failed checks threshold reached 10 Warning Synced 1m flagger Canary failed! Scaling down podinfo.test
        - + diff --git a/tutorials/gloo-progressive-delivery.html b/tutorials/gloo-progressive-delivery.html index 8588a9dd..226df730 100644 --- a/tutorials/gloo-progressive-delivery.html +++ b/tutorials/gloo-progressive-delivery.html @@ -13,7 +13,7 @@ - + @@ -266,6 +266,6 @@ Flagger will send a notification with the reason why the canary failed.

        F →

        - + diff --git a/tutorials/index.html b/tutorials/index.html index 32e74ce7..832d8f65 100644 --- a/tutorials/index.html +++ b/tutorials/index.html @@ -13,7 +13,7 @@ - + @@ -30,6 +30,6 @@ GitHub
        - + diff --git a/tutorials/istio-ab-testing.html b/tutorials/istio-ab-testing.html index 5464b7c9..ce55eacb 100644 --- a/tutorials/istio-ab-testing.html +++ b/tutorials/istio-ab-testing.html @@ -13,7 +13,7 @@ - + @@ -198,6 +198,6 @@ Events: →

        - + diff --git a/tutorials/istio-progressive-delivery.html b/tutorials/istio-progressive-delivery.html index 56075c2b..ada8d314 100644 --- a/tutorials/istio-progressive-delivery.html +++ b/tutorials/istio-progressive-delivery.html @@ -13,7 +13,7 @@ - + @@ -258,6 +258,6 @@ Metrics are collected on both requests so that the deployment will only proceed →

        - + diff --git a/tutorials/kubernetes-blue-green.html b/tutorials/kubernetes-blue-green.html index e5321698..74d333c2 100644 --- a/tutorials/kubernetes-blue-green.html +++ b/tutorials/kubernetes-blue-green.html @@ -13,7 +13,7 @@ - + @@ -248,6 +248,6 @@ If the helm test fails, Flagger will retry until the analysis threshold is reach →

        - + diff --git a/tutorials/linkerd-progressive-delivery.html b/tutorials/linkerd-progressive-delivery.html index 0cab342d..220e7e2a 100644 --- a/tutorials/linkerd-progressive-delivery.html +++ b/tutorials/linkerd-progressive-delivery.html @@ -13,7 +13,7 @@ - + @@ -340,6 +340,6 @@ Events: →

        - + diff --git a/tutorials/nginx-progressive-delivery.html b/tutorials/nginx-progressive-delivery.html index 9ab0c9e5..5d589d8a 100644 --- a/tutorials/nginx-progressive-delivery.html +++ b/tutorials/nginx-progressive-delivery.html @@ -13,7 +13,7 @@ - + @@ -319,6 +319,6 @@ Events: →

        - + diff --git a/tutorials/zero-downtime-deployments.html b/tutorials/zero-downtime-deployments.html index 3875ed89..d6c94444 100644 --- a/tutorials/zero-downtime-deployments.html +++ b/tutorials/zero-downtime-deployments.html @@ -13,7 +13,7 @@ - + @@ -135,6 +135,6 @@ perTryTimeout: 5s retryOn: "gateway-error,connect-failure,refused-stream"

        When the HPA scales down your app, your users could run into 503 errors. The above configuration will make Envoy retry the HTTP requests that failed due to gateway errors.

        - + diff --git a/usage/alerting.html b/usage/alerting.html index c97c98fc..877a0e12 100644 --- a/usage/alerting.html +++ b/usage/alerting.html @@ -13,7 +13,7 @@ - + @@ -101,6 +101,6 @@ When the severity is set to error, Flagger will alert only if the c →

        - + diff --git a/usage/deployment-strategies.html b/usage/deployment-strategies.html index c62c38cf..b4330a9a 100644 --- a/usage/deployment-strategies.html +++ b/usage/deployment-strategies.html @@ -13,7 +13,7 @@ - + @@ -155,6 +155,6 @@ the Kubernetes deployment rollout.