Introduction
There are multiple ways to interact with the Docker daemon, as the command line client API or GUI based tools like Kitematic. Docker also provides an SDK for Go and Python. This SDK can be used to create and manage Docker containers the same way it works with the Docker engine API.
In this article, I will show you how to use Docker’s SDK for Python to create and manage SQL Server containers.
Requirements
- Have Python v3 installed, along with its package manager.
- Use of a strong IDE for writing and running the Python code. Visual Studio Code is the obvious choice in my case although you can use your computer's native terminal in case you prefer.
- Have the Docker engine installed and started.
Installation
First thing first, let’s begin by installing the Python library for the Docker Engine API. Open a new terminal on your local machine. From there, we will invoke the package manager for Python (PIP) to install the Docker library as follows:
[dba mastery] $ pip3 install docker
Once the installation of the Docker library is complete, we are ready to start using Python to interact with our Docker engine. This library allows us to interact with the following Docker objects:
- Client
- Configs
- Containers
- Images
- Networks
- Nodes
- Plugins
- Secrets
- Services
- Swarm
- Volumes
Importing the Docker library
Using Docker’s SDK library in Python is not any different than using any other existing library. You just import the library at the beginning of your code, as shown here:
import docker client = docker.from_env()
Note that a variable called client is used to instantiate a client connection. In this case, it will connect to the default socket in my environment. But it can also be used to connect to a remote client by passing parameters to the docker.from_env method.
Using Docker library
The Docker SDK for Python offers many methods and classes that will be difficult to cover them all in this article. I recommend that you check the documentation here.
The scope of this article is to show you a few examples about how to manage SQL Server Docker containers the same way we do with the command line client, these are the list of methods \ classes I will be working with:
- Images:
- Pull
- List
- Containers:
- List
- Status
- Run
- Stop
- Start
- Remove
Based on the list above, I think the best way to show demonstrate how to use all these methods \ classes is completing a container life cycle.
Container life cycle
Containers are ephemeral, they are created one day and the next day stopped or even destroyed to be rebuild from a recent version of the image that includes minimal changes in the configuration of the same. For this reason, is important to become familiar with the Docker client command line. The better we learn and understand how to interact with the Docker daemon the faster will become developing, shipping and running applications.
The life cycle of a container starts identifying the base image version we want to use for our application. In the specific case of SQL Server, we can get that information from Docker Hub. Choosing the image version (tag) from the list provided on this image repository but querying this list manually every time you need to create a container could be a little bit inconvenient.
Let's begin using Python to help us with this process.
Listing MCR available images
Docker’s HTTP API V2 provides a GET method that can be used to return the complete list of images for a known repository. I will use the requests.get to return the list of all available images of SQL Server hosted in MCR (Microsoft Container registry) using this URL: https://mcr.microsoft.com/v2/mssql/server/tags/list.
The following Python block code will not use the Docker library from the SDK although I will use the native requests library from Python. The request library allows us to use HTTP methods such as GET and POST, in our case we want to GET the contents of a specific URL.
This is what is going to happen, the requests.get method will receive the MCR URL as a parameter and will send a response back. This response object in this example is called mcr_images which contains the list of available SQL Server images for Ubuntu that will be displayed on the screen as JSON format:
import requests mcr_ubuntu_images = requests.get('https://mcr.microsoft.com/v2/mssql/server/tags/list/') mcr_ubuntu_images.json()
The JSON output returned should look like this:
{'name': 'mssql/server', 'tags': ['2017-CU1-ubuntu', '2017-CU10', '2017-CU10-ubuntu', '2017-CU11', '2017-CU11-ubuntu', '2017-CU12', '2017-CU12-ubuntu', '2017-CU13', '2017-CU13-ubuntu', '2017-CU14', '2017-CU14-ubuntu', '2017-CU2-ubuntu', '2017-CU3-ubuntu', '2017-CU4-ubuntu', '2017-CU5-ubuntu', '2017-CU6-ubuntu', '2017-CU7-ubuntu', '2017-CU8-ubuntu', '2017-CU9-ubuntu', '2017-GA-ubuntu', '2017-GDR-ubuntu', '2017-latest', '2017-latest-ubuntu', '2018-CTP20', '2018-CTP20-ubuntu', '2019-CTP2.0', '2019-CTP2.0-ubuntu', '2019-CTP2.1', '2019-CTP2.1-ubuntu', '2019-CTP2.2', '2019-CTP2.2-ubuntu', '2019-CTP2.3', '2019-CTP2.3-ubuntu', '2019-CTP2.4', '2019-CTP2.4-ubuntu', '2019-CTP2.5', '2019-CTP2.5-ubuntu', '2019-latest', 'latest', 'latest-ubuntu', 'vNext-CTP2.0-ubuntu']}
As you can see, each image listed above has a unique name called a tag. This tag is used to self-describe each image. It consists of a three-part name composed as follows:
SQL Server Version – build number – operating system
Starting from SQL Server 2019, Microsoft also offers a RedHat based image. Let's do the same we did to list the Ubuntu-based images but this time using the corresponding URL for RedHat:
import requests mcr_rhel_images = requests.get('https://mcr.microsoft.com/v2/mssql/rhel/server/tags/list/') mcr_rhel_images.json()
The JSON output returned should look like this:
{'name': 'mssql/rhel/server', 'tags': ['2019-CTP2.0', '2019-CTP2.1', '2019-CTP2.2', '2019-CTP2.3', '2019-CTP2.4', '2019-CTP2.5', '2019-CTP3.0', '2019-latest', 'vNext-CTP2.0']}
That's it with only three lines of code we got the complete list of available SQL Server images for Ubuntu and RedHat in a matter of seconds. From now on, I will work with the last image available of SQL Server 2017 running on Ubuntu identified by the "2017-CU15-ubuntu" image tag.
Pulling an Image
Now that we have decided we want to create our container based on the image tag "2017-CU15-ubuntu" let's use this information to pull this image. Here is how the example using Python:
client.images.pull('mcr.microsoft.com/mssql/server:2017-CU15-ubuntu') <Image: 'mcr.microsoft.com/mssql/server:2017-CU15-ubuntu'>
As you can see the pull command has returned the image name, that is our indicator that the image with the tag "2017-CU15-ubuntu" was pulled successfully from Microsoft Container Registry (MCR).
Listing Local Images
The next step in the container life cycle is to make sure the image I just pulled exists in my local repository. I will use the list method for this purpose, which will return the complete collection of the existing images on my local repository regardless when these images were pulled into my local repository:
client.images.list() [<Image: 'mcr.microsoft.com/mssql/server:2017-CU15-ubuntu'>, <Image: 'mcr.microsoft.com/mssql/server:2017-CU14-ubuntu'>, <Image: 'mcr.microsoft.com/mssql/server:2017-CU13-ubuntu'>, <Image: 'mcr.microsoft.com/mssql/server:2017-CU12-ubuntu'>, <Image: 'mcr.microsoft.com/mssql/server:2017-CU11-ubuntu'>]
As you can see the list method returned the complete list of all existing images in my local repository, not just the latest. The SQL Server 2017 CU11, Cu12, Cu13, CU14 images already existed before I started to work on these examples using the SQL Server 2017 CU15 image.
Conclusion
In this first part of this article, we learned how to install the Docker SDK for Python libraries. We also did a summary of a container lifecycle. Because it is very important to understand this cycle in order to manage containers properly, also important for the development of this article where we will have an example by phase.
In the second part, I will continue using Python to finish the container lifecycle creating a container, check its status to finally stop it and remove it.