03 - Observability & Troubleshooting
Master container logging, real-time log streaming, Kudu (SCM) diagnostic console, interactive SSH access, Log Analytics (KQL), and production troubleshooting gotchas.
Observing & Troubleshooting Containerized Apps
When a containerized app fails to start, returns 404 errors, or crashes under load, Azure App Service provides 5 diagnostic layers to inspect and resolve issues.
Understanding Dual-Container Architecture (Kudu SCM vs App Container)
Azure App Service runs two separate containers:
- Kudu SCM Sidecar Container (
kudu_ssh_user): Azure's internal management container running deployment scripts, log streaming, and SCM diagnostics. (This is what opens when you run Kudu Debug Console). - Your Application Container: Your custom Docker image running Gunicorn/Python on port
WEBSITES_PORT. (Access this via SSH in Azure Portal oraz webapp ssh).
1. Container Logging & Real-time Log Streaming
App Service captures stdout and stderr streams emitted by your container (such as Gunicorn startup logs, Python stack traces, and framework diagnostics).
Enabling Container Logging:
- Azure CLI:
az webapp log config \ -g container-learning \ -n inference-api-test \ --docker-container-logging filesystem - Azure Portal GUI:
Navigate to Web App -> App Service logs -> Set Container logging to
Filesystem(Quota: 35 MB, Retention: 1–9 days).
Streaming Live Logs in Real Time:
- Azure CLI:
az webapp log tail -g container-learning -n inference-api-test - Azure Portal GUI: Navigate to Web App -> Log stream under Monitoring.
2. Kudu (SCM) Diagnostic Console
Kudu runs as a sidecar management site accessible at:
https://<app-name>.scm.azurewebsites.net
Key Kudu Features:
- Environment Viewer (
/Env): Inspects every active environment variable injected into the Web App host. - File Explorer (
/home/LogFiles): Browse log files saved on persistent storage. - Diagnostic Dump: Download a zip file containing raw container logs, deployment logs, and system configuration.
GUI Path: Azure Portal -> Web App -> Advanced Tools -> Go.
3. Azure Monitor & Log Analytics Integration
For long-term retention and Kusto (KQL) querying across scaled instances:
Enabling Diagnostic Settings via CLI:
resourceId=$(az webapp show -g container-learning -n inference-api-test --query id -o tsv)
workspaceId=$(az monitor log-analytics workspace show -g container-learning -n myWorkspace --query id -o tsv)
az monitor diagnostic-settings create \
--resource "$resourceId" \
--name appServiceDiagnostics \
--workspace "$workspaceId" \
--logs '[{"category":"AppServiceConsoleLogs","enabled":true},{"category":"AppServiceHTTPLogs","enabled":true}]'Querying Logs with Kusto (KQL):
AppServiceConsoleLogs
| where Level == "Error"
| where TimeGenerated > ago(1h)
| project TimeGenerated, ResultDescription
| order by TimeGenerated desc4. Interactive SSH Shell into Running Containers
To inspect running processes or check internal file paths inside the container:
Container Prerequisites:
- Install
openssh-serverin Dockerfile. - Listen on port
2222. - Set root password to
Docker!(required by Azure App Service).
RUN apt-get update && apt-get install -y openssh-server \
&& echo "root:Docker!" | chpasswd
COPY sshd_config /etc/ssh/
EXPOSE 8000 2222
CMD ["/bin/bash", "-c", "service ssh start && gunicorn app:application"]Connecting via CLI & Portal:
- Azure CLI:
az webapp ssh -g container-learning -n inference-api-test - Azure Portal GUI: Navigate to Web App -> SSH under Development Tools.
Must-Know Production Gotchas & Pro-Tips
1. Extending Container Startup Timeouts (WEBSITES_CONTAINER_START_TIME_LIMIT)
Large Python/ML container images or apps performing heavy initialization can take over 3 minutes to boot. By default, Azure kills any container that doesn't respond to HTTP pings within 230 seconds (3.8 minutes) with the error: Container did not respond to HTTP ping on port 8000, site stopped.
The Fix: Increase startup timeout limit up to 1800 seconds (30 minutes):
az webapp config appsettings set \
-g container-learning \
-n inference-api-test \
--settings WEBSITES_CONTAINER_START_TIME_LIMIT=6002. Key Log Files in Kudu (/home/LogFiles/docker/)
When inspecting logs inside Kudu or downloading a diagnostic dump:
*_docker.log: Platform-level logs (Docker pull events, image extraction progress, and Azure container lifecycle errors).*_default_docker.log: Application-level logs (stdout/stderr emitted directly by your Gunicorn or Python process).
3. Debugging ACR Task Build Failures
When building container images in the cloud using ACR Tasks (az acr build):
# List recent ACR task runs
az acr task list-runs --registry acrlab06 --output table
# View build logs for a specific run ID
az acr task logs --registry acrlab06 --run-id <RUN_ID>4. Multi-Container Apps (Docker Compose on App Service)
App Service allows deploying multi-container microservices using docker-compose.yml (e.g. Web App + Redis + Worker):
az webapp create \
-g container-learning \
-p inference-plan \
-n multi-app-test \
--multicontainer-config-type compose \
--multicontainer-config-file docker-compose.ymlPractical Troubleshooting Gotchas (Symptom -> Cause -> Fix)
Gotcha 1: Container Fails to Start (Container Crashed on Boot)
- Symptom: Web App returns HTTP 502 / 503 Bad Gateway, or
log tailshows infinite container restart loop. - Why it happened: Missing required environment variable, syntax error in startup script, or missing Python package.
- The Fix:
- Stream logs:
az webapp log tail -g container-learning -n inference-api-test - Test container locally:
docker run -e REQUIRED_VAR=test acrlab06.azurecr.io/inference-api:latest - Verify app settings in Kudu:
https://<app-name>.scm.azurewebsites.net/Env
- Stream logs:
Gotcha 2: 404 Not Found Response After Successful Deployment
- Symptom: Web App status says
Running, but accessinghttps://inference-api-test.azurewebsites.netreturns404 Not Found. - Why it happened: The container web server is bound to
127.0.0.1(localhost) instead of0.0.0.0(all network interfaces), orWEBSITES_PORTdoes not match the container's listening port. - The Fix:
- Ensure your server binds to
0.0.0.0:gunicorn --bind=0.0.0.0:8000 app:application(not127.0.0.1:8000). - Set
WEBSITES_PORT=8000via CLI:az webapp config appsettings set -g container-learning -n inference-api-test --settings WEBSITES_PORT=8000
- Ensure your server binds to
Gotcha 3: Unauthorized / 403 Image Pull Backoff Failure
- Symptom: Web App log shows
Image pull failed (403 Unauthorized). - Why it happened: Managed Identity was enabled, but
AcrPullrole assignment was not created, or--acr-use-identity truewas missing. - The Fix:
- Verify Managed Identity principal ID:
az webapp identity show -g container-learning -n inference-api-test - Re-assign
AcrPullrole:az role assignment create --assignee $PRINCIPAL_ID --scope $ACR_ID --role AcrPull - Enable identity pull:
az webapp config set -g container-learning -n inference-api-test --acr-use-identity true --acr-identity [system]
- Verify Managed Identity principal ID:
Additional Resources
02 - Runtime & App Settings
Learn how to configure startup commands, port routing, persistent SMB storage, always-on, automated health checks, environment variables, connection strings, and Key Vault references.
04 - App Service Sidecars for AI
Master deploying multi-container Linux applications with AI inference sidecars on Azure App Service.
