Azure Quickstart Part 3

This document is for an older version of Crossplane.

This document applies to Crossplane version v1.11 and not to the latest release v1.13.

Important

This guide is part 3 of a series.

Follow part 1 to install Crossplane and connect your Kubernetes cluster to Azure.

Follow part 2 to create a composition, custom resource definition and a claim.

Part 2 created a CompositeResourceDefinition to define the schema of the custom API. Users create a Claim to use the custom API and apply their options. Part 2 didn’t show how the options set in a Claim change or get applied to the associated composite resources.

Prerequisites

  • Complete quickstart part 1 and part 2 to install Crossplane and the quickstart configurations.

  1. Add the Crossplane Helm repository and install Crossplane
1helm repo add \
2crossplane-stable https://charts.crossplane.io/stable
3helm repo update
4&&
5helm install crossplane \
6crossplane-stable/crossplane \
7--namespace crossplane-system \
8--create-namespace
  1. When the Crossplane pods finish installing and are ready, apply the Azure Provider
1cat <<EOF | kubectl apply -f -
2apiVersion: pkg.crossplane.io/v1
3kind: Provider
4metadata:
5  name: upbound-provider-azure
6spec:
7  package: xpkg.upbound.io/upbound/provider-azure:v0.32.0
8EOF
  1. Use the Azure CLI to create a service principal and save the JSON output as azure-crednetials.json
1az ad sp create-for-rbac \
2--sdk-auth \
3--role Owner \
4--scopes /subscriptions/$$<subscription_id>$$
  1. Create a Kubernetes secret from the Azure JSON file.
1kubectl create secret \
2generic azure-secret \
3-n crossplane-system \
4--from-file=creds=./azure-credentials.json
  1. Create a ProviderConfig
 1cat <<EOF | kubectl apply -f -
 2apiVersion: azure.upbound.io/v1beta1
 3metadata:
 4  name: default
 5kind: ProviderConfig
 6spec:
 7  credentials:
 8    source: Secret
 9    secretRef:
10      namespace: crossplane-system
11      name: azure-secret
12      key: creds
13EOF
  1. Create a composition
Tip
Apply your resourceGroupName to each resource.
 1cat <<EOF | kubectl apply -f -
 2apiVersion: apiextensions.crossplane.io/v1
 3kind: Composition
 4metadata:
 5  name: crossplane-quickstart-vm-with-network
 6spec:
 7  compositeTypeRef:
 8    apiVersion: custom-api.example.org/v1alpha1
 9    kind: XVirtualMachine
10  resources:
11    - name: quickstart-vm
12      base:
13        apiVersion: compute.azure.upbound.io/v1beta1
14        kind: LinuxVirtualMachine
15        spec:
16          forProvider:
17            adminUsername: adminuser
18            adminSshKey:
19              - publicKey: ssh-rsa
20                  AAAAB3NzaC1yc2EAAAADAQABAAABAQC+wWK73dCr+jgQOAxNsHAnNNNMEMWOHYEccp6wJm2gotpr9katuF/ZAdou5AaW1C61slRkHRkpRRX9FA9CYBiitZgvCCz+3nWNN7l/Up54Zps/pHWGZLHNJZRYyAB6j5yVLMVHIHriY49d/GZTZVNB8GoJv9Gakwc/fuEZYYl4YDFiGMBP///TzlI4jhiJzjKnEvqPFki5p2ZRJqcbCiF4pJrxUQR/RXqVFQdbRLZgYfJ8xGB878RENq3yQ39d8dVOkq4edbkzwcUmwwwkYVPIoDGsYLaRHnG+To7FvMeyO7xDVQkMKzopTQV8AuKpyvpqu0a9pWOMaiCyDytO7GGN
21                  example@docs.crossplane.io
22                username: adminuser
23            location: "Central US"
24            osDisk:
25              - caching: ReadWrite
26                storageAccountType: Standard_LRS
27            resourceGroupName: $$<resource_group_name>$$
28            size: Standard_B1ms
29            sourceImageReference:
30              - offer: debian-11
31                publisher: Debian
32                sku: 11-backports-gen2
33                version: latest
34            networkInterfaceIdsSelector:
35              matchControllerRef: true
36    - name: quickstart-nic
37      base:
38        apiVersion: network.azure.upbound.io/v1beta1
39        kind: NetworkInterface
40        spec:
41          forProvider:
42            ipConfiguration:
43              - name: crossplane-quickstart-configuration
44                privateIpAddressAllocation: Dynamic
45                subnetIdSelector:
46                  matchControllerRef: true
47            location: "Central US"
48            resourceGroupName: $$<resource_group_name>$$
49    - name: quickstart-subnet
50      base:
51        apiVersion: network.azure.upbound.io/v1beta1
52        kind: Subnet
53        spec:
54          forProvider:
55            addressPrefixes:
56              - 10.0.1.0/24
57            virtualNetworkNameSelector:
58              matchControllerRef: true
59            resourceGroupName: $$<resource_group_name>$$
60    - name: quickstart-network
61      base:
62        apiVersion: network.azure.upbound.io/v1beta1
63        kind: VirtualNetwork
64        spec:
65          forProvider:
66            addressSpace:
67              - 10.0.0.0/16
68            location: "Central US"
69            resourceGroupName: $$<resource_group_name>$$
70EOF
  1. Create a CompositeResourceDefinition
 1cat <<EOF | kubectl apply -f -
 2apiVersion: apiextensions.crossplane.io/v1
 3kind: CompositeResourceDefinition
 4metadata:
 5  name: xvirtualmachines.custom-api.example.org
 6spec:
 7  group: custom-api.example.org
 8  names:
 9    kind: XVirtualMachine
10    plural: xvirtualmachines
11  versions:
12  - name: v1alpha1
13    served: true
14    referenceable: true
15    schema:
16      openAPIV3Schema:
17        type: object
18        properties:
19          spec:
20            type: object
21            properties:
22              region:
23                type: string
24                oneOf:
25                  - pattern: '^EU$'
26                  - pattern: '^US$'
27            required:
28              - region
29  claimNames:
30    kind: VirtualMachine
31    plural: virtualmachines
32EOF
  1. Create a new namespace
1kubectl create namespace test

Enable composition patches

In a Composition patches map fields in the custom API to fields inside the managed resources.

The example Composition has four managed resources. A LinuxVirtualMachine, NetworkInterface, Subnet and a VirtualNetwork.

 1apiVersion: apiextensions.crossplane.io/v1
 2kind: Composition
 3# Removed for Brevity
 4resources:
 5    - name: quickstart-vm
 6      base:
 7        apiVersion: compute.azure.upbound.io/v1beta1
 8        kind: LinuxVirtualMachine
 9    - name: quickstart-nic
10      base:
11        apiVersion: network.azure.upbound.io/v1beta1
12        kind: NetworkInterface
13    - name: quickstart-subnet
14      base:
15        apiVersion: network.azure.upbound.io/v1beta1
16        kind: Subnet
17    - name: quickstart-network
18      base:
19        apiVersion: network.azure.upbound.io/v1beta1
20        kind: VirtualNetwork    

The custom API defined a single option, region. A region can be either EU or US.

 1apiVersion: apiextensions.crossplane.io/v1
 2kind: CompositeResourceDefinition
 3# Removed for brevity
 4spec:
 5  group: custom-api.example.org
 6  names:
 7    kind: XVirtualMachine
 8# Removed for brevity
 9      spec:
10        type: object
11        properties:
12          region:
13            type: string
14            oneOf:
15              - pattern: '^EU$'
16              - pattern: '^US$'

Creating a composition patch allows Crossplane to update the settings of the composite resource. Patches apply to the individual managed resources inside the Composition.

A patch has a fromField and a toField specifying which value from the custom API should apply to a field in the managed resource.
Patches can create a transform to change the from field before it’s applied.

The transform type is what kind of change to make on the from field. Types of changes could include appending a string, preforming a math operation or mapping one value to another.

Applying a patch to the LinuxVirtualMachine uses the custom API region to use as the managed resource location.

The custom API value “EU” is mapped to the value “Sweden Central” and “US” is mapped to the value “Central US.”

 1apiVersion: apiextensions.crossplane.io/v1
 2kind: Composition
 3# Removed for Brevity
 4  resources:
 5    - name: quickstart-vm
 6      base:
 7        apiVersion: compute.azure.upbound.io/v1beta1
 8        kind: LinuxVirtualMachine
 9        spec:
10          forProvider:
11            location: "Central US"
12            # Removed for Brevity
13      patches:
14        - fromFieldPath: "spec.region"
15          toFieldPath: "spec.forProvider.location"
16          transforms:
17            - type: map
18              map: 
19                EU: "Sweden Central"
20                US: "Central US"

Patching is a powerful tool enabling simpler or abstracted APIs. A developer isn’t required to know the specific Azure location names, only the abstracted option of “EU” or “US.”

Apply the updated composition

Apply the same patch to all other managed resource and apply the updated Composition.

Tip
Update each resourceGroupName with your Azure Resource Group.
  1cat <<EOF | kubectl apply -f -
  2apiVersion: apiextensions.crossplane.io/v1
  3kind: Composition
  4metadata:
  5  name: crossplane-quickstart-vm-with-network
  6spec:
  7  compositeTypeRef:
  8    apiVersion: custom-api.example.org/v1alpha1
  9    kind: XVirtualMachine
 10  resources:
 11    - name: quickstart-vm
 12      base:
 13        apiVersion: compute.azure.upbound.io/v1beta1
 14        kind: LinuxVirtualMachine
 15        spec:
 16          forProvider:
 17            adminUsername: adminuser
 18            adminSshKey:
 19              - publicKey: ssh-rsa
 20                  AAAAB3NzaC1yc2EAAAADAQABAAABAQC+wWK73dCr+jgQOAxNsHAnNNNMEMWOHYEccp6wJm2gotpr9katuF/ZAdou5AaW1C61slRkHRkpRRX9FA9CYBiitZgvCCz+3nWNN7l/Up54Zps/pHWGZLHNJZRYyAB6j5yVLMVHIHriY49d/GZTZVNB8GoJv9Gakwc/fuEZYYl4YDFiGMBP///TzlI4jhiJzjKnEvqPFki5p2ZRJqcbCiF4pJrxUQR/RXqVFQdbRLZgYfJ8xGB878RENq3yQ39d8dVOkq4edbkzwcUmwwwkYVPIoDGsYLaRHnG+To7FvMeyO7xDVQkMKzopTQV8AuKpyvpqu0a9pWOMaiCyDytO7GGN
 21                  example@docs.crossplane.io
 22                username: adminuser
 23            location: "Central US"
 24            osDisk:
 25              - caching: ReadWrite
 26                storageAccountType: Standard_LRS
 27            resourceGroupName: $$<resource_group_name>$$
 28            size: Standard_B1ms
 29            sourceImageReference:
 30              - offer: debian-11
 31                publisher: Debian
 32                sku: 11-backports-gen2
 33                version: latest
 34            networkInterfaceIdsSelector:
 35              matchControllerRef: true
 36      patches:
 37        - fromFieldPath: "spec.region"
 38          toFieldPath: "spec.forProvider.location"
 39          transforms:
 40            - type: map
 41              map: 
 42                EU: "Sweden Central"
 43                US: "Central US"
 44    - name: quickstart-nic
 45      base:
 46        apiVersion: network.azure.upbound.io/v1beta1
 47        kind: NetworkInterface
 48        spec:
 49          forProvider:
 50            ipConfiguration:
 51              - name: crossplane-quickstart-configuration
 52                privateIpAddressAllocation: Dynamic
 53                subnetIdSelector:
 54                  matchControllerRef: true
 55            location: "Central US"
 56            resourceGroupName: $$<resource_group_name>$$
 57      patches:
 58        - fromFieldPath: "spec.region"
 59          toFieldPath: "spec.forProvider.location"
 60          transforms:
 61            - type: map
 62              map: 
 63                EU: "Sweden Central"
 64                US: "Central US"
 65    - name: quickstart-subnet
 66      base:
 67        apiVersion: network.azure.upbound.io/v1beta1
 68        kind: Subnet
 69        spec:
 70          forProvider:
 71            addressPrefixes:
 72              - 10.0.1.0/24
 73            virtualNetworkNameSelector:
 74              matchControllerRef: true
 75            resourceGroupName: $$<resource_group_name>$$
 76      patches:
 77        - fromFieldPath: "spec.region"
 78          toFieldPath: "spec.forProvider.location"
 79          transforms:
 80            - type: map
 81              map: 
 82                EU: "Sweden Central"
 83                US: "Central US"
 84    - name: quickstart-network
 85      base:
 86        apiVersion: network.azure.upbound.io/v1beta1
 87        kind: VirtualNetwork
 88        spec:
 89          forProvider:
 90            addressSpace:
 91              - 10.0.0.0/16
 92            location: "Sweden Central"
 93            resourceGroupName: $$<resource_group_name>$$
 94      patches:
 95        - fromFieldPath: "spec.region"
 96          toFieldPath: "spec.forProvider.location"
 97          transforms:
 98            - type: map
 99              map: 
100                EU: "Sweden Central"
101                US: "Central US"
102EOF

Create a claim

Create a new claim and set the region to “EU.”

1cat <<EOF | kubectl apply -f -
2apiVersion: custom-api.example.org/v1alpha1
3kind: VirtualMachine
4metadata:
5  name: claimed-eu-virtualmachine
6  namespace: test
7spec:
8  region: "EU"
9EOF

View the Claim with kubectl get claim

Note
It may take up to 10 minutes for the Claim to be READY.
1kubectl get claim -n test
2NAME                        SYNCED   READY   CONNECTION-SECRET   AGE
3claimed-eu-virtualmachine   True     True                        6m2s

The claim reports SYNCED and READY as True after Crossplane creates all the managed resources.

Describe the LinuxVirtualMachine resource to see the Azure location is Sweden Central.

1kubectl describe linuxvirtualmachine | grep "At Provider\|Location"
2    Location:                         Sweden Central
3  At Provider:
4    Location:                         swedencentral

Using region: "EU" patches the composite resource, updating the Azure location from Central US to Sweden Central. The developer creating the claim isn’t required to know which specific Azure location or the location naming conventions. Using the abstract API options of “EU” or “US” the developer places their resources in the desired location.

Deleting the claim removes the managed resources.

Note
The managed resources take up to 5 minutes to delete.
1kubectl delete virtualmachine claimed-eu-virtualmachine -n test

Create a Crossplane configuration package

Crossplane configuration packages allow users to combine their CustomResourceDefinition and Composition files into a single OCI image.

Note
The Open Container Initiative defines the OCI image standard.
An OCI images is a standard way to package data.

You can host configuration packages in image registries like Docker Hub or the Upbound Marketplace.

Crossplane can download and install configuration packages into a Kubernetes cluster.

Creating a configuration package makes your Crossplane custom APIs portable and versioned.

Building and installing configuration packages requires an OCI image compatible tool.

Note
You can use any software that builds OCI images. This includes Docker or Upbound’s Up CLI.

A configuration package includes at least three files:

  • crossplane.yaml defines the metadata of the package.
  • definition.yaml is the CompositeResourceDefinition for the package.
  • composition.yaml is the Composition template for the package.

Create a crossplane.yaml file

Configuration packages describe their contents and requirements with a crossplane.yaml file.

The crossplane.yaml file lists the required Crossplane Providers and their compatible versions as well as the required Crossplane version.

The Crossplane meta.pkg API defines the schema for a Configuration.

Inside the spec define the required Crossplane version.

The dependsOn section lists the dependencies for a package.

This package lists the Upbound provider-azure version 0.32.0 or later as a dependency.

Tip
Crossplane automatically installs dependencies. Dependencies can include other configuration packages.

Create a new directory and save the crossplane.yaml file.

 1mkdir crossplane-azure-quickstart
 2cat <<EOF > crossplane-azure-quickstart/crossplane.yaml
 3apiVersion: meta.pkg.crossplane.io/v1
 4kind: Configuration
 5metadata:
 6  name: crossplane-azure-quickstart
 7spec:
 8  crossplane:
 9    version: ">=v1.11.0"
10  dependsOn:
11    - provider: xpkg.upbound.io/upbound/provider-azure
12      version: ">=v0.32.0"
13EOF

Create a definition.yaml file

A configuration package requires a CompositeResourceDefinition (XRD) to define the custom API.

Save the XRD as definition.yaml in the same directory as the crossplane.yaml file.

 1cat <<EOF > crossplane-azure-quickstart/definition.yaml
 2apiVersion: apiextensions.crossplane.io/v1
 3kind: CompositeResourceDefinition
 4metadata:
 5  name: xvirtualmachines.custom-api.example.org
 6spec:
 7  group: custom-api.example.org
 8  names:
 9    kind: XVirtualMachine
10    plural: xvirtualmachines
11  versions:
12  - name: v1alpha1
13    served: true
14    referenceable: true
15    schema:
16      openAPIV3Schema:
17        type: object
18        properties:
19          spec:
20            type: object
21            properties:
22              region:
23                type: string
24                oneOf:
25                  - pattern: '^EU$'
26                  - pattern: '^US$'
27            required:
28              - region
29  claimNames:
30    kind: VirtualMachine
31    plural: virtualmachines
32EOF

Create a composition.yaml file

The Composition template creates the managed resources and allows patches to customize the managed resources.

Copy the Composition into the composition.yaml file in the same directory as crossplane.yaml.

Tip
Update each resourceGroupName with your Azure Resource Group.
  1cat <<EOF > crossplane-azure-quickstart/composition.yaml
  2apiVersion: apiextensions.crossplane.io/v1
  3kind: Composition
  4metadata:
  5  name: crossplane-quickstart-vm-with-network
  6spec:
  7  compositeTypeRef:
  8    apiVersion: custom-api.example.org/v1alpha1
  9    kind: XVirtualMachine
 10  resources:
 11    - name: quickstart-vm
 12      base:
 13        apiVersion: compute.azure.upbound.io/v1beta1
 14        kind: LinuxVirtualMachine
 15        spec:
 16          forProvider:
 17            adminUsername: adminuser
 18            adminSshKey:
 19              - publicKey: ssh-rsa
 20                  AAAAB3NzaC1yc2EAAAADAQABAAABAQC+wWK73dCr+jgQOAxNsHAnNNNMEMWOHYEccp6wJm2gotpr9katuF/ZAdou5AaW1C61slRkHRkpRRX9FA9CYBiitZgvCCz+3nWNN7l/Up54Zps/pHWGZLHNJZRYyAB6j5yVLMVHIHriY49d/GZTZVNB8GoJv9Gakwc/fuEZYYl4YDFiGMBP///TzlI4jhiJzjKnEvqPFki5p2ZRJqcbCiF4pJrxUQR/RXqVFQdbRLZgYfJ8xGB878RENq3yQ39d8dVOkq4edbkzwcUmwwwkYVPIoDGsYLaRHnG+To7FvMeyO7xDVQkMKzopTQV8AuKpyvpqu0a9pWOMaiCyDytO7GGN
 21                  example@docs.crossplane.io
 22                username: adminuser
 23            location: "Central US"
 24            osDisk:
 25              - caching: ReadWrite
 26                storageAccountType: Standard_LRS
 27            resourceGroupName: $$<resource_group_name>$$
 28            size: Standard_B1ms
 29            sourceImageReference:
 30              - offer: debian-11
 31                publisher: Debian
 32                sku: 11-backports-gen2
 33                version: latest
 34            networkInterfaceIdsSelector:
 35              matchControllerRef: true
 36      patches:
 37        - fromFieldPath: "spec.region"
 38          toFieldPath: "spec.forProvider.location"
 39          transforms:
 40            - type: map
 41              map: 
 42                EU: "Sweden Central"
 43                US: "Central US"
 44    - name: quickstart-nic
 45      base:
 46        apiVersion: network.azure.upbound.io/v1beta1
 47        kind: NetworkInterface
 48        spec:
 49          forProvider:
 50            ipConfiguration:
 51              - name: crossplane-quickstart-configuration
 52                privateIpAddressAllocation: Dynamic
 53                subnetIdSelector:
 54                  matchControllerRef: true
 55            location: "Central US"
 56            resourceGroupName: $$<resource_group_name>$$
 57      patches:
 58        - fromFieldPath: "spec.region"
 59          toFieldPath: "spec.forProvider.location"
 60          transforms:
 61            - type: map
 62              map: 
 63                EU: "Sweden Central"
 64                US: "Central US"
 65    - name: quickstart-subnet
 66      base:
 67        apiVersion: network.azure.upbound.io/v1beta1
 68        kind: Subnet
 69        spec:
 70          forProvider:
 71            addressPrefixes:
 72              - 10.0.1.0/24
 73            virtualNetworkNameSelector:
 74              matchControllerRef: true
 75            resourceGroupName: $$<resource_group_name>$$
 76      patches:
 77        - fromFieldPath: "spec.region"
 78          toFieldPath: "spec.forProvider.location"
 79          transforms:
 80            - type: map
 81              map: 
 82                EU: "Sweden Central"
 83                US: "Central US"
 84    - name: quickstart-network
 85      base:
 86        apiVersion: network.azure.upbound.io/v1beta1
 87        kind: VirtualNetwork
 88        spec:
 89          forProvider:
 90            addressSpace:
 91              - 10.0.0.0/16
 92            location: "Sweden Central"
 93            resourceGroupName: $$<resource_group_name>$$
 94      patches:
 95        - fromFieldPath: "spec.region"
 96          toFieldPath: "spec.forProvider.location"
 97          transforms:
 98            - type: map
 99              map: 
100                EU: "Sweden Central"
101                US: "Central US"
102EOF

Install the Crossplane command-line

To build a configuration package install the Crossplane Kubernetes command-line extension.

1wget "https://raw.githubusercontent.com/crossplane/crossplane/master/install.sh"
2chmod +x install.sh
3./install.sh
4sudo mv crossplane /usr/local/bin

Follow the directions and move the crossplane binary to the correct directory.

Verify the Crossplane command-line installed with crossplane --help

 1crossplane --help
 2Usage: crossplane <command>
 3
 4A command line tool for interacting with Crossplane.
 5
 6Flags:
 7  -h, --help       Show context-sensitive help.
 8  -v, --version    Print version and quit.
 9      --verbose    Print verbose logging statements.
10# Ouptut removed for brevity

Build a configuration package

Use the crossplane CLI to create an .xpkg file containing the custom APIs and Crossplane configuration.

1crossplane build configuration -f crossplane-azure-quickstart/ --name="crossplane-azure-quickstart"

Now an .xpkg OCI image is inside the crossplane-azure-quickstart directory.

1ls crossplane-azure-quickstart/
2composition.yaml  crossplane-azure-quickstart.xpkg  crossplane.yaml  definition.yaml

Next steps