{"id":516934,"date":"2020-09-01T15:11:49","date_gmt":"2020-09-01T13:11:49","guid":{"rendered":"https:\/\/www.devoteam.com\/expert-view\/using-spinnaker-for-multi-cluster-kubernetes-workloads-in-gke\/"},"modified":"2020-09-01T15:11:49","modified_gmt":"2020-09-01T13:11:49","slug":"using-spinnaker-for-multi-cluster-kubernetes-workloads-in-gke","status":"publish","type":"expert-view","link":"https:\/\/devoteam.info\/cz\/expert-view\/using-spinnaker-for-multi-cluster-kubernetes-workloads-in-gke\/","title":{"rendered":"Using Spinnaker for multi-cluster Kubernetes workloads in GKE"},"content":{"rendered":"<p><span style=\"color: #333c4e;\"><strong>In\u00a0part 1\u00a0<span style=\"text-decoration: underline;\"><a href=\"\/blog\/deploying-multi-tenant-kubernetes-deployments-in-a-vpc-native-cluster-with-spinnaker-on-google-kubernetes-engine-gke\" target=\"_blank\" rel=\"noopener\">of\u00a0<\/a><a href=\"\/blog\/deploying-multi-tenant-kubernetes-deployments-in-a-vpc-native-cluster-with-spinnaker-on-google-kubernetes-engine-gke\" target=\"_blank\" rel=\"noopener\"> this article series<\/a><\/span> about deploying multi-tenant Kubernetes deployments in a VPC-native cluster with Spinnaker on Google Kubernetes Engine (GKE), we set up a basic CI\/CD solution using Spinnaker and a Single GKE cluster. The solution as-is from part 1 is not suited for production because any change made by a developer would be automatically publish into production without proper validation. In this second article, we are going to build on top of the infrastructure we set up in part 1 and learn how we can add new environments to develop and validate our application without impacting the production environment.<\/strong><\/span><\/p>\n<p><!--more--><\/p>\n<p><strong><img decoding=\"async\" style=\"width: 600px; display: block; margin: 0px auto;\" src=\"https:\/\/devoteam.info\/wp-content\/uploads\/2024\/12\/GKE-clusters-different-environments-scaled-1.jpg\" alt=\"GKE clusters different environments\" width=\"600\" \/><\/strong><\/p>\n<p><strong>A production-grade environment requires quality and stability for the delivered applications.<\/strong> This requires development and validation processes within the application life cycle, from daily updates from the development team to the proper testing of the application by the quality assurance team before releasing the application.<\/p>\n<p><strong>By the end of this article, we will have a Development, Staging, and Production environment which will be used by Spinnaker to deploy the application in.<\/strong><\/p>\n<h2>Adding Environments<\/h2>\n<p><strong>Making sure we deliver a stable and high quality application requires proper testing and validation before being made available to the users.<\/strong> Failing to do so is likely to result in long delays between releases, incomplete (or lack of) new functionalities, or even unexpected breaking changes in the application &#8211; making it partially unusable by the users.<\/p>\n<p><strong>This can lead to financial loss for the customer relying on the solution, make the customers unhappy and impact the reputation of the company.<\/strong> In part 1 of this article series, we\u2019ve only set up one environment for the users, which has the problems we just described.<\/p>\n<h3>Production environment<\/h3>\n<p><strong>The version of application currently accessible by the users is running in the <em>Production<\/em> environment.<\/strong> It is possible to have multiple versions of an application running in <em>Production<\/em>, for example if there is a stable and beta version. As both are available to the users, they are both running in what we call a <em>Production<\/em> environment.<\/p>\n<p><strong>The application needs to evolve to offer new functionalities and having the development team directly working on this environment has a high chance of impacting the quality and reliability of the application.<\/strong> Indeed, developers can easily introduce changes that can negatively impact the user experience. In addition, some components of the infrastructure might change. This could potentially include breaking changes.<\/p>\n<p>For example, the Kubernetes version running on the cluster can be upgraded by the Cloud Provider and add incompatibilities with some Kubernetes resources, breaking the application even if it was not modified.<\/p>\n<h3>Staging environment<\/h3>\n<p><strong>To prevent this, we decide to set up a non-production environment, called <em>Staging<\/em>,<\/strong> which is not available to the users and usually runs the current or next production version of the application. This environment can safely be used to intensively test and validate the application without impacting the existing <em>Production<\/em> environment. This doesn\u2019t guarantee the application will run without issues once deployed into <em>Production<\/em>, but it greatly minimises the risk of issues the users might encounter.<\/p>\n<p><strong>That\u2019s why it\u2019s important that the <em>Staging<\/em> environment reflects as close as possible the <em>Production<\/em> environment.<\/strong> If issues are discovered in this environment, it is important that they are fixed before releasing the application into <em>Production<\/em>.<\/p>\n<p><strong>Automation testing is a great way to test for regressions in the application.<\/strong> It can greatly reduce the human time needed by the team to validate the application. If the entire validation process is automated, one can imagine releasing the application very often.<\/p>\n<p><strong>Otherwise, the validation process takes more time and requires the application not to change during that time.<\/strong> The development team is likely to publish new changes on a day-to-day basis, which can impact the validation process if the environment is shared.<\/p>\n<p><strong>If <a href=\"http:\/\/softwaretestingfundamentals.com\/acceptance-testing\/\" target=\"_blank\" rel=\"nofollow noopener\">acceptance tests<\/a> are performed, it is possible that one functionality<\/strong> might be working when tested and be broken after an update by the developers, which could then be wrongly labeled as validated.<\/p>\n<h3>Development environment<\/h3>\n<p><strong>To prevent any conflicts, we are adding an additional environment called <em>Development<\/em>.<\/strong> In this environment, developers can safely push their changes on a day-to-day basis without impacting the <em>Staging<\/em> and <em>Production<\/em> environments.<\/p>\n<p><strong>Breaking changes in the <em>Development<\/em> environment are accepted as normal and get resolved during the developments of the application.<\/strong> During each release cycle, the content of the <em>Development<\/em> environment is frozen and properly tested in the <em>Staging<\/em> environment.<\/p>\n<h2>The new infrastructure<\/h2>\n<div><img decoding=\"async\" src=\"https:\/\/devoteam.info\/wp-content\/uploads\/2024\/12\/CICD-blogPart2-2.png\" alt=\"Spinnaker multi-cluster Kubernetes workloads in GKE\" \/><\/div>\n<p>We are adding 3 environments to our current infrastructure : <em>Development<\/em> (DEV), <em>Staging<\/em>, and <em>Production<\/em> (PROD). On the diagram, <strong>we are only showing one additional environment (PROD)<\/strong>, but all 3 environments can be represented with the same components within the blue rectangle.<\/p>\n<h3>Dedicated GKE clusters<\/h3>\n<p><strong>Each environment has its own dedicated GKE cluster,<\/strong> running a specific version of the application:<\/p>\n<ul>\n<li>DEV runs the latest version of the application, which is updated and deployed multiple times per day<\/li>\n<li>The <em>Staging<\/em> runs the next release of the application, and its purpose is to validate the application runs as expected, plus that it\u2019s meeting some quality criteria before going into <em>Production<\/em>. This version is only updated with bug fixes and doesn\u2019t include changes made on the <em>Development<\/em> environment once the code is frozen<\/li>\n<li>The PROD environment runs the current release of the application, which is used by the users. This environment is only updated when a new release has been validated<\/li>\n<\/ul>\n<h3>Isolating Kubernetes resources<\/h3>\n<p>We add <strong>dedicated projects<\/strong> for each customer, to store their own Cloud resources and data to fully isolate them from other customers. For example, BigQuery Dataset, Pub\/Sub topics, etc..<\/p>\n<blockquote>\n<pre><span style=\"color: #f27922;\">\u2754What is the difference between a <em>Customer<\/em> and a <em>User<\/em> ? In this article, we consider a Customer to be paying for the application. A User is only using it. For example, it is common to provide a SaaS solution to Customers, where in turn those Customers have users. It is also possible that the users are the customers.<\/span><\/pre>\n<\/blockquote>\n<p>It is often necessary to isolate the Kubernetes resources from each customer. Using a dedicated GKE cluster per customer is possible to meet this requirement, but it quickly becomes quite expensive and increasingly difficult to manage. Instead, Kubernetes has the concept of <em>Namespace<\/em>, which virtually isolates the resources in a single physical cluster.<\/p>\n<ul>\n<li>Each customer has its own dedicated namespace to run its Kubernetes workload<\/li>\n<li>Each namespace requires specific credentials to prevent unauthorised access<\/li>\n<\/ul>\n<p>The MGMT project will only run Spinnaker workloads necessary to manage the three other environments. Only Spinnaker can deploy the application in an environment, according to the pipeline&#8217;s definitions.<\/p>\n<p>That means we won\u2019t deploy any other workloads in our MGMT cluster.<\/p>\n<h2>Spinnaker credentials<\/h2>\n<p><strong>By default, Spinnaker can only deploy resources in the namespace it is installed in.<\/strong> In our case, it\u2019s in the \u201c<em>devops<\/em>\u201d namespace in the MGMT cluster. To implement the architecture we defined, we need Spinnaker to be able to deploy workloads across multiple clusters and namespaces. To do so, we need to generate credentials for Spinnaker that have access to a specific namespace in a specific cluster.<\/p>\n<div><img decoding=\"async\" src=\"https:\/\/devoteam.info\/wp-content\/uploads\/2024\/12\/CICD-blogPart2-3.png\" alt=\"Kuberentes workloads in GKE with Spinnaker\" \/><\/div>\n<p>Spinnaker uses the <a href=\"https:\/\/kubernetes.io\/docs\/reference\/access-authn-authz\/authentication\/\" target=\"_blank\" rel=\"nofollow noopener\">Kubernetes authentication methods<\/a> to deploy Kubernetes resources. We are going to generate one Kubernetes service account per namespace with defined permissions (RBAC) and save the credentials in a kubeconfig file, which will be provisioned to Spinnaker <a href=\"https:\/\/spinnaker.io\/reference\/halyard\/commands\/#hal-config-provider-kubernetes-account-add\" target=\"_blank\" rel=\"nofollow noopener\">by Halyard<\/a>.<\/p>\n<p>Each kubeconfig file is linked to one and only one set of credentials. The credentials are saved in the \u201c<em>devops<\/em>\u201d namespace in the MGMT cluster as a Kubernetes secret. Once provisioned, Spinnaker will have a <a href=\"https:\/\/spinnaker.io\/concepts\/providers\/#accounts\" target=\"_blank\" rel=\"nofollow noopener\">Spinnaker account<\/a> linked to the namespaced credentials. A pipeline will be able to deploy the authorised Kubernetes resources into that namespace only.<\/p>\n<p>Trying to deploy any resources in another namespace, within the same cluster or not, will fail. This is great to isolate resources and prevent pipelines to manage resources from a non-authorised namespace.<\/p>\n<h3>Provisioning credentials to Spinnaker<\/h3>\n<p>Spinnaker accounts are managed by <a href=\"https:\/\/spinnaker.io\/setup\/install\/providers\/kubernetes-v2\/\" target=\"_blank\" rel=\"nofollow noopener\">Halyard using the Kubernetes Provider<\/a>. Thus in order to automate the credentials provisioning, we need to use <a href=\"https:\/\/spinnaker.io\/setup\/install\/providers\/kubernetes-v2\/#adding-an-account\" target=\"_blank\" rel=\"nofollow noopener\">Halyard to configure new Spinnaker accounts<\/a>. Manually, we would use the<a href=\"https:\/\/spinnaker.io\/reference\/halyard\/commands\/#hal-config-provider-kubernetes-account-add\" target=\"_blank\" rel=\"nofollow noopener\"> Halyard command <\/a><\/p>\n<p><span style=\"font-family: 'courier new', courier; background-color: #eeeeee; color: #333c4e;\">hal config provider kubernetes account add ACCOUNT [parameters]<\/span><\/p>\n<p>where the parameters include the kubeconfig credentials file, the namespace and additional parameters we want to use. This command adds a new account to Spinnaker. In order to take effect, Spinnaker must be redeployed with Halyard<\/p>\n<p><span style=\"color: #333c4e; background-color: #eeeeee; font-family: 'courier new', courier;\">hal deploy app<\/span><\/p>\n<p>After a few minutes, the account is available in Spinnaker in the Deploy Manifest (v2) stage.<\/p>\n<p>Because we have set up RBAC on the credentials, this account can only deploy resources in the designated namespace. Deploying resources in another namespace will fail as expected, preventing unauthorised operations.<\/p>\n<h3>Automating the process<\/h3>\n<p>Adding or updating accounts manually can be a challenge when the number of accounts grows. To simplify the management of accounts, we are going to automate the process. To do so, we\u2019re going to use Terraform.<\/p>\n<p>In each environment, we have a specific configuration for the namespaces, and thus the accounts, we want to have. In this example, we have a new environment (dev) alongside our mgmt environment.<\/p>\n<p><img decoding=\"async\" style=\"width: 600px; display: block; margin: 0px auto;\" src=\"https:\/\/devoteam.info\/wp-content\/uploads\/2024\/12\/GKE-clusters-with-spinnaker-pic-3.png\" alt=\"GKE clusters with spinnaker pic 3\" width=\"600\" \/><\/p>\n<p>And within our configuration (dev.tfvars) we have the following account configuration<\/p>\n<p><img decoding=\"async\" style=\"width: 600px; display: block; margin: 0px auto;\" src=\"https:\/\/devoteam.info\/wp-content\/uploads\/2024\/12\/GKE-clusters-with-spinnaker-pic-4.png\" alt=\"GKE clusters with spinnaker pic 4\" width=\"600\" \/>where we have hidden the full configuration for simplicity. We are going to use that configuration as an entrypoint for our provisioning process.<\/p>\n<p>We create a new module named <span style=\"color: #333c4e; background-color: #eeeeee; font-family: 'courier new', courier;\">crosscluster<\/span> in which we add the necessary resources to perform the provisioning, including service accounts, namespace, roles etc. We also write a shell script executing the Halyard commands which is run by a kubernetes job. Because halyard is running in our mgmt cluster, we can use the halyard API to run any commands we want.<\/p>\n<blockquote>\n<p><span style=\"color: #f27922;\">\u2757Halyard does not have an HTTP API, so we cannot use curl to send commands. Instead, it relies on communication via WebSocket. We use <span style=\"text-decoration: underline;\"><a style=\"color: #f27922; text-decoration: underline;\" href=\"https:\/\/www.npmjs.com\/package\/wscat\" target=\"_blank\" rel=\"nofollow noopener\">wscat<\/a> <\/span>to execute commands from the Halyard running in our mgmt cluster.<\/span><\/p>\n<\/blockquote>\n<div><img decoding=\"async\" src=\"https:\/\/devoteam.info\/wp-content\/uploads\/2024\/12\/CICD-blogPart2-1.png\" alt=\"Kubernetes GKE multi-cluster workloads with Spinnaker\" \/><\/div>\n<p>The workflow is the following:<\/p>\n<ol type=\"1\">\n<li>Add accounts in the configuration file<\/li>\n<li>Run Terraform. It will refresh the state and detect new accounts to be used with the <span style=\"font-family: 'courier new', courier; color: #333c4e; background-color: #eeeeee;\">crosscluster<\/span> module<\/li>\n<li>For each account in the configuration, Terraform does the following:\n<ol type=\"a\">\n<li>Generate a namespace according to the configuration value<\/li>\n<li>Generate the Kubernetes service account that will be used by Spinnaker<\/li>\n<li>Generate the roles and permissions, limited to the newly created namespace<\/li>\n<li>Bind the service account to the role, locking the service account to this namespace<\/li>\n<li>Save the service account token in a secret in the mgmt cluster<\/li>\n<li>Create a Kubernetes Job which runs our shell script to execute the Halyard commands<\/li>\n<\/ol>\n<\/li>\n<li>Once done, all accounts have been added to Spinnaker<\/li>\n<\/ol>\n<p>\u00a0<\/p>\n<div><img decoding=\"async\" src=\"https:\/\/devoteam.info\/wp-content\/uploads\/2024\/12\/CICD-blogPart2.png\" alt=\"GKE clusters kubernetes with Spinnaker\" \/><\/div>\n<p>\u00a0<\/p>\n<h2>Deployment strategy<\/h2>\n<p>Now that we have set up our environments and have a way to provision Spinnaker with new credentials dynamically, we need to define the deployment strategy for each environment.<\/p>\n<p>In part 1 of the series, we used GitHub as a code repository which contained only one branch, the \u201cmaster\u201d branch. We are going to upgrade the branching model to the <a href=\"https:\/\/guides.github.com\/introduction\/flow\/\" target=\"_blank\" rel=\"nofollow noopener\">GitHub flow<\/a> branching model with a few adaptations, which better suits our needs. This is perfectly fine according to the definition of the GitHub flow.<\/p>\n<blockquote>\n<p><span style=\"color: #f27922;\">\u2755Different teams may have different deployment strategies. For some, it may be best to deploy to a specially provisioned testing environment. For others, deploying directly to production may be the better choice based on the other elements in their workflow.<\/span><\/p>\n<\/blockquote>\n<p>This is the deployment strategy we are going to use in this article:<\/p>\n<ul>\n<li>The \u201cmaster\u201d branch must be deployable in <em>Production<\/em> at all times<\/li>\n<li>All \u201crelease\u201d and \u201cfeature\u201d branches are created from \u201cmaster\u201d<\/li>\n<li>The \u201crelease\u201d branches are deployed in <em>Staging<\/em><\/li>\n<li>Once the release is validated, the \u201crelease\u201d branch is merged into \u201cmaster\u201d and deployed into <em>Production<\/em><\/li>\n<li>The \u201cdevelop\u201d branch is deployed in <em>Development<\/em><\/li>\n<li>The \u201cfeature\u201d branches are reviewed and deployed in <em>Development<\/em><\/li>\n<\/ul>\n<p>To reflect this strategy, we create Cloud Build Triggers based on the branching model:<\/p>\n<ul>\n<li>A code change in \u201cdevelop\u201d or a \u201cfeature\u201d branch triggers a new deployment in the <em>Development<\/em> environment. This allows the developers to see how their changes behave within the <em>Development<\/em> environment and get instant feedback to quickly and efficiently fix rising issues<\/li>\n<li>Creating or updating a \u201crelease\u201d branch triggers a new deployment in <em>Staging<\/em><\/li>\n<li>A code change in the \u201cmaster\u201d branch triggers a new deployment in <em>Production<\/em><\/li>\n<\/ul>\n<p><strong>With this strategy, the \u201cmaster\u201d branch is deployable at all times and always contains the latest validated release of your application.<\/strong><\/p>\n<p><strong>Release branches are used to work on a release candidate which is in sync with the <em>Staging<\/em> environment.<\/strong> Finally, \u201cfeature\u201d branches are used to develop new features and are deployed first in the <em>Development<\/em> environment. Ongoing development of new features and functionalities can be deployed without impacting the <em>Production<\/em> or <em>Staging<\/em> environment. Validation of a release candidate is not impacted by daily changes made by the development team and can be performed without impacting the <em>Production<\/em>.<\/p>\n<p><strong>&gt; It is possible to work only with \u201cmaster\u201d and \u201cfeature\u201d branches, like described in the GitHub flow, and create a deployment strategy based on those branches only.<\/strong> However, using \u201cdevelop\u201d and \u201crelease\u201d branches is a nice addition to better control what is deployed in the <em>Development <\/em>and <em>Staging<\/em> environment without impacting the \u201cmaster\u201d branch.<\/p>\n<h2>Conclusion<\/h2>\n<p><span style=\"color: #333c4e;\"><strong>In this article, we have seen that we can improve from a basic CI\/CD solution using a single cluster to a more complex solution which better fits the needs of a production-grade environment.<\/strong><\/span><\/p>\n<p><span style=\"color: #333c4e;\"><strong>We have set up a <em>Development<\/em>, <em>Staging<\/em> and <em>Production<\/em> environment with Terraform. We isolated the Kubernetes workloads per account, using Kubernetes namespaces, and protected them with dedicated credentials and proper access control. We also improved the Spinnaker pipelines to use accounts in order to only deploy workloads in authorised namespaces, preventing accidental or malicious operations. <\/strong><\/span><\/p>\n<p><span style=\"color: #333c4e;\"><strong>By setting up a branching model, we were able to control what code would be deployed in which environments and when,. This allows us to easily develop, test and release new features for our applications automatically.<\/strong><\/span><\/p>\n<h3>What&#8217;s next?<\/h3>\n<p>Spinnaker is now in control of the deployments for all environments and namespaces, as it should be. However, it also becomes a weakness and a potential central point of attack: even if we can\u2019t execute pipelines which don&#8217;t have the right account, it is still possible for a Spinnaker user to modify, execute or delete Spinnaker resources. If a hacker can breach Spinnaker and access it, it will have the same capabilities than any Spinnaker user.<\/p>\n<p><span style=\"color: #999999;\">In the next article in this series, we are going to focus on security and we will see how we can protect Spinnaker by authenticating users and use proper RBAC to protect the Spinnaker resources such as <a style=\"font-weight: bold; color: #999999;\" href=\"https:\/\/spinnaker.io\/setup\/install\/providers\/kubernetes-v2\/#accounts\">accounts<\/a> and <a style=\"font-weight: bold; color: #999999;\" href=\"https:\/\/spinnaker.io\/concepts\/#application\">applications<\/a>. We will also see how we can further protect our Kubernetes Clusters by using Authorised Networks, Pod Security Policies and mTLS between services with Istio.<\/span><\/p>\n<hr \/>\n<p style=\"text-align: center;\"><span style=\"color: #333c4e;\"><strong>Questions? Need guidance from experts? Contact Us today!<\/strong><\/span><\/p>\n\n","protected":false},"excerpt":{"rendered":"<p>In\u00a0part 1\u00a0of\u00a0 this article series about deploying multi-tenant Kubernetes deployments in a VPC-native cluster with Spinnaker on Google Kubernetes Engine (GKE), we set up a basic CI\/CD solution using Spinnaker and a Single GKE cluster. The solution as-is from part 1 is not suited for production because any change made by a developer would be [&hellip;]<\/p>\n","protected":false},"featured_media":298363,"template":"","categories":[],"tags":[3138,2294,2487,3037,2931],"industry":[],"class_list":["post-516934","expert-view","type-expert-view","status-publish","has-post-thumbnail","hentry","tag-application-modernisation-cz","tag-google-cloud-cz","tag-google-cloud-platform-cz","tag-kubernetes-cz","tag-modernising-it-infrastructure-cz"],"acf":[],"cards":"\n\t<div class=\"single-post-card\">\n\n\t\t<figure class=\"wp-block-post-featured-image\"><a href=\"https:\/\/devoteam.info\/cz\/expert-view\/using-spinnaker-for-multi-cluster-kubernetes-workloads-in-gke\/\" target=\"_self\" ><img width=\"2560\" height=\"1709\" src=\"https:\/\/devoteam.info\/wp-content\/uploads\/2024\/12\/GKE-clusters-different-environments-scaled-1.jpg\" class=\"attachment-post-thumbnail size-post-thumbnail wp-post-image\" alt=\"Using Spinnaker for multi-cluster Kubernetes workloads in GKE\" style=\"aspect-ratio:4\/3;width:100%;object-fit:cover;\" decoding=\"async\" loading=\"lazy\" srcset=\"https:\/\/devoteam.info\/wp-content\/uploads\/2024\/12\/GKE-clusters-different-environments-scaled-1.jpg 2560w, https:\/\/devoteam.info\/wp-content\/uploads\/2024\/12\/GKE-clusters-different-environments-scaled-1-300x200.jpg 300w, https:\/\/devoteam.info\/wp-content\/uploads\/2024\/12\/GKE-clusters-different-environments-scaled-1-1024x684.jpg 1024w, https:\/\/devoteam.info\/wp-content\/uploads\/2024\/12\/GKE-clusters-different-environments-scaled-1-768x513.jpg 768w, https:\/\/devoteam.info\/wp-content\/uploads\/2024\/12\/GKE-clusters-different-environments-scaled-1-1536x1025.jpg 1536w, https:\/\/devoteam.info\/wp-content\/uploads\/2024\/12\/GKE-clusters-different-environments-scaled-1-2048x1367.jpg 2048w\" sizes=\"auto, (max-width: 2560px) 100vw, 2560px\" \/><\/a><\/figure>\n\n\t\t\n\t\t<div class=\"wp-block-group is-vertical is-layout-flex wp-container-core-group-is-layout-43282307 wp-block-group-is-layout-flex\">\n\t<p style=\"font-style:normal;font-weight:700\" class=\"has-link-color wp-elements-1 wp-block-lp-post-type has-text-color has-primary-color has-small-font-size\">Expert View<\/p>\n\n\t\t\n\t\t<h3 style=\"font-style:normal;font-weight:400\" class=\"wp-block-post-title has-base-font-size\"><a href=\"https:\/\/devoteam.info\/cz\/expert-view\/using-spinnaker-for-multi-cluster-kubernetes-workloads-in-gke\/\" target=\"_self\" >Using Spinnaker for multi-cluster Kubernetes workloads in GKE<\/a><\/h3><\/div>\n\t\t\n\t<\/div>\n\n","yoast_head":"<!-- This site is optimized with the Yoast SEO Premium plugin v28.4 (Yoast SEO v28.4) - https:\/\/yoast.com\/product\/yoast-seo-premium-wordpress\/ -->\n<title>Using Spinnaker for multi-cluster Kubernetes workloads in GKE | Devoteam<\/title>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/devoteam.info\/cz\/expert-view\/using-spinnaker-for-multi-cluster-kubernetes-workloads-in-gke\/\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Using Spinnaker for multi-cluster Kubernetes workloads in GKE\" \/>\n<meta property=\"og:description\" content=\"In\u00a0part 1\u00a0of\u00a0 this article series about deploying multi-tenant Kubernetes deployments in a VPC-native cluster with Spinnaker on Google Kubernetes Engine (GKE), we set up a basic CI\/CD solution using Spinnaker and a Single GKE cluster. The solution as-is from part 1 is not suited for production because any change made by a developer would be [&hellip;]\" \/>\n<meta property=\"og:url\" content=\"https:\/\/devoteam.info\/cz\/expert-view\/using-spinnaker-for-multi-cluster-kubernetes-workloads-in-gke\/\" \/>\n<meta property=\"og:site_name\" content=\"Devoteam\" \/>\n<meta property=\"og:image\" content=\"https:\/\/devoteam.info\/wp-content\/uploads\/2024\/12\/GKE-clusters-different-environments-scaled-1.jpg\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:label1\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data1\" content=\"12 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\\\/\\\/schema.org\",\"@graph\":[{\"@type\":\"WebPage\",\"@id\":\"https:\\\/\\\/devoteam.info\\\/cz\\\/expert-view\\\/using-spinnaker-for-multi-cluster-kubernetes-workloads-in-gke\\\/\",\"url\":\"https:\\\/\\\/devoteam.info\\\/cz\\\/expert-view\\\/using-spinnaker-for-multi-cluster-kubernetes-workloads-in-gke\\\/\",\"name\":\"Using Spinnaker for multi-cluster Kubernetes workloads in GKE | Devoteam\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/devoteam.info\\\/cz\\\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\\\/\\\/devoteam.info\\\/cz\\\/expert-view\\\/using-spinnaker-for-multi-cluster-kubernetes-workloads-in-gke\\\/#primaryimage\"},\"image\":{\"@id\":\"https:\\\/\\\/devoteam.info\\\/cz\\\/expert-view\\\/using-spinnaker-for-multi-cluster-kubernetes-workloads-in-gke\\\/#primaryimage\"},\"thumbnailUrl\":\"https:\\\/\\\/devoteam.info\\\/wp-content\\\/uploads\\\/2024\\\/12\\\/GKE-clusters-different-environments-scaled-1.jpg\",\"datePublished\":\"2020-09-01T13:11:49+00:00\",\"breadcrumb\":{\"@id\":\"https:\\\/\\\/devoteam.info\\\/cz\\\/expert-view\\\/using-spinnaker-for-multi-cluster-kubernetes-workloads-in-gke\\\/#breadcrumb\"},\"inLanguage\":\"en-CZ\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\\\/\\\/devoteam.info\\\/cz\\\/expert-view\\\/using-spinnaker-for-multi-cluster-kubernetes-workloads-in-gke\\\/\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"en-CZ\",\"@id\":\"https:\\\/\\\/devoteam.info\\\/cz\\\/expert-view\\\/using-spinnaker-for-multi-cluster-kubernetes-workloads-in-gke\\\/#primaryimage\",\"url\":\"https:\\\/\\\/devoteam.info\\\/wp-content\\\/uploads\\\/2024\\\/12\\\/GKE-clusters-different-environments-scaled-1.jpg\",\"contentUrl\":\"https:\\\/\\\/devoteam.info\\\/wp-content\\\/uploads\\\/2024\\\/12\\\/GKE-clusters-different-environments-scaled-1.jpg\",\"width\":2560,\"height\":1709},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\\\/\\\/devoteam.info\\\/cz\\\/expert-view\\\/using-spinnaker-for-multi-cluster-kubernetes-workloads-in-gke\\\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\\\/\\\/devoteam.info\\\/cz\\\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Expert View\",\"item\":\"https:\\\/\\\/devoteam.info\\\/cz\\\/expert-view\\\/\"},{\"@type\":\"ListItem\",\"position\":3,\"name\":\"Using Spinnaker for multi-cluster Kubernetes workloads in GKE\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\\\/\\\/devoteam.info\\\/cz\\\/#website\",\"url\":\"https:\\\/\\\/devoteam.info\\\/cz\\\/\",\"name\":\"Devoteam\",\"description\":\"\",\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\\\/\\\/devoteam.info\\\/cz\\\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"en-CZ\"}]}<\/script>\n<!-- \/ Yoast SEO Premium plugin. -->","yoast_head_json":{"title":"Using Spinnaker for multi-cluster Kubernetes workloads in GKE | Devoteam","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/devoteam.info\/cz\/expert-view\/using-spinnaker-for-multi-cluster-kubernetes-workloads-in-gke\/","og_locale":"en_US","og_type":"article","og_title":"Using Spinnaker for multi-cluster Kubernetes workloads in GKE","og_description":"In\u00a0part 1\u00a0of\u00a0 this article series about deploying multi-tenant Kubernetes deployments in a VPC-native cluster with Spinnaker on Google Kubernetes Engine (GKE), we set up a basic CI\/CD solution using Spinnaker and a Single GKE cluster. The solution as-is from part 1 is not suited for production because any change made by a developer would be [&hellip;]","og_url":"https:\/\/devoteam.info\/cz\/expert-view\/using-spinnaker-for-multi-cluster-kubernetes-workloads-in-gke\/","og_site_name":"Devoteam","og_image":[{"url":"https:\/\/devoteam.info\/wp-content\/uploads\/2024\/12\/GKE-clusters-different-environments-scaled-1.jpg","type":"","width":"","height":""}],"twitter_card":"summary_large_image","twitter_misc":{"Est. reading time":"12 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"WebPage","@id":"https:\/\/devoteam.info\/cz\/expert-view\/using-spinnaker-for-multi-cluster-kubernetes-workloads-in-gke\/","url":"https:\/\/devoteam.info\/cz\/expert-view\/using-spinnaker-for-multi-cluster-kubernetes-workloads-in-gke\/","name":"Using Spinnaker for multi-cluster Kubernetes workloads in GKE | Devoteam","isPartOf":{"@id":"https:\/\/devoteam.info\/cz\/#website"},"primaryImageOfPage":{"@id":"https:\/\/devoteam.info\/cz\/expert-view\/using-spinnaker-for-multi-cluster-kubernetes-workloads-in-gke\/#primaryimage"},"image":{"@id":"https:\/\/devoteam.info\/cz\/expert-view\/using-spinnaker-for-multi-cluster-kubernetes-workloads-in-gke\/#primaryimage"},"thumbnailUrl":"https:\/\/devoteam.info\/wp-content\/uploads\/2024\/12\/GKE-clusters-different-environments-scaled-1.jpg","datePublished":"2020-09-01T13:11:49+00:00","breadcrumb":{"@id":"https:\/\/devoteam.info\/cz\/expert-view\/using-spinnaker-for-multi-cluster-kubernetes-workloads-in-gke\/#breadcrumb"},"inLanguage":"en-CZ","potentialAction":[{"@type":"ReadAction","target":["https:\/\/devoteam.info\/cz\/expert-view\/using-spinnaker-for-multi-cluster-kubernetes-workloads-in-gke\/"]}]},{"@type":"ImageObject","inLanguage":"en-CZ","@id":"https:\/\/devoteam.info\/cz\/expert-view\/using-spinnaker-for-multi-cluster-kubernetes-workloads-in-gke\/#primaryimage","url":"https:\/\/devoteam.info\/wp-content\/uploads\/2024\/12\/GKE-clusters-different-environments-scaled-1.jpg","contentUrl":"https:\/\/devoteam.info\/wp-content\/uploads\/2024\/12\/GKE-clusters-different-environments-scaled-1.jpg","width":2560,"height":1709},{"@type":"BreadcrumbList","@id":"https:\/\/devoteam.info\/cz\/expert-view\/using-spinnaker-for-multi-cluster-kubernetes-workloads-in-gke\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/devoteam.info\/cz\/"},{"@type":"ListItem","position":2,"name":"Expert View","item":"https:\/\/devoteam.info\/cz\/expert-view\/"},{"@type":"ListItem","position":3,"name":"Using Spinnaker for multi-cluster Kubernetes workloads in GKE"}]},{"@type":"WebSite","@id":"https:\/\/devoteam.info\/cz\/#website","url":"https:\/\/devoteam.info\/cz\/","name":"Devoteam","description":"","potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/devoteam.info\/cz\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-CZ"}]}},"uagb_featured_image_src":{"full":["https:\/\/devoteam.info\/wp-content\/uploads\/2024\/12\/GKE-clusters-different-environments-scaled-1.jpg",2560,1709,false],"thumbnail":["https:\/\/devoteam.info\/wp-content\/uploads\/2024\/12\/GKE-clusters-different-environments-scaled-1-150x150.jpg",150,150,true],"medium":["https:\/\/devoteam.info\/wp-content\/uploads\/2024\/12\/GKE-clusters-different-environments-scaled-1-300x200.jpg",300,200,true],"medium_large":["https:\/\/devoteam.info\/wp-content\/uploads\/2024\/12\/GKE-clusters-different-environments-scaled-1-768x513.jpg",768,513,true],"large":["https:\/\/devoteam.info\/wp-content\/uploads\/2024\/12\/GKE-clusters-different-environments-scaled-1-1024x684.jpg",1024,684,true],"1536x1536":["https:\/\/devoteam.info\/wp-content\/uploads\/2024\/12\/GKE-clusters-different-environments-scaled-1-1536x1025.jpg",1536,1025,true],"2048x2048":["https:\/\/devoteam.info\/wp-content\/uploads\/2024\/12\/GKE-clusters-different-environments-scaled-1-2048x1367.jpg",2048,1367,true]},"uagb_author_info":{"display_name":"Julien Pawlowski","author_link":"https:\/\/devoteam.info\/cz\/author\/"},"uagb_comment_info":0,"uagb_excerpt":"In\u00a0part 1\u00a0of\u00a0 this article series about deploying multi-tenant Kubernetes deployments in a VPC-native cluster with Spinnaker on Google Kubernetes Engine (GKE), we set up a basic CI\/CD solution using Spinnaker and a Single GKE cluster. The solution as-is from part 1 is not suited for production because any change made by a developer would be&hellip;","_links":{"self":[{"href":"https:\/\/devoteam.info\/cz\/wp-json\/wp\/v2\/expert-view\/516934","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/devoteam.info\/cz\/wp-json\/wp\/v2\/expert-view"}],"about":[{"href":"https:\/\/devoteam.info\/cz\/wp-json\/wp\/v2\/types\/expert-view"}],"version-history":[{"count":0,"href":"https:\/\/devoteam.info\/cz\/wp-json\/wp\/v2\/expert-view\/516934\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devoteam.info\/cz\/wp-json\/wp\/v2\/media\/298363"}],"wp:attachment":[{"href":"https:\/\/devoteam.info\/cz\/wp-json\/wp\/v2\/media?parent=516934"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devoteam.info\/cz\/wp-json\/wp\/v2\/categories?post=516934"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devoteam.info\/cz\/wp-json\/wp\/v2\/tags?post=516934"},{"taxonomy":"industry","embeddable":true,"href":"https:\/\/devoteam.info\/cz\/wp-json\/wp\/v2\/industry?post=516934"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}