Skip to content

Commit 0225f75

Browse files
Add Azure Container Apps as a host option (#1952)
* Update bicep for ACA * First working version * Support workload profile * Add support for CORS and fix identity for openai * Add aca-host * Make acr unique * Add doc for aca host * Update ACA docs * Remove unneeded bicep files * Revert chanes to infra/main.parameters.json * Fix markdown lint issues * Run frontend build before building docker image * remove symlinks and update scripts with paths relative to its own folder instead of cwd * Merge with main.bicep * output AZURE_CONTAINER_REGISTRY_ENDPOINT * Fix deployment with app service * Improve naming and README * Fix identity name and cost esitmation for aca * Share env vars in bicep and update docs * Revert "remove symlinks and update scripts with paths relative to its own folder instead of cwd" This reverts commit 40287f2. * Add containerapps as a commented out host option * Update app/backend/.dockerignore * Apply suggestions from code review * More steps for deployment guide * Update azure.yaml * Update comment * cleanup bicep files and improve docs * Update condition for running in production for credential * Update ManagedIdentityCredential to use UAMI for containerapps --------- Co-authored-by: Pamela Fox <[email protected]> Co-authored-by: Pamela Fox <[email protected]>
1 parent 8f3abc4 commit 0225f75

19 files changed

+730
-89
lines changed

.azdo/pipelines/azure-dev.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,8 @@ steps:
109109
AZURE_ADLS_GEN2_STORAGE_ACCOUNT: $(AZURE_ADLS_GEN2_STORAGE_ACCOUNT)
110110
AZURE_ADLS_GEN2_FILESYSTEM_PATH: $(AZURE_ADLS_GEN2_FILESYSTEM_PATH)
111111
AZURE_ADLS_GEN2_FILESYSTEM: $(AZURE_ADLS_GEN2_FILESYSTEM)
112+
DEPLOYMENT_TARGET: $(DEPLOYMENT_TARGET)
113+
AZURE_CONTAINER_APPS_WORKLOAD_PROFILE: $(AZURE_CONTAINER_APPS_WORKLOAD_PROFILE)
112114

113115
- task: AzureCLI@2
114116
displayName: Deploy Application

.github/workflows/azure-dev.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,8 @@ jobs:
9393
AZURE_ADLS_GEN2_STORAGE_ACCOUNT: ${{ vars.AZURE_ADLS_GEN2_STORAGE_ACCOUNT }}
9494
AZURE_ADLS_GEN2_FILESYSTEM_PATH: ${{ vars.AZURE_ADLS_GEN2_FILESYSTEM_PATH }}
9595
AZURE_ADLS_GEN2_FILESYSTEM: ${{ vars.AZURE_ADLS_GEN2_FILESYSTEM }}
96+
DEPLOYMENT_TARGET: ${{ vars.DEPLOYMENT_TARGET }}
97+
AZURE_CONTAINER_APPS_WORKLOAD_PROFILE: ${{ vars.AZURE_CONTAINER_APPS_WORKLOAD_PROFILE }}
9698

9799
steps:
98100
- name: Checkout

CONTRIBUTING.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ contact [[email protected]](mailto:[email protected]) with any additio
2222
- [Running unit tests](#running-unit-tests)
2323
- [Running E2E tests](#running-e2e-tests)
2424
- [Code Style](#code-style)
25+
- [Adding new azd environment variables](#add-new-azd-environment-variables)
2526

2627
## Code of Conduct
2728

@@ -160,3 +161,10 @@ python -m black <path-to-file>
160161
```
161162

162163
If you followed the steps above to install the pre-commit hooks, then you can just wait for those hooks to run `ruff` and `black` for you.
164+
165+
## Adding new azd environment variables
166+
167+
When adding new azd environment variables, please remember to update:
168+
1. App Service's [azure.yaml](./azure.yaml)
169+
1. [ADO pipeline](.azdo/pipelines/azure-dev.yml).
170+
1. [Github workflows](.github/workflows/azure-dev.yml)

README.md

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,7 @@ Pricing varies per region and usage, so it isn't possible to predict exact costs
6666
However, you can try the [Azure pricing calculator](https://azure.com/e/a87a169b256e43c089015fda8182ca87) for the resources below.
6767

6868
- Azure App Service: Basic Tier with 1 CPU core, 1.75 GB RAM. Pricing per hour. [Pricing](https://azure.microsoft.com/pricing/details/app-service/linux/)
69+
- Azure Container Apps: Only provisioned if you deploy to Azure Container Apps following [the ACA deployment guide](docs/azure_container_apps.md). Consumption plan with 1 CPU core, 2.0 GB RAM. Pricing with Pay-as-You-Go. [Pricing](https://azure.microsoft.com/pricing/details/container-apps/)
6970
- Azure OpenAI: Standard tier, GPT and Ada models. Pricing per 1K tokens used, and at least 1K tokens are used per question. [Pricing](https://azure.microsoft.com/pricing/details/cognitive-services/openai-service/)
7071
- Azure AI Document Intelligence: SO (Standard) tier using pre-built layout. Pricing per document page, sample documents have 261 pages total. [Pricing](https://azure.microsoft.com/pricing/details/form-recognizer/)
7172
- Azure AI Search: Basic tier, 1 replica, free level of semantic search. Pricing per hour. [Pricing](https://azure.microsoft.com/pricing/details/search/)
@@ -126,17 +127,17 @@ A related option is VS Code Dev Containers, which will open the project in your
126127

127128
## Deploying
128129

129-
Follow these steps to provision Azure resources and deploy the application code:
130+
The steps below will provision Azure resources and deploy the application code to Azure App Service. To deploy to Azure Container Apps instead, follow [the container apps deployment guide](docs/azure_container_apps.md).
130131

131132
1. Login to your Azure account:
132133

133134
```shell
134135
azd auth login
135136
```
136137

137-
For GitHub Codespaces users, if the previous command fails, try:
138+
For GitHub Codespaces users, if the previous command fails, try:
138139
```shell
139-
azd auth login --use-device-code
140+
azd auth login --use-device-code
140141
```
141142

142143
1. Create a new azd environment:

app/backend/.dockerignore

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
.git
2+
__pycache__
3+
*.pyc
4+
*.pyo
5+
*.pyd
6+
.Python
7+
env

app/backend/Dockerfile

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
FROM python:3.11-bullseye
2+
3+
WORKDIR /app
4+
5+
COPY ./ /app
6+
7+
RUN python -m pip install -r requirements.txt
8+
9+
RUN python -m pip install gunicorn
10+
11+
CMD ["python3", "-m", "gunicorn", "-b", "0.0.0.0:8000", "main:app"]

app/backend/app.py

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -440,13 +440,25 @@ async def setup_clients():
440440
USE_SPEECH_OUTPUT_BROWSER = os.getenv("USE_SPEECH_OUTPUT_BROWSER", "").lower() == "true"
441441
USE_SPEECH_OUTPUT_AZURE = os.getenv("USE_SPEECH_OUTPUT_AZURE", "").lower() == "true"
442442

443+
# WEBSITE_HOSTNAME is always set by App Service, RUNNING_IN_PRODUCTION is set in main.bicep
444+
RUNNING_ON_AZURE = os.getenv("WEBSITE_HOSTNAME") is not None or os.getenv("RUNNING_IN_PRODUCTION") is not None
445+
443446
# Use the current user identity for keyless authentication to Azure services.
444447
# This assumes you use 'azd auth login' locally, and managed identity when deployed on Azure.
445448
# The managed identity is setup in the infra/ folder.
446449
azure_credential: Union[AzureDeveloperCliCredential, ManagedIdentityCredential]
447-
if os.getenv("WEBSITE_HOSTNAME"): # Environment variable set on Azure Web Apps
450+
if RUNNING_ON_AZURE:
448451
current_app.logger.info("Setting up Azure credential using ManagedIdentityCredential")
449-
azure_credential = ManagedIdentityCredential()
452+
if AZURE_CLIENT_ID := os.getenv("AZURE_CLIENT_ID"):
453+
# ManagedIdentityCredential should use AZURE_CLIENT_ID if set in env, but its not working for some reason,
454+
# so we explicitly pass it in as the client ID here. This is necessary for user-assigned managed identities.
455+
current_app.logger.info(
456+
"Setting up Azure credential using ManagedIdentityCredential with client_id %s", AZURE_CLIENT_ID
457+
)
458+
azure_credential = ManagedIdentityCredential(client_id=AZURE_CLIENT_ID)
459+
else:
460+
current_app.logger.info("Setting up Azure credential using ManagedIdentityCredential")
461+
azure_credential = ManagedIdentityCredential()
450462
elif AZURE_TENANT_ID:
451463
current_app.logger.info(
452464
"Setting up Azure credential using AzureDeveloperCliCredential with tenant_id %s", AZURE_TENANT_ID

azure.yaml

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,11 @@ services:
77
backend:
88
project: ./app/backend
99
language: py
10+
# Please check docs/azure_container_apps.md for more information on how to deploy to Azure Container Apps
11+
# host: containerapp
1012
host: appservice
1113
hooks:
12-
prepackage:
14+
prebuild:
1315
windows:
1416
shell: pwsh
1517
run: cd ../frontend;npm install;npm run build
@@ -86,6 +88,8 @@ pipeline:
8688
- AZURE_ADLS_GEN2_STORAGE_ACCOUNT
8789
- AZURE_ADLS_GEN2_FILESYSTEM_PATH
8890
- AZURE_ADLS_GEN2_FILESYSTEM
91+
- DEPLOYMENT_TARGET
92+
- AZURE_CONTAINER_APPS_WORKLOAD_PROFILE
8993
secrets:
9094
- AZURE_SERVER_APP_SECRET
9195
- AZURE_CLIENT_APP_SECRET

docs/appservice.md

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -631,15 +631,17 @@ To see any exceptions and server errors, navigate to the _Investigate -> Failure
631631

632632
## Configuring log levels
633633

634-
By default, the deployed app only logs messages with a level of `WARNING` or higher.
634+
By default, the deployed app only logs messages from packages with a level of `WARNING` or higher,
635+
but logs all messages from the app with a level of `INFO` or higher.
635636

636637
These lines of code in `app/backend/app.py` configure the logging level:
637638

638639
```python
640+
# Set root level to WARNING to avoid seeing overly verbose logs from SDKS
641+
logging.basicConfig(level=logging.WARNING)
642+
# Set the app logger level to INFO by default
639643
default_level = "INFO"
640-
if os.getenv("WEBSITE_HOSTNAME"): # In production, don't log as heavily
641-
default_level = "WARNING"
642-
logging.basicConfig(level=os.getenv("APP_LOG_LEVEL", default_level))
644+
app.logger.setLevel(os.getenv("APP_LOG_LEVEL", default_level))
643645
```
644646

645647
To change the default level, either change `default_level` or set the `APP_LOG_LEVEL` environment variable

docs/azure_container_apps.md

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
# Deploying on Azure Container Apps
2+
3+
Due to [a limitation](https://github.com/Azure/azure-dev/issues/2736) of the Azure Developer CLI (`azd`), there can be only one host option in the [azure.yaml](../azure.yaml) file.
4+
By default, `host: appservice` is used and `host: containerapp` is commented out.
5+
6+
To deploy to Azure Container Apps, please follow the following steps:
7+
8+
1. Comment out `host: appservice` and uncomment `host: containerapp` in the [azure.yaml](../azure.yaml) file.
9+
10+
2. Login to your Azure account:
11+
12+
```bash
13+
azd auth login
14+
```
15+
16+
3. Create a new `azd` environment to store the deployment parameters:
17+
18+
```bash
19+
azd env new
20+
```
21+
22+
Enter a name that will be used for the resource group.
23+
This will create a new folder in the `.azure` folder, and set it as the active environment for any calls to `azd` going forward.
24+
25+
4. Set the deployment target to `containerapps`:
26+
27+
```bash
28+
azd env set DEPLOYMENT_TARGET containerapps
29+
```
30+
31+
5. (Optional) This is the point where you can customize the deployment by setting other `azd1 environment variables, in order to [use existing resources](docs/deploy_existing.md), [enable optional features (such as auth or vision)](docs/deploy_features.md), or [deploy to free tiers](docs/deploy_lowcost.md).
32+
6. Provision the resources and deploy the code:
33+
34+
```bash
35+
azd up
36+
```
37+
38+
This will provision Azure resources and deploy this sample to those resources, including building the search index based on the files found in the `./data` folder.
39+
40+
**Important**: Beware that the resources created by this command will incur immediate costs, primarily from the AI Search resource. These resources may accrue costs even if you interrupt the command before it is fully executed. You can run `azd down` or delete the resources manually to avoid unnecessary spending.
41+
42+
## Customizing Workload Profile
43+
44+
The default workload profile is Consumption. If you want to use a dedicated workload profile like D4, please run:
45+
46+
```bash
47+
azd env AZURE_CONTAINER_APPS_WORKLOAD_PROFILE D4
48+
```
49+
50+
For a full list of workload profiles, please check [here](https://learn.microsoft.com/azure/container-apps/workload-profiles-overview#profile-types).
51+
Please note dedicated workload profiles have a different billing model than Consumption plan. Please check [here](https://learn.microsoft.com/azure/container-apps/billing) for details.
52+
53+
## Private endpoints
54+
55+
Private endpoints is still in private preview for Azure Conainer Apps and not supported for now.

0 commit comments

Comments
 (0)