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
- Note: Docker
- Note: Azure things
- 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)
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
1mv msdocs-python-fastapi-webapp-quickstart fastapi-quickstart
- Có chút thay đổi chỗ tạo python env
1conda create -n fastapi-quickstart python=3.11
2conda activate fastapi-quickstart
- 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!!!!
- 🎯 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 dùng fastapi mới (ko dùng
gunicorn
mà dùngfastapi
)
1fastapi run main.py
Startup command.
- 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!
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
1az acr update -n <acrName> --admin-enabled true
- ⚠️ 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!
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.
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!
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)Alternative way:
https://<app-name>.scm.azurewebsites.net/api/logs/docker
.- (Source) You can use the
/home
directory in your custom container file system to persist files across restarts and share them across instances
- Deployment slots ← need plan Standard or Premium (cannot use it with plan Basic) ← activate in Settings → Scale up (App Service plan)
- 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!
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):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.
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à
1az webapp deployment slot swap --resource-group v2da --name "ideta-v2da" --slot "preprod" --target-slot production
- 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
- 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).
- blob_devguide_create_sas.py
- 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
.
- 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.
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)
- 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)
1az group delete --name <resource-group-name> --no-wait
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!