Thi's avatar
HomeAboutNotesBlogTopicsToolsReading
About|My sketches |Cooking |Cafe icon Support Thi
💌 [email protected]

Simple Azure FastAPI app (to learn Azure step by step)

Anh-Thi Dinh
Data EngineeringAzureDockerPythonBackendAPI & ServicesWeb Dev
Vietnamese
Left aside
Mục tiêu: tạo được một web app đơn giản (có thể không cần frontend thì càng tốt), có vài endpoint có thể chạy được. Làm starter cho bất cứ project nào sau này!
⚠️
Hãy cẩn thận, khi bạn create quá nhiều (tầm 5 cái) app services thì sẽ có lỗi 429 “App Service Plan Create operation is throttled for subscription xxx. Please contact support if issue persists.”. Khi ấy bạn phải đợi 48h mới có thể tạo cái mới (trong cùng region)
Solution là có thể tạo 1 subscription mới.
Source code:
learn-azure-fastapi

References

  • Note: Docker
  • Note: Azure things
  • Build a Container Image On-Demand in Azure - Azure Container Registry | Microsoft Learn
  • Port mặc định là 80, nếu muốn đổi cái khác thì dùng WEBSITE_PORT, ref.
  • Quickstart: Deploy a Python (Django, Flask, or FastAPI) web app to Azure - Azure App Service | Microsoft Learn (lưu ý là Flask app ko cần startup script)

Create and deploy via Application Code

☝️
Nhược điểm của cái này là nếu cài 1 dependencies thêm thì làm khá phức tạp (ví dụ muốn cài ffmpeg trong container của App Service. Chỉ có cách là dùng Azure Function (1 service khác, có plan) → Trong trường hợp đó thì nên dùng Docker container!
  • ⚠️ Don’t install VSCode Azure extension, otherwise you loose your RAM!
  • Main tutorial: Quickstart: Deploy a Python (Django, Flask, or FastAPI) web app to Azure - Azure App Service | Microsoft Learn
  • Rename folder cho dễ làm việc
  • Có chút thay đổi chỗ tạo python env
  • Thử deploy app dùng Azure CLI
    • ⚠️ Ngay cái bước “Create a web app in Azure”, nếu dùng Azure CLI thì command az webapp up sẽ tự động tạo hết các resource group, app service plan, webapp service luôn!!!
      • Do đó nếu dùng Azure Portal để tạo thủ công mấy cái ở trên thì phải deploy bằng cách khác chứ ko dùng Azure CLI được
    • Lưu ý: để biết giá trị $RESOURCE_GROUP_NAME và $APP_SERVICE_NAME thì xem ở Overview.
  • 🐞 Error: didn't respond to HTTP pings on port: 8000, failing site start. See container logs for debugging. ← chưa có up cái codes lên!!!!

Github CI/CD, auto deploy.

  • 🎯 Mục tiêu: Auto CD/CI từ Github (trong cái link tut không có option này).
  • Configure continuous deployment - Azure App Service | Microsoft Learn ← Nói chung là bên trong có sẵn, chỉ cần kết nối với Github + cấp quyền cho nó là nó tự động deploy và kết nối với github!
    • Nếu làm việc với admin/boss thì nhớ nói nó làm cái này!
  • Nếu dùng fastapi mới (ko dùng gunicorn mà dùng fastapi)

Nếu muốn install 1 package như ffmpeg trong App service?

  • Nếu dùng docker, mình có thể install nó thông qua apt install -y ffmpeg.
  • 1 gợi ý để install ffmpeg là tích hợp binary của nó ngay trong project gihub và dùng trực tiếp (ko cần cài) ← nhưng buộc phải dùng Azure Function (another service, cần plan) + đọc bài hướng dẫn: Bring dependencies and third-party libraries to Azure Functions | Microsoft Learn
  • Cách hay nhất vẫn là thiết lập qua 1 docker container riêng!

Create and deploy with Docker Container

☝️
Lý do chọn cái này vì muốn cài custom dependencies trong container của App Service (ví dụ cài ffmpeg).
  • ⚠️ Mọi bước đều chú ý đến location and region cho đồng bộ và có quota!
  • ❓Build via docker + auto deploy CD/CI github, is it possible? ← Yes, mỗi khi code thay đổi (trên Github), nó sẽ build lại image + create container,…
  • Để có thể test được, tốt nhất là pay-as-you-go. Thậm chí đang dùng free $200 credits vẫn không được. Ví dụ sẽ bị lỗi không increase quota được.
  • Tạo Resource Group: cái này sẽ chung cho tất cả các cái trong cùng 1 project.
    • Có thể tạo trên Azure Portal > search “Resource Group”
    • Hoặc dùng code (source)
    • Lưu ý chọn location cho kỹ, ko đổi được (cái đang làm: “France Central”)
  • Tạo Azure Container Registry hay ACR (để upload docker image)
  • Có 2 cách build và push image lên ACR:
  • 🐞 Khi create 1 App Service mới mà gặp lỗi Cannot perform credential operations for *** as admin user is disabled. Kindly enable admin user as per docs
  • ⚠️ Tại bước Container, có mục Startup command, hãy sửa cái mặc định thành cái mong muốn.
  • Lúc tạo App Service, tới bước chọn Startup command, điền fastapi run app.py (còn nếu quên thì có thể chỉnh lại trong cái app service mới tạo → Settings → Configuration → General Settings)
  • Check xem 1 web service có chạy ok không → vào service → Deployment → “Deployment Center” → Logs
  • Nếu muốn test thử xem cái dependencies đã cài riêng trong docker có chạy được ko (eg. ffmpeg) thì có thể vào Developement Tools → SSH
    • Có thể SSH chưa được hỗ trợ, check trong Settings → Configuration
      • Dù cho trong Settings → Configuration → SSH nó nói “SSH isn't supported for your selected stack version.” nhưng vẫn có thể mở SSH được! Phải vào chỗ Developement Tools → SSH để xác nhận mới chính xác!
    • Good to read: Enabling SSH on Linux Web App for Containers
    • ⚠️ Don’t forget to restart the app service to update the latest img if things don’t work as expetected!

Update image and re-deploy App Service

Nếu image được update (change Dockerfile chẳng hạn), làm sao update lên ACR và deploy lại App Service?
  • Chỉ cần build và push lên ACR là nó tự động (nếu cùng tag, tuy nhiên thỉnh thoảng phải restart lại App Service. Nhớ là phải enable “Continuous deployment”!
    • Sau khi turn on CD thì trong Container Registries cũng sẽ tạo 1 webhook tương ứng (check trong CR → Services → Webbooks)
  • Nếu khác tag thì sau khi push lên ACR, trong App Service → Deployment → Deployment Center → chọn lại Tag đã push.

Auto CD-CI + deploy from Github

Mong muốn là chỉ cần sửa code rồi push lên Github là nó sẽ tự động build image + update và deploy lại App Service luôn! Chưa kể có thể tự động chạy tests.
  • Deploy a custom container to App Service using GitHub Actions ← lưu ý là các codes trong đây bị lỗi thời! Làm theo cách dưới!
  • Trong App Service → Deployment → Deployment Center → Chọn “Source” là “Github Actions…” → kết nối với Github và chọn các thông số tương ứng → Preview file (file mà nó sẽ ghi vào Github Action, có đầy đủ các setup mới nhất.
  • Trước đó cần kích hoạt SCM trước, ko thì sẽ có warning “SCM basic authentication is disabled for your app. Click here to go to your configuration settings to enable.” và ko thể Save được. ← Chỉ cần nhấn vào warning, vào chỗ Configuration để turn on SCM là được!

Access diagnostic logs

  • Official doc to enable log stream
Alternative way: https://<app-name>.scm.azurewebsites.net/api/logs/docker.

Good to know

  • (Source) You can use the /home directory in your custom container file system to persist files across restarts and share them across instances

Good to read

  • Configure a custom container - Azure App Service | Microsoft Learn

Health check

  • Monitor the health of App Service instances - Azure App Service | Microsoft Learn

Different envs (prod / dev)

  • Deployment slots ← need plan Standard or Premium (cannot use it with plan Basic) ← activate in Settings → Scale up (App Service plan)
  • Set up staging environments - Azure App Service | Microsoft Learn
  • Tránh cold start cho prod, có thể dùng auto swap (ko hỗ trợ web app trên Linux và Web App for Containers)
  • Vào Deployment → Deployment slots → tạo slot mới xong, trong slot mới, vào Deployment → Deployment Center chỉnh source Github và chọn nhánh dev.
    • ⚠️
      Lưu ý, cái file .yml tự động tạo có chút lỗi chỗ jobs.build.steps['Build and push container image to registry'].with.tags và chỗ jobs.deploy.steps['Deploy to Azure Web App'].with.images. Cả 2 cái đều để dư secrets.AzureAppService_PublishProfile_xxx dẫn đến tình trạng khi vào Deployment → Deployment Center của từng slot, sẽ thấy chỗ Image name bị dư kiểu v2acr2/v2daimg.
      Nếu có lỡ bị dư kiểu này, có thể sửa trực tiếp trên file .yml rồi push lên Github là nó tự động fix.
  • Lưu ý khi create new env var, có setting “Deployment slot setting”. Tick vào đó để var này không swapped. Source.
  • Để có thể swap 2 slots, read this. ← swap slots giúp cho production không bị tình trạng “cold start”. Ví dụ nếu deploy auto qua Github thì sẽ có khoảng thời gian cold start (ko thể truy cập được ở 1 số instance lúc đang build). Swap với slots đã warm up hết rùi sẽ “làm cái rụp”.
    • Lưu ý là cái này là swap (trao đổi), cái của prod sẽ qua cái của “bị swap” và ngược lại. Chỉ có những settings “deployment slot settings” mới cố định ko swapped mà thôi!
    • Sau khi swap dev ↔ prod thì phiên bản trên Azure của dev là của thằng prod và ngược lại. Ngay cả khi trên Github ko cho thấy điều đó. Khi ta push lại nhánh trên Github thì 1 trigger sẽ deploy lại lần nữa!

Workflow (personal exp)

Nên có 3 branches trên Github - prod, preprod và dev. Chỉ nên dùng Github Action với preprod và dev, còn prod trên Azure sẽ được swap với preprod. Tác dụng của preprod là có settings y chang như prod để có thể test trước khi apply vào prod.
Dùng preprod swap với prod thay vì dùng Github Action với prod là để tránh tình trạng “cold start” mỗi khi build lại. Swap sẽ đảm bảo các instance đã warmup hết rùi trước khi chuyển sang prod.
Còn nhánh prod, nếu muốn manually deploy (ko thông qua swap):

Swap slots

Cần lưu ý là Azure CLI az webapp deployment slot swap nói rằng để tên của slot vào là được, trong khi vào trong Deloyment → Deployment slots thì thấy tên là ideta-v2da-dev nhưng trong command CLI phải là “dev”!!
Lưu ý 2: production không có tên slot, tên cố định là “production”!
Do đó nếu hình sau đây,
Thì lệnh swap giữa preprod và production sẽ là

Connect to Storage Account

  • App Service to Storage Account Connection Condition Summary | Microsoft Community Hub
  • Mount Azure Storage as a local share - Azure App Service | Microsoft Learn ← Help in Settings → Configuration → Path mappings
  • Có thể create thêm File shares trong Storage Accounts → Data Storage → Files shares

Tạo upload link giới hạn trong 1h (blob / fileshare)

  • Keyword: Shared Access Signature (SAS) ← A SAS secured with Microsoft Entra credentials is called a user delegation SAS (source)
  • ☝️ Lưu ý là cái trên chỉ thiết lập file đã upload có giới hạn thời gian chứ không tự xoá sau khi hết hạn! Để có thể tự xoá, cần configure a lifecycle management policy (read next section).
    • Upload riêng, tạo sas riêng. Sau khi tạo sas thì mới có url limit trong 1h. Check the codes trong playground azure-storage-sas.ipynb.

Auto delete / configure a lifecycle management policy (blob)

  • Configure a lifecycle management policy - Azure Blob Storage | Microsoft Learn
  • Optimize costs by automatically managing the data lifecycle - Azure Blob Storage | Microsoft Learn ← thật ra trong Portal có sẵn mấy rules tạo hoàn toàn bằng UI, ko cần code rules!
  • Enable access time tracking (nếu ko enable thì last access time sẽ assigned to the date the lifecycle policy was enabled): read this.

Tạo và connect to Storage Account trong App Service

Sau khi tạo thì ngay trong container của App Service sẽ có folder dạng /test và folder này nằm trong Storage Account.
  • ⚠️ Lưu ý là Linux App Services thì chỉ Azure Files shares là có write thôi, còn lại chỉ có thể read!
    • Đọc bài này để tạo: Quickstart for creating and using Azure file shares | Microsoft Learn
    • ⚠️ Cái auto delete (Lifecycle management) không áp dụng cho Azure Files mà chỉ áp dụng cho Blob (có đứa hỏi:
      Life Cycle Management for Azure File Share
      )
      • Nếu vẫn muốn auto delete, dùng Azure Function (có phí dịch vụ)
  • Enable và tạo một Storage Account trước.
  • Trong Storage Account → Data Storage → Containers → tạo mới 1 Container trước vì bước tiếp theo sẽ cần.
  • Trong App Service → Settings → Configuration → Path mappings → New Azure Storage Mount
    • Nếu vào Settings → Configuration → Path mappings → New Azure Storage Mount mà không thấy option “Basic” có thể chọn được thì cần phải tạo một Storage Account trước!
    • Chỗ “Mount path”, chọn /test
    • ⚠️ Lưu ý là mỗi slot sẽ kết nối khác nhau, thế nên nên chọn “Deployment slot setting” là true và làm tương tự cho các slot khác!
    • Tạo xong đợi xíu.
  • Mở SSH lên thử df –h (SSH trong App Service → Development Tools → SSH)
  • Best practices

Azure Files

  • Azure Storage samples using Python - Azure Storage | Microsoft Learn
  • Create SAS example

Clean up on Azure

Còn nếu muốn delete resource group trên Azure Portal thì phải vào group đó chọn Delete mới được!
Here's the comparison table in markdown format:
◆References◆Create and deploy via Application Code○Github CI/CD, auto deploy.○Nếu muốn install 1 package như ffmpeg trong App service?◆Create and deploy with Docker Container○Update image and re-deploy App Service○Auto CD-CI + deploy from Github○Access diagnostic logs○Good to know○Good to read◆Health check◆Different envs (prod / dev)○Workflow (personal exp)○Swap slots◆Connect to Storage Account○Tạo upload link giới hạn trong 1h (blob / fileshare)○Auto delete / configure a lifecycle management policy (blob)○Tạo và connect to Storage Account trong App Service○Azure Files◆Clean up on Azure
About|My sketches |Cooking |Cafe icon Support Thi
💌 [email protected]
1mv msdocs-python-fastapi-webapp-quickstart fastapi-quickstart
1conda create -n fastapi-quickstart python=3.11
2conda activate fastapi-quickstart
1fastapi run main.py
Startup command.
1az acr update -n <acrName> --admin-enabled true
1# turn on container logging
2az webapp log config --name <app-name> --resource-group <resource-group-name> --docker-container-logging filesystem
3
4# check log stream
5az webapp log tail --name <app-name> --resource-group <resource-group-name>
If you don't see console logs immediately, check again in 30 seconds. Use Ctrl+C to stop log stream. (source)
1# build for Azure Container Registry
2# (not recommended)
3# login first
4az login
5az acr login --name v2acr2
6# build image
7docker build -t v2acr2.azurecr.io/v2daimg:prod --platform=linux/amd64 .
8# push to ACR (no need if setting up auto deploy via Github)
9docker push v2acr2.azurecr.io/v2daimg:prod
Trong Deployment → Deployment Center → Settings → Source: Container Registry:… → image tag “prod” and turn ON Continuous deployment.
1az webapp deployment slot swap --resource-group v2da --name "ideta-v2da" --slot "preprod" --target-slot production
1az group delete --name <resource-group-name> --no-wait