Dapr integration with Azure Container Apps
The Distributed Application Runtime (Dapr) is a set of incrementally adoptable features that simplify the authoring of distributed, microservice-based applications. For example, Dapr provides capabilities for enabling application intercommunication, whether through messaging via pub/sub or reliable and secure service-to-service calls. Once Dapr is enabled for a container app, a secondary process will be created alongside your application code that will enable communication with Dapr via HTTP or gRPC.
Dapr's APIs are built on best practice industry standards, that:
- Seamlessly fit with your preferred language or framework
- Are incrementally adoptable; you can use one, several, or all dapr capabilities depending on your application's needs
Dapr is an open source, Cloud Native Computing Foundation (CNCF) project. The CNCF is part of the Linux Foundation and provides support, oversight, and direction for fast-growing, cloud native projects. As an alternative to deploying and managing the Dapr OSS project yourself, the Container Apps platform:
- Provides a managed and supported Dapr integration
- Handles Dapr version upgrades seamlessly
- Exposes a simplified Dapr interaction model to increase developer productivity
This guide provides insight into core Dapr concepts and details regarding the Dapr interaction model in Container Apps.
|Service-to-service invocation||Discover services and perform reliable, direct service-to-service calls with automatic mTLS authentication and encryption.|
|State management||Provides state management capabilities for transactions and CRUD operations.|
|Pub/sub||Allows publisher and subscriber container apps to intercommunicate via an intermediary message broker.|
|Bindings||Trigger your applications based on events|
|Actors||Dapr actors are message-driven, single-threaded, units of work designed to quickly scale. For example, in burst-heavy workload situations.|
|Observability||Send tracing information to an Application Insights backend.|
|Secrets||Access secrets from your application code or reference secure values in your Dapr components.|
Dapr concepts overview
The following example based on the Pub/sub API is used to illustrate core concepts related to Dapr in Azure Container Apps.
|1||Container Apps with Dapr enabled||Dapr is enabled at the container app level by configuring a set of Dapr arguments. These values apply to all revisions of a given container app when running in multiple revisions mode.|
|2||Dapr||The fully managed Dapr APIs are exposed to each container app through a Dapr sidecar. The Dapr APIs can be invoked from your container app via HTTP or gRPC. The Dapr sidecar runs on HTTP port 3500 and gRPC port 50001.|
|3||Dapr component configuration||Dapr uses a modular design where functionality is delivered as a component. Dapr components can be shared across multiple container apps. The Dapr app identifiers provided in the scopes array dictate which dapr-enabled container apps will load a given component at runtime.|
You can configure Dapr using various arguments and annotations based on the runtime context. Azure Container Apps provides three channels through which you can configure Dapr:
- Container Apps CLI
- Infrastructure as Code (IaC) templates, as in Bicep or Azure Resource Manager (ARM) templates
- The Azure portal
The table below outlines the currently supported list of Dapr sidecar configurations in Container Apps:
|Container Apps CLI||Template field||Description|
||Enables Dapr on the container app.|
||The port your application is listening on which will be used by Dapr for communicating to your application|
||Tells Dapr which protocol your application is using. Valid options are
||A unique Dapr identifier for your container app used for service discovery, state encapsulation and the pub/sub consumer ID.|
||Set the max size of request body http and grpc servers to handle uploading of large files. Default is 4 MB.|
||Set the max size of http header read buffer in to handle when sending multi-KB headers. The default 4 KB.|
||Enables viewing the API calls from your application to the Dapr sidecar.|
||Set the log level for the Dapr sidecar. Allowed values: debug, error, info, warn. Default is
When using an IaC template, specify the following arguments in the
properties.configuration section of the container app resource definition.
The above Dapr configuration values are considered application-scope changes. When you run a container app in multiple revision mode, changes to these settings won't create a new revision. Instead, all existing revisions will be restarted to ensure they're configured with the most up-to-date values.
Dapr uses a modular design where functionality is delivered as a component. The use of Dapr components is optional and dictated exclusively by the needs of your application.
Dapr components in container apps are environment-level resources that:
- Can provide a pluggable abstraction model for connecting to supporting external services.
- Can be shared across container apps or scoped to specific container apps.
- Can use Dapr secrets to securely retrieve configuration metadata.
All Dapr OSS components conform to the following basic schema.
apiVersion: dapr.io/v1alpha1 kind: Component metadata: name: [COMPONENT-NAME] namespace: [COMPONENT-NAMESPACE] spec: type: [COMPONENT-TYPE] version: v1 initTimeout: [TIMEOUT-DURATION] ignoreErrors: [BOOLEAN] metadata: - name: [METADATA-NAME] value: [METADATA-VALUE]
In Container Apps, the above schema has been slightly simplified to support Dapr components and remove unnecessary fields, including
kind, and redundant metadata and spec properties.
componentType: [COMPONENT-TYPE] version: v1 initTimeout: [TIMEOUT-DURATION] ignoreErrors: [BOOLEAN] metadata: - name: [METADATA-NAME] value: [METADATA-VALUE]
By default, all Dapr-enabled container apps within the same environment will load the full set of deployed components. To ensure components are loaded at runtime by only the appropriate container apps, application scopes should be used. In the example below, the component will only be loaded by the two Dapr-enabled container apps with Dapr application IDs
Dapr component scopes correspond to the Dapr application ID of a container app, not the container app name.
componentType: [COMPONENT-TYPE] version: v1 initTimeout: [TIMEOUT-DURATION] ignoreErrors: [BOOLEAN] metadata: - name: [METADATA-NAME] value: [METADATA-VALUE] scopes: - [APP-ID-1] - [APP-ID-2]
Connecting to external services via Dapr
There are a few approaches supported in container apps to securely establish connections to external services for Dapr components.
- Using Managed Identity
- Using a Dapr Secret Store component reference
- Using Platform-managed Kubernetes secrets
Using managed identity
For Azure-hosted services, Dapr can use the managed identity of the scoped container apps to authenticate to the backend service provider. When using managed identity, you don't need to include secret information in a component manifest. Using managed identity is preferred as it eliminates storage of sensitive input in components and doesn't require managing a secret store.
azureClientId metadata field (the client ID of the managed identity) is required for any component authenticating with user-assigned managed identity.
Using a Dapr secret store component reference
When you create Dapr components for non-AD enabled services, certain metadata fields require sensitive input values. The recommended approach for retrieving these secrets is to reference an existing Dapr secret store component that securely accesses secret information.
Here are the steps to set up a reference:
- Create a Dapr secret store component using the Container Apps schema. The component type for all supported Dapr secret stores begins with
- Create extra components as needed which reference this Dapr secret store component to retrieve the sensitive metadata input.
When creating a secret store component in container apps, you can provide sensitive information in the metadata section in either of the following ways:
- For an Azure Key Vault secret store, use managed identity to establish the connection.
- For non-Azure secret stores, use platform-managed Kubernetes secrets that are defined directly as part of the component manifest.
The following component showcases the simplest possible secret store configuration. In this example, publisher and subscriber applications are configured to both have a system or user-assigned managed identity with appropriate permissions on the Azure Key Vault instance.
componentType: secretstores.azure.keyvault version: v1 metadata: - name: vaultName value: [your_keyvault_name] - name: azureEnvironment value: "AZUREPUBLICCLOUD" - name: azureClientId # Only required for authenticating user-assigned managed identity value: [your_managed_identity_client_id] scopes: - publisher-app - subscriber-app
Kubernetes secrets, Local environment variables and Local file Dapr secret stores are not supported in Container Apps. As an alternative for the upstream Dapr default Kubernetes secret store, container apps provides a platform-managed approach for creating and leveraging Kubernetes secrets.
Using Platform-managed Kubernetes secrets
This component configuration defines the sensitive value as a secret parameter that can be referenced from the metadata section. This approach can be used to connect to non-Azure services or in dev/test scenarios for quickly deploying components via the CLI without setting up a secret store or managed identity.
componentType: secretstores.azure.keyvault version: v1 metadata: - name: vaultName value: [your_keyvault_name] - name: azureEnvironment value: "AZUREPUBLICCLOUD" - name: azureTenantId value: "[your_tenant_id]" - name: azureClientId value: "[your_client_id]" - name: azureClientSecret secretRef: azClientSecret secrets: - name: azClientSecret value: "[your_client_secret]" scopes: - publisher-app - subscriber-app
Referencing Dapr secret store components
Once you've created a Dapr secret store using one of the above approaches, you can reference that secret store from other Dapr components in the same environment. In the following example, the
secretStoreComponent field is populated with the name of the secret store specified above, where the
sb-root-connectionstring is stored.
componentType: pubsub.azure.servicebus version: v1 secretStoreComponent: "my-secret-store" metadata: - name: connectionString secretRef: sb-root-connectionstring scopes: - publisher-app - subscriber-app
To create a Dapr component via the Container Apps CLI, you can use a container apps YAML manifest. When configuring multiple components, you must create and apply a separate YAML file for each component.
az containerapp env dapr-component set --name ENVIRONMENT_NAME --resource-group RESOURCE_GROUP_NAME --dapr-component-name pubsub --yaml "./pubsub.yaml"
# pubsub.yaml for Azure Service Bus component componentType: pubsub.azure.servicebus version: v1 secretStoreComponent: "my-secret-store" metadata: - name: connectionString secretRef: sb-root-connectionstring scopes: - publisher-app - subscriber-app
Unsupported Dapr capabilities
- Custom configuration for Dapr Observability: Instrument your environment with Application Insights to visualize distributed tracing.
- Dapr Configuration spec: Any capabilities that require use of the Dapr configuration spec.
- Declarative pub/sub subscriptions
- Any Dapr sidecar annotations not listed above
- Actor reminders: Require a minReplicas of 1+ to ensure reminders will always be active and fire correctly.
Now that you've learned about Dapr and some of the challenges it solves: