-
Notifications
You must be signed in to change notification settings - Fork 0
/
ed758c06.98e37e27.js
1 lines (1 loc) · 12.2 KB
/
ed758c06.98e37e27.js
1
(window.webpackJsonp=window.webpackJsonp||[]).push([[35],{168:function(e,t,n){"use strict";n.r(t),n.d(t,"frontMatter",(function(){return i})),n.d(t,"metadata",(function(){return s})),n.d(t,"rightToc",(function(){return l})),n.d(t,"default",(function(){return p}));var a=n(2),r=n(9),o=(n(0),n(173)),i={id:"5-8-20",title:"Istio Control Plane Upgrades using Canary Deployments",author:"Michael Fornaro",author_title:"Senior DevOps Engineer",author_url:"https://github.com/xUnholy",author_image_url:"https://avatars3.githubusercontent.com/u/20387402?s=400&u=fbb33b14f7f7328a98ea87dc162a334c9bc97523&v=4",tags:["kubernetes","raspberry pi","raspbernetes","istio","canary"]},s={permalink:"/blog/5-8-20",editUrl:"https://github.com/raspbernetes/docs/edit/master/website/blog/blog/5-8-20.md",source:"@site/blog/5-8-20.md",description:"Co-author: Omar Steitieh",date:"2021-02-08T21:41:27.523Z",tags:[{label:"kubernetes",permalink:"/blog/tags/kubernetes"},{label:"raspberry pi",permalink:"/blog/tags/raspberry-pi"},{label:"raspbernetes",permalink:"/blog/tags/raspbernetes"},{label:"istio",permalink:"/blog/tags/istio"},{label:"canary",permalink:"/blog/tags/canary"}],title:"Istio Control Plane Upgrades using Canary Deployments",readingTime:3.825,truncated:!0,prevItem:{title:"Automated HA Kubernetes deployment on Raspberry Pis",permalink:"/blog/16-7-20"}},l=[{value:"Overview",id:"overview",children:[{value:"Control Plane",id:"control-plane",children:[]},{value:"Data Plane",id:"data-plane",children:[]}]},{value:"Getting Started",id:"getting-started",children:[{value:"Control Plane",id:"control-plane-1",children:[]},{value:"Data Plane",id:"data-plane-1",children:[]}]},{value:"Summary",id:"summary",children:[]}],c={rightToc:l};function p(e){var t=e.components,n=Object(r.a)(e,["components"]);return Object(o.b)("wrapper",Object(a.a)({},c,n,{components:t,mdxType:"MDXLayout"}),Object(o.b)("p",null,"Co-author: Omar Steitieh"),Object(o.b)("p",null,Object(o.b)("img",Object(a.a)({parentName:"p"},{src:"https://github.com/raspbernetes/raspbernetes.github.io/raw/master/img/istio-blog-banner.jpg",alt:"Istio Blog Banner",title:"Istio Blog Banner"}))),Object(o.b)("h2",{id:"overview"},"Overview"),Object(o.b)("p",null,"A new feature to support canary deployments of the Control Plane was included in Istio version 1.5.x. This blog aims to demonstrate this feature, The steps below assume you have version 1.6+ installed and running in your cluster."),Object(o.b)("p",null,"An introduction to deployment strategies; blue-green, canary and more can be found ",Object(o.b)("a",Object(a.a)({parentName:"p"},{href:"https://dev.to/mostlyjason/intro-to-deployment-strategies-blue-green-canary-and-more-3a3"}),"here")),Object(o.b)("p",null,"Istio service mesh has two main components; Control Plane & Data Plane"),Object(o.b)("h3",{id:"control-plane"},"Control Plane"),Object(o.b)("p",null,"The Control Plane is responsible for service discovery, routing configuration, providing service-to-service, and end-user authentication. It also allows secure mTLS communication in the data plane by maintaining a CA and generating certificates. Since 1.5.x, the control plane components have been consolidated into a single service called istiod."),Object(o.b)("h3",{id:"data-plane"},"Data Plane"),Object(o.b)("p",null,"The Data Plane consists of Envoy proxies deployed as sidecars to every Istio enabled pod in the cluster. They intercept any incoming or outgoing requests from the main container in the pod for two purposes; firstly they provide encryption, controlling the communication between pods and secondly they provide telemetry on all network traffic."),Object(o.b)("p",null,"We will deploy a second Istio control plane which will be used to canary traffic in a namespace."),Object(o.b)("h2",{id:"getting-started"},"Getting Started"),Object(o.b)("h3",{id:"control-plane-1"},"Control Plane"),Object(o.b)("p",null,"You currently have an existing Istio control plane running. To deploy a canary control plane you must set the revision field. This can be done either using the istioctl CLI tool installation method or via using the istio-operator."),Object(o.b)("p",null,"istioctl example:"),Object(o.b)("pre",null,Object(o.b)("code",Object(a.a)({parentName:"pre"},{className:"language-bash"}),"istioctl install --set revision=canary\n")),Object(o.b)("p",null,"When installing Istio using istioctl the default profile will be applied automatically unless otherwise specified, to use a custom profile our preferred method is to deploy using the IstioOperator resource. Pre-configured profiles can be viewed ",Object(o.b)("a",Object(a.a)({parentName:"p"},{href:"https://istio.io/latest/docs/setup/additional-setup/config-profiles/"}),"here"),"."),Object(o.b)("p",null,"istio-operator example:"),Object(o.b)("pre",null,Object(o.b)("code",Object(a.a)({parentName:"pre"},{className:"language-yaml"}),"apiVersion: install.istio.io/v1alpha1\nkind: IstioOperator\nmetadata:\n name: istio-canary\n namespace: istio-system\nspec:\n ...\n revision: canary\n ...\n")),Object(o.b)("p",null,"Note: IstioOperator available options can be viewed ",Object(o.b)("a",Object(a.a)({parentName:"p"},{href:"https://istio.io/latest/docs/reference/config/istio.operator.v1alpha1/"}),"here")),Object(o.b)("p",null,"Once applied a second control plane will be created. Both the existing and the canary revision will be running in the cluster."),Object(o.b)("pre",null,Object(o.b)("code",Object(a.a)({parentName:"pre"},{className:"language-bash"}),"NAME READY STATUS RESTARTS AGE\nistiod-7f7d5496cf-ltff2 1/1 Running 0 5m45s\nistiod-canary-7f7d5496cf-ltff2 1/1 Running 0 15s\n")),Object(o.b)("p",null,"When the canary istiod pod is running it\u2019s worth mentioning that both the ",Object(o.b)("inlineCode",{parentName:"p"},"ingress")," and ",Object(o.b)("inlineCode",{parentName:"p"},"egress")," gateway pods will upgrade to the new version and old pods will be terminated \u2014 this was surprising as now all the data plane proxies within the cluster do not have version parity. Consequently, it is ",Object(o.b)("strong",{parentName:"p"},"highly")," recommended to check changelogs between versions!"),Object(o.b)("h3",{id:"data-plane-1"},"Data Plane"),Object(o.b)("p",null,"Creating a canary control plane has no impact on the data plane. To roll out your sidecar ",Object(o.b)("inlineCode",{parentName:"p"},"istio-proxy")," updates to the new version of the control plane take the following steps."),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"https://github.com/raspbernetes/raspbernetes.github.io/raw/master/img/istio-canary-1.png",alt:"Istio Canary 1"})),Object(o.b)("p",null,"Remove the existing namespace label ",Object(o.b)("inlineCode",{parentName:"p"},"istio-injection")," and add a new label ",Object(o.b)("inlineCode",{parentName:"p"},"istio.io/rev=canary"),"."),Object(o.b)("p",null,"This can be done with the following command:"),Object(o.b)("pre",null,Object(o.b)("code",Object(a.a)({parentName:"pre"},{className:"language-bash"}),"kubectl label namespace <namespace> istio-injection- istio.io/rev=canary\n")),Object(o.b)("p",null,Object(o.b)("em",{parentName:"p"},"Note: The ",Object(o.b)("inlineCode",{parentName:"em"},"istio-injection")," label must be removed because it takes precedence over the ",Object(o.b)("inlineCode",{parentName:"em"},"istio.io/rev")," label for backward compatibility.")),Object(o.b)("p",null,"After the namespace labels have been updated you will need to restart the pods to trigger re-injection:"),Object(o.b)("pre",null,Object(o.b)("code",Object(a.a)({parentName:"pre"},{className:"language-bash"}),"kubectl rollout restart deployment -n <namespace>\n")),Object(o.b)("p",null,"Once the pods have been recreated they will be configured to point to the new canary Istio control plane."),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"https://github.com/raspbernetes/raspbernetes.github.io/raw/master/img/istio-canary-2.png",alt:"Istio Canary 2"})),Object(o.b)("p",null,"Confirm the pods are now using the canary revision of the Istio control plane by running this command against one of the restarted pods:"),Object(o.b)("pre",null,Object(o.b)("code",Object(a.a)({parentName:"pre"},{className:"language-bash"}),"istioctl proxy-config endpoints <pod>.<namespace> --cluster xds-grpc -ojson | grep hostname\n")),Object(o.b)("p",null,"Expected output:"),Object(o.b)("pre",null,Object(o.b)("code",Object(a.a)({parentName:"pre"},{className:"language-bash"}),"\u201chostname\u201d: \u201cistiod-canary.istio-system.svc\u201d\n")),Object(o.b)("p",{align:"center"},Object(o.b)("img",{src:"https://github.com/raspbernetes/raspbernetes.github.io/raw/master/img/istio-canary-3.png",alt:"Istio Canary 3"})),Object(o.b)("p",null,"After successfully testing the new control plane version continue to roll out the upgrade to the remainder of the cluster workloads using the same approach."),Object(o.b)("h2",{id:"summary"},"Summary"),Object(o.b)("p",null,"Points to consider when choosing to use Istio canary releases using revisions:"),Object(o.b)("p",null,Object(o.b)("strong",{parentName:"p"},"Promoting the canary release")," \u2014 We recommend using the version as the revision. This keeps each namespace with an explicit label of the control plane version being used."),Object(o.b)("p",null,Object(o.b)("strong",{parentName:"p"},"Potential downtime")," \u2014 Consideration for the ingress and egress gateways must be taken into account. Possible version disparity between istio-proxy sidecars could introduce breaking changes that impact proxy traffic and would require a re-deployment of the previous control plane."),Object(o.b)("p",null,Object(o.b)("strong",{parentName:"p"},"Validating revision before adoption")," \u2014 Restarting all pods in a namespace may cause a large impact if something goes wrong. Consider scaling the deployments instead to test new pods communicating to the new control plane revision."),Object(o.b)("p",null,Object(o.b)("em",{parentName:"p"},"Note: Everything in this article was tested using Istio 1.6.5 running on our Raspberry Pi Kubernetes cluster built using the ",Object(o.b)("a",Object(a.a)({parentName:"em"},{href:"https://github.com/raspbernetes"}),"Raspbernetes project"),".")))}p.isMDXComponent=!0},173:function(e,t,n){"use strict";n.d(t,"a",(function(){return b})),n.d(t,"b",(function(){return m}));var a=n(0),r=n.n(a);function o(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function i(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);t&&(a=a.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,a)}return n}function s(e){for(var t=1;t<arguments.length;t++){var n=null!=arguments[t]?arguments[t]:{};t%2?i(Object(n),!0).forEach((function(t){o(e,t,n[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(n)):i(Object(n)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(n,t))}))}return e}function l(e,t){if(null==e)return{};var n,a,r=function(e,t){if(null==e)return{};var n,a,r={},o=Object.keys(e);for(a=0;a<o.length;a++)n=o[a],t.indexOf(n)>=0||(r[n]=e[n]);return r}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(a=0;a<o.length;a++)n=o[a],t.indexOf(n)>=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(r[n]=e[n])}return r}var c=r.a.createContext({}),p=function(e){var t=r.a.useContext(c),n=t;return e&&(n="function"==typeof e?e(t):s(s({},t),e)),n},b=function(e){var t=p(e.components);return r.a.createElement(c.Provider,{value:t},e.children)},u={inlineCode:"code",wrapper:function(e){var t=e.children;return r.a.createElement(r.a.Fragment,{},t)}},d=r.a.forwardRef((function(e,t){var n=e.components,a=e.mdxType,o=e.originalType,i=e.parentName,c=l(e,["components","mdxType","originalType","parentName"]),b=p(n),d=a,m=b["".concat(i,".").concat(d)]||b[d]||u[d]||o;return n?r.a.createElement(m,s(s({ref:t},c),{},{components:n})):r.a.createElement(m,s({ref:t},c))}));function m(e,t){var n=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var o=n.length,i=new Array(o);i[0]=d;var s={};for(var l in t)hasOwnProperty.call(t,l)&&(s[l]=t[l]);s.originalType=e,s.mdxType="string"==typeof e?e:a,i[1]=s;for(var c=2;c<o;c++)i[c]=n[c];return r.a.createElement.apply(null,i)}return r.a.createElement.apply(null,n)}d.displayName="MDXCreateElement"}}]);