Skip to content

Commit

Permalink
Add Azure Container Apps
Browse files Browse the repository at this point in the history
  • Loading branch information
benc-uk committed Dec 23, 2023
1 parent d895eb4 commit b88f516
Show file tree
Hide file tree
Showing 14 changed files with 683 additions and 4 deletions.
5 changes: 4 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@ VERSION ?= 0.8.5
BUILD_INFO ?= "Local makefile build"
DAPR_RUN_LOGLEVEL := warn

# Only change this if you know what you're doing
#DAPR_STORE_NAME := statestore-table

# Most likely want to override these when calling `make image-all`
IMAGE_REG ?= ghcr.io
IMAGE_REPO ?= azure-samples/dapr-store
Expand Down Expand Up @@ -47,7 +50,7 @@ clean: ## 🧹 Clean the project, remove modules, binaries and outputs

run: ## 🚀 Start & run everything locally as processes
cd $(FRONTEND_DIR); npm run dev &
dapr run --app-id cart --app-port 9001 --log-level $(DAPR_RUN_LOGLEVEL) go run github.com/azure-samples/dapr-store/cmd/cart &
dapr run --app-id cart --app-port 9001 --log-level $(DAPR_RUN_LOGLEVEL) go run github.com/azure-samples/dapr-store/cmd/cart &
dapr run --app-id products --app-port 9002 --log-level $(DAPR_RUN_LOGLEVEL) go run github.com/azure-samples/dapr-store/cmd/products ./cmd/products/sqlite.db &
dapr run --app-id users --app-port 9003 --log-level $(DAPR_RUN_LOGLEVEL) go run github.com/azure-samples/dapr-store/cmd/users &
dapr run --app-id orders --app-port 9004 --log-level $(DAPR_RUN_LOGLEVEL) go run github.com/azure-samples/dapr-store/cmd/orders &
Expand Down
2 changes: 1 addition & 1 deletion components/readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ There are two Dapr components required for the app to function:
- `pubsub.yaml` - Default pub/sub component of type **pubsub.redis**, included here for reference. No configuration required.

- _Running locally_: This should exist by default in your dapr components dir, eg. $HOME/.dapr/components
- _Running in Kubernetes_: The daprstore Helm chart should deploy this component for you
- _Running in Kubernetes_: The Dapr store Helm chart should deploy this component for you

- `statestore.yaml` - Default state component of type **state.redis**, included here for reference. No configuration required

Expand Down
11 changes: 11 additions & 0 deletions deploy/container-app/bicepconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"analyzers": {
"core": {
"rules": {
"explicit-values-for-loc-params": {
"level": "off"
}
}
}
}
}
238 changes: 238 additions & 0 deletions deploy/container-app/dapr-store.bicep
Original file line number Diff line number Diff line change
@@ -0,0 +1,238 @@
// ============================================================================
// Deploy a container app with app container environment and log analytics
// ============================================================================

targetScope = 'subscription'

@description('Name used for resource group, and default base name for all resources')
param appName string = 'dapr-store'

@description('Azure region for all resources')
param location string = deployment().location

@description('Container image')
param imageBase string = 'ghcr.io/azure-samples/dapr-store'

@description('Version of the container image')
param imageTag string = 'latest'

// ===== Variables ============================================================

// Using my own benc-uk/nanoproxy-proxy as a simple HTTP proxy for the API gateway
// NGINX had issues which I couldn't resolve
var imageGateway = 'ghcr.io/benc-uk/nanoproxy-proxy:0.0.4'

var imageProducts = '${imageBase}/products:${imageTag}'
var imageOrders = '${imageBase}/orders:${imageTag}'
var imageUsers = '${imageBase}/users:${imageTag}'
var imageCart = '${imageBase}/cart:${imageTag}'
var imageFrontend = '${imageBase}/frontend-host:${imageTag}'

var daprTableName = 'daprstate'

// ===== Base shared resources ==================================================

resource resGroup 'Microsoft.Resources/resourceGroups@2021-04-01' = {
name: appName
location: location
}

module logAnalytics './modules/log-analytics.bicep' = {
scope: resGroup
name: 'logs'
}

module storageAcct 'modules/storage.bicep' = {
scope: resGroup
name: 'storage'
params: {
name: 'daprstore'
tableName: daprTableName
}
}

module serviceBus 'modules/service-bus.bicep' = {
scope: resGroup
name: 'service-bus'
params: {
sku: 'Standard'
topicName: 'orders-queue'
}
}

module containerAppEnv './modules/app-env.bicep' = {
scope: resGroup
name: 'app-env'
params: {
logAnalyticsName: logAnalytics.outputs.name
logAnalyticsResGroup: resGroup.name
}
}

// ===== Dapr components ======================================================

module daprComponentState './modules/dapr-component.bicep' = {
scope: resGroup
name: 'dapr-component-store'
params: {
name: 'statestore'
environmentName: containerAppEnv.outputs.name
componentType: 'state.azure.tablestorage'

componentMetadata: [
{
name: 'accountName'
value: storageAcct.outputs.name
}
{
name: 'tableName'
value: daprTableName
}
{
name: 'accountKey'
value: storageAcct.outputs.accountKey
}
]

scopes: [ 'cart', 'users', 'orders' ]
}
}

module daprComponentPubsub './modules/dapr-component.bicep' = {
scope: resGroup
name: 'dapr-component-pubsub'
params: {
name: 'pubsub'
environmentName: containerAppEnv.outputs.name
componentType: 'pubsub.azure.servicebus.topics'

componentMetadata: [
{
name: 'connectionString'
value: serviceBus.outputs.connectionString
}
]

scopes: [ 'cart', 'orders' ]
}
}

// ===== Deploy the API gateway =============================================

module apiGateway './modules/app.bicep' = {
scope: resGroup
name: 'apigw-deploy'
params: {
name: 'api-gateway'
environmentId: containerAppEnv.outputs.id

image: imageGateway

daprAppId: 'api-gateway'
daprAppPort: 8080

ingressExternal: true
ingressPort: 8080

envs: [
{
name: 'CONFIG_B64'
value: loadFileAsBase64('./gateway-conf.yaml')
}
{
name: 'DEBUG'
value: '1'
}
]
}
}

// ===== Deploy the Dapr store container apps =============================================

module productsApp './modules/app.bicep' = {
scope: resGroup
name: 'products-deploy'
params: {
name: 'products'
environmentId: containerAppEnv.outputs.id

image: imageProducts

probePath: '/health'
probePort: 9002

daprAppId: 'products'
daprAppPort: 9002
}
}

module ordersApp './modules/app.bicep' = {
scope: resGroup
name: 'orders-deploy'
params: {
name: 'orders'
environmentId: containerAppEnv.outputs.id

image: imageOrders

probePath: '/health'
probePort: 9004

daprAppId: 'orders'
daprAppPort: 9004
}
}

module usersApp './modules/app.bicep' = {
scope: resGroup
name: 'users-deploy'
params: {
name: 'users'
environmentId: containerAppEnv.outputs.id

image: imageUsers

probePath: '/health'
probePort: 9003

daprAppId: 'users'
daprAppPort: 9003
}
}

module cartApp './modules/app.bicep' = {
scope: resGroup
name: 'cart-deploy'
params: {
name: 'cart'
environmentId: containerAppEnv.outputs.id

image: imageCart

probePath: '/health'
probePort: 9001

daprAppId: 'cart'
daprAppPort: 9001
}
}

module frontendApp './modules/app.bicep' = {
scope: resGroup
name: 'frontend-deploy'
params: {
name: 'frontend'
environmentId: containerAppEnv.outputs.id

image: imageFrontend

ingressExternal: false
ingressPort: 8000
}
}

// ===== Dapr components ======================================================

// ===== Outputs ==============================================================

output storeURL string = 'https://${apiGateway.outputs.fqdn}/'
12 changes: 12 additions & 0 deletions deploy/container-app/gateway-conf.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
upstreams:
- name: frontend
host: frontend
noHostRewrite: true
- name: dapr
host: localhost
port: 3500
rules:
- upstream: dapr
path: /v1.0
- upstream: frontend
path: /
57 changes: 57 additions & 0 deletions deploy/container-app/modules/app-env.bicep
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
// ============================================================================
// Container App Environment to host container apps
// ============================================================================

param name string = resourceGroup().name
param location string = resourceGroup().location

@description('Existing Log Analytics workspace name')
param logAnalyticsName string

@description('Resource group containing the Log Analytics workspace')
param logAnalyticsResGroup string

@description('Custom VNet; subnet to be used for the control plane. Leave when using a managed VNet')
param controlPlaneSubnetId string = ''
@description('Custom VNet; what type of Load Balancer to use. Leave when using a managed VNet')
param loadBalancerInternal bool = false

// Unlikely you will ever want to change these, but they are exposed as parameters
param dockerBridgeCidr string = '10.1.0.1/16'
param platformReservedCidr string = '10.0.0.0/16'
param platformReservedDnsIP string = '10.0.0.2'

// ===== Modules & Resources ==================================================

resource logAnalytics 'Microsoft.OperationalInsights/workspaces@2020-08-01' existing = {
name: logAnalyticsName
scope: resourceGroup(logAnalyticsResGroup)
}

resource managedEnv 'Microsoft.App/managedEnvironments@2022-03-01' = {
location: location
name: name

properties: {
appLogsConfiguration: {
destination: 'log-analytics'
logAnalyticsConfiguration: {
customerId: logAnalytics.properties.customerId
sharedKey: logAnalytics.listKeys().primarySharedKey
}
}

vnetConfiguration: controlPlaneSubnetId != '' ? {
internal: loadBalancerInternal
infrastructureSubnetId: controlPlaneSubnetId
dockerBridgeCidr: dockerBridgeCidr
platformReservedCidr: platformReservedCidr
platformReservedDnsIP: platformReservedDnsIP
} : null
}
}

// ===== Outputs ==============================================================

output id string = managedEnv.id
output name string = managedEnv.name
Loading

0 comments on commit b88f516

Please sign in to comment.