Summary
The user is unable to run sqlcmd inside the official SQL Server 2022 Docker container because the base image (mcr.microsoft.com/mssql/server:2022-latest) does not include the mssql-tools package by default. This is a deliberate design choice to keep the database server image lean and focused on the engine. Additionally, attempting to install the tools using apt-get fails because the SQL Server Linux images are based on Ubuntu, but the apt package repositories are typically disabled or missing in the minimal runtime layers to optimize image size and security.
Root Cause
The root cause is a misunderstanding of the contents of the official Microsoft SQL Server Docker images.
- Separation of Concerns: Microsoft separates the database engine (
mssql/server) from the client tools (mssql-tools). - Minimalist Image Design: The
mssql/serverimage contains only the SQL Server engine and necessary dependencies. Tools likesqlcmdandbcpare packaged separately in themssql-toolsimage or package, which is not included in the base server image. - Restricted Environment: The SQL Server Linux container environment is minimal. While it is based on Ubuntu, many system package management tools and repositories are removed or restricted to prevent modification and reduce the attack surface. Consequently,
apt-getis not available or functional, making it impossible to install packages directly inside the running container via standard means.
Why This Happens in Real Systems
In production engineering, container images are optimized for specific roles.
- Image Size and Security: Including development and administration tools (like
sqlcmd) in a production database image increases the container size and potential attack surface. In a hardened production environment, access to a shell inside the container is often restricted, and management is performed externally. - Ephemeral Containers: Containers are designed to be immutable and ephemeral. If a tool is needed, it should ideally be added during a custom build process (creating a new image layer) rather than installed manually on a running instance.
- Dependency Hell: Relying on
apt-getinside a runtime container can lead to version conflicts or broken dependencies if the repositories are out of sync with the locked base OS version of the image.
Real-World Impact
- Operational Blockers: Administrators cannot connect to the database using the standard command-line interface (
sqlcmd) to perform maintenance tasks, such as restoring backups (.bakfiles), running scripts, or checking server status directly from the host viadocker exec. - Inefficient Workarounds: Teams often waste time trying to “hack” the container by installing tools, which violates the immutable infrastructure principle and can lead to unstable or non-reproducible environments.
- Deployment Delays: Without
sqlcmd, automating database initialization or migration steps in CI/CD pipelines requires finding alternative drivers or containers, complicating the workflow.
Example or Code
To verify the issue and the environment constraints, one might run the following commands.
Checking for sqlcmd (which fails):
docker exec -it sqlserver /opt/mssql-tools/bin/sqlcmd
Result: No such file or directory
Checking for apt-get (which fails):
docker exec -it sqlserver apt-get update
Result: bash: apt-get: command not found
The Correct Approach (Mounting Tools):
Instead of installing tools inside the DB container, use a sidecar container or a volume mount with the tools image to interact with the DB container.
# Run a separate container with mssql-tools that shares the network with the sqlserver container
docker run --rm -it \
--network host \
-e PGPASSWORD='youdontneedtoknow' \
mcr.microsoft.com/mssql-tools \
/opt/mssql-tools/bin/sqlcmd -S localhost -U sa -P 'youdontneedtoknow' -Q "SELECT @@VERSION;"
How Senior Engineers Fix It
Senior engineers adhere to the separation of infrastructure and management tooling.
-
Use the Dedicated Tools Image: Use the
mcr.microsoft.com/mssql-toolsimage. It is lightweight and containssqlcmdandbcppre-installed. Run it as a sidecar container communicating with the SQL Server container via Docker networking. -
Custom Dockerfile (Build Time): If you absolutely require
sqlcmdinside the same container (e.g., for a specific startup script), create a custom Dockerfile. Crucially, you must enable the package repositories and install dependencies during the build phase, not the run phase.Example Dockerfile snippet:
FROM mcr.microsoft.com/mssql/server:2022-latest # Switch to root to install tools USER root # Enable repositories and install mssql-tools (Ubuntu specific) # Note: This requires the official Microsoft apt repo keys and sources list RUN apt-get update && \ apt-get install -y mssql-tools && \ apt-get clean && \ rm -rf /var/lib/apt/lists/* # Switch back to the non-root user defined in the base image USER mssql -
Host Mapping: For simple manual tasks, you can mount the
mssql-toolsbinaries from your host machine into the container if you have them installed locally, though networking a sidecar container is the preferred cloud-native method.
Why Juniors Miss It
- Assumption of Linux Norms: Junior engineers often assume that any Linux-based container acts like a standard Linux server (like an EC2 instance or VPS) where
apt-getis universally available. They don’t realize that production container images are often stripped down. - Lack of Awareness of Image Variants: They might not know that Microsoft publishes a separate
mssql-toolsimage. They look for tools in the main server image and assume they are just missing or corrupted. - Confusion with “Runtime” vs. “Build”: They try to modify a running container (runtime) to add features, rather than building a new image (build time) that includes those features. This violates the concept of immutable infrastructure.