Backing SQL on Linux to Windows Share

How to back up a database from SQL Server on Linux (perhaps in a Docker container) to a Windows Share already on the network?

If you want to know how to run SQL Server on Linux in a Docker container read my earlier post.

Container run-time privileges and Linux capabilities

Before we start it is important to note that by default the containers are run with very limited privileges and cannot do much. That’s by design, to make them more secure. However, that prevents them from being able to use CIFS protocol to mount to an SMB share, exactly what we are trying to do. If you just follow the steps in the next sections when you try to mount the share you will get

Unable to apply new capability set.

To avoid this problem the container needs to be created with two extra capabilities: SYS_ADMIN and DAC_READ_SEARCH. You can read more about it on the here. But to make the long story short you need to add two --cap-add parameters to your docker run command.

The full command from my earlier post becomes:

docker run -d `
   -e ACCEPT_EULA=Y -e SA_PASSWORD=Secret1234 `
   -p 14333:1433 --name sql1 `
   --cap-add SYS_ADMIN --cap-add DAC_READ_SEARCH ` 
   mcr.microsoft.com/mssql/server:latest

Create a container with those capabilities before continuing.

The Naive Approach

Let’s assume you have a network share already available and it is accessible using UNC \\FileShare1\SqlBackups\. Being used to Windows networking one would expect to simply take a backup like so, for example:

backup database [TestDb] 
   to disk='\\FileShare1\SqlBackups\TestDB.bak'

The command completes with no errors and yet there is no TestDB.bak file in \\FileShare1\SqlBackups. Stranger still it is possible to restore from that file which doesn’t seem to exist. Try:

restore filelistonly 
   from disk='\\FileShare1\SqlBackups\TestDB.bak'

It works, because Linux translates the UNC it knows nothing about (after all it’s a Windows thing) to a local file /FileShare/SqlBackups/TestDB.bak. If you remote to the container (or execute bash on it with docker exec -it sql bash) you will find /FileShare1/SqlBackups/TestDB.bak file.

Interesting, but not what we expected.

Getting into SMB and CIFS

To solve this problem a network share needs to be mounted to a node in the Linux file system. There are two ways to do it, one is temporary using the mount command only, or a more permanent involving editing the fstab file and then using mount. But before we can do it, one problem has to be solved first. The Windows file server shares the folder using the SMB protocol which is gibberish to Linux. Luckily Linux can be taught to speak CIFS protocol which is compatible with SMB. The way to do it is to install the cifs-utils package. On Ubuntu (SQL Server vNext in a container runs on Ubuntu so I use it as an example) is to install the package with apt-get. Other flavours of the OS will use their own package managers, but overall the process is the same.

First, you will have to Connect to SQL Server on Linux.

Then the CIFS protocol utilities have to be installed using apt-get on Ubuntu.

apt-get update
apt-get install cifs-utils

You will be asked if you want to really do it as it will take an extra 41 MB of disk space. Press Y to agree.

After this operation, 41.2 MB of additional disk space will be used.
Do you want to continue? [Y/n]

Now a directory where the backups will be mounted needs to be created. Typically the external mounts are all in /mnt. So let’s create a backups directory there.

mkdir /mnt/backups

Now it is time to mount.

mount -t cifs //FileShare/SqlBackups /mnt/backups \
   -o username=yourusername,domain=yourdomain,file_mode=0777,dir_mode=0777,rw,sec=ntlm

You will be asked for a password and if everything is correct you will get prompt again which means everything went well. It is important to note the change from \ to /.

It should not be possible to navigate to that directory and create a test text file.

cd /mnt/backups
touch test.txt

With that, the test.txt file should be now visible on \\FileShare1\Backups.

And to take the backup to that share becomes no different to taking any other backup to disk:

backup database [TestDb] 
   to disk='/mnt/backups/testdb.bak'

Using Shares to Interact with the Host

It is also possible to use this approach instead of using -v or --mount to share the file system between a container and its host. It is arguably a bit more effort but it allows to easily share backup and restore location between multiple containers without read/write issues associated with folder binding.

Connect to SQL Server on Linux

How to connect to SQL Server on Linux?
It really depends on what one means by ‘connect’.

Query SQL Server on Linux from Windows

To connect to the SQL Server instance running on Linux directly or in a container to run a query it is no different from connecting to one running on Windows. Just connect using the DNS name or an IP and a port number if it is not the default 1433. The only difference is that only SQL Authentication is supported so you will not be able to use Windows Authentication and your domain credentials.

Query SQL Server from Linux

Azure Data Studio (formerly known as SQL Server Operations Studio) can run on Linux offering the same user experience as on Windows. It is also possible to use the sqlcmd which works exactly the same as the one on windows. To install it on Ubuntu or any Linux flavour using apt-get package manager you can simply do

apt-get install mssql-tools

End then just use it the same way as you would normally do

sqlcmd -S localhost -U sa -P mysecretpassword

In the default SQL Server Docker image the mssql-tools are already installer but they are not added to the $PATH variable. You can either add it, or use the full path to execute it which changes the above command to

/opt/mssql-tools/bin/sqlcmd -S localhost -U sa -P mysecretpassword

Remote to Linux remote server

When managing a SQL Server instance it is sometimes necessary to connect to the operating system on which it runs. This is very different on Linux to running SQL Server on Windows. There is no remote desktop, and PowerShell doesn’t really work either. That’s where the typical Linux admin tools become necessary.

In a way the Secure Shell or SSH is the Linux equivalent of the Remote Desktop. There are many ways to do it, especially from another Linux box. Most of us, SQL DBAs, will be typically on a Windows machine. In that case a common approach is to use PuTTy. But if you use PowerShell and keep up with updates it is now possible to SSH directly for a PowerShell terminal too.

ssh mysqlonlinux.mydomain.com

or

ssh 10.11.12.13

Simple as that. You will connect with a specific user and now most of the admin commands will have to start with sudo which allows to execute them with elevated permissions. It’s similar to Windows’ Run as Administrator.

Connect to Docker container from the host

If you want to connect to a container running your SQL Server on Linux from the host use docker exec to start a bash shell.

docker exec -it sql1 bash

where sql1 is the name of the container hosting SQL Server.

You will connect with superuser permissions and sudo will not be necessary. The prompt will look something like this:

root@2ff21ad83800:/#

SSH into a container running SQL Server on Linux

If you cannot or don’t want to remote onto the host first to connect to the container running your SQL Server instance SSH is the way to go, again. By default, the SQL Server image does not have SSH server so you will have to install it or a custom image will have to be created. Once that is done it is no different from connecting with the ssh (or PuTTy) to any other Linux server. It doesn’t matter that it runs in a container.