Category Archives: Training

Updated Pluralsight Course – Kubernetes Installation and Configuration Fundamentals

My updated course “Kubernetes Installation and Configuration Fundamentals” in now available on Pluralsight here! If you want to learn about the course, check out the trailer here or if you want to dive right in check it out here

This course targets IT professionals that design and maintain Kubernetes and container based solutions. The course can be used by both the IT pro learning new skills and the system administrator or developer preparing for using Kubernetes both on premises and in the Cloud.

Let’s take your Kubernetes administration and configuration skills to the next level and get you started now!

Key updates to the course include:

  • Using containerd as a container runtime

  • Building clusters with kubeadm and Cluster Configuration Files

  • Using kubectl command options to create workloads and build YAML manifest templates fast such as --dry-run

The modules of the course are:

  • Exploring the Kubernetes Architecture – In this module we introduce Kubernetes, deep dive into each component and its responsibility in a cluster. We also look at higher level abstractions such as Services, Controllers, and Deployments and how they can be used to ensure the desired state of an application deployed in Kubernetes

  • Installing and Configuring Kubernetes – In this module, we learn several ways to install a Kubernetes cluster. We start off simple with an installation using kubeadm using containerd. Then we head off to the Cloud, we look at the current state of the cloud managed Kubernetes services and installation methods for each of the major cloud providers (Google, AWS, and Azure) and perform a cluster deployment using Azure Kubernetes Service (AKS).

  • Working with Your Kubernetes Cluster – In this module, we learn how to interact with our cluster. We learn how to use and configure the primary tool for communicating with Kubernetes clusters, kubectl. We then learn how to perform a simple application Deployment both imperatively and declaratively in our Kubernetes cluster. And also learn how to use kubectl to generated YAML manifests for cluster resources quickly and correctly

Check out the course at Pluralsight!

Availability Group StatusNewImage 3

Kubernetes Precon at DPS

Pre-conference Workshop at Data Platform Virtual Summit 2020

DPS 2020 Transparent Logo 150 x 55 01

I’m proud to announce that I will be be presenting pre-conference workshop at Data Platform Virtual Summit 2020 split into Two four hour sessions on 30 November and 1 December! This one won’t let you down!

Here is the start and stop times in various time zones:

Time Zone Start Stop
EST 5.00 PM 9 PM
CET 11.00 PM 3.00 AM (+1)
IST 3.30 AM (+1) 7.30 AM (+1)
AEDT 9.00 AM (+1) 1.00 PM (+1)

The workshop is “Kubernetes Zero to Hero – Installation, Configuration, and Application Deployment”

Abstract: Modern application deployment needs to be fast and consistent to keep up with business objectives, and Kubernetes is quickly becoming the standard for deploying container-based applications fast. In this day-long session, we will start container fundamentals and then get into Kubernetes with an architectural overview of how it manages application state. Then you will learn how to build a cluster. With our cluster up and running, you will learn how to interact with our cluster, common administrative tasks, then wrap up with how to deploy applications and SQL Server. At the end of the session, you will know how to set up a Kubernetes cluster, manage a cluster, deploy applications and databases, and how to keep everything up and running.

PS: This class will be recorded, and the registered attendee will get 12 months streaming access to the recorded class. The recordings will be available within 30 days of class completion.

Workshop Objectives

  • Introduce Kubernetes Cluster Components
  • Introduce Kubernetes API Objects and Controllers
  • Installing Kubernetes
  • Interacting with your cluster
  • Storing persistent data in Kubernetes
  • Deploying Applications in Kubernetes
  • Deploying SQL Server in Kubernetes
  • High Availability scenarios in Kubernetes

Click here to register now!

Anthony dps 2020 Kubernetes Training Class

Announcing EightKB 2021

The first EightKB back in July was a real blast. Five expert speakers delivered mind-melting content to over 1,000 attendees!

We were honestly blown away by how successful the first event was and we had so much fun putting it on, we thought we’d do it again 🙂

The next EightKB is going to be on January 27th 2021 and the schedule has just been announced!

EightKB Schedule

Once again we have five top-notch speakers delivering the highest quality sessions you can get! Expect a deep dive into the subject matter and demos, demos, demos!

Registration is open and it’s completely free! You can sign up for the next EightKB here!

We also run a monthly podcast called Mixed Extents where experts from the industry join us to talk about different topics related to SQL Server. They’re all on YouTube or you can listen to the podcasts wherever you get your podcasts!

EightKB and Mixed Extents are 100% community driven with no sponsors…so, we’ve launched our own Mixed Extents t-shirts! Any money generated from these t-shirts will be put straight back into the events.

EightKB was setup by Andrew Pruski (b|t), Mark Wilkinson (b|t), and myself as we wanted to put on an event that delved into the internals of SQL Server and we’re having great fun doing just that 🙂

Hope to see you there!

Pre-Conference Workshop and Sessions at PASS Summit

I’m pleased to announce that I will be presenting at PASS Summit. This year I have a pre-conference workshop and a regular session. Let’s dive into each.

Pre-Conference Workshop: The Future of Deployment for Modern Data Platform Applications

Ben Weissman and I teach a pre-conference workshop called “The Future of Deployment for Modern Data Platform Applications” in this workshop. We’re going to cover how you will be deploying data platform applications in the near future. Here’s a listing of the topics we’re going to cover.

  • Kubernetes Fundamentals – building a cluster and deploying applications
  • Deploying SQL Server in Kubernetes – diving deep into what it takes to run a stateful application in Kubernetes
  • Deploying Big Data Clusters – showcasing how you can deploy a complex stateful application in Kubernetes.
  • Azure Arc Enabled Data Services Fundamentals – learn how to run any Azure Data Service anywhere you have Kubernetes, in any cloud or on-premises.
  • Deploying Azure Arc Enabled Data Services – tons of demos and code samples to highlighting how to deploy SQL Managed Instance and PostgreSQL HyperScale in any cloud or on-premises. 

You will leave this session with the knowledge, scripts, and tools to get started with Kubernetes and Kubernetes based applications.

Sign up for our workshop here:

Regular Session: Deploying and Managing SQL Server with dbatools

Well, if you’ve been following my blog and work over the last few years, it’s been all containers and Kubernetes. But I still have clients that run SQL Server on Windows. And for those clients, there’s only one that I install SQL Server…with dbatools. So I wrote a session describing how I did it for my client, and I’m going to share all that knowledge with you! Check out the deets…


The dbatools project brings automation to the forefront of the SQL Server configuration, operations, and deployment tasks. This session will look at how to install and configure multiple SQL Servers quickly and consistently using dbatools deployment tools. Once those systems are up and running, we will look at how to configure and manage multiple systems using PowerShell automation techniques. By the end of this session, you will have the tools, techniques, and code to automatically and consistently deploy and configure SQL Server in your environment.

Hope to see you at PASS Summit this year!

Sign up PASS Summit here:

PASS Summit 2020

Workshop – Kubernetes Zero to Hero at SQL Saturday Denver!

Pre-conference Workshop at SQLSaturday Denver

I’m proud to announce that I will be be presenting an all day pre-conference workshop at SQL Saturday Denver on October 11th 2019! This one won’t let you down! 

The workshop is Kubernetes Zero to Hero – Installation, Configuration, and Application Deployment” 


Here’s the abstract for the workshop

Modern application deployment needs to be fast and consistent to keep up with business objectives and Kubernetes is quickly becoming the standard for deploying container-based applications, fast. In this day-long session, we will start with an architectural overview of a Kubernetes cluster and how it manages application state. Then we will learn how to build a production-ready cluster. With our cluster up and running, we will learn how to interact with our cluster, common administrative tasks, then wrap up with how to deploy applications and SQL Server. At the end of the session, you will know how to set up a Kubernetes cluster, manage a cluster, deploy applications and databases, and how to keep everything up and running.

Session Objectives

  • Introduce Kubernetes Cluster Components
  • Introduce Kubernetes API Objects and Controllers
  • Installing Kubernetes
  • Interacting with your cluster
  • Storing persistent data in Kubernetes
  • Deploying Applications in Kubernetes
  • Deploying SQL Server in Kubernetes
  • High Availability scenarios in Kubernetes


How much does it cost?

The full day training event is $150 per attendee.

What can I bring into the event?
WiFi at the location is limited. The workshop will be primarily demonstration based. Code will be made available for download prior to the event if you would like to follow along during the session.

How can I contact the organizer with any questions?
Please feel free to email me with any questions:

What’s the refund policy?
7 days: Attendees can receive refunds up to 1 days before your event start date.

Do I need to know SQL Server or Kubernetes to attend this workshop?
No, while we will be focusing on deploying SQL Server in Kubernetes, no prior knowledge of SQL Server or Kubernetes is needed. We will build up our Kubernetes skills using SQL Server as the primary application we will deploy.

What are the prerequisites for the workshop?
All examples will be executed at the command line, so proficiency at a command line is required. Platform dependent (Linux/Windows,Cloud CLIs) configurations and commands will be introduced and discussed in the workshop.  

Docker Image Tags are Case Sensitive

A quick post about pulling docker containers (this applies to docker run too)…when specifying the container image, the container image name and tag are case sensitive. We’re not going to discuss how much time troubleshooting it too me to figure this out…but let’s just say it’s more than I care to admit publicly. 

In this code you can see I’m specifying the following image and tag server:2019-rc1-ubuntu (notice the lowercase rc in the tag)

docker pull 

Docker responds that it cannot find that image manifest

Error response from daemon: manifest for not found: manifest unknown: manifest unknown 

If we specify server:2019-RC1-ubuntu (notice the uppercase RC in the tag)

docker pull

Then docker is able to find that image and downloads it to my local machine

2019-RC1-ubuntu: Pulling from mssql/server
59ab41dd721a: Already exists
57da90bec92c: Already exists
06fe57530625: Already exists
5a6315cba1ff: Already exists
739f58768b3f: Already exists
e39f945bda21: Pull complete
6689ce95f395: Pull complete
ec004dcfdfb5: Pull complete
e44708601d04: Pull complete
Digest: sha256:a11facbda1b1cc299d4a37499ef79cd18e38bfb8e5dd7e45cc73670cc07772e5
Status: Downloaded newer image for

Want to get a list of tags for a container image so you know what image and tags to specify? Here’s how you do that with curl.

 curl -L 

If you’re of the PowerShell persuasion (shout out to Andrew Pruski for this gem) here how you can generate a list of tags with Invoke-Webrequest


Persisting SQL Server Data in Docker Containers – Part 3

In the first two posts in this series we discussed the need for data persistency in containers then we discussed where the data actually lives on our systems. Now let’s look at specifying the location of the data on the underlying file system of the base OS. 

This is the third post in a three part series on Persisting SQL Server Data in Docker Containers. The first post introducing Docker Volumes is hereThe second post on where Docker actually stores your data is here.

Exposing Directories on the Base OS into a Container

Now what if I wanted to expose a directory from my base OS, macOS directly into the container avoiding placing my data inside the Docker Linux VM. Let’s try it and see what happens…let’s start up a container with a Docker Volume mapping /Users/demo/demos/data on the base OS into the container at /var/opt/mssql.

docker run \
    --name 'sql19dv' \
    -p 1433:1433 \
    -v /Users/demo/demos/data:/var/opt/mssql \

If we do a docker ps -a we’ll find our conainer existed with a non-zero exit code. That’s bad.

CONTAINER ID        IMAGE                                        COMMAND                  CREATED             STATUS                        PORTS                    NAMES
2f4a9efc2f89   "/opt/mssql/bin/perm…"   21 seconds ago      Exited (1) 11 seconds ago                              sql19dv

The first thing you should do when this happens is to examine the container’s logs. We can do that with docker logs sql19dv (where sql19dv is our container name) and we’ll get this output.

This program has encountered a fatal error and cannot continue running at Sun Sep  1 14:19:06 2019
The following diagnostic information is available:

         Reason: 0x00000006
        Message: Kernel bug check
        Address: 0x6b047d50
     Parameters: 0x10861f590
    Stack Trace:
        Process: 9 - sqlservr
         Thread: 13 (application thread 0x4)
    Instance Id: 866b1bc1-211d-4390-aa43-a48b32d6f78e
       Crash Id: 07c2a35d-5ddf-4e5d-ad69-a91ef0f5d0e9
    Build stamp: 228a531f7a324b94dd3127e706f889b081f5677bd368be8b30485d8edda4d02b
   Distribution: Ubuntu 16.04.6 LTS
     Processors: 6
   Total Memory: 6246559744 bytes
      Timestamp: Sun Sep  1 14:19:06 2019
     Last errno: 2
Last errno text: No such file or directory

Ubuntu 16.04.6 LTS
Capturing core dump and information to /var/opt/mssql/log...
dmesg: read kernel buffer failed: Operation not permitted No journal files were found.
No journal files were found.
Sun Sep  1 14:19:07 UTC 2019 Capturing program information
Sun Sep  1 14:19:08 UTC 2019 Attempting to capture a dump with paldumper
Captured a dump with paldumper
Sun Sep  1 14:19:11 UTC 2019 Capturing program binaries
Sun Sep  1 14:19:12 UTC 2019 Compressing the dump files

In the output above, SQL Server crashes trying to access the file inside the container that isn’t there…see the ‘Last errno text’ using strace inside the container yields the following information. 

[pid    11] lstat("/opt/mssql/lib/system", 0x7f8f15b63350) = -1 ENOENT (No such file or directory)
[pid    11] <... lstat resumed> 0x7f8f15b63350) = -1 ENOENT (No such file or directory)

Let’s Map a Different Path and See What Happens

docker run \
    --name 'sql19dv2' \
    -p 1432:1433 \
    -v /Users/demo/demos/data:/var/opt/mssql/data \

Here we’re mapping to /var/opt/mssql/data (where above we mapped /var/opt/mssql). This mapping will fail and the container won’t start but this time for a different reason.

If we look at  docker logs you’ll find the following error in from the SQL Server Error Log.

2019-09-02 18:10:15.08 Server      Error 87(The parameter is incorrect.) occurred while opening file '/var/opt/mssql/data/master.mdf' to obtain configuration information at startup. An invalid startup option might have caused the error. Verify your startup options, and correct or remove them if necessary.

Makes sense…we changed where SQL Server is reading/writing data. macOS doesn’t support a file mode called O_DIRECT which allows for unbuffered read/write access to the file opened using the open system call.  O_DIRECT is used by systems that manage their own file caching, like relational database management systems (RDBMS). So as SQL starts up and tries to open the master database with O_DIRECT the files can’t be opened because the macOS kernel doesn’t support this mode. And this is the reason why we have to have that Linux VM around. That Linux VM will support O_DIRECT option on the file opened. See more about this at the GitHub issue here.

An strace of the thread shows the following:

open("/var/opt/mssql/data/master.mdf", O_RDONLY|O_DIRECT
<... open resumed> )        = -1 EINVAL (Invalid argument)
...output omitted...
--- SIGSEGV {si_signo=SIGSEGV, si_code=SEGV_ACCERR, si_addr=0xb804b1fe8} —
...the remainder of the strace shows the creation of the SQL Server Error Log record above...

This issue is specific to macOS. On a Linux machine it would map the base OS directory directly into the container and the file operations will work because the kernel supports the correct file modes on the open system call. On a Window machine this works as confirmed by my friend and fellow MVP Andrew Pruski

But we still can use our base OS directories…really!

All isn’t lost if you’re running Linux containers on a Mac and need to run SQL Server to access the base OS’s file system. We can still use Docker Volumes for other parts of the container. Let’s create a container using TWO Docker Volumes. Let’s define sqldata1 as using the file system inside the Docker VM and we’ll define a second Docker Volume that we can use to read/write other information…like backups. 

 docker run \
    --name 'sql19dv1' \
    -p 1433:1433 \
    -v sqldata1:/var/opt/mssql \
    -v /Users/demo/demos/backup:/backup \

In this configuration our SQL instance will use sqldata1 mapped to /var/opt/mssql for its instance data directories inside the Docker Linux VM so SQL is able to open the files with the appropriate file modes. But we can still read/write information directly to our base OS in the directory /Users/demo/demos/backup which is mapped into the container at the location /backup. Backup files do not use the O_DIRECT flag.

Now let’s run a backup of our database to that location.

sqlcmd -S localhost,1433 -U sa -Q "BACKUP DATABASE [TestDB1] TO DISK = '/backup/TestDB1.bak'" -P $PASSWORD -W

And if we look at that directory on the base operating system we’ll see the databases backup outside the container. That’s cool. Now your automatic backups of your workstations can pick up that file and back it up into the cloud for you…right?

ls -la /Users/demo/demos/backup
total 6504
drwxr-xr-x  3 demo  staff       96 Sep  1 10:04 .
drwxr-xr-x  5 demo  staff      160 Sep  1 09:48 ..
-rw-r-----  1 demo  staff  3330048 Sep  1 10:03 TestDB1.bak

Let’s do something cool…

We can share that /backup volume with other containers on our system. With the container sql19dv1 still running we can start up another container, sql19dv2. We’ll need to ensure this container has a unique name, unique port to listen on and a unique Volume for the instance’s files. The only thing it’s going to share is the backup volume. This technique isn’t specific to containers macOS. This will work on Windows and Linux as well.

 docker run \
    --name 'sql19dv2' \
    -p 1432:1433 \
    -v sqldata2:/var/opt/mssql \
    -v /Users/demo/demos/backup:/backup \

With this container running we can execute a RESTORE statement on the backups that are on the base OS at /Users/demo/demos/backup and mapped into the container at /backup. This technique can be effective if you’re using larger data sets avoiding having to copy the backup into the container with docker cp. 

sqlcmd -S localhost,1432 -U sa -Q "RESTORE DATABASE [TestDB1] FROM DISK = '/backup/TestDB1.bak'" -P $PASSWORD -W
Processed 392 pages for database 'TestDB1', file 'TestDB1' on file 1.
Processed 2 pages for database 'TestDB1', file 'TestDB1_log' on file 1.
RESTORE DATABASE successfully processed 394 pages in 0.026 seconds (118.239 MB/sec).

Wrapping things up 

In this post, we introduced being able to map a file location from the base OS into a container and use it for reading and writing data, in our examples backup files. This could be any type of data. We also learned that for SQL Server data files we still need to use the Docker Volume that’s serviced by the Linux container. We also learned how we can share a Docker Volume between containers a quick way to move backups and other data between containers without having to use docker cp

This technique isn’t specific to containers macOS. This will work on Windows and Linux as well.

Persisting SQL Server Data in Docker Containers – Part 2

So in my previous post, we discussed Docker Volumes and how they have a lifecycle independent of the container enabling us to service the container image independent of the data inside the container. Now let’s dig into Volumes a little bit more and learn where Docker actually stores that data on the underlying operating system.  

This is the second post in a three part series on Persisting SQL Server Data in Docker Containers. The first post introducing Docker Volumes is here. And the third post on mapping base OS directories directly into containers is here.

Docker Volumes

When we working with Docker Volumes we can use the -v option to create the Volume at the time the container is created or we can create the Volume ahead of time with the docker volume create command. The left side sqldata1 is the Volume name. The right side /var/opt/mssql is the directory the Volume will be mapped to inside the container. 

We can specify the location of the Volume on the underlying OS but if we don’t it will be created in the default location defined in your Docker preferences which is /var/lib/docker/volumes. Let’s go with the default location for now…we’re going to cover specifying locations in an upcoming post.

docker run \
    --name 'sql19' \
    -p 1433:1433 \
    -v sqldata1:/var/opt/mssql \

On a system where Linux is the base OS running Docker the container runtime will create Volumes on the base OS’s file system and map them into the container. So as we create Volumes, they will land in /var/lib/docker/volumes when using the code above that doesn’t specify a specific file location on the base OS. Well, /var/lib/docker/volumes is quite a Linux’y sounding path and if I try to browse to that path on my Mac or Windows it doesn’t exist. OK, I don’t have a Windows system but I think it’s a safe bet that’s not there either :)

Let’s use the inspect command to get more information on a Docker resource and here we’re using docker volume inspect on sqldata1.

docker volume inspect sqldata1
        "CreatedAt": "2019-09-01T11:51:25Z",
        "Driver": "local",
        "Labels": null,
        "Mountpoint": "/var/lib/docker/volumes/sqldata1/_data",
        "Name": "sqldata1",
        "Options": null,
        "Scope": "local"

In the output here we can see the Mountpoint, which is where the data lives on the underlying OS, as /var/lib/docker/volumes/sqldata1/_data that’s where Docker put the Volume since I didn’t define a path it put the Volume data in the default location of /var/lib/docker/volumes…but like we said a second ago that path doesn’t exists on my local filesystem…what’s going on?

Docker Volumes on non-Linux Operating Systems

Docker on Mac (and Windows uses the same technique for now) exposes a small Linux VM to provide kernel services to Linux containers. When we create a Docker Volume without specifying a file location for the Volume it will be created *inside* this VM. So that’s where our Volume data is stored. Let’s keep digging…

Using the technique defined here we can get a shell into that Virtual Machine and browse the file system to find the actual data files. Here’s how you attach a shell to the Docker VM.

screen ~/Library/Containers/com.docker.docker/Data/vms/0/tty

Now let’s decompose this command below a bit…screen is a command used to attach a shell to a process, the path (~/Library/Containers/com.docker.docker/Data/vms/0/tty) is the default disk image path defined in your Docker preferences. And the file tty is a process running that exposes a shell interface to the running VM supporting our Linux containers. Everything in Linux is a file, so that tty is actually a terminal process inside the VM that’s exposed outside the VM on your base operating system’s file system. Screen will ‘open’ that file and start to read from it…since it’s exposes a terminal you get a shell into the VM. 

Now that we’re inside the VM let’s look around and see where our Volume data lives, we see all of the actual SQL Server file data supporting the instance and the databases and log files.

ls /var/lib/docker/volumes/
metadata.db sqldata1

In the directory listing above we’ll see a directory for each named Docker Volume in this case we see sqldata1.

ls /var/lib/docker/volumes/sqldata1/_data/
data     log      secrets

Inside of sqldata1, we will start to see the directories and files created by SQL Server in the Docker Volume. Remember SQL Server thinks this is /var/opt/mssql because this path is being mapped into the container at that location.  

ls /var/lib/docker/volumes/sqldata1/_data/data/
Entropy.bin                     model.mdf
MS_AgentSigningCertificate.cer  modellog.ldf
TestDB1.mdf                     msdbdata.mdf
TestDB1_log.ldf                 msdblog.ldf
master.mdf                      tempdb.mdf
mastlog.ldf                     templog.ldf

And if we look inside the data directory we’ll see system and user databases. 

What’s Next? 

So now that we know where Docker Volume data lives when running Linux Containers on a Mac (this same technique applies to Windows too), in our next post we’re going to go a little bit further into this and define a specific location for Docker to store our data on the base OS.

Persisting SQL Server Data in Docker Containers – Part 1

What’s the number one thing a data professional wants to do with their data…keep it around. Let’s talk about running SQL Server in Containers using Docker Volumes on a Mac

This is the first post in a three part series on Persisting SQL Server Data in Docker Containers. The second post on where Docker actually stores your data is here. And the third post on mapping base OS directories directly into containers is here.

The Need for Data Persistency in Containers

A container image is read-only. When an application changes data inside a running container writes are written to a writable layer. The writable layer plus the read-only container image are brought together by the container runtime and presenting to the processes running inside the container as a single file system. 

The primary issue with this is that the writeable layer has the lifecycle of the container. If you delete the container, you delete the writeable layer and any data that was in there. Luckily Docker containers give us a way to decouple the container and its data.

In Figure 1, you can see a container image and it’s writeable layer. The application inside the container sees this has a single file system. If we delete this container, any data written to the writeable layer will be deleted too. 


Figure 1: A container and it’s writable layer

Docker Volumes

A Docker Volume is a Docker managed resource that is mapped into a defined point in the filesystem inside the container. The primary benefit of using Docker Volumes is that they have a lifecycle that’s independent of a container. This enables you to decouple your application from its state to the point where you can simply throw away the container and replace it with a new container image start up your application and point it to your data.

In Figure 2, we have a container, a writeable layer and a volume. A container will always have a writeable layer even when a Volume is defined. A Volume will be mounted at a specific location in the file system inside the container and writes to that location will be written to the Volume. Writes to other parts of the file system will be written to the writable layer. 


Figure 2: A container, it’s writable layer and a Volume

SQL Server using Docker Volumes

Let’s talk about how we can use Docker Volumes and SQL Server to persist data. If we want to run SQL Server in a container we will want to decouple our data from the container itself. Doing so will enable us to delete the container, replace it and start up a new one pointing at our existing data. When running SQL Server in a container will store data in /var/opt/mssql by default. When the container starts up for the first time it will put the system databases in that location and any user databases created will also be placed at this location by default. 

Now, if we don’t use a Volume that data will be written into the writeable layer of the container and if we delete the container…we delete our data. We don’t want that so let’s start up a container with a Volume. To do so we use the -v option when we use the docker run command. 

docker run \
    --name 'sql17' \
    -p 1433:1433 \
    -v sqldata1:/var/opt/mssql \

In the code above you can see –v sqldata1:/var/opt/mssql specified as part of the docker run command. This creates a Docker Volume sqldata1 and maps that inside the container to /var/opt/mssql. Now during this container’s start up when SQL Server will write its data to /var/opt/mssql which is actually going to be written to the Volume. If we delete this container and replace it…when SQL Server starts up it will see the master database and proceed initializing the system as defined in master. If there are any user databases defined in master and they’re accessible they will be brought online too. Let’s try it out…first up let’s create a user database and query the file information about the databases in this container.

sqlcmd -S localhost,1433 -U sa -Q 'CREATE DATABASE TestDB1' -P $PASSWORD

sqlcmd -S localhost,1433 -U sa -Q 'SELECT name, physical_name from sys.master_files' -P $PASSWORD -W

name physical_name
---- -------------
master /var/opt/mssql/data/master.mdf
mastlog /var/opt/mssql/data/mastlog.ldf
tempdev /var/opt/mssql/data/tempdb.mdf
templog /var/opt/mssql/data/templog.ldf
modeldev /var/opt/mssql/data/model.mdf
modellog /var/opt/mssql/data/modellog.ldf
MSDBData /var/opt/mssql/data/MSDBData.mdf
MSDBLog /var/opt/mssql/data/MSDBLog.ldf
TestDB1 /var/opt/mssql/data/TestDB1.mdf
TestDB1_log /var/opt/mssql/data/TestDB1_log.ldf

In the code above we create a database, when query master for the information about the databases running inside this container. You can see all of the paths are /var/opt/mssql which is our volume. 

Container and Data Independence

The Docker Volume created with the -v option created a Docker managed Volume that is independent of the container so our data will live in there and we can service the container independent of the volume. So let’s do that…let’s delete the container and start up a new container and let’s go so far as to use a 2019 container to upgrade SQL Server…that’s cool!

docker stop sql17
docker rm sql17

The code above will stop and then delete the container. When the container is deleted, so is its writeable layer. But we are storing out data in the Volume and that still exists.

docker volume ls
local               sqldata1

Above we can see there is a Volume using the local driver and its name is sqldata1…this still exists and can be mounted by new containers. The local drive is used to map directories from the base OS inside the container. There are other types of drivers that expose other types of storage into the container. More on this later.

docker run \
    --name 'sql19' \
    -p 1433:1433 \
    -v sqldata1:/var/opt/mssql \

With this code, we start up a new container and tell it to use the same Volume and mount it into /var/opt/mssql. So when SQL Server starts it finds the master database, master has the metadata about any configuration and user databases and we get back into the state we were previously in. Let’s ask SQL Server for a list of databases.

sqlcmd -S localhost,1433 -U sa -Q 'SELECT name, physical_name from sys.master_files' -P $PASSWORD -W

name physical_name
---- -------------
master /var/opt/mssql/data/master.mdf
mastlog /var/opt/mssql/data/mastlog.ldf
tempdev /var/opt/mssql/data/tempdb.mdf
templog /var/opt/mssql/data/templog.ldf
modeldev /var/opt/mssql/data/model.mdf
modellog /var/opt/mssql/data/modellog.ldf
MSDBData /var/opt/mssql/data/MSDBData.mdf
MSDBLog /var/opt/mssql/data/MSDBLog.ldf
TestDB1 /var/opt/mssql/data/TestDB1.mdf
TestDB1_log /var/opt/mssql/data/TestDB1_log.ldf

…and there you can see in the output above, SQL Server is in the state it was in the initial running of the container on the 2017 image. Now we’re on the 2019 image and have access to all of our persisted data independent of the container image. 

sqlcmd -S localhost,1433 -U sa -Q 'SELECT @@VERSION' -P $PASSWORD
Microsoft SQL Server 2019 (RC1) - 15.0.1900.25 (X64)
        Aug 16 2019 14:20:53
        Copyright (C) 2019 Microsoft Corporation
        Developer Edition (64-bit) on Linux (Ubuntu 16.04.6 LTS)                                                                                                                       

Containers have replaced virtual machines for me and the decoupling of data and computation will have a significant impact on how we design data platforms and systems going forward. In this post, I wanted to highlight how you can use a container with persistent state systems like SQL Server. In the next post, I’m going to show you where that data actually lives on the underlying Operating System.

Speaking at SQL Saturday Dallas

Speaking at SQLSaturday Dallas!

I’m proud to announce that I will be speaking at SQL Saturday Dallas on May 17th 2018! This one won’t let you down! Check out the amazing schedule!

If you don’t know what SQLSaturday is, it’s a whole day of free SQL Server training available to you at no cost!

If you haven’t been to a SQLSaturday, what are you waiting for! Sign up now!

My presentation is Practical Container Scenarios in Azure” 


Here’s the abstract for the talk

You’ve heard the buzz about containers and Kubernetes, now let’s start your journey towards rapidly deploying and scaling your container-based applications in Azure. In this session, we will introduce containers and the container orchestrator Kubernetes. Then we’ll dive into how to build a container image, push it into our Azure Container Registry and deploy it our Azure Kubernetes Services cluster. Once deployed, we’ll learn how to keep our applications available and how to scale them using Kubernetes.

Key topics introduced
Building Container based applications
Publishing containers to Azure Container Registry
Deploying Azure Kubernetes Services Clusters
Scaling our container-based applications in Azure Kubernetes Services