Skip to content

Azure Container Apps: Running secure and cost-aware .NET APIs

Practical guide · Azure Container Apps · ASP.NET Core · security and cost

When Azure Container Apps is a good fit

Azure Container Apps (ACA) provides managed hosting for containerized HTTP APIs, background workers and event-driven workloads without requiring teams to administer Kubernetes directly. Suitable apps can reduce the number of active replicas during periods of low traffic. This can save compute charges, but does not eliminate the cost of related Azure services.

1. Start with the architecture

Client → HTTPS ingress → Azure Container App (.NET API)
                             ↓ Managed Identity
                      Key Vault / Azure services
                             ↓
                       Application Insights
Container registry → versioned image → Revision

An app runs inside a Container Apps environment. Networking, observability, registry, queue and database services have distinct operating and billing characteristics. Decide early whether traffic truly needs to reach the service from the public internet or only from a private network.

2. Prepare a small .NET API

Create a simple ASP.NET Core application that can be deployed as a container:

dotnet new webapi -n ContainerDemo
cd ContainerDemo
dotnet publish -c Release

A minimal illustrative Program.cs:

var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();
app.MapGet("/health", () => Results.Ok(new { status = "ok" }));
app.MapGet("/api/version", () => Results.Ok(new { version = "1.0" }));
app.Run();

These routes demonstrate connectivity only. They do not implement application authorization. Health endpoints should never expose configuration secrets or sensitive diagnostics.

3. Build a multi-stage image

The following Dockerfile uses a build stage so the final container includes the runtime rather than the complete SDK. Match the framework version to your project and maintain supported base images.

FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build
WORKDIR /src
COPY . .
RUN dotnet publish -c Release -o /app/publish

FROM mcr.microsoft.com/dotnet/aspnet:8.0
WORKDIR /app
COPY --from=build /app/publish .
USER $APP_UID
EXPOSE 8080
ENV ASPNETCORE_HTTP_PORTS=8080
ENTRYPOINT ["dotnet", "ContainerDemo.dll"]

Use a .dockerignore, pin immutable image versions or digests in production and review security updates. .NET 8 is shown as an established LTS example; check current support guidance when building a new service.

4. How scale-to-zero actually behaves

With minReplicas: 0, a compatible workload may scale down to zero running replicas when idle. Actual behavior depends on scale rules, revisions and triggers. Cold starts can increase the latency of the first request after a quiet period. Continuous background polling or a misconfigured scaler may prevent scale-to-zero. For latency-sensitive integrations, keeping one replica running can be the more appropriate choice.

5. Ingress, identity and secrets

Choose external ingress only for use cases that require it. For internal integrations, prefer restricted network reachability. HTTPS transport protection is not application-level authorization: secure your business routes with Entra ID or an appropriate API gateway. Never treat an unguessable URL as the primary access control.

Use a managed identity to access Azure services and grant only the required roles. Store remaining secrets in a supported secret store such as Key Vault. Do not bake credentials into Dockerfiles or images. A Key Vault reference still requires correct identity permissions.

6. Revisions, deployment and rollback

Deploy immutable image versions and test new revisions before assigning production traffic. Multiple revision mode can support controlled traffic splitting when configured appropriately. Rollbacks are easiest when a previously verified revision is available. Keep database changes and message formats compatible with a transition between old and new application versions.

7. Estimate the entire Azure bill

A useful monthly estimate includes Container Apps CPU and memory usage, container registry, telemetry and log retention, network egress, Key Vault, database, queues and any network appliances. Billing depends on region and consumption model. Zero active replicas do not imply zero charges for dependent services.

Measure requests per month, processing duration, peak concurrency, container sizing, data transfer and logging retention. Configure Azure Cost Management budgets and alerts; remember that a budget alert does not automatically stop an application or prevent overrun.

8. Monitoring and incident diagnosis

Monitor request latency, cold-start effects, HTTP error ratios, replica counts, container restarts, failed revisions and downstream dependencies. Propagate correlation IDs for end-to-end diagnosis. Keep access tokens and confidential request bodies out of telemetry. Alert on sustained operational errors rather than CPU consumption alone.

9. Production checklist

  1. Run the container as a nonprivileged user with a consistent listening port.
  2. Keep secrets out of the image and repository.
  3. Restrict ingress and enforce authentication and authorization on application routes.
  4. Load-test scale rules, cold starts and concurrency.
  5. Verify health probes, deployment revisions and rollback.
  6. Track budgets for every supporting Azure resource.
  7. Configure monitoring, alerting and backups of stateful dependencies.

Conclusion: Azure Container Apps can be operationally efficient and cost-effective when its scaling model fits the workload. Assess security, latency and total cost together rather than treating scale-to-zero as a universal cost-saving switch.

Microsoft documentation

Discussion (0)

No comments yet. Be the first to contribute.

Leave a comment