Setting Permissions on Files Inside a Container for SQL Server

This post will walk you through setting file permissions on database files copied into a container. The SQL Server process sqlservr running in containers runs as the non-privileged user mssql. The appropriate permissions on files are needed, so the SQL Server process has the proper access to any database files, log files, and backup files.

Start up a container

First up, let’s start up a container. Here’s we’re starting up SQL Server 2019 CU11 and attaching a Docker data volume for our persistent data.

docker run \
    --env 'ACCEPT_EULA=Y' \
    --env 'MSSQL_SA_PASSWORD=S0methingS@Str0ng!' \
    --name 'sql1' \
    --publish 1433:1433 \
    --volume sqldata1:/var/opt/mssql \
    --detach mcr.microsoft.com/mssql/server:2019-CU11-ubuntu-18.04

With the container up and running, let’s check out a few things. First, using ps -aux, in the output below, you can see the sqlservr processes are running as the user mssql.

docker exec sql1 bash -c 'ps -aux'         
USER       PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
mssql        1  0.0  0.2 152092  4968 ?        Ssl  06:38   0:00 /opt/mssql/bin/sqlservr
mssql       10  5.9 45.4 8916492 924852 ?      Sl   06:38  18:43 /opt/mssql/bin/sqlservr
mssql     2858  0.0  0.1  34416  2736 ?        Rs   11:53   0:00 ps -aux

We can use the id command to look at the UID and GID information for a user. The UID for mssql is 10001 and the user is a member of the root group, GID 0.

docker exec sql1 bash -c 'id mssql'                           
uid=10001(mssql) gid=0(root) groups=0(root)

Copy the database files into the container

Next, let’s use docker cp to copy an existing database, both the data and log files, into the container.

docker cp tpcc100.mdf sql1:/var/opt/mssql/data/
docker cp tpcc100_log.ldf sql1:/var/opt/mssql/data/

Examine the ownership and permissions after copying the file into the container

When using docker cp to copy files into a container, the UID and GID of the user executing the copy are used as the default permission set on the files copied into the container.

The user accounts and groups on the base OS likely don’t sync up with the user accounts and groups inside the container. So we need to look at things using the UID and GID. In Linux, UID and GID are used for permissions. The human-readable names are just for us humans. So let’s look at things file ownership and permissions using the -n parameter on the ls command.

In the directory listing below, for the files that we copied in, you can see the UID is 501 and the GID is 20. I’m on a Mac and my current user’s UID is 501 and GID is 20. So those are the permissions on the files copied into the container. These files are not accessible by SQL Server since the UID of user mssql is 10001.

docker exec sql1 bash -c 'ls -lan /var/opt/mssql/data/tpcc*'
-rw-r----- 1   501 20 21474836480 Sep 24 14:23 tpcc100.mdf
-rw-r----- 1   501 20  1073741824 Sep 24 14:23 tpcc_log100.ldf

Set the appropriate owners and permissions on the database files in the container

So let’s fix things up and set the appropriate owners and permissions on the files. We’ll use docker exec to run the appropriate commands inside the container to set the ownership and permissions. Since the container is running as mssql we need to specify the -u 0 parameter to run these commands as root.

The first command run is chown, which sets the user and group owner as mssql, UID 10001 inside the container, and GID 0, which is the root user.

docker exec -u 0 sql1 bash -c 'chown 10001:0 /var/opt/mssql/data/tpcc*'

The second command we’ll need is chmod to set the permissions on the files. Here we’re going to set the permissions to rw using the octal notation of 660 for both the user and group owner.

docker exec -u 0 sql1 bash -c 'chmod 660 /var/opt/mssql/data/tpcc*'

Check out the new permissions

The user and group owners of the files are now mssql and root and the permissions are rw for each file. These permissions enable the mssql user to read and write these files.

docker exec sql1 bash -c 'ls -laR /var/opt/mssql/data/tpcc*'

-rw-rw---- 1 mssql root 21474836480 Sep 24 14:23 /var/opt/mssql/data/tpcc100.mdf
-rw-rw---- 1 mssql root  1073741824 Sep 24 14:23 /var/opt/mssql/data/tpcc_log100.ldf

Attach the database

With everything set properly, let’s attach the database.

QUERY="CREATE DATABASE tpcc100 ON (FILENAME = '/var/opt/mssql/data/tpcc100.mdf'), (FILENAME = '/var/opt/mssql/data/tpcc_log100.ldf') FOR ATTACH;"
sqlcmd -S localhost,1433 -U sa -Q $QUERY -P 'S0methingS@Str0ng!'

Finally, let’s check to see if our database is there and tpcc100 is in there!

sqlcmd -S localhost,1433 -U sa -Q 'SELECT name from sys.databases' -P 'S0methingS@Str0ng!'

name                                                 
----------------
master         
tempdb                    
model                     
msdb                      
tpcc100

PS: If you’re copying a backup into a container to restore you can use this same technique to set permissions on the backup file so SQL Server has access to read the file.