diff --git a/azure-py-aks/.gitignore b/azure-py-aks/.gitignore new file mode 100644 index 000000000..0d20b6487 --- /dev/null +++ b/azure-py-aks/.gitignore @@ -0,0 +1 @@ +*.pyc diff --git a/azure-py-aks/Pulumi.yaml b/azure-py-aks/Pulumi.yaml new file mode 100644 index 000000000..b5aaae153 --- /dev/null +++ b/azure-py-aks/Pulumi.yaml @@ -0,0 +1,3 @@ +name: azure-py-aks +runtime: python +description: A minimal Azure Python Pulumi program diff --git a/azure-py-aks/README.md b/azure-py-aks/README.md new file mode 100644 index 000000000..1d064ad8d --- /dev/null +++ b/azure-py-aks/README.md @@ -0,0 +1,68 @@ +[![Deploy](https://get.pulumi.com/new/button.svg)](https://app.pulumi.com/new) + +# Azure Kubernetes Service (AKS) Cluster + +This example deploys an AKS cluster, virtual network and Azure Container Registry and grants AKS permissions to access and manage those. + +## Deploying the App + +To deploy your infrastructure, follow the below steps. + +### Prerequisites + +1. [Install Pulumi](https://pulumi.io/install) +2. [Install Python 3.6](https://www.python.org/downloads/) +3. [Configure Azure Credentials](https://pulumi.io/install/azure.html) +4. [Generate SSH Key](https://git-scm.com/book/en/v2/Git-on-the-Server-Generating-Your-SSH-Public-Key) + +### Steps + +After cloning this repo, from this working directory, run these commands: + +1. Install the required Python packages packages: + + ```bash + $ pip install -r requirements.txt + ``` + +2. Create a new stack, which is an isolated deployment target for this example: + + ```bash + $ pulumi stack init + ``` + +3. Set the configuration variables for this program: + + ```bash + $ pulumi config set prefix all_resources_will_be_prefixed_with_this_value + $ pulumi config set password service_principal_password + $ pulumi config set sshkey < ~/.ssh/id_rsa.pub + $ # this has a default value, so you can skip it + $ pulumi config set location any_valid_azure_location_for_aks + ``` + +4. Stand up the AKS cluster: + + ```bash + $ pulumi up + ``` + +5. After 10-15 minutes, your cluster will be ready, and the kubeconfig YAML you'll use to connect to the cluster will be available as an output. You can save this kubeconfig to a file like so: + + ```bash + $ pulumi stack output kubeconfig > kubeconfig.yaml + ``` + + Once you have this file in hand, you can interact with your new cluster as usual via `kubectl`: + + ```bash + $ KUBECONFIG=./kubeconfig.yaml kubectl get nodes + ``` +6. From there, feel free to experiment. Simply making edits and running `pulumi up` will incrementally update your stack. + +7. Once you've finished experimenting, tear down your stack's resources by destroying and removing it: + + ```bash + $ pulumi destroy --yes + $ pulumi stack rm --yes + ``` diff --git a/azure-py-aks/__main__.py b/azure-py-aks/__main__.py new file mode 100644 index 000000000..bfe584dc5 --- /dev/null +++ b/azure-py-aks/__main__.py @@ -0,0 +1,125 @@ +import pulumi +from pulumi import ResourceOptions +from pulumi_azure.core import ResourceGroup +from pulumi_azure.role import Assignment +from pulumi_azure.ad import Application, ServicePrincipal, ServicePrincipalPassword +from pulumi_azure.containerservice import KubernetesCluster, Registry +from pulumi_azure.network import VirtualNetwork, Subnet + +config = pulumi.Config('azure-py-aks') +PREFIX = config.require('prefix') +PASSWORD = config.require('password') +SSHKEY = config.require('sshkey') +LOCATION = config.get('location') or 'east us' + +# create Azure AD Application for AKS +app = Application( + 'aks-app', + name=PREFIX + 'aks-app' +) + +# create service principal for the application so AKS can act on behalf of the application +sp = ServicePrincipal( + 'aks-sp', + application_id=app.application_id +) + +# create service principal password +sppwd = ServicePrincipalPassword( + 'aks-sp-pwd', + service_principal_id=sp.id, + end_date='2025-01-01T01:02:03Z', + value=PASSWORD +) + +rg = ResourceGroup( + 'rg', + name=PREFIX + 'rg', + location=LOCATION +) + +vnet = VirtualNetwork( + 'vnet', + name=PREFIX + 'vnet', + location=rg.location, + resource_group_name=rg.name, + address_spaces=['10.0.0.0/8'] +) + +subnet = Subnet( + 'subnet', + name=PREFIX + 'subnet', + resource_group_name=rg.name, + address_prefix='10.0.0.0/23', + virtual_network_name=vnet.name +) + +# create Azure Container Registry to store images in +acr = Registry( + 'acr', + name=PREFIX + 'acr', + location=rg.location, + resource_group_name=rg.name, + sku="basic" +) + +# assignments are needed for AKS to be able to interact with those resources +acr_assignment = Assignment( + 'acr-permissions', + principal_id=sp.id, + role_definition_name='AcrPull', + scope=acr.id +) + +subnet_assignment = Assignment( + 'subnet-permissions', + principal_id=sp.id, + role_definition_name='Network Contributor', + scope=subnet.id +) + +aks = KubernetesCluster( + 'aks', + name=PREFIX + 'aks', + location=rg.location, + resource_group_name=rg.name, + kubernetes_version="1.12.5", + dns_prefix="dns", + agent_pool_profile=( + { + "name": "type1", + "count": 3, + "vmSize": "Standard_B2ms", + "osType": "Linux", + "maxPods": 110, + "vnet_subnet_id": subnet.id + } + ), + linux_profile=( + { + "adminUsername": "azureuser", + "ssh_key": [ + { + "keyData": SSHKEY + } + ] + } + ), + service_principal={ + "clientId": app.application_id, + "clientSecret": sppwd.value + }, + role_based_access_control={ + "enabled": "true" + }, + network_profile=( + { + "networkPlugin": "azure", + "serviceCidr": "10.10.0.0/16", + "dns_service_ip": "10.10.0.10", + "dockerBridgeCidr": "172.17.0.1/16" + } + ), __opts__=ResourceOptions(depends_on=[acr_assignment, subnet_assignment]) +) + +pulumi.export('kubeconfig', aks.kube_config_raw) diff --git a/azure-py-aks/requirements.txt b/azure-py-aks/requirements.txt new file mode 100644 index 000000000..64b8736b3 --- /dev/null +++ b/azure-py-aks/requirements.txt @@ -0,0 +1,2 @@ +pulumi>=0.16.4 +pulumi_azure>=0.16.4