<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>3. Pulumi for Azure :: Cloud Native Engineering</title><link>https://cloud-native.labs.netrics.dev/3-pulumi-azure/index.html</link><description>In this chapter you connect Pulumi to Azure and provision real cloud infrastructure: a Resource Group, virtual network, AKS cluster, container registry, and a static public IP for the ingress controller.
Azure Resource Model Azure organises resources into a three-level hierarchy:
Level Description Example Subscription Billing and access boundary — one per team or project sub-garaio-lab Resource Group Lifecycle container — deploy and delete resources as a group rg-lab-dev Resource Individual Azure service (VM, VNet, cluster, …) aks-lab-dev Naming Convention This workshop follows the Azure Cloud Adoption Framework naming pattern:
[abbreviation]-[purpose]-[environment].</description><generator>Hugo</generator><language>en-us</language><atom:link href="https://cloud-native.labs.netrics.dev/3-pulumi-azure/index.xml" rel="self" type="application/rss+xml"/><item><title>3.1. Bootstrap</title><link>https://cloud-native.labs.netrics.dev/3-pulumi-azure/1-bootstrap/index.html</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://cloud-native.labs.netrics.dev/3-pulumi-azure/1-bootstrap/index.html</guid><description>In this lab you will provision the Azure prerequisites every participant needs before creating their Pulumi project: a Blob Storage backend for state and a Key Vault key for secret encryption.
Step 1 — Bootstrap the State Storage The state backend must exist before Pulumi can use it, so it is created with the az CLI rather than Pulumi itself. Run the following commands to create a dedicated Resource Group, Storage Account, and Blob Container:</description></item><item><title>3.2. Project Setup</title><link>https://cloud-native.labs.netrics.dev/3-pulumi-azure/2-project-setup/index.html</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://cloud-native.labs.netrics.dev/3-pulumi-azure/2-project-setup/index.html</guid><description>In this lab you will scaffold a new Pulumi project connected directly to the Azure backend provisioned in 3.1, and wire up the pulumi-azure-native provider.
Step 1 — Log in to Azure Authenticate the Azure CLI — Pulumi reads credentials from this session automatically:
az login Confirm the active subscription:
az account show You should see output similar to:</description></item><item><title>3.3. Networking</title><link>https://cloud-native.labs.netrics.dev/3-pulumi-azure/3-networking/index.html</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://cloud-native.labs.netrics.dev/3-pulumi-azure/3-networking/index.html</guid><description>In this lab you will declare the Resource Group that holds all lab resources, then provision the virtual network and subnet that AKS requires for its node pools.
Step 1 — Set the Username Config Add your unique participant name to the stack config:
pulumi config set username &lt;insert your name&gt; Explanation The program derives a suffix from the stack name and this username:</description></item><item><title>3.4. AKS Cluster</title><link>https://cloud-native.labs.netrics.dev/3-pulumi-azure/4-aks-cluster/index.html</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://cloud-native.labs.netrics.dev/3-pulumi-azure/4-aks-cluster/index.html</guid><description>In this lab you will introduce a Pulumi ComponentResource that owns its own resource group and models the full AKS cluster lifecycle, add node pool configuration to the stack config, deploy a running Kubernetes cluster, and grant yourself admin access via a role assignment.
Step 1 — Create the Kubernetes Component Create a new file kubernetes.py next to __main__.py:</description></item><item><title>3.5. Container Registry</title><link>https://cloud-native.labs.netrics.dev/3-pulumi-azure/5-container-registry/index.html</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://cloud-native.labs.netrics.dev/3-pulumi-azure/5-container-registry/index.html</guid><description>In this lab you will add an Azure Container Registry (ACR) to the Kubernetes component and grant the cluster’s kubelet identity permission to pull images from it.
Step 1 — Install the Random Provider ACR names must be globally unique and contain only alphanumeric characters. To guarantee uniqueness without manual coordination, add the pulumi-random provider to requirements.txt:</description></item><item><title>3.6. Static IP and DNS</title><link>https://cloud-native.labs.netrics.dev/3-pulumi-azure/6-static-ip-dns/index.html</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://cloud-native.labs.netrics.dev/3-pulumi-azure/6-static-ip-dns/index.html</guid><description>In this lab you will provision a static public IP for the ingress controller, create a personal DNS zone under labs.netrics.dev, and delegate it from the shared parent zone using a secondary Pulumi provider targeting a different Azure subscription.
Step 1 — Create the DnsZone Component Create a new file dns_zone.py next to __main__.py:
import pulumi import pulumi_azure_native as azure_native class DnsZone(pulumi.ComponentResource): def __init__( self, name: str, zone_name: str, opts: pulumi.ResourceOptions = None, ): super().__init__("workshop:azure:DnsZone", name, {}, opts) self.child_opts = pulumi.ResourceOptions(parent=self) self._zone_name = zone_name self._subdomain = zone_name.split(".")[0] self._rg = azure_native.resources.ResourceGroup( name, resource_group_name=f"rg-{name}", opts=self.child_opts ) self.zone = azure_native.dns.Zone( self._zone_name, resource_group_name=self._rg.name, zone_name=self._zone_name, zone_type=azure_native.dns.ZoneType.PUBLIC, opts=self.child_opts ) def delegate_from_zone( self, parent_zone: pulumi.Output[azure_native.dns.GetZoneResult], dns_provider: pulumi.ProviderResource, ) -&gt; azure_native.dns.RecordSet: parent_rg = parent_zone.id.apply(lambda resource_id: resource_id.split("/")[4]) ns_records = self.zone.name_servers.apply( lambda servers: [ azure_native.dns.NsRecordArgs(nsdname=ns) for ns in servers ] ) return azure_native.dns.RecordSet( self._zone_name, resource_group_name=parent_rg, zone_name=parent_zone.name, relative_record_set_name=self._subdomain, record_type="NS", ttl=3600, ns_records=ns_records, opts=pulumi.ResourceOptions( parent=self, provider=dns_provider ) ) def create_a_record( self, name: str, ip_address: pulumi.Input, ) -&gt; azure_native.dns.RecordSet: return azure_native.dns.RecordSet( f"{name}.{self._zone_name}", resource_group_name=self._rg.name, zone_name=self.zone.name, relative_record_set_name=name, record_type="A", ttl=300, a_records=[azure_native.dns.ARecordArgs(ipv4_address=ip_address)], opts=self.child_opts ) Explanation DnsZone owns a resource group and an Azure DNS zone. The zone_name is passed in by the caller — the component is agnostic about the zone hierarchy it belongs to. self._subdomain is derived by splitting on . to get the first label (e.g. angehrig), which is used as the relative record name when delegating from the parent zone.</description></item></channel></rss>