Building your first Radius application on Azure Kubernetes Service

willvelida

Will Velida

Posted on February 8, 2024

Building your first Radius application on Azure Kubernetes Service

Earlier on this week, I gave a presentation to two user groups on the Radius project. If you want to check them out you can view them here:

This one is from Coding Nights NZ, run by Microsoft MVP Marcel Medina:

The other is from the Azure Community Enthusiasts User Group, run by Microsoft MVP Nicholas Chang:

Following these two talks, I wanted to write a blog post on setting up a basic Radius application on a Azure Kubernetes Service cluster, which is what we'll go through now 🙂

I hope after NDC Sydney, I'll have some time to do some YouTube content on Radius. But for now, let's get stuck in and build a Radius application from scratch. I'll start by giving a brief explanation of what Radius is, then we'll jump into creating an AKS cluster in Azure, setting up our local machine to use Radius, then build our first Radius application.

What is Radius?

Radius is an open-source cloud-native application platform that enables collaboration between developers and operators to build cloud-native applications across private and public clouds.

Using Radius, developers will define their applications, and the dependencies that their application relies on. Operators define the environments that those applications will run on. Radius brings both developers and operators together to help them build and deploy apps and infrastructure that meets the requirements of both the application, and the environment that those applications need to run on.

Lots of enterprises (perhaps maybe the one you work for) attempting to build custom internal developer platforms to help standardize the way that they deploy and manage cloud-native applications. Radius attempts to provide an open-source solution that helps lower the barrier of entry to standardize the deployment and development of cloud-native applications.

With Platform Engineering still emerging from our experiences with DevOps and DevSecOps, we need tools, frameworks and platforms that can help enable collaboration between application developers, platform engineers and IT operators.

Radius provides concepts like Environments and Recipes that support collaboration between these roles. Platform Engineers can create templates to start development, IT operations can deploy Radius Environments and provide Recipes that conform to their organization's policies, and developers can focus on the architecture of their application.

Let's start developing our Radius application, and along the way I'll explain the core concepts behind Radius.

Building our Radius application

To build our Radius application, we need to do the following:

  • Create our AKS cluster
  • Set up the tools we need to run our Radius application
  • Create and run a new Radius environment and application on our AKS cluster
  • Add components to our Radius application.

Let's get started!

Creating our AKS cluster

First thing we'll need to do is create a new AKS cluster. We can do this easily by using the AZ CLI. Let's start by creating a new resource group and then deploying the AKS cluster in that resource group:



# Create the Resource Group
az group create --name <RG_NAME> --location <RG_LOCATION>

# Create the AKS Cluster
az aks create --resource-group <RG_NAME> --name <AKS_CLUSTER_NAME> --location <RG_LOCATION> --node-count 3


Enter fullscreen mode Exit fullscreen mode

Just replace the values with your own, and provision the cluster in a Azure region closest to you.

Once your AKS cluster has been deployed, you'll need to grab the credentials for your cluster. We can get those by running this AZ CLI command:



az aks get-credentials --resource-group <RG_NAME> --name <AKS_CLUSTER_NAME>


Enter fullscreen mode Exit fullscreen mode

Now that we have our AKS cluster, we'll also need to set up our machine with the tools needed to work with Radius.

Setting up our local machine to use Radius

To work with Radius, we'll need to install two tools.

First up is the rad CLI. The rad CLI manages your applications, resources, and environments. To install it on your local machine in PowerShell, you can run this command:



iwr -useb "https://raw.githubusercontent.com/radius-project/radius/main/deploy/install.ps1" | iex


Enter fullscreen mode Exit fullscreen mode

You may need to refresh your $PATH environment variable to access the rad CLI:



$Env:Path = [System.Environment]::GetEnvironmentVariable("Path","User")


Enter fullscreen mode Exit fullscreen mode

On Linux/WSL, you can install the CLI with this:



wget -q "https://raw.githubusercontent.com/radius-project/radius/main/deploy/install.sh" -O - | /bin/bash


Enter fullscreen mode Exit fullscreen mode

Once the installation has been completed, you can verify by running:



rad version

## Example output
RELEASE   VERSION   BICEP     COMMIT
0.30.0    v0.30.0   0.30.0    f5a4a551b95168fbc2f33358bc8551c2cedece54


Enter fullscreen mode Exit fullscreen mode

The second tool we'll need is the VS Code extension. There's a Radius Bicep extension available in VS code that provides support for writing Radius resources in Bicep.

At the time of writing, this is a temporary fork of the official Bicep extension to support Radius. In the future (or present, depending on when you read this), this will be merged into the official Bicep repository.

That being said, you can only have one VS Code Bicep extension installed at a time, so you'll either have to disable the official extension on your existing VS Code, or you can do what I did and install VS Code Insiders, and just have the Radius Bicep extension running on that.

Whichever option you choose, to install the Radius Bicep extension, simply just search for Radius Bicep in the Extension tab in VS Code or the Visual Studio marketplace.

Now that you have the tools installed, we can start to build our first Radius app!

Creating a new Radius Environment and Application

The first thing we'll need to do is initialize a Radius Environment. Environments are where are applications are deployed, and they determine how an application runs on a particular platform. They act as landing zones for Radius Applications, and application deployed to environments inherit the container runtime, configuration, Recipes and other settings from the environment.

To initialize a new environment, we'll create a new directory, navigate into it, and then initialize a new environment. Using the command line, run the following:



mkdir radius-demo
cd radius-demo


Enter fullscreen mode Exit fullscreen mode

With our directory created, we can initialize a new environment:



rad init


Enter fullscreen mode Exit fullscreen mode

When asked if you want to create a new application, select Yes. rad int will set up a local development environment where the environment configuration is handled for you. This will also create a new file in your directory called app.bicep, where your application will be defined.

We can view all our app's resources and relationships using the rad CLI. To view the full application definition, run the following:



rad app show myapp -o json


Enter fullscreen mode Exit fullscreen mode

You should get output similar to the below:



{
  "id": "/planes/radius/local/resourcegroups/default/providers/Applications.Core/applications/radius-demo",
  "location": "global",
  "name": "radius-demo",
  "properties": {
    "environment": "/planes/radius/local/resourceGroups/default/providers/Applications.Core/environments/default",
    "provisioningState": "Succeeded",
    "status": {
      "compute": {
        "kind": "kubernetes",
        "namespace": "default-radius-demo"
      }
    }
  },
  "systemData": {
    "createdAt": "0001-01-01T00:00:00Z",
    "createdBy": "",
    "createdByType": "",
    "lastModifiedAt": "0001-01-01T00:00:00Z",
    "lastModifiedBy": "",
    "lastModifiedByType": ""
  },
  "tags": {},
  "type": "Applications.Core/applications"
}


Enter fullscreen mode Exit fullscreen mode

In this JSON format, there's a couple of things we should note:

  • The id property is what we refer to as the Universal Control Plane ID of the application. The Universal Control Plane is the service that performs the central functionality in Radius. It receives inbound HTTP traffic to the Radius API, and either serves the response itself, or routes the request to a cloud resource provider.
  • The location is where your Application resides. At the time of writing, all application are deployed to the global location, but it'll live in the location where you deployed your cluster.
  • The environment specifies the Radius Environment that the Applications will bind to at deployment. This is where the containers will run, and which namespace they will be deployed to.
  • Finally, compute specifies the hosting platform where running services in the Application will run. Currently, Kubernetes is the only compute platform for now. When I was at Microsoft, when you created a new Radius app, it was exclusive to Azure Container Apps, so it's possible that we'll be able to provision Radius apps on Container Apps soon.

With our application deployed, we can use the CLI to see what's deployed. Run the following:



rad app connections


Enter fullscreen mode Exit fullscreen mode

Since we haven't deployed anything, we should see the following:



Displaying application: radius-demo

(empty)


Enter fullscreen mode Exit fullscreen mode

When we ran rad init, a Bicep file was generated for us. We'll use this file to define all the resources we need for our application. Let's start to work with this file, add some resources, and deploy our application.

Deploying and Running our basic Radius Application

In your directory, you should see the following scaffolded Bicep file:



import radius as radius

@description('The Radius Application ID. Injected automatically by the rad CLI.')
param application string

resource demo 'Applications.Core/containers@2023-10-01-preview' = {
  name: 'demo'
  properties: {
    application: application
    container: {
      image: 'ghcr.io/radius-project/samples/demo:latest'
      ports: {
        web: {
          containerPort: 3000
        }
      }
    }
  }
}


Enter fullscreen mode Exit fullscreen mode

Let's go ahead and deploy this file using the rad CLI! Using the command line, and in the directory that your Bicep file is in, run the following:



rad deploy app.bicep


Enter fullscreen mode Exit fullscreen mode

You should see your container being deployed:



Building .\app.bicep...
Deploying template '.\app.bicep' for application 'radius-demo' and environment 'default' from workspace 'default'...

Deployment In Progress...

..                   demo            Applications.Core/containers

Deployment Complete

Resources:
    demo            Applications.Core/containers


Enter fullscreen mode Exit fullscreen mode

Now, if we run rad app connections again, we'll see the container that we just deployed, along with the Kubernetes resources that were created to run it:



Displaying application: radius-demo

Name: demo (Applications.Core/containers)
Connections: (none)
Resources:
  demo (apps/Deployment)
  demo (core/Service)
  demo (core/ServiceAccount)
  demo (rbac.authorization.k8s.io/Role)
  demo (rbac.authorization.k8s.io/RoleBinding)


Enter fullscreen mode Exit fullscreen mode

With our application deployed, we can run the application by running the following command:



rad run app.bicep


Enter fullscreen mode Exit fullscreen mode

This command will deploy our container, port-forward the application to 3000, and start a log stream:



Building .\app.bicep...
Deploying template '.\app.bicep' for application 'radius-demo' and environment 'default' from workspace 'default'...

Deployment In Progress...

..                   demo            Applications.Core/containers

Deployment Complete

Resources:
    demo            Applications.Core/containers

Starting log stream...

+ demo-5876f78f84-rkqz8 › demo
demo-5876f78f84-rkqz8 demo No APPLICATIONINSIGHTS_CONNECTION_STRING found, skipping Azure Monitor setup
demo-5876f78f84-rkqz8 demo Using in-memory store: no connection string found
demo-5876f78f84-rkqz8 demo Server is running at http://localhost:3000
demo-5876f78f84-rkqz8 demo [port-forward] connected from localhost:3000 -> ::3000


Enter fullscreen mode Exit fullscreen mode

Once the log stream has started, we can navigate to http://localhost:3000 to view the container:

From here we can see the Radius connections that have configured, the metadata for the container, and a page for a Todo List 😅

Navigate to the Todo list page, and you should see the following:

Image description

As you can see from the above, we haven't configured a database yet, so any Todo items that we persist will only be saved to memory. Let's create a database connections to we can save our items to that, rather than in-memory.

Adding a database and backend container

First, let's add a MongoDB database to store our Todo items in. Using Radius Bicep, we can add dependencies like Dapr State Stores, MongoDB databases, Redis Caches and more. To add a Mongo Database, we can add the following in our app.bicep file:



@description('The ID of your Radius Environment. Set automatically by the rad CLI.')
param environment string

resource mongodb 'Applications.Datastores/mongoDatabases@2023-10-01-preview' = {
  name: 'mongodb'
  properties: {
    environment: environment
    application: application
  }
}


Enter fullscreen mode Exit fullscreen mode

All we've done here is add a MongoDB database using a Radius resource block. We haven't specified where or how to run the MongoDB database. This is where Recipes come into play.

Recipes enable a seperation of concerns between developers and IT operators by automating infrastructure deployment. As developers, we can select the resource we want (such as a MongoDB database) and IT operators can codify how these resources should be deployed and configured:

So in this example, a developer could simply say that they just want a Cache as part of their application. Platform Engineers define how that infrastructure is deployed and configured within their environment. Here, our Recipe states that this is a Redis Cache that's going to be deployed on Azure, with a Private Endpoint. It'll have a particular SKU and we'll also enable some diagnostic logging.

The advantage here is that developers who may not have a complete understanding of the cloud environment can simply state what it is their application requires, and Platform Engineers with a greater understanding of how the cloud works within their environment can provide Recipes for developers to consume.

To add a connection from our container to the MongoDB database we just defined, all we need to do is this to our container resource block:



connections: {
      mongodb: {
        source: mongodb.id
      }
    }


Enter fullscreen mode Exit fullscreen mode

So our complete demo container should look like this:



resource demo 'Applications.Core/containers@2023-10-01-preview' = {
  name: 'demo'
  properties: {
    application: application
    container: {
      image: 'ghcr.io/radius-project/samples/demo:latest'
      ports: {
        web: {
          containerPort: 3000
        }
      }
    }
    connections: {
      mongodb: {
        source: mongodb.id
      }
    }
  }
}


Enter fullscreen mode Exit fullscreen mode

Our MongoDB database is now a defined connection in our application. To re-run the app, we simply run the rad run command. We should see the following output:



Building .\app.bicep...
Deploying template '.\app.bicep' for application 'radius-demo' and environment 'default' from workspace 'default'...

Deployment In Progress...

Completed            mongodb         Applications.Datastores/mongoDatabases
.                    demo            Applications.Core/containers

Deployment Complete

Resources:
    demo            Applications.Core/containers
    mongodb         Applications.Datastores/mongoDatabases

Starting log stream...


Enter fullscreen mode Exit fullscreen mode

Navigate to localhost:3000, and we'll see that our MongoDB container is listed as a connection:

Image description

When we run rad app connections, we should see MongoDB added as a new dependency, along with the underlying Kubernetes resources used to create them:



Displaying application: radius-demo

Name: demo (Applications.Core/containers)
Connections:
  demo -> mongodb (Applications.Datastores/mongoDatabases)
Resources:
  demo (apps/Deployment)
  demo (core/Secret)
  demo (core/Service)
  demo (core/ServiceAccount)
  demo (rbac.authorization.k8s.io/Role)
  demo (rbac.authorization.k8s.io/RoleBinding)

Name: mongodb (Applications.Datastores/mongoDatabases)
Connections:
  demo (Applications.Core/containers) -> mongodb
Resources:
  mongo-bzmp2btdgzez6 (apps/Deployment)
  mongo-bzmp2btdgzez6 (core/Service)


Enter fullscreen mode Exit fullscreen mode

Adding a gateway

Now every time we connect to localhost:3000, we are connecting directly with the container. Adding a gateway is a much better alternative for exposing our applications to the internet, and Radius provides a default recipe for a gateway. To add the gateway, we add it to our Bicep file with this resource:



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


Enter fullscreen mode Exit fullscreen mode

Once this is added, we can use the rad deploy command to deploy our application.

We should see a public endpoint that has been created as part of our deployment:



Building .\app.bicep...
Deploying template '.\app.bicep' for application 'radius-demo' and environment 'default' from workspace 'default'...

Deployment In Progress...

Completed            mongodb         Applications.Datastores/mongoDatabases
Completed            gateway         Applications.Core/gateways
.                    demo            Applications.Core/containers

Deployment Complete

Resources:
    demo            Applications.Core/containers
    gateway         Applications.Core/gateways
    mongodb         Applications.Datastores/mongoDatabases

Public Endpoints:
    gateway         Applications.Core/gateways http://gateway.radius-demo.20.227.63.98.nip.io


Enter fullscreen mode Exit fullscreen mode

When we navigate to it, we should be redirected to our application:

Image description

Cleanup

We've successfully created our first Radius application!! Once you're done, you can delete the Radius environment from your AKS cluster:



rad env delete default --yes


Enter fullscreen mode Exit fullscreen mode

If you want to delete the resource group that you created as part of this tutorial, run the following:



az group delete --name <RG_NAME>

Enter fullscreen mode Exit fullscreen mode




Conclusion

In this tutorial, we built our first Radius application on Azure Kubernetes Services! Hopefully you had a lot of fun, and learnt the basic concepts of Radius along the way!

I'll be doing more Radius content in the future, so keep your eyes peeled for that. In the meantime, I recommend that you take a look at the following resources:

If you have any questions on the above, feel free to reach out to me on twitter @willvelida

Until next time, Happy coding! 🤓🖥️

💖 💪 🙅 🚩
willvelida
Will Velida

Posted on February 8, 2024

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related