powershelldba.de · Uwe Janke

Why Linux Containers Are the Best Way to Run SQL Server

Docker and Kubernetes compared with downloading binaries, first-generation VMs and cloud-managed databases: speed, reproducibility, density, version control and portability, plus the honest limits of running SQL Server in containers.

The Short Version

For most of my career, "installing SQL Server" meant an ISO, a setup wizard, a checklist, and an afternoon. Today a SQL Server instance can be a single command that finishes in seconds and can be thrown away just as fast. Linux containers, run with Docker on a workstation or orchestrated by Kubernetes in a data center, change what a SQL Server instance is: not a hand-built server with a history, but a versioned artifact you start, test, replace and reproduce.

This article walks through why I think containers are the best default for SQL Server in development, test, CI and a growing number of production scenarios, compared with the three alternatives most teams still use: downloading and installing binaries, running a first-generation virtual machine, or buying a cloud-managed database service. It also lists where containers are not the answer, because pretending otherwise would cost you credibility the first time someone asks about SSRS.

Versus Downloading and Installing Binaries

The classic installer is the baseline everything else gets compared to, and it has well-known costs.

A container image bundles the engine, its libraries and its defaults into one immutable unit. Starting an instance becomes:

docker run -e "ACCEPT_EULA=Y" -e "MSSQL_SA_PASSWORD=<a strong password>" \
  -e "MSSQL_PID=Developer" -p 1433:1433 \
  -v sqldata:/var/opt/mssql --name sql2025 \
  -d mcr.microsoft.com/mssql/server:2025-latest

Everything the instance needs is declared in that command or in a compose file next to your code. Want a different version? Change the tag. Want a clean slate? Remove the container and the volume, start again. Want two versions at once? Start two containers on two ports. There is no installer state to corrupt because there is no installer state.

Versus a First-Generation Virtual Machine

VMware, Hyper-V and similar platforms solved a real problem: many servers on fewer boxes. But a VM virtualizes hardware, so every SQL Server instance still drags a complete guest operating system along with it.

Fair note: A VM still gives stronger isolation than a container, and many production estates will keep running SQL Server in VMs for good reasons: existing tooling, Windows-only features, change-control processes built around VMs. On Windows and macOS desktops, Docker itself runs the Linux containers inside a lightweight VM (WSL2 or similar). That is fine for the workflow benefits described here, but it is not "bare metal" performance.

Versus a Cloud-Managed Database Service

Managed services remove real operational toil, and for many workloads they are the right choice. For the DBA who needs to understand, reproduce and test the engine, they come with limits.

What Kubernetes Adds

Docker on a single host is excellent for development and test. Kubernetes turns the same containers into a platform you can operate.

The key requirement is storage. SQL Server is a stateful workload, and its behavior under Kubernetes is only as good as the persistent volumes behind it: latency, durability, and how volumes move between nodes. Treat the storage class as part of the database design, not as an afterthought.

Where Containers Pay Off Most for a DBA

Side-by-side versions

In my own lab I keep SQL Server 2022 and SQL Server 2025 running at the same time on the same machine, on different ports, each with its own volume. Testing a script or a tool against both versions is a matter of choosing a connection string. A compose file is all it takes:

services:
  mssql-2022:
    image: mcr.microsoft.com/mssql/server:2022-latest
    environment:
      ACCEPT_EULA: "Y"
      MSSQL_PID: "Developer"
      MSSQL_MEMORY_LIMIT_MB: "2048"
    ports: [ "1433:1433" ]
    volumes: [ "mssql-2022-data:/var/opt/mssql" ]

  mssql-2025:
    image: mcr.microsoft.com/mssql/server:2025-latest
    environment:
      ACCEPT_EULA: "Y"
      MSSQL_PID: "Developer"
      MSSQL_MEMORY_LIMIT_MB: "2048"
    ports: [ "1434:1433" ]
    volumes: [ "mssql-2025-data:/var/opt/mssql" ]

volumes:
  mssql-2022-data:
  mssql-2025-data:

Add a health check that runs SELECT 1 through sqlcmd, and your scripts can wait until the instance is genuinely ready instead of sleeping for a guessed number of seconds. The SA password in a lab compose file is acceptable. In anything shared, use secrets.

Availability groups without a domain or a cluster

A two-node availability group normally needs a Windows failover cluster and, in most setups, Active Directory. On Linux containers you can create an availability group with CLUSTER_TYPE = NONE between two containers on one bridge network. There is no WSFC and no domain. That is not a production high availability design (nothing orchestrates failover), but it is perfect for learning replica behavior, testing monitoring queries for send and redo queues, and rehearsing seeding and failover commands in minutes instead of days.

Upgrade rehearsals and regression testing

Restore last night's backup into a container running the target version, run your test suite, and delete the container. Do it in a CI pipeline and every change to a stored procedure or migration script is verified against a real engine before it goes anywhere near production. Do it for a new cumulative update and you know the result before the maintenance window.

Restore verification

A backup you have never restored is a hope, not a backup. A container makes restore testing cheap enough to automate: start, restore, run DBCC CHECKDB, report, remove.

Training and demos

A broken lab takes one command to rebuild. Participants in a workshop get identical environments, and a demo that goes wrong is reset in seconds.

Side-by-Side Summary

CriterionInstallerFirst-gen VMManaged serviceLinux container
Time to a new instanceTens of minutes to hoursMinutes to days (provisioning)Minutes to hoursSeconds
ReproducibilityLow, driftsMedium, clones driftVendor-definedHigh, image plus manifest
Several versions side by sideAwkwardOne VM eachSeparate resourcesTrivial
Resource overheadHost OS onlyFull guest OS per instanceVendor-managedShared kernel, small
Reset to clean stateRestore or reinstallSnapshot or rebuildRecreate resourceRemove and start
Same engine as on-premisesYesYesNot alwaysYes
Patch and version controlYoursYoursVendor's scheduleYours, by image tag
PortabilityLowMediumLow, vendor-boundHigh
Fits CI pipelinesPoorlyPoorlyCostlyNatively

Where Containers Are Not the Answer

Being honest about the limits is what makes the case credible.

A Practical Starting Path

  1. Install Docker Desktop (or a Linux host with Docker) and run a single Developer-edition container with a named volume.
  2. Move your database project's test environment into a compose file in the same repository as the code.
  3. Add a health check and a restore step so that a fresh test database can be built from a backup with one command.
  4. Run the same compose file in your CI pipeline so every change is tested on a real engine.
  5. Rehearse your next cumulative update or major version upgrade against a container before you schedule the change.
  6. Only then evaluate Kubernetes for the workloads where self-healing, declarative operations and a shared platform justify the added complexity.

The Bottom Line

Installers give you a server. Virtual machines give you a server inside a server. Managed services give you someone else's server. Containers give you an instance as code: small, fast, identical wherever it runs, and disposable by design. For development, testing, upgrade rehearsal, training and CI, that is a clear win, and with Kubernetes and sound storage design it is a credible production option as well. Keep the VM or the managed service where the workload needs Windows-only features or where the operational model fits, and use containers everywhere else, starting with the test environment you currently build by hand.