Tutorial: Create a composite Recipe

Learn how to create a composite recipe for a custom resource type

Overview

This tutorial introduces composite Recipes. Rather than being composed of infrastructure or cloud resources like typical Recipes, composite Recipes are composed of other Radius resource types. Composite Recipes are authored in Bicep and can include any Radius resource types including built-in types, other custom types, AWS types, and/or Azure types.

The previous tutorial demonstrated how to define a custom resource type for a PostgreSQL database, author a Recipe for deploying the database on Kubernetes, and adding the new Resource Type to an application. The sample Todo List application used the built-in Containers resource type for the frontend service. This tutorial continues using the same application but extends the Containers resource type with additional functionality.

This tutorial demonstrates:

  • Creating a web service custom resource type which adds an ingress property to the Containers schema
  • Creating a composite Recipe in Bicep which creates a Gateway resource when the ingress property is true
  • Modifying the Todo List application to use the new web service

Prerequisites

This tutorial assumes you have completed the Add a custom resource type tutorial and have the demo application deployed with a PostgreSQL database and have Radius installed and configured.

Composite Recipes are only written in Bicep. If you used Terraform in the previous tutorial for your Recipes, you will need an OCI registry to store your Recipe. While Terraform-based Recipes are stored in Git, Bicep-based Recipes can only be published to OCI registry.

Step 1: Create the web service resource type

Create or modify the types.yaml file so that it has both the postgreSQL type from the previous tutorial and the new webServices type. The schema for the new web services resource type is lengthy, so it is best to download the fully prepared file with both resource types.

Download types.yaml

This web services schema is simpler than it appears:

  • environment and application have the same purpose as in the previous PostgreSQL example. These properties are on all resource types.
  • connections is used to create dependencies, see How-To: Connect to dependencies for more details
  • ingress is the first property the developer can set. The purpose of this property is to expose an option for developers to specify if the web service is accessible to connections from outside the cluster. This functionality will be implemented in the Recipe in step 3.
  • container is a duplication of the Containers schema. Since the web service resource type extended Containers, the original schema must be included here. As you will see when implementing the Recipe, duplicating the Containers schema exactly makes it simple to pass multiple properties in only a few lines of code.

Create the resource type using the rad resource-type create command.

rad resource-type create webServices -f types.yaml
$ rad resource-type create webServices -f types.yaml
Resource provider "Radius.Resources" found. Registering resource type "webServices".
Creating resource type Radius.Resources/webServices with capabilities SupportsRecipes 
Creating API Version Radius.Resources/webServices@2023-10-01-preview
Updating location Radius.Resources/global with new resource type
Resource type Radius.Resources/webServices created successfully

TYPE                          NAMESPACE         APIVERSION
Radius.Resources/webServices  Radius.Resources  ["2023-10-01-preview"]

You can confirm the resource type was created using rad resource-type list command.

rad resource-type list
$ rad resource-type list
TYPE                                    NAMESPACE                APIVERSION
...
Radius.Resources/postgreSQL             Radius.Resources         ["2023-10-01-preview"]
Radius.Resources/webServices            Radius.Resources         ["2023-10-01-preview"]

Step 2: Update the Bicep extension

Generate the Bicep extension using the rad bicep publish-extension command.

rad bicep publish-extension -f types.yaml --target radiusResources.tgz
$ rad bicep publish-extension -f types.yaml --target radiusResources.tgz
Writing types to /var/folders/w8/89pqzjp52pbg4g256z9cpkww0000gn/T/bicep-extension-542196227/types.json
Writing index to /var/folders/w8/89pqzjp52pbg4g256z9cpkww0000gn/T/bicep-extension-542196227/index.json
Writing documentation to /var/folders/w8/89pqzjp52pbg4g256z9cpkww0000gn/T/bicep-extension-542196227/index.md
WARNING: The 'publish-extension' CLI command group is an experimental feature. Experimental features should be enabled for testing purposes only, as there are no guarantees about the quality or stability of these features. Do not enable these settings for any production usage, or your production environment may be subject to breaking.
Successfully published Bicep extension "types.yaml" to "radiusResources.tgz"

Since the bicepconfig.json file was modified in the previous tutorial, it does not need to be further modified.

Step 3: Create, publish, and register the composite Recipe

The previous tutorial demonstrated deploying a resource using Terraform or Bicep resource providers such as the Kubernetes provider. This tutorial creates a composite Recipes which uses only built-in Radius types. These composite Recipes are only possible using Bicep.

  1. Create a new file called webservices.bicep and add the following:

    extension radius
    
    @description('Information about what resource is calling this Recipe. Generated by Radius.')
    param context object
    
    // Create a gateway resource if ingress property is set to true
    resource gateway 'Applications.Core/gateways@2023-10-01-preview' = if (context.resource.properties.ingress) {
      name: 'gateway'
      properties: {
        application: context.application.id
        routes: [
          {
            path: '/'
            destination: 'http://${container.name}:${context.resource.properties.container.ports.web.containerPort}'
          }
        ]
      }
    }
    
    resource container 'Applications.Core/containers@2023-10-01-preview' = {
      name: 'container'
      properties: {
        application: context.application.id
        container: context.resource.properties.container
        connections: context.resource.properties.connections
      }
    }
    

    Notice that the container and connections properties are passed to the Applications.Core/containers built-in type using a single line.

  2. Publish the Recipe to an OCI registry. Make sure to replace host and registry with your container registry.

    rad bicep publish --file webservices.bicep --target br:<host>/<registry>/webservices:latest
    
    $ rad bicep publish --file webservices.bicep --target br:<host>/<registry>/tutorial/webservices:latest
    Building webservices.bicep...
    WARNING: The following experimental Bicep features have been enabled: Extensibility. Experimental features should be enabled for testing purposes only, as there are no guarantees about the quality or stability of these features. Do not enable these settings for any production usage, or your production environment may be subject to breaking.
    Pushed to <host>/<registry>/webservices@...
    
    Successfully published Bicep file "webservices.bicep" to "<host>/<registry>/tutorial/webservices:latest"
    
  3. Register the Bicep template as the default Recipe in the default environment.

    rad recipe register default --environment default \
      --resource-type Radius.Resources/webServices \
      --template-kind bicep \
      --template-path <host>/<registry>/webservices:latest
    
    Successfully linked recipe "default" to environment "default" 
    

    You can confirm the Recipe was registered using rad recipe list command.

    rad recipe list
    
     rad recipe list                                    
     RECIPE    TYPE                                    TEMPLATE KIND  TEMPLATE VERSION  TEMPLATE
     ...
     default   Radius.Resources/webServices            bicep                            <host>/<registry>/webservices:latest
     default   Radius.Resources/postgreSQL             terraform                        git::https://github.com/<github-user-name>/recipes.git//kubernetes/postgres
     ...
    

Step 4: Replace the container resource with a web service

  1. Using the same app.bicep file, change the resource type for the demo resource from Applications.Core/containers to Radius.Resources/webServices.

    - resource demo 'Applications.Core/containers@2023-10-01-preview' = {
    + resource demo 'Radius.Resources/webServices@2023-10-01-preview' = {
    
  2. Add ingress: true to the demo resource so that a Gateway gets deployed as part of the web service. The web service also needs an environment property similar to the database custom resource.

    resource demo 'Radius.Resources/webServices@2023-10-01-preview' = {
      name: 'demo'
        properties: {
          application: application
    +     environment: environment
    +     ingress: true
    
  3. Since the web service resource type has a built-in Gateway, remove the Gateway resource.

    - resource gateway 'Applications.Core/gateways@2023-10-01-preview' = {
    -   name: 'gateway'
    -   properties: {
    -     application: application
    -     routes: [
    -       {
    -         path: '/'
    -         destination: 'http://demo:3000'
    -       }
    -     ]
    -   }
    - }
    
  4. Run the application using rad run.

    rad deploy app.bicep
    
    $ rad deploy app.bicep
    Building app.bicep...
    WARNING: The following experimental Bicep features have been enabled: Extensibility. Experimental features should be enabled for testing purposes only, as there are no guarantees about the quality or stability of these features. Do not enable these settings for any production usage, or your production environment may be subject to breaking.
    Deploying template 'app.bicep' for application 'todolist' and environment '/planes/radius/local/resourceGroups/default/providers/Applications.Core/environments/default' from workspace 'default'...
    
    Deployment In Progress... 
    
    Completed            postgresql      Radius.Resources/postgreSQL
    Completed            backend         Applications.Core/containers
    Completed            demo            Radius.Resources/webServices
    
    Deployment Complete
    
    Resources:
        backend         Applications.Core/containers
        postgresql      Radius.Resources/postgreSQL
        demo            Radius.Resources/webServices
    
  5. Unlike before, the Gateway URL is not automatically shown. Use the rad resource show command to get the URL of the application.

    rad resource show Applications.Core/gateways gateway -o json | grep url
    
    "url": "http://gateway.todolist.172.18.0.6.nip.io"
    
  6. Open the URL in your browser. The application has not changed despite changing the demo from a container to a web service resource and removing the gateway.

Step 6: Clean up

  1. Delete the application and all resources created by the application.

    rad application delete todolist
    
  2. Delete the PostgreSQL and web service resource types.

    rad resource-type delete Radius.Resources/postgreSQL
    rad resource-type delete Radius.Resources/webServices