CalSync — Automate Outlook Calendar Colors

Auto-color-code events for your team using rules. Faster visibility, less admin. 10-user minimum · 12-month term.

CalSync Colors is a service by CPI Consulting

In this blog post Keep .NET App Running in Docker we will walk through how to containerise a .NET application, start it automatically when the container launches, and keep it running reliably.

Containers shine when you want consistent, repeatable runtime environments. Docker gives you a lightweight, portable unit to ship and run your .NET service anywhere.

High-level overview

Running a .NET app “all the time” in Docker means two things:

  • Start it automatically when the container starts (using the image’s entrypoint).
  • Keep it alive with sensible restart policies and health checks.

Docker images package your app and its runtime. Containers are running instances of those images. In each container, your application is PID 1—the primary foreground process. If it exits, the container stops. So the right way to keep a .NET app running is to launch the app in the foreground, let Docker manage the process lifecycle, and rely on Docker policies to restart the container on failures or host restarts.

The technology behind it

Several core Docker and .NET concepts make this work:

  • Images and layers: Your Dockerfile defines steps to build an image. Each step creates a layer you can cache and reuse.
  • ENTRYPOINT and CMD: These define what process runs when the container starts. For .NET, that’s usually dotnet YourApp.dll.
  • Foreground process model: Containers aren’t virtual machines. They run a single primary process in the foreground. When that process ends, the container stops.
  • Signals and graceful shutdown: Docker sends SIGTERM then SIGKILL on stop. ASP.NET Core and .NET’s Generic Host respond to SIGTERM and shut down gracefully by default.
  • Logging: Write logs to stdout/stderr. Docker captures these so you can use docker logs or forward them to a central system.
  • Health checks and restart policies: Health checks declare when your app is healthy. Restart policies tell Docker how to react when a container exits.

Create a minimal .NET web API

We’ll create a tiny ASP.NET Core app that exposes a health endpoint and listens on port 8080.

Ensure your project file references .NET 8 LTS (or your target LTS):

Build a production-friendly Docker image

Use a multi-stage Dockerfile to keep the final image small, create a non-root user, and expose port 8080. We’ll install curl to support a simple in-container health check. If you prefer a leaner image, you can omit curl and rely on external checks.

Key details:

  • The ENTRYPOINT ensures your .NET app is PID 1 and runs in the foreground.
  • USER appuser avoids running as root in production.
  • HEALTHCHECK helps orchestrators know when to restart the container.
  • ASPNETCORE_URLS binds to 0.0.0.0 so traffic from the host can reach the app.

Build and run the container

From the folder containing your Dockerfile and project:

If the app exits unexpectedly, Docker restarts it due to the --restart unless-stopped policy. For servers that reboot, the container comes back up automatically.

Keep it running the right way

Use Docker restart policies

  • --restart no: default; don’t restart.
  • --restart on-failure[:max-retries]: restart on non-zero exit.
  • --restart unless-stopped: restart always unless you manually stop it.
  • --restart always: always restart—even after manual stop (less common for services you might stop by hand).

Expose a health endpoint

The /health route we added is a simple way for Docker (and load balancers) to confirm the app is responsive. In real apps, use ASP.NET Core Health Checks to test dependencies like databases or queues.

Log to stdout and stderr

Don’t write logs to local files in the container. Use console logging so Docker can capture and rotate them. In production, ship them to a central logging system.

Graceful shutdown

.NET’s Generic Host handles SIGTERM gracefully. If you need to run cleanup code on shutdown, hook into IHostApplicationLifetime:

Use Docker Compose for daily workflows

Compose lets you describe your app’s runtime settings in a file, then start/stop with one command. Great for dev and single-host deployments.

Run it with:

To view logs and status:

In production, Compose is fine for a single host. At scale, consider Kubernetes, Amazon ECS, or Azure Container Apps for orchestration, rolling updates, and auto-scaling.

Always-on background jobs with .NET Worker

If you’re building a long-running worker (not HTTP), use the .NET Worker template. It runs until cancelled, which is perfect for containers:

The Dockerfile pattern is the same—just set the ENTRYPOINT to run the worker DLL. It will keep running until Docker sends SIGTERM or the process fails.

Wrap-up

That’s the practical path to keep a .NET app running in Docker:

  1. Write a .NET app that runs in the foreground and exposes a health endpoint.
  2. Build a multi-stage image with an ENTRYPOINT that launches your app.
  3. Run it with a sensible --restart policy so it stays up.
  4. Add health checks and logs to stdout for observability.
  5. Use Docker Compose for convenient start/stop and configuration.

Follow these patterns and your .NET services will start cleanly, survive restarts, and run reliably—without hacks or heavyweight infrastructure.


Discover more from CPI Consulting

Subscribe to get the latest posts sent to your email.