<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0"><channel><title>Pulumi Blog: Aks</title><link>https://www.pulumi.com/blog/tags/aks/</link><description>Pulumi blog posts: Aks.</description><language>en-us</language><pubDate>Fri, 01 Jul 2022 00:00:00 +0000</pubDate><item><title>How Elkjøp Nordic enables self-service infrastructure for developers</title><link>https://www.pulumi.com/blog/how-elkjop-nordic-enables-developers-to-self-serve-infrastructure/</link><pubDate>Fri, 01 Jul 2022 00:00:00 +0000</pubDate><guid>https://www.pulumi.com/blog/how-elkjop-nordic-enables-developers-to-self-serve-infrastructure/</guid><description>
&lt;img src="https://www.pulumi.com/images/generated/blog/how-elkjop-nordic-enables-developers-to-self-serve-infrastructure/index.png" /&gt;
&lt;p&gt;At PulumiUP 2022, Tomas Jansson, software architect at Elkjøp Nordic, gave a presentation on how to enable developers to self-service infrastructure by using Pulumi’s &lt;a href="https://www.pulumi.com/automation/"&gt;Automation API&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Elkjøp Nordic is the leading consumer electronics retailer in the Nordics. The company sells consumer electronics, mobile phones, computers, white goods, domestic appliances, and services linked to these products both directly to consumers and to businesses. It is an omnichannel retailer and serves customers both online and through more than 400 stores. Elkjøp has retail outlets in Norway, Sweden, Finland and Denmark, and franchise operations in Greenland and Faroe Islands.&lt;/p&gt;
&lt;p&gt;To support the company’s modernization strategy, Tomas developed a self-service infrastructure platform that would enable any developer to easily provision cloud infrastructure that uses approved resources and security practices. The goal was to empower teams at Elkjøp to increase their development velocity by using the cloud, while maintaining guardrails that uphold security and compliance.&lt;/p&gt;
&lt;p&gt;Watch the full presentation below or read on to learn the highlights of his presentation:&lt;/p&gt;
&lt;div style="position: relative; padding-bottom: 56.25%; height: 0; overflow: hidden;"&gt;
&lt;iframe allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share; fullscreen" loading="eager" referrerpolicy="strict-origin-when-cross-origin" src="https://www.youtube.com/embed/aoa_O-rh5KE?autoplay=0&amp;amp;controls=1&amp;amp;end=0&amp;amp;loop=0&amp;amp;mute=0&amp;amp;start=0" style="position: absolute; top: 0; left: 0; width: 100%; height: 100%; border:0;" title="YouTube video"&gt;&lt;/iframe&gt;
&lt;/div&gt;
&lt;h2 id="the-problem-balancing-agility-and-governance"&gt;The Problem: Balancing Agility and Governance&lt;/h2&gt;
&lt;p&gt;To achieve his goals, Tomas knew he had to solve the problem of balancing freedom with control. On the one hand, he wanted to foster the creativity of his developers and encourage innovation. He wanted his team to feel they were trusted and had the room to create the best solutions they could. On the other hand, he knew he had to maintain some control. Elkjøp needed to keep its applications secure. It also needed good governance so that teams can keep track of who is making changes. Tomas also wanted to limit the impact of deploying untested code. Code that was still being developed needed to be confined to the developer’s own environment. Finding the right balance between independence and control was paramount. Tomas believed this would result in great software and in developers who would enjoy their work.&lt;/p&gt;
&lt;h2 id="the-solution-a-self-service-infrastructure-platform"&gt;The Solution: A Self-Service Infrastructure Platform&lt;/h2&gt;
&lt;p&gt;Tomas’ solution was to build a self-service infrastructure platform. Self-service infrastructure makes it possible for developers to easily access the infrastructure they need while limiting access to resources they don’t need. In effect, self-service infrastructure is a walled garden. Within the garden, developers have all the freedom they need. However, nothing they do affects what’s outside the wall. Code that causes unintended changes only affects them and no one else.&lt;/p&gt;
&lt;p&gt;Tomas built an application that provides a “walled garden” of self-service infrastructure. Developers can create the environments they need, including an Azure resource group and a Kubernetes namespace, all through a graphical user interface. Developers can define whether the environment is for development, test or production. They can also assign values, such as which team members should have admin privileges to the associated GitHub repositories or who can contribute. From there, the platform handles provisioning and configuring all of these resources.&lt;/p&gt;
&lt;p&gt;Here is an example that shows how a developer can create a repository simply by selecting a few parameters from a drop-down list.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://www.pulumi.com/blog/how-elkjop-nordic-enables-developers-to-self-serve-infrastructure/create-repo.png" alt="Creating a new repository"&gt;&lt;/p&gt;
&lt;p&gt;Tomas determined that the best way to implement self-service infrastructure was with Pulumi and its &lt;a href="https://www.pulumi.com/automation/"&gt;Automation API&lt;/a&gt;. By using Pulumi, he could use standard programming languages to define infrastructure while using familiar software tools like IDEs and test frameworks. Pulumi also natively supports Azure and Kubernetes with 100% coverage of each provider’s APIs and same-day access to new features and updates. Finally, the Pulumi Automation API would enable him to program infrastructure automation directly into his application.&lt;/p&gt;
&lt;p&gt;The Pulumi Automation API is a programmatic interface for running Pulumi programs without the Pulumi CLI. Automation API encapsulates the functionality of the CLI (&lt;code&gt;pulumi up&lt;/code&gt;, &lt;code&gt;pulumi preview&lt;/code&gt;, &lt;code&gt;pulumi destroy&lt;/code&gt;, &lt;code&gt;pulumi stack init&lt;/code&gt;, etc.) but with more flexibility since infrastructure operations can be controlled programmatically.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://www.pulumi.com/blog/how-elkjop-nordic-enables-developers-to-self-serve-infrastructure/automation-api-diagram.png" alt="Deploying with the Pulumi CLI and Automation API"&gt;&lt;/p&gt;
&lt;h2 id="how-the-self-service-infrastructure-platform-was-built"&gt;How the self-service infrastructure platform was built&lt;/h2&gt;
&lt;p&gt;Here is the workflow for the Elkjøp self-service infrastructure platform.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://www.pulumi.com/blog/how-elkjop-nordic-enables-developers-to-self-serve-infrastructure/elkjop-platform-diagram.png" alt="The Elkjøp self-service infrastructure platform"&gt;&lt;/p&gt;
&lt;p&gt;The self-service platform is a web application that runs the Pulumi Automation API on the server side. The application uses Pulumi to provision and configure every environment resource such as Azure resource groups, Kubernetes namespaces, service principals, and Kubernetes service accounts. Each environment comes with a Git repository that&amp;rsquo;s used by developers to manage their deployments. The Git repositories are the locus of each environment because they store everything needed to deploy changes such as infrastructure code and environment credentials.&lt;/p&gt;
&lt;p&gt;Using the Pulumi Automation API, the application creates an Azure resource group, a team in both Azure AD and GitHub, and a new GitHub repository. The application then grants administrative access to the GitHub repo to members of the AD group. In addition to creating a Git repository for each environment, the application uses stack references for each Azure environment to inject the associated credentials into the GitHub Secret Store. These credentials are scoped to each GitHub environment so that developers can only work in their own environment. If a team has multiple environments, each environment has its own credentials so developers can’t, for example, deploy from a test environment to a production environment. Secrets are managed through the &lt;a href="https://www.pulumi.com/docs/administration/"&gt;Pulumi Service&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Every new repository comes with Pulumi programs that developers can use to deploy their application. GitHub Actions initiate the deployment. When an action triggers, Pulumi reads the credentials that were generated by the self-service application, allowing Pulumi to deploy new Kubernetes or Azure resources to the environment.&lt;/p&gt;
&lt;h2 id="watch-the-demo"&gt;Watch the demo&lt;/h2&gt;
&lt;p&gt;To illustrate how Elkjøp’s self-service platform works, Tomas presented a simplified demo application that’s based on Elkjøp’s production platform. The code for the application is available at &lt;a href="https://github.com/mastoj/pulumi-automation-demo"&gt;https://github.com/mastoj/pulumi-automation-demo&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;The demo is a TypeScript application that includes an API that provisions Azure and GitHub resources. Pulumi Automation API code is used to deploy new stacks by calling handler code, which is a Pulumi program that defines resources and outputs. The handler code can create Azure resource groups or GitHub repositories, and stack references are used so that outputs generated by the Azure resources can be stored in GitHub (e.g., resource group credentials).&lt;/p&gt;
&lt;p&gt;Ready to dive into how this works in detail? Watch the demo in the video below starting around 10:20.&lt;/p&gt;
&lt;div style="position: relative; padding-bottom: 56.25%; height: 0; overflow: hidden;"&gt;
&lt;iframe allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share; fullscreen" loading="eager" referrerpolicy="strict-origin-when-cross-origin" src="https://www.youtube.com/embed/aoa_O-rh5KE?autoplay=0&amp;amp;controls=1&amp;amp;end=0&amp;amp;loop=0&amp;amp;mute=0&amp;amp;start=0" style="position: absolute; top: 0; left: 0; width: 100%; height: 100%; border:0;" title="YouTube video"&gt;&lt;/iframe&gt;
&lt;/div&gt;
&lt;h2 id="next-steps"&gt;Next steps&lt;/h2&gt;
&lt;p&gt;After watching the &lt;a href="https://youtu.be/aoa_O-rh5KE?list=PLyy8Vx2ZoWlpcvhSsUXdT5CXjRwAaM_My&amp;amp;t=620"&gt;demo&lt;/a&gt; of a self-service infrastructure platform, you can try it out for yourself by checking out the &lt;a href="https://github.com/mastoj/pulumi-automation-demo"&gt;demo code&lt;/a&gt;. You can also learn more about &lt;a href="https://www.pulumi.com/automation/"&gt;Pulumi Automation API&lt;/a&gt; in our &lt;a href="https://www.pulumi.com/docs/iac/concepts/automation-api/"&gt;documentation&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;If you’re new to Pulumi, then follow our &lt;a href="https://www.pulumi.com/docs/get-started/"&gt;getting started guide&lt;/a&gt;.&lt;/p&gt;</description><author>George Huang</author><category>automation-api</category><category>aks</category><category>azure</category><category>infrastructure-as-code</category><category>kubernetes</category><category>typescript</category><category>pulumi-enterprise</category><category>cloud-engineering</category><category>github-actions</category></item><item><title>Top 5 Things an Azure Developer Needs to Know: Kubernetes Infrastructure</title><link>https://www.pulumi.com/blog/top-5-things-for-azure-devs-kubernetes-infrastructure/</link><pubDate>Thu, 12 Aug 2021 00:00:00 +0000</pubDate><guid>https://www.pulumi.com/blog/top-5-things-for-azure-devs-kubernetes-infrastructure/</guid><description>
&lt;img src="https://www.pulumi.com/images/generated/blog/top-5-things-for-azure-devs-kubernetes-infrastructure/index.png" /&gt;
&lt;p&gt;History lesson time! In 2011, microservices debuted as an architectural style suited for the cloud. In 2013, Docker simplified building containers. Combining containers and microservices sparked a change in how applications were built and distributed in the cloud. As performance, scaling, and reliability became an increasing concern, container orchestration platforms became widely available. Kubernetes became the dominant container orchestration through community and corporate support, and some have suggested it was &lt;a href="https://elastisys.com/why-kubernetes-was-inevitable/"&gt;inevitable&lt;/a&gt;. Every major cloud service provider, including Azure, offers a version of Kubernetes.&lt;/p&gt;
&lt;p&gt;Kubernetes streamlines container deployment and management, making applications scale and accessible. This article demonstrates configuring and deploying Kubernetes with Azure.&lt;/p&gt;
&lt;h2 id="a-kubernetes-review"&gt;A Kubernetes Review&lt;/h2&gt;
&lt;p&gt;If you&amp;rsquo;re not familiar with Kubernetes concepts and terminology, the Getting Started with Kubernetes series can help get you up to speed.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.pulumi.com/blog/getting-started-with-k8s-part1"&gt;Getting Started With Kubernetes: Clusters and Nodes&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.pulumi.com/blog/getting-started-with-k8s-part2"&gt;Getting Started With Kubernetes: Application Basics&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.pulumi.com/blog/getting-started-with-k8s-part3"&gt;Getting Started With Kubernetes: Advanced Deployment&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.pulumi.com/blog/getting-started-with-k8s-part4"&gt;Getting Started with Kubernetes: Stateful Applications&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.pulumi.com/blog/getting-started-with-k8s-part5"&gt;Getting Started With Kubernetes: Networking&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.pulumi.com/blog/getting-started-with-k8s-part6"&gt;Getting Started With Kubernetes: Day 2&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="azure-kubernetes-service"&gt;Azure Kubernetes Service&lt;/h2&gt;
&lt;p&gt;Azure Kubernetes Service (AKS) is a hosted Kubernetes service. Azure manages the Kubernetes master nodes, and you are responsible for managing the agent or worker nodes. You only pay for the worker nodes in your cluster that make up your application.&lt;/p&gt;
&lt;p&gt;Kubernetes nodes are the worker machines that can be either physical or virtual. AKS nodes use Azure virtual machines (VMs); and you can add storage, upgrade cluster components, or even run multiple node pools with mixed operating systems.&lt;/p&gt;
&lt;p&gt;You can create an AKS cluster with&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;the Azure CLI,&lt;/li&gt;
&lt;li&gt;the Azure portal,&lt;/li&gt;
&lt;li&gt;PowerShell, and&lt;/li&gt;
&lt;li&gt;templates, such as Azure Resource Manager (ARM) templates.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="aks-features"&gt;AKS features&lt;/h3&gt;
&lt;p&gt;Configuring and deploying Kubernetes can be complex. AKS provides many features to simplify the process, including the following features:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Cluster node and pod scaling adjust the number of nodes or pods as resource demand changes. &lt;a href="https://docs.microsoft.com/en-us/azure/aks/tutorial-kubernetes-scale?tabs=azure-cli"&gt;Pods can scale horizontally, and the cluster can also autoscale&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Kubernetes is a fast-moving open source project, and AKS supports multiple versions. You can &lt;a href="https://docs.microsoft.com/en-us/azure/aks/node-image-upgrade"&gt;upgrade the cluster nodes&lt;/a&gt; without interrupting the application.&lt;/li&gt;
&lt;li&gt;If you perform machine learning, AKS can create &lt;a href="https://docs.microsoft.com/en-us/azure/aks/gpu-cluster"&gt;GPU-enabled node pools&lt;/a&gt; for compute-intensive, graphics-intensive, and visualization workloads.&lt;/li&gt;
&lt;li&gt;AKS supports access control through &lt;a href="https://kubernetes.io/docs/reference/access-authn-authz/rbac/"&gt;Kubernetes RBAC&lt;/a&gt; and Azure &lt;a href="https://docs.microsoft.com/en-us/azure/aks/managed-aad"&gt;Active Directory&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Integrated logging and monitoring with &lt;a href="https://docs.microsoft.com/en-us/azure/azure-monitor/containers/container-insights-overview"&gt;Azure Monitor for Containers&lt;/a&gt; collects memory and processor metrics from containers, nodes, and controllers.&lt;/li&gt;
&lt;li&gt;AKS lets you mount &lt;a href="https://docs.microsoft.com/en-us/azure/storage/common/storage-introduction"&gt;static or dynamic storage volumes&lt;/a&gt; for persistent data. Storage volumes use Azure Disks for single pod access or Azure Files for concurrent pod access.&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.microsoft.com/en-us/azure/aks/concepts-network"&gt;Virtual networking&lt;/a&gt; for pods in the cluster and other nodes let you use a peered virtual network. The network also provides ingress for applications with HTTP application routing.&lt;/li&gt;
&lt;li&gt;Integration with development tools for Helm and a &lt;a href="https://marketplace.visualstudio.com/items?itemName=ms-kubernetes-tools.vscode-kubernetes-tools"&gt;Visual Studio Code extension for Kubernetes&lt;/a&gt; improves the developer experience.&lt;/li&gt;
&lt;li&gt;Support for Docker images, including storage with &lt;a href="https://azure.microsoft.com/en-us/services/container-registry/"&gt;Azure Container Registry&lt;/a&gt;, makes deployment easier.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="create-an-aks-cluster-with-the-azure-portal"&gt;Create an AKS Cluster with the Azure Portal&lt;/h2&gt;
&lt;p&gt;We&amp;rsquo;ll use the Azure Portal to illustrate the steps to configure and deploy an AKS Cluster.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Step 1&lt;/strong&gt;: Create a Kubernetes Service.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Open the &lt;a href="https://portal.azure.com"&gt;Azure Portal&lt;/a&gt; and select &lt;strong&gt;Create Resource&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Select &lt;strong&gt;Containers &amp;gt; Kubernetes Service&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Select &lt;strong&gt;Create&lt;/strong&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img src="https://www.pulumi.com/blog/top-5-things-for-azure-devs-kubernetes-infrastructure/kubernetes_service.png" alt="Create Kubernetes service"&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Step 2&lt;/strong&gt;: Create an AKS cluster.&lt;/p&gt;
&lt;p&gt;For this example, we will configure several options in the &lt;strong&gt;Basic&lt;/strong&gt; window but use defaults for most options.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;In &lt;strong&gt;Subscription&lt;/strong&gt;, select an &lt;strong&gt;Azure Subscription&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Create or select a &lt;a href="https://docs.microsoft.com/en-us/azure/azure-resource-manager/management/overview"&gt;Resource Group&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;In &lt;strong&gt;Cluster details&lt;/strong&gt;, set the &lt;strong&gt;Kubernetes cluster name&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Change the &lt;strong&gt;Region&lt;/strong&gt; if needed.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Use the default values for &lt;strong&gt;Primary node pool&lt;/strong&gt;, and select &lt;strong&gt;Next: node pools&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://www.pulumi.com/blog/top-5-things-for-azure-devs-kubernetes-infrastructure/create_aks_cluster.png" alt="Create AKS Cluster"&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Step 3&lt;/strong&gt;: Configure node pools.&lt;/p&gt;
&lt;p&gt;A node pool is a logical grouping of nodes. Nodes in a pool can have different virtual machines, different Kubernetes versions, and other attributes. You can use different node pools for different purposes, such as grouping workflows, e.g., a node pool for production and one for dev or test.&lt;/p&gt;
&lt;p&gt;For this example, use the default values for node pools.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://www.pulumi.com/blog/top-5-things-for-azure-devs-kubernetes-infrastructure/node_pools.png" alt="Node pools"&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Step 4&lt;/strong&gt;: Configure authentication.&lt;/p&gt;
&lt;p&gt;You can authenticate, authorize, secure, and control access to Kubernetes clusters with&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://kubernetes.io/docs/reference/access-authn-authz/rbac/"&gt;Kubernetes role-based access control&lt;/a&gt; (Kubernetes RBAC) to grant access to service accounts or&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.microsoft.com/en-us/azure/aks/managed-aad"&gt;Azure Active Directory integration&lt;/a&gt; that provides a multi-tenant, cloud-based directory and identity management service.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;To configure &lt;strong&gt;Authentication&lt;/strong&gt; for this example, set the &lt;strong&gt;Authentication method&lt;/strong&gt; to &lt;strong&gt;System-assigned managed identity&lt;/strong&gt;. You can set &lt;strong&gt;Role-based access control (RBAC)&lt;/strong&gt; to enabled, but it&amp;rsquo;s unnecessary for the example. Use the default value for the &lt;strong&gt;Node pool OS disk encryption&lt;/strong&gt; type.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://www.pulumi.com/blog/top-5-things-for-azure-devs-kubernetes-infrastructure/authentication.png" alt="Authentication"&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Step 5&lt;/strong&gt;: Configure networking&lt;/p&gt;
&lt;p&gt;AKS can use either &lt;code&gt;kubenet&lt;/code&gt; or &lt;code&gt;Azure CNI&lt;/code&gt; networking. Kubenet is the default configuration for AKS cluster creation.&lt;/p&gt;
&lt;p&gt;With &lt;code&gt;kubenet&lt;/code&gt;, Azure creates and configures the virtual network. However, only the nodes receive a routable IP address and pods use a NAT to communicate with resources outside the AKS cluster. This approach reduces the number of IP addresses you need to reserve in your network space for pods to use.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;Azure CNI&lt;/code&gt;assigns an IP address to every pod, which makes them directly accessible. The IP addresses must be unique and planned in advance. Each node must be configured for the maximum number of pods to reserve IP addresses per node. Without accounting for the number of pods, the network can run out of IP addresses to allocate or necessitate the need to rebuild clusters with a larger subnet.&lt;/p&gt;
&lt;p&gt;For this example, we&amp;rsquo;ll use &lt;code&gt;kubenet&lt;/code&gt; for it&amp;rsquo;s simplicity, but in production &lt;code&gt;Azure CNI&lt;/code&gt; maybe the better choice for applications.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://www.pulumi.com/blog/top-5-things-for-azure-devs-kubernetes-infrastructure/networking.png" alt="Networking"&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Step 6&lt;/strong&gt;: Complete the deployment&lt;/p&gt;
&lt;p&gt;Select &lt;strong&gt;Review + create&lt;/strong&gt; to deploy. Deployment takes several minutes to complete. On completion, you can verify the &lt;strong&gt;Deployment details&lt;/strong&gt; or select &lt;strong&gt;Connect to cluster&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;&lt;img src="deployment_complete.png" alt="Deployment complete"&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Step 7&lt;/strong&gt;: Connect to the cluster&lt;/p&gt;
&lt;p&gt;You can manage your cluster with &lt;a href="https://kubernetes.io/docs/tasks/tools/#kubectl"&gt;&lt;code&gt;kubectl&lt;/code&gt;&lt;/a&gt;, a command line tool for managing Kubernetes. You can install &lt;code&gt;kubectl&lt;/code&gt; on &lt;a href="https://kubernetes.io/docs/tasks/tools/install-kubectl-linux"&gt;linux&lt;/a&gt;, &lt;a href="https://kubernetes.io/docs/tasks/tools/install-kubectl-macos"&gt;macOS&lt;/a&gt;, and &lt;a href="https://kubernetes.io/docs/tasks/tools/install-kubectl-windows"&gt;Windows&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Copy and paste the commands to connect and authenticate to your cluster using the &lt;a href="https://docs.microsoft.com/en-us/cli/azure/install-azure-cli"&gt;Azure CLI&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://www.pulumi.com/blog/top-5-things-for-azure-devs-kubernetes-infrastructure/connect.png" alt="Connect"&gt;&lt;/p&gt;
&lt;p&gt;After connecting and authenticating to your cluster, you can use &lt;code&gt;kubectl&lt;/code&gt; to query your cluster.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ kubectl get nodes
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;NAME STATUS ROLES AGE VERSION
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;aks-agentpool-19694923-vmss000000 Ready agent 9m35s v1.20.7
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;aks-agentpool-19694923-vmss000001 Ready agent 9m39s v1.20.7
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;aks-agentpool-19694923-vmss000002 Ready agent 9m47s v1.20.7
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ kubectl get all
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;NAME TYPE CLUSTER-IP EXTERNAL-IP PORT&lt;span class="o"&gt;(&lt;/span&gt;S&lt;span class="o"&gt;)&lt;/span&gt; AGE
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;service/kubernetes ClusterIP 10.0.0.1 &amp;lt;none&amp;gt; 443/TCP 11m
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Your AKS cluster is deployed and running.&lt;/p&gt;
&lt;h2 id="deploying-an-aks-cluster-with-code"&gt;Deploying an AKS cluster with code&lt;/h2&gt;
&lt;p&gt;Now that we have reviewed the process for creating an AKS cluster using the Azure Portal, we can repeat the process using code.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Step 1&lt;/strong&gt;: Create a &lt;code&gt;Resource group&lt;/code&gt; and a &lt;code&gt;Service principal&lt;/code&gt; for the cluster. Note that we used a &lt;code&gt;System-assigned managed identity&lt;/code&gt; in the Azure Portal example.&lt;/p&gt;
&lt;div&gt;
&lt;pulumi-chooser type="language" options="csharp,go,python,typescript" mode=""&gt;
&lt;div&gt;
&lt;pulumi-choosable type="language" values="csharp" mode=""&gt;&lt;pre&gt;&lt;code&gt; // Create an Azure Resource Group
var resourceGroup = new ResourceGroup(&amp;quot;azure-cs-aks&amp;quot;);
// Create an AD service principal
var adApp = new Application(&amp;quot;aks&amp;quot;, new ApplicationArgs
{
DisplayName = &amp;quot;aks&amp;quot;
});
var adSp = new ServicePrincipal(&amp;quot;aksSp&amp;quot;, new ServicePrincipalArgs
{
ApplicationId = adApp.ApplicationId
});
// Generate random password
var password = new RandomPassword(&amp;quot;password&amp;quot;, new RandomPasswordArgs
{
Length = 20,
Special = true
});
// Create the Service Principal Password
var adSpPassword = new ServicePrincipalPassword(&amp;quot;aksSpPassword&amp;quot;, new ServicePrincipalPasswordArgs
{
ServicePrincipalId = adSp.Id,
Value = password.Result,
EndDate = &amp;quot;2099-01-01T00:00:00Z&amp;quot;
});
// Generate an SSH key
var sshKey = new PrivateKey(&amp;quot;ssh-key&amp;quot;, new PrivateKeyArgs
{
Algorithm = &amp;quot;RSA&amp;quot;,
RsaBits = 4096
});
&lt;/code&gt;&lt;/pre&gt;
&lt;/pulumi-choosable&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;pulumi-choosable type="language" values="go" mode=""&gt;&lt;pre&gt;&lt;code&gt; // Create an Azure Resource Group
resourceGroup, err := resources.NewResourceGroup(ctx, &amp;quot;azure-go-aks&amp;quot;, nil)
if err != nil {
return err
}
// Create an AD service principal.
adApp, err := azuread.NewApplication(ctx, &amp;quot;aks&amp;quot;, &amp;amp;azuread.ApplicationArgs{
DisplayName: pulumi.String(&amp;quot;aks&amp;quot;),
})
if err != nil {
return err
}
adSp, err := azuread.NewServicePrincipal(ctx, &amp;quot;aksSp&amp;quot;, &amp;amp;azuread.ServicePrincipalArgs{
ApplicationId: adApp.ApplicationId,
})
if err != nil {
return err
}
// Generate a random password.
password, err := random.NewRandomPassword(ctx, &amp;quot;password&amp;quot;, &amp;amp;random.RandomPasswordArgs{
Length: pulumi.Int(20),
Special: pulumi.Bool(true),
})
if err != nil {
return err
}
// Create the Service Principal Password.
adSpPassword, err := azuread.NewServicePrincipalPassword(ctx, &amp;quot;aksSpPassword&amp;quot;, &amp;amp;azuread.ServicePrincipalPasswordArgs{
ServicePrincipalId: adSp.ID(),
Value: password.Result,
EndDate: pulumi.String(&amp;quot;2099-01-01T00:00:00Z&amp;quot;),
})
if err != nil {
return err
}
// Generate an SSH key.
sshArgs := tls.PrivateKeyArgs{
Algorithm: pulumi.String(&amp;quot;RSA&amp;quot;),
RsaBits: pulumi.Int(4096),
}
sshKey, err := tls.NewPrivateKey(ctx, &amp;quot;ssh-key&amp;quot;, &amp;amp;sshArgs)
if err != nil {
return err
}
&lt;/code&gt;&lt;/pre&gt;
&lt;/pulumi-choosable&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;pulumi-choosable type="language" values="python" mode=""&gt;&lt;pre&gt;&lt;code&gt; # Create new resource group
resource_group = resources.ResourceGroup(&amp;quot;azure-native-py-aks&amp;quot;)
# Create an AD service principal
ad_app = azuread.Application(&amp;quot;aks&amp;quot;, display_name=&amp;quot;aks&amp;quot;)
ad_sp = azuread.ServicePrincipal(&amp;quot;aksSp&amp;quot;, application_id=ad_app.application_id)
# Generate random password
password = random.RandomPassword(&amp;quot;password&amp;quot;, length=20, special=True)
# Create the Service Principal Password
ad_sp_password = azuread.ServicePrincipalPassword(&amp;quot;aksSpPassword&amp;quot;,
service_principal_id=ad_sp.id,
value=password.result,
end_date=&amp;quot;2099-01-01T00:00:00Z&amp;quot;)
# Generate an SSH key
ssh_key = tls.PrivateKey(&amp;quot;ssh-key&amp;quot;, algorithm=&amp;quot;RSA&amp;quot;, rsa_bits=4096)
&lt;/code&gt;&lt;/pre&gt;
&lt;/pulumi-choosable&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;pulumi-choosable type="language" values="typescript" mode=""&gt;&lt;pre&gt;&lt;code&gt; // Create an Azure Resource Group
const resourceGroup = new resources.ResourceGroup(&amp;quot;azure-go-aks&amp;quot;);
// Create an AD service principal
const adApp = new azuread.Application(&amp;quot;aks&amp;quot;, {
displayName: &amp;quot;aks&amp;quot;,
});
const adSp = new azuread.ServicePrincipal(&amp;quot;aksSp&amp;quot;, {
applicationId: adApp.applicationId,
});
// Generate random password
const password = new random.RandomPassword(&amp;quot;password&amp;quot;, {
length: 20,
special: true,
});
// Create the Service Principal Password
const adSpPassword = new azuread.ServicePrincipalPassword(&amp;quot;aksSpPassword&amp;quot;, {
servicePrincipalId: adSp.id,
value: password.result,
endDate: &amp;quot;2099-01-01T00:00:00Z&amp;quot;,
});
// Generate an SSH key
const sshKey = new tls.PrivateKey(&amp;quot;ssh-key&amp;quot;, {
algorithm: &amp;quot;RSA&amp;quot;,
rsaBits: 4096,
});
&lt;/code&gt;&lt;/pre&gt;
&lt;/pulumi-choosable&gt;
&lt;/div&gt;
&lt;/pulumi-chooser&gt;
&lt;/div&gt;
&lt;p&gt;&lt;strong&gt;Step 2&lt;/strong&gt;: Configure the AKS cluster&lt;/p&gt;
&lt;p&gt;We set the configuration options in &lt;code&gt;ManagedClusterAgentPoolProfileArgs&lt;/code&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;Count&lt;/code&gt;: Number of virtual machines&lt;/li&gt;
&lt;li&gt;&lt;code&gt;MaxPods&lt;/code&gt;: Maximum number of pods that can run on a node.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Mode&lt;/code&gt;: Sets the type of pool node, which can be &lt;a href="https://docs.microsoft.com/en-us/azure/aks/use-system-pools"&gt;system or user&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Name&lt;/code&gt;: Name of the pool node&lt;/li&gt;
&lt;li&gt;&lt;code&gt;OsType&lt;/code&gt;: Specifies the OS type&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Type&lt;/code&gt;: Choose between a &lt;a href="https://docs.microsoft.com/en-us/azure/aks/use-system-pools"&gt;&lt;code&gt;VirtualMachineScaleSet&lt;/code&gt;&lt;/a&gt; or an &lt;a href="https://docs.microsoft.com/en-us/azure/aks/availability-zones"&gt;&lt;code&gt;AvailabilitySet&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;VmSize&lt;/code&gt;: The virtual machine size used by the cluster.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The remaining parameters set the Kubernetes version, enables RBAC, and configures the Linux profile for the &lt;code&gt;ContainerService&lt;/code&gt;.&lt;/p&gt;
&lt;div&gt;
&lt;pulumi-chooser type="language" options="csharp,go,python,typescript" mode=""&gt;
&lt;div&gt;
&lt;pulumi-choosable type="language" values="csharp" mode=""&gt;&lt;pre&gt;&lt;code&gt; var cluster = new ManagedCluster(&amp;quot;my-aks&amp;quot;, new ManagedClusterArgs
{
ResourceGroupName = resourceGroup.Name,
AgentPoolProfiles =
{
new ManagedClusterAgentPoolProfileArgs
{
Count = 3,
MaxPods = 110,
Mode = &amp;quot;System&amp;quot;,
Name = &amp;quot;agentpool&amp;quot;,
OsDiskSizeGB = 30,
OsType = &amp;quot;Linux&amp;quot;,
Type = &amp;quot;VirtualMachineScaleSets&amp;quot;,
VmSize = &amp;quot;Standard_DS2_v2&amp;quot;,
}
},
DnsPrefix = &amp;quot;AzureNativeprovider&amp;quot;,
EnableRBAC = true,
KubernetesVersion = &amp;quot;1.18.14&amp;quot;,
LinuxProfile = new ContainerServiceLinuxProfileArgs
{
AdminUsername = &amp;quot;testuser&amp;quot;,
Ssh = new ContainerServiceSshConfigurationArgs
{
PublicKeys =
{
new ContainerServiceSshPublicKeyArgs
{
KeyData = sshKey.PublicKeyOpenssh,
}
}
}
},
NodeResourceGroup = $&amp;quot;MC_azure-cs_my_aks&amp;quot;,
ServicePrincipalProfile = new ManagedClusterServicePrincipalProfileArgs
{
ClientId = adApp.ApplicationId,
Secret = adSpPassword.Value
}
});
&lt;/code&gt;&lt;/pre&gt;
&lt;/pulumi-choosable&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;pulumi-choosable type="language" values="go" mode=""&gt;&lt;pre&gt;&lt;code&gt; // Create the Azure Kubernetes Service cluster.
cluster, err := containerservice.NewManagedCluster(ctx, &amp;quot;go-aks&amp;quot;, &amp;amp;containerservice.ManagedClusterArgs{
ResourceGroupName: resourceGroup.Name,
AgentPoolProfiles: containerservice.ManagedClusterAgentPoolProfileArray{
&amp;amp;containerservice.ManagedClusterAgentPoolProfileArgs{
Name: pulumi.String(&amp;quot;agentpool&amp;quot;),
Mode: pulumi.String(&amp;quot;System&amp;quot;),
OsDiskSizeGB: pulumi.Int(30),
Count: pulumi.Int(3),
VmSize: pulumi.String(&amp;quot;Standard_DS2_v2&amp;quot;),
OsType: pulumi.String(&amp;quot;Linux&amp;quot;),
},
},
LinuxProfile: &amp;amp;containerservice.ContainerServiceLinuxProfileArgs{
AdminUsername: pulumi.String(&amp;quot;testuser&amp;quot;),
Ssh: containerservice.ContainerServiceSshConfigurationArgs{
PublicKeys: containerservice.ContainerServiceSshPublicKeyArray{
containerservice.ContainerServiceSshPublicKeyArgs{
KeyData: sshKey.PublicKeyOpenssh,
},
},
},
},
DnsPrefix: resourceGroup.Name,
ServicePrincipalProfile: &amp;amp;containerservice.ManagedClusterServicePrincipalProfileArgs{
ClientId: adApp.ApplicationId,
Secret: adSpPassword.Value,
},
KubernetesVersion: pulumi.String(&amp;quot;1.18.14&amp;quot;),
})
if err != nil {
return err
}
&lt;/code&gt;&lt;/pre&gt;
&lt;/pulumi-choosable&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;pulumi-choosable type="language" values="python" mode=""&gt;&lt;pre&gt;&lt;code&gt; # Create cluster
managed_cluster_name = config.get(&amp;quot;managedClusterName&amp;quot;)
if managed_cluster_name is None:
managed_cluster_name = &amp;quot;azure-native-aks&amp;quot;
managed_cluster = containerservice.ManagedCluster(
managed_cluster_name,
resource_group_name=resource_group.name,
agent_pool_profiles=[{
&amp;quot;count&amp;quot;: 3,
&amp;quot;max_pods&amp;quot;: 110,
&amp;quot;mode&amp;quot;: &amp;quot;System&amp;quot;,
&amp;quot;name&amp;quot;: &amp;quot;agentpool&amp;quot;,
&amp;quot;node_labels&amp;quot;: {},
&amp;quot;os_disk_size_gb&amp;quot;: 30,
&amp;quot;os_type&amp;quot;: &amp;quot;Linux&amp;quot;,
&amp;quot;type&amp;quot;: &amp;quot;VirtualMachineScaleSets&amp;quot;,
&amp;quot;vm_size&amp;quot;: &amp;quot;Standard_DS2_v2&amp;quot;,
}],
enable_rbac=True,
kubernetes_version=&amp;quot;1.18.14&amp;quot;,
linux_profile={
&amp;quot;admin_username&amp;quot;: &amp;quot;testuser&amp;quot;,
&amp;quot;ssh&amp;quot;: {
&amp;quot;public_keys&amp;quot;: [{
&amp;quot;key_data&amp;quot;: ssh_key.public_key_openssh,
}],
},
},
dns_prefix=resource_group.name,
node_resource_group=f&amp;quot;MC_azure-native-go_{managed_cluster_name}_westus&amp;quot;,
service_principal_profile={
&amp;quot;client_id&amp;quot;: ad_app.application_id,
&amp;quot;secret&amp;quot;: ad_sp_password.value
})
&lt;/code&gt;&lt;/pre&gt;
&lt;/pulumi-choosable&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;pulumi-choosable type="language" values="typescript" mode=""&gt;&lt;pre&gt;&lt;code&gt; const cluster = new containerservice.ManagedCluster(managedClusterName, {
resourceGroupName: resourceGroup.name,
agentPoolProfiles: [{
count: 3,
maxPods: 110,
mode: &amp;quot;System&amp;quot;,
name: &amp;quot;agentpool&amp;quot;,
nodeLabels: {},
osDiskSizeGB: 30,
osType: &amp;quot;Linux&amp;quot;,
type: &amp;quot;VirtualMachineScaleSets&amp;quot;,
vmSize: &amp;quot;Standard_DS2_v2&amp;quot;,
}],
dnsPrefix: resourceGroup.name,
enableRBAC: true,
kubernetesVersion: &amp;quot;1.18.14&amp;quot;,
linuxProfile: {
adminUsername: &amp;quot;testuser&amp;quot;,
ssh: {
publicKeys: [{
keyData: sshKey.publicKeyOpenssh,
}],
},
},
nodeResourceGroup: `MC_azure-go_${managedClusterName}`,
servicePrincipalProfile: {
clientId: adApp.applicationId,
secret: adSpPassword.value,
},
});
&lt;/code&gt;&lt;/pre&gt;
&lt;/pulumi-choosable&gt;
&lt;/div&gt;
&lt;/pulumi-chooser&gt;
&lt;/div&gt;
&lt;p&gt;&lt;strong&gt;Step 3&lt;/strong&gt;: Export the &lt;code&gt;kubeconfig&lt;/code&gt; file&lt;/p&gt;
&lt;p&gt;A &lt;a href="https://kubernetes.io/docs/concepts/configuration/organize-cluster-access-kubeconfig/"&gt;&lt;code&gt;kubeconfig&lt;/code&gt;&lt;/a&gt; file organizes information about clusters and allows &lt;code&gt;kubectl&lt;/code&gt; connect to the cluster.&lt;/p&gt;
&lt;div&gt;
&lt;pulumi-chooser type="language" options="csharp,go,python,typescript" mode=""&gt;
&lt;div&gt;
&lt;pulumi-choosable type="language" values="csharp" mode=""&gt;&lt;pre&gt;&lt;code&gt;...
// Export the KubeConfig
this.KubeConfig = Output.Tuple(resourceGroup.Name, cluster.Name).Apply(names =&amp;gt;
GetKubeConfig(names.Item1, names.Item2));
}
[Output]
public Output&amp;lt;string&amp;gt; KubeConfig { get; set; }
private static async Task&amp;lt;string&amp;gt; GetKubeConfig(string resourceGroupName, string clusterName)
{
var credentials = await ListManagedClusterUserCredentials.InvokeAsync(new ListManagedClusterUserCredentialsArgs
{
ResourceGroupName = resourceGroupName,
ResourceName = clusterName
});
var encoded = credentials.Kubeconfigs[0].Value;
var data = Convert.FromBase64String(encoded);
return Encoding.UTF8.GetString(data);
}
&lt;/code&gt;&lt;/pre&gt;
&lt;/pulumi-choosable&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;pulumi-choosable type="language" values="go" mode=""&gt;&lt;pre&gt;&lt;code&gt; ctx.Export(&amp;quot;kubeconfig&amp;quot;, pulumi.All(cluster.Name, resourceGroup.Name, resourceGroup.ID()).ApplyT(func(args interface{}) (string, error) {
clusterName := args.([]interface{})[0].(string)
resourceGroupName := args.([]interface{})[1].(string)
creds, err := containerservice.ListManagedClusterUserCredentials(ctx, &amp;amp;containerservice.ListManagedClusterUserCredentialsArgs{
ResourceGroupName: resourceGroupName,
ResourceName: clusterName,
})
if err != nil {
return &amp;quot;&amp;quot;, err
}
encoded := creds.Kubeconfigs[0].Value
kubeconfig, err := base64.StdEncoding.DecodeString(encoded)
if err != nil {
return &amp;quot;&amp;quot;, err
}
return string(kubeconfig), nil
}))
&lt;/code&gt;&lt;/pre&gt;
&lt;/pulumi-choosable&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;pulumi-choosable type="language" values="python" mode=""&gt;&lt;pre&gt;&lt;code&gt; # Export kubeconfig
encoded = creds.kubeconfigs[0].value
kubeconfig = encoded.apply(
lambda enc: base64.b64decode(enc).decode())
pulumi.export(&amp;quot;kubeconfig&amp;quot;, kubeconfig)
&lt;/code&gt;&lt;/pre&gt;
&lt;/pulumi-choosable&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;pulumi-choosable type="language" values="typescript" mode=""&gt;&lt;/pulumi-choosable&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;pulumi-choosable type="language" values="typescript" mode=""&gt;&lt;pre&gt;&lt;code&gt; const creds = pulumi.all([cluster.name, resourceGroup.name]).apply(([clusterName, rgName]) =&amp;gt; {
return containerservice.listManagedClusterUserCredentials({
resourceGroupName: rgName,
resourceName: clusterName,
});
});
const encoded = creds.kubeconfigs[0].value;
export const kubeconfig = encoded.apply(enc =&amp;gt; Buffer.from(enc, &amp;quot;base64&amp;quot;).toString());
&lt;/code&gt;&lt;/pre&gt;
&lt;/pulumi-choosable&gt;
&lt;/div&gt;
&lt;/pulumi-chooser&gt;
&lt;/div&gt;
&lt;p&gt;&lt;strong&gt;Step 4&lt;/strong&gt;: Connect to the AKS cluster&lt;/p&gt;
&lt;p&gt;We can use the &lt;code&gt;kubeconfig&lt;/code&gt; file connect to the cluster. It&amp;rsquo;s common practice to copy the &lt;code&gt;kubeconfig&lt;/code&gt; file to &lt;code&gt;~/.kube/config&lt;/code&gt;, which is the directory that &lt;code&gt;kubectl&lt;/code&gt; looks for the file. However, you can use any directory with the &lt;code&gt;--kubeconfig&lt;/code&gt; flag, e.g.,&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ kubectl --kubeconfig /path/to/kubeconfig_file get pods
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;As this example shows, deploying an AKS cluster requires setting parameters. This action can be done in the portal or with code. The advantage of code is that clusters can be created on demand without having to use the Azure portal. This setup is convenient when you have different environments, such as a dev/test environment and a production environment.&lt;/p&gt;
&lt;p&gt;The complete code for deploying AKS is available on GitHub for &lt;a href="https://github.com/pulumi/examples/tree/master/azure-ts-aks"&gt;Typescript&lt;/a&gt;, &lt;a href="https://github.com/pulumi/examples/tree/master/azure-py-aks"&gt;Python&lt;/a&gt;, &lt;a href="https://github.com/pulumi/examples/tree/master/azure-go-aks"&gt;Go&lt;/a&gt;, and &lt;a href="https://github.com/pulumi/examples/tree/master/azure-cs-aks"&gt;C#&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id="summary"&gt;Summary&lt;/h2&gt;
&lt;p&gt;Azure Kubernetes Service lets you deploy a Kubernetes cluster quickly and efficiently. An AKS deployment configures the worker nodes since the master nodes are provided by Azure. The Azure Portal provides a simplified interface for configuration, but if you want fine-grain control over the deployment, infrastructure as code is an option. This is particularly true for production deployments where the configuration requires tuning for an application deployment.&lt;/p&gt;
&lt;p&gt;In the next article in this series, we&amp;rsquo;ll deploy an application on an AKS cluster using different methods.&lt;/p&gt;</description><author>Sophia Parafina</author><category>kubernetes</category><category>aks</category><category>azure</category></item><item><title>Top 5 Things an Azure Developer Needs to Know: Introduction</title><link>https://www.pulumi.com/blog/top-5-things-for-azure-devs-intro/</link><pubDate>Mon, 02 Aug 2021 00:00:00 +0000</pubDate><guid>https://www.pulumi.com/blog/top-5-things-for-azure-devs-intro/</guid><description>
&lt;img src="https://www.pulumi.com/images/generated/blog/top-5-things-for-azure-devs-intro/index.png" /&gt;
&lt;p&gt;The Azure cloud platform includes over 200 products and cloud services. Wherever you are in your Microsoft cloud engineering journey, you should be familiar with these top 5 cloud tasks that are essential building blocks commonly used to deploy applications and infrastructure to the Azure cloud.&lt;/p&gt;
&lt;p&gt;In this series of articles, we&amp;rsquo;ll go in-depth on &lt;a href="https://www.pulumi.com/blog/top-5-things-for-azure-devs-vm/"&gt;virtual machines&lt;/a&gt;, &lt;a href="https://www.pulumi.com/blog/top-5-things-for-azure-devs-serverless/"&gt;Azure Functions&lt;/a&gt;, &lt;a href="https://www.pulumi.com/blog/top-5-things-for-azure-devs-static-websites/"&gt;static websites&lt;/a&gt;, &lt;a href="https://www.pulumi.com/blog/top-5-things-for-azure-devs-kubernetes-infrastructure/"&gt;building an Azure Kubernetes Service cluster&lt;/a&gt; and &lt;a href="https://www.pulumi.com/blog/top-5-things-for-azure-devs-kubernetes-apps/"&gt;deploying applications on AKS&lt;/a&gt;, and &lt;a href="https://www.pulumi.com/blog/top-5-things-for-azure-devs-devops/"&gt;DevOps with Azure App Service&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id="azure---a-comprehensive-cloud-platform"&gt;Azure - a comprehensive cloud platform&lt;/h2&gt;
&lt;p&gt;With Azure, you can develop, test, deploy and manage your applications in an integrated cloud computing environment. With the Azure Portal, you can manage the cloud infrastructure for your applications. Azure gives you the choice of a portal for managing services or managing them programmatically using service APIs and templates.&lt;/p&gt;
&lt;p&gt;With over 200 services, knowing which one to use can be confusing. Deciding where to host your application is the first step. This series of articles covers the most commonly used Azure services such as virtual machines, serverless functions, static websites, Kubernetes, and Azure App Service. In addition, we&amp;rsquo;ll cover how to deploy applications using Azure DevOps.&lt;/p&gt;
&lt;p&gt;In this article, we&amp;rsquo;ll match use cases to cloud services to help you navigate Azure.&lt;/p&gt;
&lt;h2 id="azure-virtual-machines"&gt;Azure Virtual Machines&lt;/h2&gt;
&lt;p&gt;A common cloud migration path is to use virtual machines if you have existing infrastructure or on-premise applications. It is especially true if you want complete control over the infrastructure and application environment.&lt;/p&gt;
&lt;p&gt;Azure provides Infrastructure as a Service (IaaS) for deploying your applications on either Linux or Windows VMs. IaaS includes all necessary support, such as Azure Virtual Network and storage. As with any IaaS solution, you are responsible for the installation of software, configuration, and maintenance of your application and any maintenance the VM might require, such as operating system patches.&lt;/p&gt;
&lt;p&gt;If your application doesn&amp;rsquo;t fit into a Platform as a Service (PaaS) model, consider using virtual machines to provide the fine-grained control required for your deployment.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://www.pulumi.com/blog/top-5-things-for-azure-devs-intro/image3.png" alt="VM in Azure Portal"&gt;&lt;/p&gt;
&lt;h2 id="serverless"&gt;Serverless&lt;/h2&gt;
&lt;p&gt;At the opposite end of cloud infrastructure is serverless computing. Serverless eliminates the need to manage infrastructure and lets you focus on writing and deploying code. Azure automatically provisions, scales, and manages the infrastructure. You can write code that runs in response to events or on a schedule.&lt;/p&gt;
&lt;p&gt;Azure Functions lets you focus on the application&amp;rsquo;s business logic, and the code executes when called by a webhook, an HTTP or REST request, a schedule, or an event. Serverless is particularly appealing because you can use the development language of your choice, ranging from PHP, Python, Node.js, or .NET languages. Azure functions scale as needed, and consumption-based pricing means that you&amp;rsquo;re charged only when the code runs.&lt;/p&gt;
&lt;p&gt;If you don’t need a completely hosted project and only pay for what you use, choose Azure Functions triggered by web-based events, a schedule, or other Azure services.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://www.pulumi.com/blog/top-5-things-for-azure-devs-intro/image2.png" alt="Serverless function"&gt;&lt;/p&gt;
&lt;h2 id="static-websites"&gt;Static websites&lt;/h2&gt;
&lt;p&gt;Static websites are quickly becoming the defacto way to publish content. Built from libraries and frameworks that don&amp;rsquo;t use server side rendering like React, Angular, or Vue, they include HTML, CSS, image assets, and Javascript in the application. Instead of serving assets from a server or servers scaled horizontally, the static assets are distributed through a Content Delivery Network (CDN). This reduces latency, resulting in faster websites and increased customer satisfaction.&lt;/p&gt;
&lt;p&gt;Azure provides two ways to deploy static websites. Azure lets you deploy a static web application with Azure App Service and the recently released Azure Static Web Apps. Azure App Service deploys websites by uploading the website to Azure storage configured to serve web content. Azure App Service automatically builds and deploys full stack web apps to Azure from a code repository, which follows the &lt;a href="https://jamstack.org/"&gt;Jamstack&lt;/a&gt; model for developing and deploying websites.&lt;/p&gt;
&lt;p&gt;We&amp;rsquo;ll look at both methods and discuss the pros and cons of both methods.&lt;/p&gt;
&lt;h2 id="kubernetes"&gt;Kubernetes&lt;/h2&gt;
&lt;p&gt;Kubernetes is the leading container orchestration service. Azure Kubernetes Service (AKS) is a hosted service that can deploy, scale, and manage containerized applications in a cluster. AKS fulfills many different use cases, for example:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;If you have an existing application, think n-tier applications, you can containerize the components and &amp;ldquo;lift and shift&amp;rdquo; your application to run in Kubernetes.&lt;/li&gt;
&lt;li&gt;You can deploy microservices on AKS to add horizontal scaling, load balancing, secrets management, and self-healing.&lt;/li&gt;
&lt;li&gt;Data scientists are training machine learning models on AKS using TensorFlow and Kubeflow.&lt;/li&gt;
&lt;li&gt;You can even use AKS as part of a build pipeline by pairing with a CI, such as Jenkins, to build containers for your application.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;AKS supports many use cases by providing provisioning, scaling, and resource upgrades without requiring expertise in container orchestration. With AKS, the Kubernetes master nodes are managed by Azure, and you are only charged for the worker nodes in your cluster.&lt;/p&gt;
&lt;p&gt;We’ll do two separate deep dives into deploying AKS clusters and deploying applications in AKS in this series.&lt;/p&gt;
&lt;h3 id="deploy-aks"&gt;Deploy AKS&lt;/h3&gt;
&lt;p&gt;Azure provides many ways to deploy an AKS cluster, including:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://docs.microsoft.com/en-us/cli/azure/"&gt;Azure CLI&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.microsoft.com/en-us/azure/aks/kubernetes-walkthrough-portal"&gt;Azure portal&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.microsoft.com/en-us/azure/azure-resource-manager/management/overview"&gt;Azure Resource Manager templates&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/Azure/bicep"&gt;Bicep&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.pulumi.com/registry/packages/azure-native/how-to-guides/azure-cs-aks/"&gt;Infrastructure as Code&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;When you deploy an AKS Cluster, the worker nodes and Kubernetes master are configured with a basic configuration. You can additionally configure networking, storage, monitoring, and policies. We&amp;rsquo;ll cover configuring AKS in this series.&lt;/p&gt;
&lt;h3 id="deploy-applications"&gt;Deploy Applications&lt;/h3&gt;
&lt;p&gt;Deploying applications on AKS is equally flexible, and you can deploy using:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://kubernetes.io/docs/reference/generated/kubectl/kubectl-commands#-strong-app-management-strong-"&gt;kubectl&lt;/a&gt; and YAML manifests&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.microsoft.com/en-us/azure/aks/kubernetes-helm"&gt;Helm&lt;/a&gt;, an open-source Kubernetes packaging tool&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.microsoft.com/en-us/azure/devops/pipelines/apps/cd/deploy-aks?view=azure-devops&amp;amp;tabs=java"&gt;Azure Pipelines&lt;/a&gt;
&lt;a href="https://www.pulumi.com/registry/packages/kubernetes/how-to-guides/configmap-rollout/"&gt;Infrastructure as Code&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;We&amp;rsquo;ll examine these options and do a deep dive on application deployment in a follow-up article.&lt;/p&gt;
&lt;h2 id="devops-integration"&gt;DevOps integration&lt;/h2&gt;
&lt;p&gt;Before Continuous integration (CI) and Continuous Deployment (CD) became prevalent, applications were manually built, compiled, and maintained in a large codebase. CI/CD automation lets you build quickly, test, and deploy services. Both application fixes and new features are shipped quickly to your customers, and you can rapidly respond to changing customer demands. For example, if demand increases, you can quickly add resources to your application or add a serverless function that increases and decreases resources as needed.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://www.pulumi.com/blog/top-5-things-for-azure-devs-intro/image1.png" alt="Devops architecture"&gt;&lt;/p&gt;
&lt;p&gt;If you&amp;rsquo;re deploying applications on Azure Functions, virtual machines, AKS, or provisioning infrastructure, the build process should be automated. Azure offers a range of services such as Azure Container Registry, AKS, and Azure Cosmos DB that can integrate with popular CI/CD pipelines like Azure DevOps, Jenkins, GitHub, and TeamCity.&lt;/p&gt;
&lt;p&gt;If you&amp;rsquo;re interested in using Azure DevOps to automate infrastructure and application delivery, stay tuned!&lt;/p&gt;
&lt;h2 id="lets-get-started"&gt;Let&amp;rsquo;s Get Started!&lt;/h2&gt;
&lt;p&gt;So here are the top 5 things essential to know as an Azure developer:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;configuring and deploying virtual machines&lt;/li&gt;
&lt;li&gt;developing and deploying Azure Functions&lt;/li&gt;
&lt;li&gt;deploying static websites on Azure&lt;/li&gt;
&lt;li&gt;configuring Azure Kubernetes Service and deploying containerized applications&lt;/li&gt;
&lt;li&gt;using Azure DevOps to automate the building and deployment of infrastructure and applications&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;First up and next in this series of articles is deploying Azure virtual machines with an application.&lt;/p&gt;</description><author>Sophia Parafina</author><category>azure</category><category>virtual-machines</category><category>serverless</category><category>aks</category><category>devops</category></item><item><title>Multicloud Kubernetes: Running Apps Across EKS, AKS, and GKE</title><link>https://www.pulumi.com/blog/multicloud-app/</link><pubDate>Wed, 14 Aug 2019 00:00:00 +0000</pubDate><guid>https://www.pulumi.com/blog/multicloud-app/</guid><description>
&lt;img src="https://www.pulumi.com/images/generated/blog/multicloud-app/index.png" /&gt;
&lt;p&gt;Multi-cloud Kubernetes means running clusters on more than one cloud provider, typically some mix of Amazon EKS, Azure AKS, and Google GKE, and managing them through one consistent workflow instead of three separate ones. Teams take this on to avoid vendor lock-in, meet data-residency requirements, or let each application team run on the cloud that fits its workload.&lt;/p&gt;
&lt;p&gt;The catch is that EKS, AKS, and GKE each provision and configure clusters differently, so treating them as one target complicates cluster provisioning, application deployment, and CI/CD. If you also need to run the &lt;em&gt;same&lt;/em&gt; application across providers for testing or resilience, details like load balancer outputs and cluster connection settings become one more thing to keep in sync by hand.&lt;/p&gt;
&lt;p&gt;This post shows how to provision Kubernetes clusters on EKS, AKS, and GKE with Pulumi, and how to deploy the same application to all three from one codebase. We&amp;rsquo;ll use TypeScript for the full walkthrough, with a Python equivalent for the AWS cluster to show the pattern carries across languages.&lt;/p&gt;
&lt;center&gt;![Architecture diagram showing an application deployed identically across EKS, AKS, and GKE clusters](multicloud.png)&lt;/center&gt;
&lt;h2 id="why-run-kubernetes-across-multiple-clouds"&gt;Why run Kubernetes across multiple clouds?&lt;/h2&gt;
&lt;p&gt;A few situations make multi-cloud Kubernetes worth the extra coordination:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Avoiding lock-in.&lt;/strong&gt; Workloads that run identically on EKS, AKS, and GKE keep you free to negotiate on price or move a workload if a provider&amp;rsquo;s roadmap or pricing changes.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Meeting compliance and data-residency requirements.&lt;/strong&gt; Some customers or regulations require workloads to run on a specific provider or in a specific region that only one cloud serves well.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Matching teams to the cloud they already use.&lt;/strong&gt; In a company built through acquisition, or one where different teams standardized on different clouds, multi-cloud Kubernetes lets each team keep its cloud without forking the deployment pipeline.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Testing across environments.&lt;/strong&gt; Running the same app on EKS, AKS, and GKE surfaces provider-specific bugs, such as differences in default storage classes or load balancer behavior, before they reach customers.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="what-are-the-challenges-of-multi-cloud-kubernetes"&gt;What are the challenges of multi-cloud Kubernetes?&lt;/h2&gt;
&lt;p&gt;Multi-cloud Kubernetes is a real tradeoff, not a free upgrade. Cluster provisioning APIs, IAM models, default networking, and managed add-ons differ across EKS, AKS, and GKE, so a setup that is one API call on one provider can be several resources on another. Application manifests are mostly portable, but anything that touches a provider&amp;rsquo;s native load balancer, storage class, or identity system needs provider-specific configuration. Running clusters on three providers also means three sets of the provider&amp;rsquo;s own operational quirks, upgrade cadences, and support channels to track. Most teams find multi-cloud Kubernetes worth it only once the reason for doing it (compliance, team autonomy, or genuine lock-in risk) is concrete, rather than adopting it as a default posture.&lt;/p&gt;
&lt;h2 id="how-do-you-provision-kubernetes-clusters-across-eks-aks-and-gke-with-pulumi"&gt;How do you provision Kubernetes clusters across EKS, AKS, and GKE with Pulumi?&lt;/h2&gt;
&lt;p&gt;Pulumi provisions each provider&amp;rsquo;s managed Kubernetes clusters using ordinary TypeScript, Python, Go, C#, Java, or YAML, so cluster definitions get the same code review, testing, and reuse as the rest of your infrastructure.&lt;/p&gt;
&lt;p&gt;Provision an EKS cluster with the &lt;a href="https://www.pulumi.com/registry/packages/eks/"&gt;&lt;code&gt;@pulumi/eks&lt;/code&gt;&lt;/a&gt; package, which wraps the underlying VPC, IAM, and node group resources behind a single component:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-typescript" data-lang="typescript"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kr"&gt;import&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="kr"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;eks&lt;/span&gt; &lt;span class="kr"&gt;from&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;@pulumi/eks&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kr"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;eksCluster&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;eks&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Cluster&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;eks-cluster&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;instanceType&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;t3.medium&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;desiredCapacity&lt;/span&gt;: &lt;span class="kt"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;minSize&lt;/span&gt;: &lt;span class="kt"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;maxSize&lt;/span&gt;: &lt;span class="kt"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kr"&gt;export&lt;/span&gt; &lt;span class="kr"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;eksKubeconfig&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;eksCluster&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;kubeconfig&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Provision an AKS cluster with the &lt;a href="https://www.pulumi.com/registry/packages/azure-native/"&gt;&lt;code&gt;azure-native&lt;/code&gt;&lt;/a&gt; provider, which maps directly onto the Azure Resource Manager API:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-typescript" data-lang="typescript"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kr"&gt;import&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="kr"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;resources&lt;/span&gt; &lt;span class="kr"&gt;from&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;@pulumi/azure-native/resources&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kr"&gt;import&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="kr"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;containerservice&lt;/span&gt; &lt;span class="kr"&gt;from&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;@pulumi/azure-native/containerservice&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kr"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;resourceGroup&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;resources&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ResourceGroup&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;aks-rg&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kr"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;aksCluster&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;containerservice&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ManagedCluster&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;aks-cluster&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;resourceGroupName&lt;/span&gt;: &lt;span class="kt"&gt;resourceGroup.name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;agentPoolProfiles&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;agentpool&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;count&lt;/span&gt;: &lt;span class="kt"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;vmSize&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;Standard_DS2_v2&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;mode&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;System&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}],&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;dnsPrefix&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;multicloudaks&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;identity&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="kr"&gt;type&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;SystemAssigned&amp;#34;&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kr"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;aksCreds&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;containerservice&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;listManagedClusterUserCredentialsOutput&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;resourceGroupName&lt;/span&gt;: &lt;span class="kt"&gt;resourceGroup.name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;resourceName&lt;/span&gt;: &lt;span class="kt"&gt;aksCluster.name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kr"&gt;export&lt;/span&gt; &lt;span class="kr"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;aksKubeconfig&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;aksCreds&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;kubeconfigs&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;apply&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;v&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;Buffer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="kr"&gt;from&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;v&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;base64&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;toString&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Provision a GKE cluster with the &lt;a href="https://www.pulumi.com/registry/packages/gcp/"&gt;&lt;code&gt;gcp&lt;/code&gt;&lt;/a&gt; provider:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-typescript" data-lang="typescript"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kr"&gt;import&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="kr"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;pulumi&lt;/span&gt; &lt;span class="kr"&gt;from&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;@pulumi/pulumi&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kr"&gt;import&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="kr"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;gcp&lt;/span&gt; &lt;span class="kr"&gt;from&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;@pulumi/gcp&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kr"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;gkeCluster&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;gcp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;container&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Cluster&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;gke-cluster&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;initialNodeCount&lt;/span&gt;: &lt;span class="kt"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;nodeConfig&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;machineType&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;e2-medium&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;oauthScopes&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;https://www.googleapis.com/auth/cloud-platform&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;],&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;},&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kr"&gt;export&lt;/span&gt; &lt;span class="kr"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;gkeKubeconfig&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;pulumi&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;all&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="nx"&gt;gkeCluster&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;gkeCluster&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;endpoint&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;gkeCluster&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;masterAuth&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;apply&lt;/span&gt;&lt;span class="p"&gt;(([&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;endpoint&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;auth&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="sb"&gt;`apiVersion: v1
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="sb"&gt;kind: Config
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="sb"&gt;clusters:
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="sb"&gt;- name: &lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sb"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="sb"&gt; cluster:
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="sb"&gt; certificate-authority-data: &lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;auth&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;clusterCaCertificate&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sb"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="sb"&gt; server: https://&lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;endpoint&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sb"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="sb"&gt;contexts:
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="sb"&gt;- name: &lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sb"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="sb"&gt; context:
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="sb"&gt; cluster: &lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sb"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="sb"&gt; user: &lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sb"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="sb"&gt;current-context: &lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sb"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="sb"&gt;users:
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="sb"&gt;- name: &lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sb"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="sb"&gt; user:
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="sb"&gt; exec:
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="sb"&gt; apiVersion: client.authentication.k8s.io/v1beta1
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="sb"&gt; command: gke-gcloud-auth-plugin
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="sb"&gt; installHint: Install gke-gcloud-auth-plugin to authenticate to GKE
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="sb"&gt; provideClusterInfo: true
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="sb"&gt;`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The same EKS cluster in Python looks like this, using &lt;a href="https://www.pulumi.com/registry/packages/eks/installation-configuration/?section=python"&gt;&lt;code&gt;pulumi_eks&lt;/code&gt;&lt;/a&gt;:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;pulumi&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;pulumi_eks&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nn"&gt;eks&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;cluster&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;eks&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Cluster&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;eks-cluster&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;instance_type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;t3.medium&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;desired_capacity&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;min_size&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;max_size&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;pulumi&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;export&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;kubeconfig&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;cluster&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;kubeconfig&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Each block above is a normal Pulumi resource, so it gets the same &lt;code&gt;pulumi preview&lt;/code&gt;, unit tests, and code review as any other change in the stack, rather than living in a separate cluster-provisioning tool.&lt;/p&gt;
&lt;h2 id="how-do-you-deploy-the-same-application-to-multiple-kubernetes-clusters"&gt;How do you deploy the same application to multiple Kubernetes clusters?&lt;/h2&gt;
&lt;p&gt;Once the clusters exist, the &lt;a href="https://www.pulumi.com/registry/packages/kubernetes/"&gt;&lt;code&gt;kubernetes&lt;/code&gt;&lt;/a&gt; provider deploys workloads to any of them using the same resource definitions, by pointing a separate provider instance at each cluster&amp;rsquo;s kubeconfig:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-typescript" data-lang="typescript"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kr"&gt;import&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="kr"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;pulumi&lt;/span&gt; &lt;span class="kr"&gt;from&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;@pulumi/pulumi&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kr"&gt;import&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="kr"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;k8s&lt;/span&gt; &lt;span class="kr"&gt;from&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;@pulumi/kubernetes&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;ClusterTarget&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;name&lt;/span&gt;: &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;kubeconfig&lt;/span&gt;: &lt;span class="kt"&gt;pulumi.Output&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kr"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;clusters&lt;/span&gt;: &lt;span class="kt"&gt;ClusterTarget&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;eks&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;kubeconfig&lt;/span&gt;: &lt;span class="kt"&gt;eksCluster.kubeconfig&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;aks&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;kubeconfig&lt;/span&gt;: &lt;span class="kt"&gt;aksKubeconfig&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;gke&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;kubeconfig&lt;/span&gt;: &lt;span class="kt"&gt;gkeKubeconfig&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kr"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;cluster&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt; &lt;span class="nx"&gt;clusters&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kr"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;provider&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;k8s&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Provider&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sb"&gt;`&lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;cluster&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sb"&gt;-provider`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;kubeconfig&lt;/span&gt;: &lt;span class="kt"&gt;cluster.kubeconfig&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;});&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;k8s&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;apps&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;v1&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Deployment&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sb"&gt;`&lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;cluster&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sb"&gt;-kuard`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;spec&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;replicas&lt;/span&gt;: &lt;span class="kt"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;selector&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;matchLabels&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;kuard&amp;#34;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;template&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;metadata&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;labels&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;kuard&amp;#34;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;spec&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;containers&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;kuard&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;image&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;gcr.io/kuar-demo/kuard-amd64:blue&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;ports&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[{&lt;/span&gt; &lt;span class="nx"&gt;containerPort&lt;/span&gt;: &lt;span class="kt"&gt;8080&lt;/span&gt; &lt;span class="p"&gt;}],&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}],&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;},&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;},&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;},&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;provider&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Because the loop body is ordinary code, adding a fourth provider, or a local cluster reachable through a &lt;code&gt;kubeconfig&lt;/code&gt; file (Docker Desktop, kind, or a self-managed cluster), means adding one more entry to the &lt;code&gt;clusters&lt;/code&gt; array rather than writing a new deployment pipeline. The full, runnable version of this example, including cluster provisioning for all three providers, is in the &lt;a href="https://github.com/pulumi/examples/tree/master/kubernetes-ts-multicloud"&gt;&lt;code&gt;kubernetes-ts-multicloud&lt;/code&gt;&lt;/a&gt; example.&lt;/p&gt;
&lt;h2 id="which-tools-manage-multi-cloud-kubernetes-fleets"&gt;Which tools manage multi-cloud Kubernetes fleets?&lt;/h2&gt;
&lt;p&gt;Provisioning the clusters is one job; keeping workloads scheduled and consistent across them once they exist is another. These are complementary layers, not competing choices:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Layer&lt;/th&gt;
&lt;th&gt;What it does&lt;/th&gt;
&lt;th&gt;Example tools&lt;/th&gt;
&lt;th&gt;Best for&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Fleet and control-plane federation&lt;/td&gt;
&lt;td&gt;Coordinates workload placement and policy across clusters that already exist, from one control plane&lt;/td&gt;
&lt;td&gt;&lt;a href="https://karmada.io/"&gt;Karmada&lt;/a&gt;, Google Anthos, Rancher, Gardener&lt;/td&gt;
&lt;td&gt;Teams that already run multiple clusters and want centralized scheduling and policy enforcement&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Kubernetes-native infrastructure as code&lt;/td&gt;
&lt;td&gt;Manages cloud infrastructure through Kubernetes custom resources and controllers&lt;/td&gt;
&lt;td&gt;&lt;a href="https://www.crossplane.io/"&gt;Crossplane&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;Teams standardized on GitOps and the Kubernetes API as the control plane for infrastructure&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;General-purpose infrastructure as code&lt;/td&gt;
&lt;td&gt;Provisions the clusters themselves, and every supporting resource around them (networking, IAM, node pools), in the same codebase and language as the rest of your infrastructure&lt;/td&gt;
&lt;td&gt;&lt;a href="https://www.pulumi.com/registry/packages/kubernetes/"&gt;Pulumi&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;Teams that want the clusters, the workloads, and the surrounding cloud resources under one review and testing process&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;A fleet tool like Karmada doesn&amp;rsquo;t create the EKS, AKS, and GKE clusters it schedules onto; something has to provision those first. Pulumi is a good fit for that provisioning step, and it can sit alongside a fleet-management tool rather than replacing it.&lt;/p&gt;
&lt;h2 id="where-to-go-next"&gt;Where to go next&lt;/h2&gt;
&lt;p&gt;This post covers provisioning and deploying across EKS, AKS, and GKE directly. If your goal is closer to sharing a golden-path Kubernetes setup across teams through a reusable component and the &lt;a href="https://www.pulumi.com/docs/iac/concepts/automation-api/"&gt;Automation API&lt;/a&gt;, see &lt;a href="https://www.pulumi.com/blog/multicloud-with-kubernetes-and-pulumi/"&gt;Multicloud with Kubernetes and Pulumi&lt;/a&gt;, which walks through building a customizable, self-service Kubernetes provisioning experience for other teams to consume.&lt;/p&gt;
&lt;p&gt;To get started with Kubernetes on Pulumi:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.pulumi.com/docs/iac/get-started/kubernetes/"&gt;Get started with Pulumi and Kubernetes&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.pulumi.com/registry/packages/kubernetes/"&gt;Kubernetes provider reference&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.pulumi.com/registry/packages/eks/"&gt;EKS package reference&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.pulumi.com/docs/esc/"&gt;Manage secrets and configuration across clusters with Pulumi ESC&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="is-multi-cloud-kubernetes-worth-the-added-complexity"&gt;Is multi-cloud Kubernetes worth the added complexity?&lt;/h2&gt;
&lt;p&gt;It depends on why you&amp;rsquo;re considering it. If the driver is a concrete requirement, such as a customer contract that specifies a provider, a compliance rule tied to a region only one cloud serves, or a team that already standardized on a different cloud after an acquisition, the coordination cost is worth paying. If the driver is &amp;ldquo;just in case we need to switch providers someday,&amp;rdquo; the ongoing cost of testing and operating three cluster types usually outweighs a lock-in risk that may never materialize. Start with the workloads that actually need to run on more than one cloud, rather than replicating everything by default.&lt;/p&gt;
&lt;h2 id="can-i-use-the-same-kubernetes-manifests-across-eks-aks-and-gke"&gt;Can I use the same Kubernetes manifests across EKS, AKS, and GKE?&lt;/h2&gt;
&lt;p&gt;Mostly. Core Kubernetes resources, such as Deployments, Services of type &lt;code&gt;ClusterIP&lt;/code&gt;, and ConfigMaps, behave the same way regardless of provider, because they&amp;rsquo;re implemented by Kubernetes itself rather than the cloud. Anything that touches provider-specific infrastructure differs: a Service of type &lt;code&gt;LoadBalancer&lt;/code&gt; provisions an AWS load balancer (a Network Load Balancer with the AWS Load Balancer Controller or EKS Auto Mode, a Classic Load Balancer otherwise), an Azure Load Balancer, or a Google Cloud Load Balancer depending on the cluster, each with its own annotations for things like internal-only access or SSL termination. Persistent volume storage classes also differ by default (&lt;code&gt;gp3&lt;/code&gt; on EKS, &lt;code&gt;managed-csi&lt;/code&gt; on AKS, &lt;code&gt;standard-rwo&lt;/code&gt; on GKE). Plan for a small provider-specific configuration layer around an otherwise-shared manifest, rather than expecting one manifest to be entirely provider-agnostic.&lt;/p&gt;
&lt;h2 id="do-i-still-need-a-tool-like-karmada-if-im-provisioning-clusters-with-pulumi"&gt;Do I still need a tool like Karmada if I&amp;rsquo;m provisioning clusters with Pulumi?&lt;/h2&gt;
&lt;p&gt;Only if you need active workload scheduling and policy enforcement across clusters that are already running. Pulumi provisions the clusters and can deploy the same workload definitions to each one, which covers most teams running a handful of clusters with a known, mostly static placement. A fleet-management tool like Karmada earns its keep once you&amp;rsquo;re actively rebalancing workloads between clusters based on capacity or failures, or enforcing cluster-wide policy from a single control plane across a larger fleet. The two aren&amp;rsquo;t mutually exclusive: Pulumi can provision the clusters that Karmada then manages.&lt;/p&gt;</description><author>Mike Metral</author><category>kubernetes</category><category>aws</category><category>azure</category><category>google-cloud</category><category>eks</category><category>aks</category><category>gke</category></item></channel></rss>