Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 7 additions & 1 deletion plugin/skills/azure-prepare/references/analyze.md
Original file line number Diff line number Diff line change
Expand Up @@ -96,4 +96,10 @@ Converting an existing application to run on Azure.

> ⚠️ **Critical**: The Functions `bicep.md` and `terraform.md` files are **REFERENCE DOCUMENTATION**, not templates to copy. Hand-writing infrastructure from these patterns results in missing RBAC, incorrect managed identity configuration, and security vulnerabilities.

For other compute targets (Container Apps, App Service, Static Web Apps), load their respective README files in `services/` for guidance.
For **Container Apps**, load the composition rules the same way:

1. Load `services/container-apps/templates/selection.md` — decision tree for base template + recipe
2. Load `services/container-apps/templates/recipes/composition.md` — the exact algorithm to follow
3. Use `azd init -t <template>` for **new projects only** to generate proven IaC — **NEVER hand-write Bicep/Terraform**

For other compute targets (App Service, Static Web Apps), load their respective README files in `services/` for guidance.
4 changes: 3 additions & 1 deletion plugin/skills/azure-prepare/references/research.md
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,8 @@ For each selected service, load the README.md first, then load specific files as
Selected: Container Apps, Cosmos DB, Key Vault

→ Load: services/container-apps/README.md (overview)
→ If need templates: services/container-apps/templates/selection.md
→ Follow: services/container-apps/templates/recipes/composition.md
→ If need Bicep: services/container-apps/bicep.md
→ If need Terraform: services/container-apps/terraform.md
→ If need scaling: services/container-apps/scaling.md
Expand Down Expand Up @@ -103,7 +105,7 @@ Add research findings to `.azure/deployment-plan.md` under a `## Research Summar

### Web Application + API + Database (Cosmos DB)

1. Load: [services/container-apps/README.md](services/container-apps/README.md) → [bicep.md](services/container-apps/bicep.md) or [terraform.md](services/container-apps/terraform.md), [scaling.md](services/container-apps/scaling.md)
1. Load: [services/container-apps/README.md](services/container-apps/README.md) → [templates/selection.md](services/container-apps/templates/selection.md), [bicep.md](services/container-apps/bicep.md) or [terraform.md](services/container-apps/terraform.md), [scaling.md](services/container-apps/scaling.md)
2. Load: [services/cosmos-db/README.md](services/cosmos-db/README.md) → [partitioning.md](services/cosmos-db/partitioning.md)
3. Load: [services/key-vault/README.md](services/key-vault/README.md)
4. Invoke: `azure-observability` (monitoring setup)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,12 @@ services:
| Background Worker | None | 0 (scale to zero) | Queue-based |
| Web Application | External | 1 | HTTP-based |

## Templates & Recipes

- **[Selection Guide](templates/selection.md)** — Start here: decision tree for base template + recipe
- **[Composition Algorithm](templates/recipes/composition.md)** — How to fetch and compose templates
- [AZD Templates](templates/recipes/README.md) — Recipe overview

## References

- [Bicep Patterns](bicep.md)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,161 @@
# API Template — REFERENCE ONLY

REST and gRPC API services on Azure Container Apps with ingress configuration.

## When to Use

- REST API with OpenAPI/Swagger
- gRPC service
- API gateway backend
- Backend-for-frontend (BFF) pattern

## Project Structure

```
project-root/
├── azure.yaml
├── Dockerfile
├── src/
│ └── (API code)
└── infra/
├── main.bicep
└── app/
└── api.bicep
```

## azure.yaml

```yaml
name: my-api
metadata:
template: container-apps-api
services:
api:
host: containerapp
project: .
language: <js|ts|python|csharp|java|go>
```

## Bicep — API Container App

```bicep
param name string
param location string = resourceGroup().location
param tags object = {}
param envId string
param containerRegistryName string
param imageName string
param userAssignedIdentityId string
param isGrpc bool = false
param allowedOrigins array = ['https://example.com']

resource api 'Microsoft.App/containerApps@2024-03-01' = {
name: name
location: location
tags: union(tags, { 'azd-service-name': 'api' })
identity: {
type: 'UserAssigned'
userAssignedIdentities: { '${userAssignedIdentityId}': {} }
}
properties: {
managedEnvironmentId: envId
configuration: {
ingress: {
external: true
targetPort: 8080
transport: isGrpc ? 'http2' : 'auto'
corsPolicy: {
allowedOrigins: allowedOrigins
allowedMethods: ['GET', 'POST', 'PUT', 'DELETE', 'OPTIONS']
allowedHeaders: ['*']
}
Comment thread
paulyuk marked this conversation as resolved.
// Use ['*'] only for local/dev smoke tests; set explicit origins for production.
}
registries: [
{
server: '${containerRegistryName}.azurecr.io'
identity: userAssignedIdentityId
}
]
}
template: {
containers: [
{
name: 'api'
image: imageName
resources: { cpu: json('0.5'), memory: '1Gi' }
env: [
{ name: 'PORT', value: '8080' }
]
}
]
scale: {
minReplicas: 1
maxReplicas: 20
rules: [
{
name: 'http-scale'
http: { metadata: { concurrentRequests: '50' } }
}
]
}
}
}
}

output fqdn string = api.properties.configuration.ingress.fqdn
output name string = api.name
```

## REST vs gRPC

| Setting | REST | gRPC |
|---------|------|------|
| `transport` | `auto` | `http2` |
| `targetPort` | 8080 | 8080 |
| Ingress | External or internal | External or internal |

> ⚠️ **gRPC requires `transport: 'http2'`** — without it, gRPC calls fail.

## Internal API (No External Ingress)

For backend APIs only consumed by other Container Apps:

```bicep
ingress: {
external: false // internal only
targetPort: 8080
transport: 'auto'
}
```

Internal APIs are reachable at `https://<app-name>.internal.<env-domain>`.

## API with Authentication

Use Easy Auth or integrate with Microsoft Entra ID:

```bicep
configuration: {
ingress: {
external: true
targetPort: 8080
}
}
```

> 💡 **Tip:** For API authentication, consider using the built-in authentication
> feature of Container Apps (Easy Auth) or validating JWT tokens in your application code.

## CORS Configuration

Restrict `allowedOrigins` for production:

```bicep
corsPolicy: {
allowedOrigins: ['https://myapp.example.com']
allowedMethods: ['GET', 'POST', 'PUT', 'DELETE']
allowedHeaders: ['Authorization', 'Content-Type']
maxAge: 3600
}
```
Original file line number Diff line number Diff line change
@@ -0,0 +1,180 @@
# Functions on Container Apps — REFERENCE ONLY

Azure Functions hosted on Container Apps for event-driven triggers and bindings
with Container Apps scaling and networking.

## When to Use

- Event-driven processing requiring Functions triggers/bindings
- Need KEDA-based scaling with Functions programming model
- Want Container Apps networking (VNet, private endpoints) with Functions
- Migrating from Functions Consumption/Premium to Container Apps

## Why Functions on Container Apps?

| Feature | Functions (Flex) | Functions on ACA |
|---------|-----------------|------------------|
| Programming model | Functions v4 | Functions v4 |
| Triggers/bindings | ✅ Full support | ✅ Full support |
| Scaling | Flex Consumption | KEDA (Container Apps) |
| Networking | VNet integration | Container Apps VNet |
| Container support | Managed | Full Dockerfile control |
| Dapr integration | ❌ | ✅ |
| Side-cars | ❌ | ✅ |

## Project Structure

```
project-root/
├── azure.yaml
├── Dockerfile
├── host.json
├── src/
│ └── (Functions code)
└── infra/
├── main.bicep
└── app/
└── functions-app.bicep
```

## Dockerfile

```dockerfile
# Example: Node.js Functions on ACA
FROM mcr.microsoft.com/azure-functions/node:4-node20

ENV AzureWebJobsScriptRoot=/home/site/wwwroot
COPY . /home/site/wwwroot
RUN cd /home/site/wwwroot && npm install --production
```

## azure.yaml

```yaml
name: my-functions-aca
Comment thread
paulyuk marked this conversation as resolved.
metadata:
template: container-apps-functions
services:
api:
host: containerapp
project: .
language: js
```

## Bicep — Functions on Container Apps

```bicep
param name string
param location string = resourceGroup().location
param tags object = {}
param envId string
param containerRegistryName string
param imageName string
param userAssignedIdentityId string
param uamiClientId string
param storageAccountName string

resource funcApp 'Microsoft.App/containerApps@2024-03-01' = {
name: name
location: location
tags: union(tags, { 'azd-service-name': 'api' })
identity: {
type: 'UserAssigned'
userAssignedIdentities: { '${userAssignedIdentityId}': {} }
}
properties: {
managedEnvironmentId: envId
configuration: {
ingress: {
external: true
targetPort: 80
transport: 'auto'
}
registries: [
{
server: '${containerRegistryName}.azurecr.io'
identity: userAssignedIdentityId
}
]
}
template: {
containers: [
{
name: 'functions'
image: imageName
resources: { cpu: json('0.5'), memory: '1Gi' }
env: [
{
name: 'AzureWebJobsStorage__accountName'
value: storageAccountName
}
{
name: 'AzureWebJobsStorage__credential'
Comment thread
paulyuk marked this conversation as resolved.
value: 'managedidentity'
}
{
name: 'AzureWebJobsStorage__clientId'
value: uamiClientId
}
Comment thread
paulyuk marked this conversation as resolved.
{
name: 'FUNCTIONS_EXTENSION_VERSION'
value: '~4'
}
]
}
]
scale: {
minReplicas: 0
maxReplicas: 30
}
}
}
}
```

## Supported Triggers

All Functions triggers work on Container Apps:

| Trigger | KEDA Scaler | Notes |
|---------|-------------|-------|
| HTTP | `http` | Built-in HTTP scaling |
| Timer | `cron` | Cron-based scheduling |
| Service Bus | `azure-servicebus` | Queue/topic scaling |
| Event Hubs | `azure-eventhub` | Partition-based scaling |
| Cosmos DB | `azure-cosmosdb` | Change feed scaling |
| Blob Storage | `azure-blob` | Blob count scaling |
| Storage Queue | `azure-queue` | Queue length scaling |

## KEDA Scale Rules for Triggers

```bicep
scale: {
minReplicas: 0
maxReplicas: 30
rules: [
{
name: 'servicebus-scale'
custom: {
type: 'azure-servicebus'
Comment thread
paulyuk marked this conversation as resolved.
metadata: {
queueName: 'myqueue'
namespace: 'my-sb-namespace'
messageCount: '5'
}
identity: userAssignedIdentityId
}
}
]
}
```

## Key Differences from Standard Functions

1. **You manage the Dockerfile** — base image must be `mcr.microsoft.com/azure-functions/<runtime>`
2. **Scaling is KEDA-based** — configure scale rules explicitly
3. **Storage is still required** — Functions runtime needs `AzureWebJobsStorage`
4. **No Flex Consumption billing** — billed as Container Apps

> ⚠️ **Always use the official Functions base images** from MCR.
> Custom base images may break the Functions runtime.
Loading
Loading