-
Notifications
You must be signed in to change notification settings - Fork 183
Gap-2: Container Apps Develop (C → A) — Templates + Dapr + Jobs + Functions-on-ACA #1636
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
paulyuk
wants to merge
16
commits into
main
Choose a base branch
from
pass-equity-gap-2
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
Show all changes
16 commits
Select commit
Hold shift + click to select a range
6cb41cf
feat(develop): Container Apps templates + composition (Gap-2)
paulyuk 1452d81
fix(develop): 17 corrections + orphan fix for PR #1636
simonjj 364cbb8
fix(develop): resolve 3 remaining JonG review comments on PR #1636
paulyuk 69ef4ff
fix(develop): Redis SKU Basic→Standard C1 for Entra ID auth support
paulyuk 3288d2a
fix(develop): merge main, address 6 new review comments on PR #1636
paulyuk 87868d8
fix: restore version placeholder for build pipeline stamping
paulyuk df07832
fix(develop): final batch — 4 legit review fixes
paulyuk 1efbc22
fix(develop): Redis recipe — use accessPolicyAssignments, fix username
paulyuk 4417507
Address review feedback: split decision tree into base+recipe phases,…
paulyuk 6859bd0
fix(gap-2): address container apps review feedback
61f2597
Merge remote-tracking branch 'origin/main' into pass-equity-gap-2
9833598
fix(gap-2): add UAMI identity to Service Bus KEDA scaler example
552b816
fix: correct KEDA Event Hubs scaler metadata in worker template
paulyuk e22a85c
Merge branch 'main' into pass-equity-gap-2
paulyuk c168b3f
fix(gap-2): secure Log Analytics shared key
f28d838
fix(gap-2): remove incomplete validator change
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
161 changes: 161 additions & 0 deletions
161
plugin/skills/azure-prepare/references/services/container-apps/templates/api.md
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| 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: ['*'] | ||
| } | ||
| // 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 | ||
| } | ||
| ``` | ||
180 changes: 180 additions & 0 deletions
180
.../azure-prepare/references/services/container-apps/templates/functions-on-aca.md
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| 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 | ||
|
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' | ||
|
paulyuk marked this conversation as resolved.
|
||
| value: 'managedidentity' | ||
| } | ||
| { | ||
| name: 'AzureWebJobsStorage__clientId' | ||
| value: uamiClientId | ||
| } | ||
|
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' | ||
|
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. | ||
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.