diff --git a/.github/config/en-custom.txt b/.github/config/en-custom.txt index 53ee07afe..8098127d9 100644 --- a/.github/config/en-custom.txt +++ b/.github/config/en-custom.txt @@ -1301,6 +1301,8 @@ DeploymentTemplate gitops auditable bicepparam +cleartext +MyCompany backendRequest GatewayRouteTimeoutPolicy timeoutPolicy @@ -1309,4 +1311,6 @@ aci managedIdentity gatewayID Ngroup -dns \ No newline at end of file +resourcegroups +webservices +webServices \ No newline at end of file diff --git a/docs/content/getting-started/demo-dashboard-appgraph.png b/docs/content/getting-started/demo-dashboard-appgraph.png index 265c20e8f..5f6e06a21 100644 Binary files a/docs/content/getting-started/demo-dashboard-appgraph.png and b/docs/content/getting-started/demo-dashboard-appgraph.png differ diff --git a/docs/content/tutorials/composite-recipe/index.md b/docs/content/tutorials/composite-recipe/index.md new file mode 100644 index 000000000..12faa9d4e --- /dev/null +++ b/docs/content/tutorials/composite-recipe/index.md @@ -0,0 +1,228 @@ +--- +type: docs +title: "Tutorial: Create a composite Recipe" +linkTitle: "Create a composite Recipe" +description: "Learn how to create a composite recipe for a custom resource type" +weight: 140 +categories: ["Tutorial"] +--- +## 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 + +{{< image src="tutorial3.png" alt="Diagram of the Todo List application with using a web service" width=600px >}} + +## Prerequisites + +This tutorial assumes you have completed the [Add a custom resource type]({{< ref "/tutorials/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. + +{{< button text="Download types.yaml" link="snippets/types.yaml" newtab="true" >}} + +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]({{< ref "guides/author-apps/containers/howto-connect-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]({{< ref rad_resource-type_create >}}) command. + +```bash +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`]({{< ref rad_resource-type_list >}}) command. + +```bash +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]({{< ref rad_bicep_publish-extension >}}) command. + +```bash +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: + + {{% rad file="snippets/webservices.bicep" lang="bicep" embed=true %}} + + Notice that the `container` and `connections` properties are passed to the `Applications.Core/containers` built-in type using a single line. + +1. Publish the Recipe to an OCI registry. Make sure to replace `host` and `registry` with your container registry. + + ```bash + rad bicep publish --file webservices.bicep --target br://webservices:latest + ``` + ``` + $ rad bicep publish --file webservices.bicep --target br://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 //webservices@... + + Successfully published Bicep file "webservices.bicep" to "//tutorial/webservices:latest" + ``` + +1. Register the Bicep template as the `default` Recipe in the `default` environment. + + ```bash + rad recipe register default --environment default \ + --resource-type Radius.Resources/webServices \ + --template-kind bicep \ + --template-path //webservices:latest + ``` + ``` + Successfully linked recipe "default" to environment "default" + ``` + + You can confirm the Recipe was registered using `rad recipe list` command. + + ```bash + rad recipe list + ``` + ``` + rad recipe list + RECIPE TYPE TEMPLATE KIND TEMPLATE VERSION TEMPLATE + ... + default Radius.Resources/webServices bicep //webservices:latest + default Radius.Resources/postgreSQL terraform git::https://github.com//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`. + + ```diff + - resource demo 'Applications.Core/containers@2023-10-01-preview' = { + + resource demo 'Radius.Resources/webServices@2023-10-01-preview' = { + ``` + +1. 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. + + ```diff + resource demo 'Radius.Resources/webServices@2023-10-01-preview' = { + name: 'demo' + properties: { + application: application + + environment: environment + + ingress: true + ``` + +1. Since the web service resource type has a built-in Gateway, remove the Gateway resource. + + ```diff + - resource gateway 'Applications.Core/gateways@2023-10-01-preview' = { + - name: 'gateway' + - properties: { + - application: application + - routes: [ + - { + - path: '/' + - destination: 'http://demo:3000' + - } + - ] + - } + - } + ``` + +1. Run the application using `rad run`. + + ```bash + 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 + ``` + +1. Unlike before, the Gateway URL is not automatically shown. Use the `rad resource show` command to get the URL of the application. + + ```bash + rad resource show Applications.Core/gateways gateway -o json | grep url + ``` + ``` + "url": "http://gateway.todolist.172.18.0.6.nip.io" + ``` + +1. 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. + + ```bash + rad application delete todolist + ``` + +1. Delete the PostgreSQL and web service resource types. + + ```bash + rad resource-type delete Radius.Resources/postgreSQL + rad resource-type delete Radius.Resources/webServices + ``` \ No newline at end of file diff --git a/docs/content/tutorials/composite-recipe/snippets/types.yaml b/docs/content/tutorials/composite-recipe/snippets/types.yaml new file mode 100644 index 000000000..d67295fd5 --- /dev/null +++ b/docs/content/tutorials/composite-recipe/snippets/types.yaml @@ -0,0 +1,191 @@ +name: Radius.Resources +types: + postgreSQL: + capabilities: ["SupportsRecipes"] + apiVersions: + '2023-10-01-preview': + schema: + type: object + properties: + environment: + type: string + application: + type: string + size: + type: string + description: The size of the PostgreSQL database + database: + type: string + description: The name of the database + readOnly: true + host: + type: string + description: The host name of the database + readOnly: true + port: + type: string + description: The port number of the database + readOnly: true + username: + type: string + description: The username for the database + readOnly: true + password: + type: string + description: The password for the database + readOnly: true + webServices: + capabilities: ["SupportsRecipes"] + apiVersions: + '2023-10-01-preview': + schema: + type: object + properties: + environment: + type: string + description: The Radius environment, typically set by the rad CLI + application: + type: string + description: The application which the resource is associated with + connections: + type: object + description: The List of connections to other resources + properties: + name: + type: string + description: The name of the connection + source: + type: string + description: The id of the resource the webService is connecting to + ingress: + type: boolean + description: When true, deployes an ingress gateway mapped to the port named web (MUST use web for the port name) + container: + type: object + properties: + image: + type: string + description: The container image + env: + type: object + description: Environment variables injected into the application container + properties: + value: + type: string + valueFrom: + type: object + properties: + secretRef: + type: object + properties: + source: + type: string + description: The name of the secret + key: + type: string + description: The key in the secret + command: + type: string + description: Overrides the container images ENTRYPOINT + args: + type: string + description: Overrides the container images CMD + imagePullPolicy: + type: string + description: The image pull policy for the container image (Always, IfNotPresent, Never) + workingDir: + type: string + description: The working directory for the container + ports: + type: object + properties: + containerPort: + type: string + description: The port the container is listening on + protocol: + type: string + description: The protocol the container listening on, defaults to tcp + readinessProbe: + type: object + properties: + kind: + type: string + description: The kind of probe (exec, httpGet, tcp) + containerPort: + type: string + description: The listening port number, used when kind is httpGet or tcp + path: + type: string + description: The route to make the HTTP request on, used when kind is httpGet + command: + type: string + description: Command to execute to probe readiness, used when kind is exec + initialDelaySeconds: + type: integer + description: The number of seconds to wait before starting the probe + failureThreshold: + type: integer + description: The number of failed probes required to mark the container as not ready + periodSeconds: + type: integer + description: The number of seconds between each probe + required: + - kind + livenessProbe: + type: object + properties: + kind: + type: string + description: The kind of probe (exec, httpGet, tcp) + containerPort: + type: string + description: The listening port number, used when kind is httpGet or tcp + path: + type: string + description: The route to make the HTTP request on, used when kind is httpGet + command: + type: string + description: Command to execute to probe readiness, used when kind is exec + initialDelaySeconds: + type: integer + description: The number of seconds to wait before starting the probe + failureThreshold: + type: integer + description: The number of failed probes required to mark the container as not ready + periodSeconds: + type: integer + description: The number of seconds between each probe + required: + - kind + volumes: + type: object + properties: + name: + type: string + description: The name of the volume + kind: + type: string + description: The type of volume, either ephemeral or persistent + mountPath: + type: string + description: The container path to mount the volume to + managedStore: + type: string + description: The backing storage medium to use when kind is ephemeral, either disk or memory + source: + type: string + description: A volume resource to mount when kind is persistent + rbac: + type: string + description: The RBAC level when kind is persistent, allowed values are read and write, defaults to read + required: + - name + - kind + - mountPath + - managedStore + - source + required: + - image + required: + - environment + - container \ No newline at end of file diff --git a/docs/content/tutorials/composite-recipe/snippets/webservices.bicep b/docs/content/tutorials/composite-recipe/snippets/webservices.bicep new file mode 100644 index 000000000..2bdef6f7b --- /dev/null +++ b/docs/content/tutorials/composite-recipe/snippets/webservices.bicep @@ -0,0 +1,27 @@ +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 + } +} diff --git a/docs/content/tutorials/composite-recipe/todolist.png b/docs/content/tutorials/composite-recipe/todolist.png new file mode 100644 index 000000000..0b89d65cc Binary files /dev/null and b/docs/content/tutorials/composite-recipe/todolist.png differ diff --git a/docs/content/tutorials/composite-recipe/tutorial3.png b/docs/content/tutorials/composite-recipe/tutorial3.png new file mode 100644 index 000000000..88f68bbf0 Binary files /dev/null and b/docs/content/tutorials/composite-recipe/tutorial3.png differ diff --git a/docs/content/tutorials/custom-resource-type/bicepconfig.json b/docs/content/tutorials/custom-resource-type/bicepconfig.json new file mode 100644 index 000000000..e8c3c4bb0 --- /dev/null +++ b/docs/content/tutorials/custom-resource-type/bicepconfig.json @@ -0,0 +1,11 @@ +// The bicepconfig.json file is needed so the bicep files for this tutorial can be compiled with the correct setup +{ + "experimentalFeaturesEnabled": { + "extensibility": true + }, + "extensions": { + "radius": "br:biceptypes.azurecr.io/radius:latest", + "aws": "br:biceptypes.azurecr.io/aws:latest", + "radiusResources": "./radiusResources.tgz" + } +} \ No newline at end of file diff --git a/docs/content/tutorials/custom-resource-type/index.md b/docs/content/tutorials/custom-resource-type/index.md new file mode 100644 index 000000000..cbdf5d26f --- /dev/null +++ b/docs/content/tutorials/custom-resource-type/index.md @@ -0,0 +1,345 @@ +--- +type: docs +title: "Tutorial: Add a custom resource type" +linkTitle: "Add a custom resource type" +description: "Learn how to define and deploy a resource type in your Radius application" +weight: 120 +categories: ["Tutorial"] +--- + +## Overview + +Radius includes several built-in resource types which developers can use to build applications. These include core resource types such as Containers, Gateways, and Secrets. You can also create your own custom resource types. This tutorial guides you through creating a PostgreSQL resource and deploying the sample Todo List application with PostgreSQL. + +{{< image src="tutorial2.png" alt="Diagram of the Todo List with PostgreSQL" width=600px >}} + +## Prerequisites + +This tutorial assumes you have completed the [Create a new application]({{< ref "/tutorials/new-app" >}}) tutorial and have Radius installed and the demo application deployed. + +Additionally, you will need a location to store your Recipe: + + - **Terraform** configurations must be stored in a Git repository. Ideally for this tutorial the Git repository has anonymous access. If not, you will need to configure [Git authentication]({{< ref "guides/recipes/terraform/howto-private-registry" >}}). + + - **Bicep** templates must be stored in an OCI registry. As with Git, you must have anonymous access to the registry or configure [authentication]({{< ref "guides/recipes/howto-private-bicep-registry" >}}). + +Finally, [Node.js](https://nodejs.org/en/download) must be installed on the workstation to generate the Bicep extension to deploy the new resource type. + + + +## Step 1: Create a PostgreSQL resource type in Radius + +To create a PostgreSQL resource type in Radius, first create the resource type definition then add the resource type to Radius. + +1. Create a new file called `types.yaml` and add the following: + + {{% rad file="snippets/types.yaml" lang=YAML embed=true %}} + + The PostgreSQL resource type definition includes: + + - **`name`**: The namespace of the resource type, as a convention `Radius.Resources` is recommended but any name in the form `PrimaryName.SecondaryName` can be used + - **`types`**: The resource type name + - **`capabilities`**: This specifies features of the resource type. The only available option is `SupportsRecipes` which indicates that the resource type can be deployed via a Recipe. + - **`apiVersions`**: The version of the schema defined below + - **`schema`**: The OpenAPI v3 schema which defines the properties of the resource type + - **`environment`**: The Radius environment ID which the resource is deployed to, this property is set by the Radius CLI when the resource is deployed + - **`application`**: The application ID which the resource belongs to + - **`size`**: The size of the PostgreSQL database + - **`host`**: The hostname of the database server + - **`port`**: The port of the database server + - **`username`**: The username + - **`password`**: The password + + The `host`, `port`, `username`, and `password` properties are read-only properties set by Recipe. + +1. Create the resource type using the [rad resource-type]({{< ref rad_resource-type_create >}}) command: + + ```bash + rad resource-type create postgreSQL -f types.yaml + ``` + + ``` + $ rad resource-type create postgreSQL -f types.yaml + Resource provider "Radius.Resources" not found. + Creating resource provider Radius.Resources at location global + Creating resource type Radius.Resources/postgreSQL + Creating API Version Radius.Resources/postgreSQL@2023-10-01-preview + Creating location Radius.Resources/global/ + ``` + +## Step 2: Create a Bicep extension + +The `rad resource-type create` command created the resource type in the Radius control plane. The next step is to create a Bicep extension which will be used by the Radius CLI and VS Code (if you have the Bicep VS Code extension installed). + +{{% alert title="Warning" color="warning" %}} +This step is required even if you use Terraform-based Recipes to deploy the PostgreSQL resource type as part of the application. +{{% /alert %}} + +1. Generate the Bicep extension using the [rad bicep publish-extension]({{< ref rad_bicep_publish-extension >}}) command. + + ```bash + 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-2214011863/types.json + Writing index to /var/folders/w8/89pqzjp52pbg4g256z9cpkww0000gn/T/bicep-extension-2214011863/index.json + Writing documentation to /var/folders/w8/89pqzjp52pbg4g256z9cpkww0000gn/T/bicep-extension-2214011863/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" + ``` + +1. Open the `bicepconfig.json` file and modify the contents. + + ```diff + { + "experimentalFeaturesEnabled": { + "extensibility": true + }, + "extensions": { + "radius": "br:biceptypes.azurecr.io/radius:latest", + - "aws": "br:biceptypes.azurecr.io/aws:latest" + + "aws": "br:biceptypes.azurecr.io/aws:latest", + + "radiusResources": "radiusResources.tgz" + } + } + ``` + + The final file should be: + + ``` + { + "experimentalFeaturesEnabled": { + "extensibility": true + }, + "extensions": { + "radius": "br:biceptypes.azurecr.io/radius:latest", + "aws": "br:biceptypes.azurecr.io/aws:latest", + "radiusResources": "radiusResources.tgz" + } + } + ``` + + Now, any Bicep template with `extension radiusResources` will reference the `radiusResources.tgz` file for details about the PostgreSQL resource type. + +## Step 3: Create a Recipe for the PostgreSQL resource type + +[Recipes]({{< ref "/guides/recipes/overview" >}}) define how resource are deployed. Recipes can be either Terraform configurations or Bicep templates. Once the Terraform configuration or Bicep template has been published in a Git repo or OCI registry, it can be registered as a recipe in a Radius environment. + +{{< tabs Terraform Bicep >}}{{% codetab %}} + +Terraform configurations must be stored in a Git repository accessible by Radius. As discussed in the prerequisites, using a Git repository with anonymous access is easiest for this tutorial, otherwise you will need to configure [Git authentication]({{< ref "guides/recipes/terraform/howto-private-registry" >}}). Learn more about Recipes in this [How-to guide]({{< ref "/guides/recipes/howto-author-recipes" >}}). + +1. Create a new directory in your Git repository for the PostgreSQL Terraform module then create the `main.tf` file and add the following: + + {{% rad file="snippets/recipes/terraform/main.tf" embed=true %}} + + + +1. Register the Terraform configuration as a Recipe called `default`. Since Recipes are registered with Environments, use the `default` environment created in the previous tutorial. + + ```bash + rad recipe register default \ + --environment default \ + --resource-type Radius.Resources/postgreSQL \ + --template-kind terraform \ + --template-path git::/.git/// + ``` + + For example, if the `main.tf` file is in a GitHub repository named `recipes` in a directory called `/kubernetes/postgresql`, the command would look like this: + + ```bash + --template-path git::https://github.com//recipes.git//kubernetes/postgresql + ``` + + The output will be: + + ``` + Successfully linked recipe "default" to environment "default" + ``` + +1. Verify the Recipe is registered using the [`rad recipe list`]({{< ref rad_recipe_list >}}) command. + + ```bash + rad recipe list + ``` + + ``` + $ rad recipe list + RECIPE TYPE TEMPLATE KIND TEMPLATE VERSION TEMPLATE + ... + default Radius.Resources/postgreSQL terraform git::https://github.com//recipes.git//kubernetes/postgres + ``` + +{{% /codetab %}} +{{% codetab %}} + +Bicep templates must be stored in an OCI registry accessible by Radius. As discussed in the prerequisites, using an OCI registry with anonymous access is easiest for this tutorial, otherwise you will need to configure [authentication]({{< ref "guides/recipes/howto-private-bicep-registry" >}}). Learn more about Recipes in this [How-to guide]({{< ref "/guides/recipes/howto-author-recipes" >}}). + +1. Create a new file called `postgresql.bicep` and add the following: + + {{% rad file="snippets/recipes/bicep/postgresql.bicep" embed=true %}} + + + +1. Publish the Recipe to the OCI registry. Make sure to replace `host` and `registry` with your container registry. + + ```bash + rad bicep publish --file postgresql.bicep --target br://postgresql:latest + ``` + + ``` + Successfully published Bicep file "postgresql.bicep" to "//postgresql:latest" + ``` + +1. Register the Bicep template as a Recipe called `default`. Since Recipes are registered with Environments, use the `default` environment created in the previous tutorial. + + ```bash + rad recipe register default --environment default \ + --resource-type Radius.Resources/postgreSQL \ + --template-kind bicep \ + --template-path //postgresql:latest + ``` + + ``` + Successfully linked recipe "default" to environment "default" + ``` + +1. Verify the Recipe is registered using the [`rad recipe list`]({{< ref rad_recipe_list >}}) command. You should see output similar to: + + ```bash + rad recipe list + ``` + + ``` + $ rad recipe list + RECIPE TYPE TEMPLATE KIND TEMPLATE VERSION TEMPLATE + ... + default Radius.Resources/postgreSQL bicep //postgresql:latest + ``` + +{{% /codetab %}} +{{< /tabs >}} + +## Step 4: Replace MongoDB with PostgreSQL + +1. Edit the `app.bicep` file from the previous tutorial and add the `radiusResources` extension at the top of the file. + + ```diff + extension radius + + extension radiusResources + ``` + +1. Remove the MongoDB resource and replace it with a PostgreSQL resource. + + ```diff + - resource mongodb 'Applications.Datastores/mongoDatabases@2023-10-01-preview' = { + - name: 'mongodb' + - properties: { + - environment: environment + - application: application + - } + - } + + resource postgresql 'Radius.Resources/postgreSQL@2023-10-01-preview' = { + + name: 'postgresql' + + properties: { + + environment: environment + + application: application + + size: 'S' + + } + + } + ``` + +1. Modify the `demo` container to use the PostgreSQL. Because PostgreSQL is a custom resource type, the environment variables must be manually specified. + + ```diff + 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 + } + } + + env: { + + CONNECTION_POSTGRES_HOST: { + + value: postgresql.properties.host + + } + + CONNECTION_POSTGRES_PORT: { + + value: string(postgresql.properties.port) + + } + + CONNECTION_POSTGRES_USERNAME: { + + value: postgresql.properties.username + + } + + CONNECTION_POSTGRES_DATABASE: { + + value: postgresql.properties.database + + } + + //This is stored and passed as cleartext for demo purposes. In production, use a secret store. + + CONNECTION_POSTGRES_PASSWORD: { + + value: postgresql.properties.password + + } + + } + } + connections: { + - mongodb: { + - source: mongodb.id + - } + + postgresql: { + + source: postgresql.id + + } + backend: { + source: 'http://backend:80' + } + } + } + } + ``` + + {{% alert title="Caution" color="warning" %}} + In this example the POSTGRESQL_PASSWORD is stored as a cleartext property for demo purposes. In production environments, always use secrets to store and reference sensitive information like passwords. + {{% /alert %}} + +## Step 5: Run the application + +Run the application using `rad run`. The `rad run` command sets up port forwarding to the application. . + +```bash +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 gateway Applications.Core/gateways +Completed demo Applications.Core/containers + +Deployment Complete + +Resources: + backend Applications.Core/containers + demo Applications.Core/containers + gateway Applications.Core/gateways + postgresql Radius.Resources/postgreSQL + +Public Endpoints: + gateway Applications.Core/gateways http://gateway.todolist.172.18.0.6.nip.io +``` + +Open the gateway URL in your browser. The Radius Connections section now has PostgreSQL details and MongoDB is no longer there. + +{{< image src="todolist_postgresql.png" alt="Todo List with PostgreSQL connection" width=800px >}} + +

+ +{{< button text="Next step: Create a composite Recipe →" page="composite-recipe" >}} \ No newline at end of file diff --git a/docs/content/tutorials/custom-resource-type/radiusResources.tgz b/docs/content/tutorials/custom-resource-type/radiusResources.tgz new file mode 100644 index 000000000..9f38932a5 Binary files /dev/null and b/docs/content/tutorials/custom-resource-type/radiusResources.tgz differ diff --git a/docs/content/tutorials/custom-resource-type/snippets/recipes/bicep/postgresql.bicep b/docs/content/tutorials/custom-resource-type/snippets/recipes/bicep/postgresql.bicep new file mode 100644 index 000000000..14ffba39c --- /dev/null +++ b/docs/content/tutorials/custom-resource-type/snippets/recipes/bicep/postgresql.bicep @@ -0,0 +1,135 @@ +@description('Information about what resource is calling this Recipe. Generated by Radius.') +param context object + +@description('Name of the PostgreSQL database. Defaults to the name of the Radius resource.') +param database string = context.resource.name + +@description('PostgreSQL username') +param user string = 'postgres' + +@description('PostgreSQL password') +@secure() +#disable-next-line secure-parameter-default +param password string = uniqueString(context.resource.id) + +@description('Tag to pull for the postgres container image.') +param tag string = '16-alpine' + +@description('Memory limits for the PostgreSQL container') +var memory ={ + S: { + memoryRequest: '512Mi' + memoryLimit: '1024Mi' + } + M: { + memoryRequest: '1Gi' + memoryLimit: '2Gi' + } +} + +extension kubernetes with { + kubeConfig: '' + namespace: context.runtime.kubernetes.namespace +} as kubernetes + +var uniqueName = 'postgres-${uniqueString(context.resource.id)}' +var port = 5432 + +// Based on https://hub.docker.com/_/postgres/ +resource postgresql 'apps/Deployment@v1' = { + metadata: { + name: uniqueName + } + spec: { + selector: { + matchLabels: { + app: 'postgresql' + resource: context.resource.name + } + } + template: { + metadata: { + labels: { + app: 'postgresql' + resource: context.resource.name + // Label pods with the application name so `rad run` can find the logs. + 'radapp.io/application': context.application == null ? '' : context.application.name + } + } + spec: { + containers: [ + { + // This container is the running postgresql instance. + name: 'postgres' + image: 'postgres:${tag}' + ports: [ + { + containerPort: port + } + ] + resources: { + requests: { + memory: memory[context.resource.properties.size].memoryRequest + } + limits: { + memory: memory[context.resource.properties.size].memoryLimit + } + } + env: [ + { + name: 'POSTGRES_USER' + value: user + } + { + name: 'POSTGRES_PASSWORD' + value: password + } + { + name: 'POSTGRES_DB' + value: database + } + ] + } + ] + } + } + } +} + +resource svc 'core/Service@v1' = { + metadata: { + name: uniqueName + labels: { + name: uniqueName + } + } + spec: { + type: 'ClusterIP' + selector: { + app: 'postgresql' + resource: context.resource.name + } + ports: [ + { + port: port + } + ] + } +} + +output result object = { + resources: [ + '/planes/kubernetes/local/namespaces/${svc.metadata.namespace}/providers/core/Service/${svc.metadata.name}' + '/planes/kubernetes/local/namespaces/${postgresql.metadata.namespace}/providers/apps/Deployment/${postgresql.metadata.name}' + ] + values: { + host: '${svc.metadata.name}.${svc.metadata.namespace}.svc.cluster.local' + port: port + database: database + username: user + } + secrets: { + #disable-next-line outputs-should-not-contain-secrets + password: password + } +} diff --git a/docs/content/tutorials/custom-resource-type/snippets/recipes/terraform/main.tf b/docs/content/tutorials/custom-resource-type/snippets/recipes/terraform/main.tf new file mode 100644 index 000000000..57aee2940 --- /dev/null +++ b/docs/content/tutorials/custom-resource-type/snippets/recipes/terraform/main.tf @@ -0,0 +1,124 @@ +terraform { + required_providers { + kubernetes = { + source = "hashicorp/kubernetes" + version = ">= 2.0" + } + } +} + +variable "context" { + description = "This variable contains Radius recipe context." + type = any +} + +variable "memory" { + description = "Memory limits for the PostgreSQL container" + type = map(object({ + memoryRequest = string + memoryLimit = string + })) + default = { + S = { + memoryRequest = "512Mi" + memoryLimit = "1024Mi" + }, + M = { + memoryRequest = "1Gi" + memoryLimit = "2Gi" + } + } +} + +locals { + uniqueName = var.context.resource.name + port = 5432 + namespace = var.context.runtime.kubernetes.namespace +} + +resource "random_password" "password" { + length = 16 +} + +resource "kubernetes_deployment" "postgresql" { + metadata { + name = local.uniqueName + namespace = local.namespace + } + + spec { + selector { + match_labels = { + app = "postgres" + } + } + + template { + metadata { + labels = { + app = "postgres" + } + } + + spec { + container { + image = "postgres:16-alpine" + name = "postgres" + resources { + requests = { + memory = var.memory[var.context.resource.properties.size].memoryRequest + } + limits = { + memory= var.memory[var.context.resource.properties.size].memoryLimit + } + } + env { + name = "POSTGRES_PASSWORD" + value = random_password.password.result + } + env { + name = "POSTGRES_USER" + value = "postgres" + } + env { + name = "POSTGRES_DB" + value = "postgres_db" + } + port { + container_port = local.port + } + } + } + } + } +} + +resource "kubernetes_service" "postgres" { + metadata { + name = local.uniqueName + namespace = local.namespace + } + + spec { + selector = { + app = "postgres" + } + + port { + port = local.port + target_port = local.port + } + } +} + +output "result" { + value = { + values = { + host = "${kubernetes_service.postgres.metadata[0].name}.${kubernetes_service.postgres.metadata[0].namespace}.svc.cluster.local" + port = local.port + database = "postgres_db" + username = "postgres" + password = random_password.password.result + } + } +} \ No newline at end of file diff --git a/docs/content/tutorials/custom-resource-type/snippets/types.yaml b/docs/content/tutorials/custom-resource-type/snippets/types.yaml new file mode 100644 index 000000000..8ea0872d7 --- /dev/null +++ b/docs/content/tutorials/custom-resource-type/snippets/types.yaml @@ -0,0 +1,36 @@ +name: Radius.Resources +types: + postgreSQL: + capabilities: ["SupportsRecipes"] + apiVersions: + '2023-10-01-preview': + schema: + type: object + properties: + environment: + type: string + application: + type: string + size: + type: string + description: The size of the PostgreSQL database + database: + type: string + description: The name of the database. + readOnly: true + host: + type: string + description: The host name of the database. + readOnly: true + port: + type: string + description: The port number of the database. + readOnly: true + username: + type: string + description: The username for the database. + readOnly: true + password: + type: string + description: The password for the database. + readOnly: true \ No newline at end of file diff --git a/docs/content/tutorials/custom-resource-type/todolist_postgresql.png b/docs/content/tutorials/custom-resource-type/todolist_postgresql.png new file mode 100644 index 000000000..16627209f Binary files /dev/null and b/docs/content/tutorials/custom-resource-type/todolist_postgresql.png differ diff --git a/docs/content/tutorials/custom-resource-type/tutorial2.png b/docs/content/tutorials/custom-resource-type/tutorial2.png new file mode 100644 index 000000000..230d1577c Binary files /dev/null and b/docs/content/tutorials/custom-resource-type/tutorial2.png differ diff --git a/docs/content/tutorials/new-app/dashboard.png b/docs/content/tutorials/new-app/dashboard.png new file mode 100644 index 000000000..342c14dbd Binary files /dev/null and b/docs/content/tutorials/new-app/dashboard.png differ diff --git a/docs/content/tutorials/new-app/diagram.png b/docs/content/tutorials/new-app/diagram.png deleted file mode 100644 index 66416e46c..000000000 Binary files a/docs/content/tutorials/new-app/diagram.png and /dev/null differ diff --git a/docs/content/tutorials/new-app/index.md b/docs/content/tutorials/new-app/index.md index 62eb0ec46..5e90adab0 100644 --- a/docs/content/tutorials/new-app/index.md +++ b/docs/content/tutorials/new-app/index.md @@ -7,141 +7,195 @@ weight: 100 categories: "Tutorial" --- +## Overview + This tutorial will teach you the basics of creating a new Radius Application. You will learn how to: 1. Define and deploy a Radius Environment and Application 1. Add a container to your application and customize that container -1. Add a Mongo database to your application and connect it to your container -1. Add a second container and connect it to your first container -1. Securely expose your application to the internet through a gateway +1. Add a MongoDB database to your application and connect it to your container +1. Add a second container and connect it to the first container +1. Expose your application through a Gateway By the end of the tutorial, you will have created and deployed a new Radius Application. -{{< image src="diagram.png" alt="Diagram of the application resources and their connections" width=600px >}} +{{< image src="todolist-app.png" alt="Diagram of the application resources and their connections" width=600px >}} ## Prerequisites -- [Supported Kubernetes cluster]({{< ref "/guides/operations/kubernetes/overview" >}}) -- [rad CLI]({{< ref "installation#step-1-install-the-rad-cli" >}}) -- [Bicep VSCode extension]({{< ref "installation#step-2-install-the-vs-code-extension" >}}) +- [Supported Kubernetes cluster]({{< ref "/guides/operations/kubernetes/overview#supported-kubernetes-clusters" >}}) +- [Radius CLI]({{< ref "installation#step-1-install-the-rad-cli" >}}) +- [Bicep extension for VS Code]({{< ref "installation#step-2-install-the-vs-code-extension" >}}) -## Step 1: Initialize a Radius Environment and Application +## Step 1: Install Radius with a default Environment and Workspace -[Radius Environments]({{< ref "/guides/deploy-apps/environments/overview" >}}) are where applications are deployed. Environments determine how an application runs on a particular platform (_like AWS or Azure_). +This tutorial will use the [`rad init`]({{< ref rad_initialize >}}) command to install Radius on a Kubernetes cluster and initialize the configuration with an Environment called *default* and Recipes for deploying to Kubernetes. Future tutorials will demonstrate using Recipes for deploying to AWS and Azure. -1. Begin by creating a new directory for your application: +1. Create a new directory for the Todo List application. ```bash - mkdir myapp - cd myapp + mkdir todolist + cd todolist ``` -1. Initialize a new Radius Environment with [`rad init`]({{< ref rad_initialize >}}): +1. Install Radius. ```bash rad init ``` - When asked if you want to create a new application select "Yes". This will create a new file named `app.bicep` in your directory where your application will be defined. It will also create a [`bicepconfig.json`]({{< ref "/guides/tooling/bicepconfig/overview" >}}) file that will contain the necessary setup to use Radius types with Bicep. - - {{< alert title="💡 Development Environments" color="info" >}} - By default `rad init` gets you up and running with a local, development-focused environment where most of the environment configuration is handled for you, including Recipes (_more on that soon_). If you would like to fully customize your environment, you can run `rad init --full` - {{< /alert >}} + When asked if you want to create a new application select *Yes*. This will create a new file named `app.bicep` in your working directory where. It will also create a [`bicepconfig.json`]({{< ref "/guides/tooling/bicepconfig/overview" >}}) file that will contain the necessary configuration to use Radius core resource types. -## Step 2: Inspect your Application +## Step 2: Explore the default configuration -Radius Applications are where all your app's resources and relationships come together. Let's take a look at this Radius Application to learn more about it. +Inspect the Workspace created by `rad init`. -1. View the full Application definition by running [`rad app show -o json`]({{< ref rad_application_show >}}): +1. List the available Workspaces using [`rad workspace list`]({{< ref rad_workspace_list >}}) ```bash - rad app show myapp -o json + rad workspace list + ``` + + ``` + $ rad workspace list + WORKSPACE KIND KUBECONTEXT ENVIRONMENT + default kubernetes my-kube-context default ``` - You will see the full App definition in its raw JSON format: + Show the current Workspace. The `--output json` will show all the details of the Workspace. + + ```bash + rad workspace show -o json + ``` ``` + $ rad workspace show -o json { - "id": "/planes/radius/local/resourcegroups/default/providers/Applications.Core/applications/myapp", - "location": "global", - "name": "myapp", - "properties": { - "environment": "/planes/radius/local/resourceGroups/default/providers/Applications.Core/environments/default", - "provisioningState": "Succeeded", - "status": { - "compute": { - "kind": "kubernetes", - "namespace": "default-myapp" - } - } + "connection": { + "context": "my-kube-context", + "kind": "kubernetes" }, - "systemData": {}, - "tags": {}, - "type": "Applications.Core/applications" + "environment": "/planes/radius/local/resourceGroups/default/providers/Applications.Core/environments/default", + "scope": "/planes/radius/local/resourceGroups/default" } ``` - There are a few important things to note about the application definition: + Notice that a Radius Workspace is a combination of a Kubernetes context, a Radius Environment, and a Resource Group. - - **`id`** is the fully-qualified UCP resource ID of the application. This value is used to uniquely identify the application in the Radius system. - - **`location`** is the _where_ your Application resides. For now, all applications are deployed to the `global` location, which corresponds to the cluster where Radius is running. - - **`environment`** specifies the Radius Environment which the Applications "binds" to at deployment. This is what determines where containers should run (_Kubernetes_) and which namespace to deploy into (_prefixed with "default"_). In this case, the application will be deployed into the `default` Environment that was created by `rad init`. - - **`compute`** specifies the hosting platform where running services in the Application will run. In this case, the services will be deployed into the `default-myapp` Kubernetes namespace within the same cluster where Radius is installed. + {{< alert title="💡 Workspaces" color="info" >}} + [Workspaces]({{< ref Workspaces >}}) are configurations set for the Radius CLI. Similar to kubectl contexts, you can have multiple Workspaces pointing to different Radius installation, Resource Groups, and Environments. + {{< /alert >}} -1. Let's take a look inside the Application to see what's deployed. Run [`rad app graph`]({{< ref rad_application_graph >}}) to print the Application's resources and relationships: +1. List the resource groups created by `rad init` using the [`rad group list`]({{< ref rad_group_list >}}) command. ```bash - rad app graph + rad group list + ``` + + ``` + $ rad group list + GROUP ID + default /planes/radius/local/resourcegroups/default ``` - You'll see that nothing has been deployed yet and the app is empty: + `rad init` creates a group called `default`. + {{< alert title="💡 Resource Groups" color="info" >}} + Every resource deployed in Radius belongs to one and only [resource group]({{< ref Groups >}}). And each resource in a group must have a unique name. This includes environments and applications which are modeled as resources in Radius. + {{< /alert >}} + +1. Inspect the Environment using the [`rad environment list`]({{< ref rad_environment_list >}}) and [`rad environment show`]({{< ref rad_environment_show >}}) commands. + + ```bash + rad environment list + ``` + + ``` + $ rad environment list + RESOURCE TYPE GROUP STATE + default Applications.Core/environments default Succeeded ``` - Displaying application: myapp - (empty) + ```bash + rad environment show default --output json ``` - Let's deploy some resources to start building out the application. + ``` + $ rad environment show default --output json + { + "id": "/planes/radius/local/resourcegroups/default/providers/Applications.Core/environments/default", + "location": "global", + "name": "default", + "properties": { + "compute": { + "kind": "kubernetes", + "namespace": "default" + }, + "provisioningState": "Succeeded", + "recipes": { + ... + } + }, + ... + "type": "Applications.Core/environments" + } + ``` -## Step 3: Inspect and deploy `app.bicep` + {{< alert title="💡 Development Environments" color="info" >}} + By default `rad init` gets you up and running with a local, development-focused [environment](/guides/deploy-apps/environments/overview/) where most of the environment configuration is handled for you, including Recipes (_more on that soon_). If you would like to fully customize your environment, you can run `rad init --full` + {{< /alert >}} + +## Step 3: Deploy the Todo List application + +The `app.bicep` file defines all the resources (Containers, Gateways, cloud services, etc.) that make up the Todo List application, including how those resources are connected to each other. + +1. Open `app.bicep` and review the application definition created by `rad init`. The Todo List application definition includes: + + {{% rad file="snippets/1-app.bicep" embed=true marker="//IMPORT" %}} + + The `extension` statement imports the resource types built into Radius. -`app.bicep` will define all the resources (containers, gateways, cloud services, etc) that make up your application, including how those resources are connected to each other. Given this explicit and comprehensive application definition, Radius Application files make it simple to consistently deploy and manage your application. + {{% rad file="snippets/1-app.bicep" embed=true marker="//PARAM" %}} -1. Open `app.bicep` and see the scaffolded application created by `rad init`: + The `application` parameter is defined so it can be used later in the resources. This parameter is set by the Radius CLI when deploying the application. - {{% rad file="snippets/1-app.bicep" embed=true %}} + {{% rad file="snippets/1-app.bicep" embed=true marker="//CONTAINER" %}} + + The initial version of the application only has a single container named demo. -1. Deploy `app.bicep` with [`rad deploy`]({{< ref rad_deploy >}}): +1. Deploy Todo List application using the [`rad deploy`]({{< ref rad_deploy >}}) command. ```bash rad deploy app.bicep ``` - You should see your container deployed: - ``` - Building .\app.bicep... - Deploying template '.\app.bicep' for application 'myapp' and environment 'default' from workspace 'default'... + $ 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... - Deployment In Progress... + Completes demo Applications.Core/containers Deployment Complete Resources: - demo Applications.Core/containers + demo Applications.Core/containers ``` -1. Run `rad app graph` again to see the container you just deployed: +1. Run `rad app graph` command to print the application resources and relationships: ```bash rad app graph ``` - You should see the container you just deployed, along with the underlying Kubernetes resources that were created to run it: + You should see the container you just deployed, along with the underlying Kubernetes resources that were created to run it: - ``` - Displaying application: myapp + ``` + $ rad app graph + Displaying application: myapp Name: demo (Applications.Core/containers) Connections: (none) @@ -151,29 +205,27 @@ Radius Applications are where all your app's resources and relationships come to demo (kubernetes: core/ServiceAccount) demo (kubernetes: rbac.authorization.k8s.io/Role) demo (kubernetes: rbac.authorization.k8s.io/RoleBinding) - ``` - - {{< alert title="💡 Kubernetes mapping" color="info" >}} - Radius Environments map how Applications "bind" to a particular platform. Earlier we saw the Application compute was set to `kubernetes` and the namespace was set to `default-myapp`. This means the container resources were deployed to the `default-myapp` namespace in the Kubernetes cluster where Radius is installed. Visit the [Kubernetes mapping docs]({{< ref "/guides/operations/kubernetes/overview#resource-mapping" >}}) to learn more. - {{< /alert >}} + ``` -## Step 4: Run your application +## Step 4: Connect to the Todo List application -When working with Radius Applications you will probably want to access container endpoints and view logs. [`rad run`]({{< ref rad_run >}}) makes it simple to deploy your application and automatically set up port-forwarding and log streaming: +The `rad deploy` command simply deployed the application to the Kubernetes cluster but does not configure network access via an ingress controller or load balancer. In order to access the application, you must either setup Kubernetes port forwarding, or simply use the [`rad run`]({{< ref rad_run >}}) command which sets up port forwarding and log streaming. ```bash rad run app.bicep ``` -You should see the container deployed and the port-forward and log stream started: +You should see the container deployed and the port forward and log stream started: ``` -Building .\app.bicep... -Deploying template '.\app.bicep' for application 'myapp' and environment 'default' from workspace 'default'... +$ rad run 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... +Deployment In Progress... -.. demo Applications.Core/containers +Completes demo Applications.Core/containers Deployment Complete @@ -182,28 +234,30 @@ Resources: Starting log stream... -demo-bb9df8798-b68rc › demo -demo-bb9df8798-b68rc demo Using in-memory store: no connection string found -demo-bb9df8798-b68rc demo Server is running at http://localhost:3000 -demo-bb9df8798-b68rc demo [port-forward] connected from localhost:3000 -> ::3000 ++ demo-5bc9b77586-cf95n › demo +demo-5bc9b77586-cf95n demo No APPLICATIONINSIGHTS_CONNECTION_STRING found, skipping Azure Monitor setup +demo-5bc9b77586-cf95n demo Using in-memory store: no connection string found +demo-5bc9b77586-cf95n demo Server is running at http://localhost:3000 +dashboard-5965dd78b9-xt2k6 dashboard [port-forward] connected from localhost:7007 -> ::7007 +demo-5bc9b77586-cf95n demo [port-forward] connected from localhost:3000 -> ::3000 ``` -Open [http://localhost:3000](http://localhost:3000) to view the Radius demo container: +Open [http://localhost:3000](http://localhost:3000) to view the Radius demo container. {{< image src="demo-landing.png" alt="Screenshot of the Radius demo container" width=500px >}} -When you're done press `CTRL + c` to terminate the port-forward and log stream. +When you're done press `CTRL + c` to terminate the port forward and log stream. The application continues to be deployed. ## Step 5: Add a database and a connection -In addition to containers, you can add dependencies like Redis caches, Dapr State Stores, Mongo databases, and more. +Add a database to the Todo List application so that the todo items are persisted. Radius ships with a built-in MongoDB resource type. -1. Add a Mongo database and an environment parameter to your `app.bicep` file: +1. Add a MongoDB database and an environment parameter to your `app.bicep` file: {{% rad file="snippets/2-app-mongo.bicep" embed=true marker="//MONGO" %}} {{< alert title="💡 Radius Recipes" color="info" >}} - Note that when you added the Mongo database to your application you didn't need to specify _how or where_ to run the underlying infrastructure. The Radius Environment and its Recipes take care of that for you. Just like how the Radius Environment bound your container to a Kubernetes cluster, it also deploys and binds your Mongo database to underlying infrastructure using [Recipes]({{< ref "/guides/recipes/overview" >}}). + Note that when you added the MongoDB database to your application you didn't need to specify _how or where_ to run the underlying infrastructure. The Radius Environment and its Recipes take care of that for you. Just like how the Radius Environment bound your container to a Kubernetes cluster, it also deploys and binds your MongoDB database to underlying infrastructure using [Recipes]({{< ref "/guides/recipes/overview" >}}). {{< /alert >}} 1. To learn about the underlying Recipe that will deploy and manage the Mongo infrastructure run [`rad recipe show`]({{< ref rad_recipe_show >}}): @@ -215,6 +269,7 @@ In addition to containers, you can add dependencies like Redis caches, Dapr Stat You'll see details on the Recipe, including available parameters and defaults: ``` + $ rad recipe show default --resource-type Applications.Datastores/mongoDatabases NAME TYPE TEMPLATE KIND TEMPLATE VERSION TEMPLATE default Applications.Datastores/mongoDatabases bicep ghcr.io/radius-project/recipes/local-dev/mongodatabases:latest @@ -224,77 +279,63 @@ In addition to containers, you can add dependencies like Redis caches, Dapr Stat database string - - ``` - If you want to learn more about the Recipe template it's in the [Recipes repo](https://github.com/radius-project/recipes/blob/main/local-dev/mongodatabases.bicep). + You can view the Bicep template used as the Recipe in the [Recipes GitHub repository](https://github.com/radius-project/recipes/blob/main/local-dev/mongodatabases.bicep). -1. Add a connection from your container to the Mongo database, which indicates to Radius that your container needs to communicate with the Mongo database: +1. Add a connection from your container to the MongoDB database, which indicates to Radius that your container needs to communicate with the database: - {{% rad file="snippets/2-app-mongo.bicep" embed=true marker="//CONTAINER" markdownConfig="{hl_lines=[\"16-20\"]}" %}} + {{% rad file="snippets/2-app-mongo.bicep" embed=true marker="//CONTAINER" markdownConfig="{hl_lines=[\"13-17\"]}" %}} {{< alert title="💡 Radius Connections" color="info" >}} Radius Connections are more than just bookkeeping. They are used to automatically configure access for your containers. Learn more in the [containers documentation]({{< ref "/guides/author-apps/containers/overview" >}}). {{< /alert >}} -1. Re-run your app with [`rad run`]({{< ref rad_run >}}) to deploy the Mongo database and container and start the port-forward and log stream: - - ```bash - rad run app.bicep - ``` +1. Re-run your app using [`rad run`]({{< ref rad_run >}}) to deploy the MongoDB database and container and start the port forward and log stream: - ``` - Building .\app.bicep... - Deploying template '.\app.bicep' for application 'myapp' and environment 'default' from workspace 'default'... - - Deployment In Progress... - - Deployment Complete - - Resources: - myapp Applications.Core/applications - demo Applications.Core/containers - mongodb Applications.Datastores/mongoDatabases - - Starting log stream... - ``` + ```bash + rad run app.bicep + ``` -1. Open [localhost:3000](http://localhost:3000) to interact with the demo container. You should see the container's connections and metadata, this time with a connection to the Mongo database and new environment variables set: +1. Open [localhost:3000](http://localhost:3000) to interact with the demo container. You should see the container's connections and metadata, this time with a connection to the Mongo database and new environment variables set. {{< image src="demo-landing-connection.png" alt="Screenshot of the Radius demo container" width=500px >}} -1. Press CTRL+C to terminate the port-forward and log stream. +1. Press `CTRL + c` to terminate the port forward and log stream. -1. Run `rad app graph` again to see the new dependency: +1. Run `rad app graph` again to see the new resource. - ```bash - rad app graph - ``` + ```bash + rad app graph + ``` - You should see the container and Mongo database you just deployed, along with the underlying Kubernetes resources that were created to run them: + You should see the container and MongoDB database you just deployed, along with the underlying Kubernetes resources that were created: - ``` - Displaying application: myapp - - Name: demo (Applications.Core/containers) - Connections: - demo -> mongodb (Applications.Datastores/mongoDatabases) - Resources: - demo (kubernetes: apps/Deployment) - demo (kubernetes: core/Secret) - demo (kubernetes: core/Service) - demo (kubernetes: core/ServiceAccount) - demo (kubernetes: rbac.authorization.k8s.io/Role) - demo (kubernetes: rbac.authorization.k8s.io/RoleBinding) - - Name: mongodb (Applications.Datastores/mongoDatabases) - Connections: - demo (Applications.Core/containers) -> mongodb - Resources: - mongo-bzmp2btdgzez6 (kubernetes: apps/Deployment) - mongo-bzmp2btdgzez6 (kubernetes: core/Service) + ``` + $ rad app graph + rad app graph + Displaying application: todolist + + 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) ``` ## Step 6: Add a backend container -In addition to dependencies, you can add more containers to make your application code more modular. Containers can be configured to interact with each other as needed. +In addition to dependencies, you can add more containers to make your application code more modular. Containers can be configured to interact with each other as needed. 1. Add a second container named `backend` to your `app.bicep` file, specifying the image and port to open to other containers: @@ -302,7 +343,7 @@ In addition to dependencies, you can add more containers to make your applicatio 1. Add a new connection from your `demo` container to the `backend` container: - {{% rad file="snippets/3-app-backend.bicep" embed=true marker="//CONTAINER" markdownConfig="{hl_lines=[\"20-22\"]}" %}} + {{% rad file="snippets/3-app-backend.bicep" embed=true marker="//CONTAINER" markdownConfig="{hl_lines=[\"17-19\"]}" %}} 1. Re-run your app with [`rad run`]({{< ref rad_run >}}): @@ -310,31 +351,21 @@ In addition to dependencies, you can add more containers to make your applicatio rad run app.bicep ``` - ``` - Building .\app.bicep... - Deploying template '.\app.bicep' for application 'myapp' and environment 'default' from workspace 'default'... - - Deployment In Progress... - - Deployment Complete - - Resources: - demo Applications.Core/containers - backend Applications.Core/containers - mongodb Applications.Datastores/mongoDatabases - - Starting log stream... - ``` - 1. Open [localhost:3000](http://localhost:3000) to interact with the demo container. You should see the container's connections and metadata, this time with a connection to the backend container and new environment variables set: {{< image src="demo-landing-backend.png" alt="Screenshot of the demo container with a connection to the backend container" width=600px >}} Note the environment variables that are set with connection information for the backend container. -## Step 7: Add a gateway +## Step 7: View the application graph in the Radius Dashboard + +Navigate to the Radius Dashboard at [http://localhost:7007](http://localhost:7007/resources/default/Applications.Core/applications/todolist/application), You should see a visualization of the application graph for the application, including the connection from the `demo` container to `mongodb` and `backend`. + +{{< image src="dashboard.png" alt="Screenshot of the Radius dashboard showing the demo container with a connection to the backend container" width=600px >}} -Finally, you can add a gateway to your application. Gateways are used to expose your application to the internet. They can expose a single container or multiple containers. +## Step 8: Add a Gateway + +Finally, add a Gateway to your application to expose the application so that it is accessible from outside the cluster. 1. Add a gateway to your `app.bicep` file: @@ -342,32 +373,37 @@ Finally, you can add a gateway to your application. Gateways are used to expose 1. Deploy your app with [`rad deploy`]({{< ref rad_deploy >}}): - ```bash - rad deploy app.bicep - ``` + ```bash + rad deploy app.bicep + ``` - ``` - Building .\app.bicep... - Deploying template '.\app.bicep' for application 'myapp' and environment 'default' from workspace 'default'... + ``` + Building app.bicep... + 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... - Deployment In Progress... + Completed mongodb Applications.Datastores/mongoDatabases + Completed backend Applications.Core/containers + Completed gateway Applications.Core/gateways + Completed demo Applications.Core/containers - Deployment Complete + Deployment Complete - Resources: - demo Applications.Core/containers - backend Applications.Core/containers - gateway Applications.Core/gateways - mongodb Applications.Datastores/mongoDatabases + Resources: + backend Applications.Core/containers + demo Applications.Core/containers + gateway Applications.Core/gateways + mongodb Applications.Datastores/mongoDatabases - Public Endpoints: - gateway Applications.Core/gateways http://localhost + Public Endpoints: + gateway Applications.Core/gateways http://gateway.todolist.172.18.0.6.nip.io ``` -1. Open the gateway URL in your browser. Unlike before, you are connecting to the gateway instead of directly to the container. You will see the same container connections and metadata as before. - -1. Done! You've successfully created your first Radius application. +1. Open the gateway resource's URL in your browser. Unlike before, you are connecting to the Gateway instead of directly to the container. You will see the same container connections and metadata as before. -## Next steps + {{% alert title="Warning" color="warning" %}} + The application will only be accessible if the Kubernetes cluster you are using has a load balancer controller. If you are using AKS or EKS, the controller is enabled by default. If you are using a local Kubernetes cluster such as kind or k3d, you will need to configure a load balancer controller. See this tutorial for [k3d](https://k3d.io/v5.3.0/usage/exposing_services/) and this for [kind](https://kind.sigs.k8s.io/docs/user/loadbalancer). + {{% /alert %}} -Now that you've created your first application, try out more [tutorials]({{< ref tutorials >}}) or jump into the [user guides]({{< ref guides >}}) to learn more about Radius. +{{< button text="Next step: Add a custom resource →" page="custom-resource-type" >}} diff --git a/docs/content/tutorials/new-app/snippets/1-app.bicep b/docs/content/tutorials/new-app/snippets/1-app.bicep index 0fd6cc3e2..0300c8cc2 100644 --- a/docs/content/tutorials/new-app/snippets/1-app.bicep +++ b/docs/content/tutorials/new-app/snippets/1-app.bicep @@ -1,9 +1,13 @@ -// Import the set of Radius resources (Applications.*) into Bicep +//IMPORT extension radius +//IMPORT +//PARAM @description('The ID of your Radius Application. Set automatically by the rad CLI.') param application string +//PARAM +//CONTAINER resource demo 'Applications.Core/containers@2023-10-01-preview' = { name: 'demo' properties: { @@ -18,3 +22,4 @@ resource demo 'Applications.Core/containers@2023-10-01-preview' = { } } } +//CONTAINER diff --git a/docs/content/tutorials/new-app/snippets/2-app-mongo.bicep b/docs/content/tutorials/new-app/snippets/2-app-mongo.bicep index 71fad3fdb..3e51c5fa2 100644 --- a/docs/content/tutorials/new-app/snippets/2-app-mongo.bicep +++ b/docs/content/tutorials/new-app/snippets/2-app-mongo.bicep @@ -11,11 +11,6 @@ resource demo 'Applications.Core/containers@2023-10-01-preview' = { application: application container: { image: 'ghcr.io/radius-project/samples/tutorial/demo:edge' - env: { - FOO: { - value: 'bar' - } - } ports: { web: { containerPort: 3000 diff --git a/docs/content/tutorials/new-app/snippets/3-app-backend.bicep b/docs/content/tutorials/new-app/snippets/3-app-backend.bicep index cfcd6fc9e..ee4a56864 100644 --- a/docs/content/tutorials/new-app/snippets/3-app-backend.bicep +++ b/docs/content/tutorials/new-app/snippets/3-app-backend.bicep @@ -14,11 +14,6 @@ resource demo 'Applications.Core/containers@2023-10-01-preview' = { application: application container: { image: 'ghcr.io/radius-project/samples/tutorial/demo:edge' - env: { - FOO: { - value: 'bar' - } - } ports: { web: { containerPort: 3000 diff --git a/docs/content/tutorials/new-app/snippets/4-app-gateway.bicep b/docs/content/tutorials/new-app/snippets/4-app-gateway.bicep index 2cc822376..0c103c18d 100644 --- a/docs/content/tutorials/new-app/snippets/4-app-gateway.bicep +++ b/docs/content/tutorials/new-app/snippets/4-app-gateway.bicep @@ -14,11 +14,6 @@ resource demo 'Applications.Core/containers@2023-10-01-preview' = { application: application container: { image: 'ghcr.io/radius-project/samples/tutorial/demo:edge' - env: { - FOO: { - value: 'bar' - } - } ports: { web: { containerPort: 3000 @@ -30,7 +25,7 @@ resource demo 'Applications.Core/containers@2023-10-01-preview' = { source: mongodb.id } backend: { - source: 'http://backend:3000' + source: 'http://backend:80' } } } diff --git a/docs/content/tutorials/new-app/todolist-app.png b/docs/content/tutorials/new-app/todolist-app.png new file mode 100644 index 000000000..94aea9584 Binary files /dev/null and b/docs/content/tutorials/new-app/todolist-app.png differ