Skip to content
30 changes: 30 additions & 0 deletions Data/redisCaches/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
## Overview

The Radius.Data/redisCaches Resource Type represents Redis, an in-memory, key/value store used as an application cache. This Resource Type allows developers to create and easily connect to Redis caches as part of their Radius applications.

Developer documentation is embedded in the Resource Type definition YAML file. Developer documentation is accessible via `rad resource-type show Radius.Data/redisCaches`.

## Recipes

A list of available Recipes for this Resource Type, including links to the Bicep and Terraform templates:

|Platform| IaC Language| Recipe Name | Stage |
|---|---|---|---|
| Kubernetes | Bicep | kubernetes-redis.bicep | Alpha |
| Kubernetes | Terraform | kubernetes/main.tf | Alpha |

## Recipe Input Properties

Properties for the redisCaches resource are provided to the Recipe via the [Recipe Context](https://docs.radapp.io/reference/context-schema/) object. These properties include:

- `context.properties.capacity`(enum, optional): The capacity of the Redis server. Available options are S-Small, M-Medium, and L-Large. This property allows the developer to specify the size of the Redis cache instance. If not specified, Recipes should assume `S` as the capacity.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
- `context.properties.capacity`(enum, optional): The capacity of the Redis server. Available options are S-Small, M-Medium, and L-Large. This property allows the developer to specify the size of the Redis cache instance. If not specified, Recipes should assume `S` as the capacity.
- `context.properties.capacity`(enum, optional): The capacity of the Redis server. Available options are (S)mall, (M)edium, and (L)arge. This property allows the developer to specify the size of the Redis cache instance. If not specified, Recipes should assume `S` as the capacity.


## Recipe Output Properties

The RedisCaches Resource Type expects the following output properties to be set in the Results object in the Recipe:

- `context.properties.host` (string): The hostname used to connect to the Redis server.
- `context.properties.port` (integer): The port number used to connect to the Redis server.
- `context.properties.tls` (boolean): Indicates if TLS is enabled for the Redis server.
- `context.properties.username` (string): The username for connecting to the Redis server.
- `context.properties.password` (string): The password for connecting to the Redis server.
109 changes: 109 additions & 0 deletions Data/redisCaches/recipes/kubernetes/bicep/kubernetes-redis.bicep
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
@description('Information about the resource calling this Recipe. Generated by Radius. For more information visit https://docs.radapp.io/reference/context-schema/ ')
param context object

extension kubernetes with {
kubeConfig: ''
namespace: context.runtime.kubernetes.namespace
} as kubernetes

@description('Memory limits for the Redis container')
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why are we setting limits? This makes me wonder if capacity is the right property. I would expect the develop is requesting memory capacity, not requesting limits.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good point. I think we should configure the memory capacity in addition to the container limits for K8s. For Azure and AWS capacity equates to the sku and node type in the respective platforms

var memory ={
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
var memory ={
var memory = {

S: {
memoryRequest: '512Mi'
memoryLimit: '1024Mi'
}
M: {
memoryRequest: '1Gi'
memoryLimit: '2Gi'
}
L: {
memoryRequest: '2Gi'
memoryLimit: '4Gi'
}
}

resource redis 'apps/Deployment@v1' = {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Once Container Recipes are available, this will be updated to use Radius.Compute/Containers

metadata: {
name: 'redis-${uniqueString(context.resource.id)}'
}
spec: {
selector: {
matchLabels: {
app: 'redis'
resource: context.resource.name
Comment on lines +32 to +33
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What are our labeling standards? app: 'redis' does not seem correct. I would expect the Radius Application and Environment name.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I do not know if we have a labelling standard. We can create a standard and publish it to the guidelines. I think Radius Environment name makes sense but application wouldn't if this is a shared resource.

}
}
template: {
metadata: {
labels: {
app: 'redis'
resource: context.resource.name
}
}
spec: {
containers: [
{
name: 'redis'
image: 'redis'
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Make the image and image tag a parameter.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

U mean parameter local to the Recipe that PE's can change ?

ports: [
{
containerPort: 6379
}
]
resources: {
requests: {
memory: memory[context.resource.properties.?capacity ?? 'S'].memoryRequest
}
limits: {
memory: memory[context.resource.properties.?capacity ?? 'S'].memoryLimit
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should this be ?. not .??

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Tested with .? and it worked. I think Bicep accepts both forms of safe access.

}
}
}
{
// This container will connect to redis and stream logs to stdout for aid in development.
name: 'redis-monitor'
image: 'redis'
args: [
'redis-cli'
'-h'
'localhost'
'MONITOR'
]
Comment on lines +63 to +71
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is this here? Does the redis container image not stream logs to stdout? That would be very weird if that was the case.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Retained this is from local-dev Recipe implementation.

}
]
}
}
}
}

resource svc 'core/Service@v1' = {
metadata: {
name: 'redis-${uniqueString(context.resource.id)}'
}
spec: {
type: 'ClusterIP'
selector: {
app: 'redis'
resource: context.resource.name
}
ports: [
{
port: 6379
}
]
}
}

output result object = {
// This workaround is needed because the deployment engine omits Kubernetes resources from its output.
// This allows Kubernetes resources to be cleaned up when the resource is deleted.
// Once this gap is addressed, users won't need to do this.
Comment on lines +98 to +100
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there an issue to reference?

resources: [
'/planes/kubernetes/local/namespaces/${svc.metadata.namespace}/providers/core/Service/${svc.metadata.name}'
'/planes/kubernetes/local/namespaces/${redis.metadata.namespace}/providers/apps/Deployment/${redis.metadata.name}'
]
values: {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There are five read-only properties. They should all be set.

host: '${svc.metadata.name}.${svc.metadata.namespace}.svc.cluster.local'
port: 6379
}
}
85 changes: 85 additions & 0 deletions Data/redisCaches/recipes/kubernetes/terraform/main.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
terraform {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Output from tflint:

$ tflint               
1 issue(s) found:

Warning: terraform "required_version" attribute is required (terraform_required_version)

  on main.tf line 1:
   1: terraform {

Reference: https://github.com/terraform-linters/tflint-ruleset-terraform/blob/v0.12.0/docs/rules/terraform_required_version.md

required_providers {
kubernetes = {
source = "hashicorp/kubernetes"
version = ">= 2.0"
}
}
}

locals {
uniqueName = "redis-${substr(sha1(var.context.resource.id), 0, 8)}"
port = 6379
namespace = var.context.runtime.kubernetes.namespace
}

resource "kubernetes_deployment" "redis" {
metadata {
name = local.uniqueName
namespace = local.namespace
labels = {
app = "redis"
}
}
spec {
selector {
match_labels = {
app = "redis"
resource = local.uniqueName
}
}
template {
metadata {
labels = {
app = "redis"
resource = local.uniqueName
}
}
spec {
container {
name = "redis"
image = "redis:6"
resources {
requests = {
memory = var.memory[try(var.context.resource.properties.capacity, "S")].memoryRequest
}
limits = {
memory= var.memory[try(var.context.resource.properties.capacity, "S")].memoryLimit
}
}
port {
container_port = local.port
}

}
}
}
}
}

resource "kubernetes_service" "redis" {
metadata {
name = local.uniqueName
namespace = local.namespace
}
spec {
type = "ClusterIP"
selector = {
app = "redis"
resource = local.uniqueName
}
port {
port = local.port
target_port = local.port
}
}
}

output "result" {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is resources not required here as it is in the Bicep recipe? If so, be sure to include the same comment from the Bicep file.

value = {
values = {
host = "${kubernetes_service.redis.metadata[0].name}.${kubernetes_service.redis.metadata[0].namespace}.svc.cluster.local"
port = local.port
Comment on lines +81 to +82
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There are five read-only properties. They should all be set.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this a rule for Recipes that all read-only properties must be set? This Recipe implementation is similar to a alpha stage contribution not covering all the scenarios(e.g configuring TLS) and hence some properties are not set.

}
}
}
26 changes: 26 additions & 0 deletions Data/redisCaches/recipes/kubernetes/terraform/var.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
variable "context" {
description = "Information about the resource calling this Recipe. Generated by Radius. For more information visit https://docs.radapp.io/reference/context-schema/"
type = any
}

variable "memory" {
description = "Memory limits for the Redis container"
type = map(object({
memoryRequest = string
memoryLimit = string
}))
default = {
S = {
memoryRequest = "512Mi"
memoryLimit = "1024Mi"
},
M = {
memoryRequest = "1Gi"
memoryLimit = "2Gi"
}
L = {
memoryRequest = "2Gi"
memoryLimit = "4Gi"
}
}
}
74 changes: 74 additions & 0 deletions Data/redisCaches/redisCaches.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
namespace: Radius.Data
types:
redisCaches:
description: |
The Radius.Data/redisCaches Resource Type deploys Redis, an in-memory, key/value store used as an application cache.

To deploy a new Redis cache, add a RedisCaches resource to the application definition Bicep file.

param environment string
resource redisCache 'Radius.Data/redisCaches@2025-08-01-preview' = {
name: 'redisCache'
properties: {
environment: environment
}
}
Comment on lines +9 to +15
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
param environment string
resource redisCache 'Radius.Data/redisCaches@2025-08-01-preview' = {
name: 'redisCache'
properties: {
environment: environment
}
}
extension radius
param environment string
resource myApplication 'Radius.Core/applications@2025-08-01-preview' = { ... }
resource redis 'Radius.Data/redisCaches@2025-08-01-preview' = {
name: 'redis'
properties: {
environment: environment
}
}

I've been making sure the examples were whole.


When `capacity` is not set, the value is assumed to be `S`(Small) in Recipes.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should be in the property description, not here.


To connect your application to the Redis Cache, establish a connection from the container to the Redis Cache as shown below. Once connected, all Redis Cache properties are automatically injected as environment variables into the container.

resource myContainer 'Radius.Compute/containers@2025-08-01-preview' = {
name: 'myContainer'
properties: {
environment: environment
application: myApplication.id
containers: {
frontend: {
image: 'frontend:1.25'
}
}
connections: {
redis:{
source: redis.id
}
}
}
}
apiVersions:
'2025-08-01-preview':
schema:
type: object
properties:
environment:
type: string
description: (Required) The Radius Environment ID. Typically set by the rad CLI. Typically value should be `environment`.
application:
type: string
description: (Optional) The Radius Application ID. `myApplication.id` for example.
capacity:
type: string
enum: [S, M, L]
description: (Optional) The capacity of the Redis server.
host:
type: string
description: (Read-Only) The hostname used to connect to the Redis server.
readOnly: true
port:
type: integer
description: (Read-Only) The port used to connected to the Redis server.
readOnly: true
tls:
type: boolean
description: (Read-Only) Set to true if the Redis server requires a TLS/SSL connection.
readOnly: true
username:
type: string
description: (Read-Only) The username used to connected to the Redis server.
readOnly: true
password:
type: string
description: (Read-Only) The password used to connected to the Redis server.
readOnly: true
required:
- environment