.NET Migration · 2026-06-01
Containerizing a Legacy .NET App: From Windows Server to Docker in 5 Steps
A five-step path for putting a legacy .NET Framework application into containers — base images, state, config, health checks, and the deployment order that does not require a rewrite.
You can containerize a legacy .NET Framework app without rewriting it. The five steps below are what I used to move Framework-era services onto Kubernetes — each step is small, reversible, and testable on its own.
1. Pick the base image honestly
.NET Framework apps need Windows containers: mcr.microsoft.com/dotnet/framework:4.8 as the runtime base. If that feels heavy, treat that as a signal — .NET 8 (or 6) with the same app logic often needs no rewrite at all, just the migration checklist. Decide the target before you touch a Dockerfile: Windows Server Core containers are fine for an internal service; they cost more and patch differently.
2. Make config external before you containerize
Config files baked into the image are a trap. Move connection strings, endpoints and feature flags to environment variables or a mounted config file first. The container image should be identical across environments — only the environment differs.
3. Handle state as the exception
If the app writes to local disk, that’s a problem containers will expose immediately. Move logs to stdout (Windows containers forward console output), move file caches to a shared volume or object storage, and treat the container filesystem as disposable. Sessions belong in a store, not on a local disk.
4. Give it a health check
A container that “runs” but serves 500s is worse than one that restarts. Add a lightweight HTTP endpoint (or TCP check) the orchestrator can probe:
HEALTHCHECK CMD powershell -Command "Invoke-WebRequest -UseBasicParsing http://localhost/health"
Then wire liveness and readiness in Kubernetes — and tune restartPolicy and terminationGracePeriodSeconds so the old app gets time to finish in-flight work.
5. Ship in the old/new order
Deploy order: build the image → run it side by side on a test port → point a canary at it → shift traffic → cut over. Keep the Windows Server host until the container has survived a full business cycle (patch cycles included). Retire it only when the container has proven it can take the load — not on day one.
The one-liner summary
Make config external, state disposable, and health checkable — and the container is just packaging. The rewrite debate can wait until the container is in production, where the real bottlenecks show themselves.