8 · Deploy
เนื้อหานี้ยังไม่ได้แปลเป็นภาษาไทย แสดงเป็นภาษาอังกฤษแทน
The final step takes the app from “runs on my laptop” to “running on Azure Container Apps with a real database and a real observability backend”. The same shape applies to Kubernetes, Linux systemd, and Windows Service — pick the target that matches your environment.
8.1 Build the container image
Section titled “8.1 Build the container image”The scaffold already provided a multi-stage Dockerfile:
# buildFROM mcr.microsoft.com/dotnet/sdk:10.0 AS buildWORKDIR /srcCOPY . .RUN dotnet publish src/Acme.Store.Host/Acme.Store.Host.csproj -c Release -o /app /p:UseAppHost=false
# runtimeFROM mcr.microsoft.com/dotnet/aspnet:10.0 AS runtimeWORKDIR /appCOPY --from=build /app .ENV ASPNETCORE_URLS=http://+:8080EXPOSE 8080ENTRYPOINT ["dotnet", "Acme.Store.Host.dll"]Build and tag it locally:
docker build -t acmestore:latest .docker run --rm -p 8080:8080 ` -e ConnectionStrings__Products="<your-postgres-conn>" ` -e ConnectionStrings__Orders="<your-postgres-conn>" ` acmestore:latestThe host should boot to http://localhost:8080.
8.2 Publish to a registry
Section titled “8.2 Publish to a registry”Use the included script (Azure Container Registry example):
./deploy/container-image/publish-image.ps1 ` -Registry acmestore.azurecr.io ` -Tag 1.0.0The script logs in (az acr login), tags the image as acmestore.azurecr.io/acme/store:1.0.0, and pushes it.
8.3 Deploy to Azure Container Apps
Section titled “8.3 Deploy to Azure Container Apps”The scaffolded script wraps az containerapp up:
./deploy/azure-container-apps/deploy-up.ps1 ` -ResourceGroup acme-prod ` -EnvironmentName acme-aca-env ` -AppName acmestore ` -Image acmestore.azurecr.io/acme/store:1.0.0 ` -Location eastusThe first run provisions the Container Apps environment, Log Analytics workspace, and the app itself. Subsequent runs perform a revision update.
8.4 Wire production configuration
Section titled “8.4 Wire production configuration”ACA accepts environment variables and secrets at the app level. The script supports -EnvVar and -Secret:
./deploy/azure-container-apps/deploy-up.ps1 ` -AppName acmestore ` -Image acmestore.azurecr.io/acme/store:1.0.0 ` -EnvVar @{ "Engine__Id" = "acme-store-prod" "ASPNETCORE_ENVIRONMENT" = "Production" "Observability__Endpoint" = "https://otlp-gateway-prod-eu-west-2.grafana.net/otlp" } ` -Secret @{ "connectionstrings-products" = "<your-secret-conn>" "connectionstrings-orders" = "<your-secret-conn>" "observability-headers" = "Authorization=Basic <BASE64>" } ` -SecretRef @{ "ConnectionStrings__Products" = "connectionstrings-products" "ConnectionStrings__Orders" = "connectionstrings-orders" "Observability__Headers" = "observability-headers" }8.5 Validate the deploy
Section titled “8.5 Validate the deploy”$fqdn = az containerapp show -n acmestore -g acme-prod --query properties.configuration.ingress.fqdn -o tsv
curl https://$fqdn/healthcurl https://$fqdn/engine/manifestcurl https://$fqdn/productsYou should see:
200 Healthyfrom/healthwith the dependency probes green.- the expected modules from
/engine/manifest. - products served from the production database.
8.6 Roll back
Section titled “8.6 Roll back”ACA revisions make rollback trivial:
az containerapp revision list -n acmestore -g acme-prod -o tableaz containerapp revision activate -n acmestore -g acme-prod --revision <previous-revision-name>This is your “if everything is on fire” button. Keep the previous revision active for a while after each deploy.
8.7 Wire CI/CD
Section titled “8.7 Wire CI/CD”Once the manual deploy works, automate it. The CI/CD tutorial walks through a GitHub Actions reference pipeline that:
- restores + builds + tests on PR.
- publishes the container image on merge to
main. - runs composition + behavior + integration tests against a temporary ACA environment.
- promotes the image to the production environment on tag.
8.8 What to monitor
Section titled “8.8 What to monitor”In your observability backend, set alerts on:
/healthnon-200for more than 60 seconds.cephalon.engine.startedevent missing after a deploy (boot failure).- traces from
POST /ordersexceeding p99 latency budget. - the Postgres dependency probe going
DegradedorUnhealthy.
Templates for these alerts live in the Observability stack tutorial.
Series wrap-up
Section titled “Series wrap-up”You built:
- a modular monolith with three modules.
- full CRUD over Products via REST.
- an event-driven flow for Orders.
- production observability and dependency health.
- a tiered test suite (composition, behavior, integration).
- a CI/CD-ready container image deployed to Azure Container Apps.
The same shape ships to Kubernetes (./deploy/kubernetes/apply.ps1), Linux systemd, IIS, Windows Service, or any container runtime — see Deployment.
Where to go next
Section titled “Where to go next”- Multi-tenant SaaS tutorial — add tenancy on top of this app.
- Microservice suite tutorial — split Orders and Products across two hosts.
- Observability stack tutorial — wire Grafana, Tempo, Loki, and SLO templates.
- Reference → Architecture — read the canonical contracts you’ve been relying on.