How to be Dangerous with Docker as a Data Scientist
By: Kyle Stahl
Tags: Getting Started, Data Science, Docker

How to be Dangerous with Docker as a Data Scientist

Docker is going to allow you to package up and deploy your data science solution anywhere (typically moving into the cloud). It can be a vital tool in the data science tool bet to move data science work from theory & research into practice & value-add for your business.

What is Docker?

Click here for the boring, formal definition from Wikipedia. Then move onto my description below.

Docker lets you bundle up everything that your code needs to run in a completely reproducible environment that is easy to bring to other machines (like running it in the cloud). Docker (and container management systems like Kubernetes) isolate these bundles from each other. This brings added reliabililty and security because if my code gets hacked or breaks down, it will not affect your code.

So… is Docker like a virtual machine?

Yes, kinda. People who know a lot about docker on the internet will tell you it’s actually not like a virtual machine because of some confusing computer mumbo-jumbo. Nonetheless, it is a useful analogy to draw. You can run multiple different, completely isolated apps on the same computer. With VM’s you have the whole operating system for each new application; while with docker you only bring what you need. This is what makes it lightweight, scalable, and even more secure.

The architecture difference between Docker and VMs

What you need to know to get started

Terminology

Popular Dockerfile steps

Common CLI commands

Terminology

Dockerfile

This is just a text file that contains specific instructions for building docker images. Some common things you do with this file include: specifying the base image, copying the required files, defining environment variables, installing third-party packages, and writing the default command that will be run when containers are launched from that image.

Image

An image is created from Dockerfiles and used to create Docker containers. Images are generally stored in a repository like Dockerhub (public), Elastic Container Registry (AWS), and Artifactory (other).

Container

This is where work actually gets done. Creating a new container will run your code. Some docker containers are built to run for a certain period & shut down afterward (like a training job or data processing job); others are launched and stay up forever (like web services, API endpoints, web app dashboards).

If your are familiar with Object-Oriented program, an “image” is like a class definition, while a “container” is an instance of that class. Once you have a class definition, you can create as many instances of that class as you want.

Registry

Think of a GitHub repository, but for Docker images. You can work locally on Dockerfiles to create images. Once you are done developing those images you can push them to a registry where they will launch containers, or other people can use it as a base image for their projects.

Entrypoint

This is the CLI command that is run whenever a container is launched from an image. It is usually specified by the ENTRYPOINT or CMD step at the end of your Dockerfile, or inherited from your base image. You want this command to kick off whatever script or code is needed to accomplish your task. (read more)

Tag

This is a way to name versions of images. This is useful to track the version history of an image over time (similarly to how git tags commits); or just to have an easy name used to reference that image. (read more)

Base Image

This is the starting point of a docker image, usually defined in the FROM statement of the Dockerfile. There is a base image for almost everything. Any image can be a base image for another image, as long as it is accessible from a registry. The most basic of base images is just an operating system.

Some possibly useful of Base Images:

Popular Dockerfile Steps

FROM

This command is in every Dockerfile. It defines the base image you will build upon. You must have access to the registry that contains the base image.

COPY

This will copy files from your local machine (or where-ever you are building the image) to the docker image (and ensuing containers). The files should be relative to the current working directory that you are building the docker image from.

ENV

This sets OS environment variables for your docker containers * Note: Use this instead of RUN export . (here's why)

RUN

This will run OS CLI commands. Usually, this is done to edit the base file system or install third-party packages.

WORKDIR

Sets the starting directory from which your ENTRYPOINT or CMD will be executed.

ARG

Allows you to pass arguments into your Dockerfile through the docker build command.

EXPOSE

This exposes a port that can be accessed by the world through the machine the container is running on. If you have a web app, dashboard, or API endpoint then you need to expose a port. Many times this already is done by your the Base Image.

ENTRYPOINT or CMD

The CLI command that will run when a new container starts up. This should invoke all the other things that you want the docker container to do.

The difference between ENTRYPOINT and CMD is that CMD can be overwritten, while ENTRYPOINT cannot be overwritten. (read more)

ENTRYPOINT will run no matter what. CMD can either be run on its own or be used to add extra parameters to ENTRYPOINT. CMD will specify some default value to be run when the container launches, but that parameter or command can be overwritten though docker run .

Common CLI commands

Docker build commands

The simplest version is to just build the Dockerfile in the current directory:

docker build .

The next thing you might want to do is add a tag (registry & version name):

docker build -t localRegistryName:TagName .

Then maybe you want to pass in some arguments into your Dockerfile with ARG :

docker build \

-t localRegistryName:TagName \

--build-arg DEPLOY_ENV=dev \

.

Another option for complex applications, you might hide your Dockerfile in a folder, or want to copy some files from a parent directory. You can specify -f as a path to your Dockerfile.

docker build \

-t localRegistryName:TagName \

--build-arg DEPLOY_ENV=dev \

-f path/to/the/Dockerfile \

.

Docker run commands

The simplest way to run a container from an image:

docker run localRegistryName:TagName

Port Mapping

One thing you’ll have to do when testing containers locally is to map the port that is exposed for your dashboard or endpoint to your local machine:

docker run -p PORTNUM:PORTNUM localRegistryName:TagName

Note: the first PORTNUM is the port on your local machine that you want to map to, the second PORTNUM is the exposed port from the docker container that you want to view. The port numbers can be different, but that just makes things confusing.

Debugging with Bash

Another thing you might want to do is explore your container with the CLI. You can do this to inspect things like: Is my code files being copied correctly? Are the environment variables correctly defined?

docker run -it localRegistryName:TagName /bin/bash

Note: For this to work, a few things need to be true. 1) your image needs to have bash installed. So this wouldn’t work on a windows container. 2) You need to use CMD instead of ENTRYPOINT. the /bin/bash is there to override the CMD when the docker container starts up. An ENTRYPOINT will still run and block your attempt to run bash.

Miscellaneous

You can easily list all your current images or running containers with:

docker image ls

docker container ls

You might forget to tag an image, or you just want to add another tag. You can add a tag to an image by referencing other tags or it’s IMAGE ID. (IMAGE ID can be found by listing all images)

docker tag OldRegistry:OldTag NewRegistry:NewTag or

docker tag b25r13lkj89 NewRegistry:NewTag

You can stop containers that are currently running by:

docker stop ContainerName or docker kill ContainerName

Cleaning up your system

There are different ways to remove old images to clean up your workspace.

docker rmi RegistryName:TagName will remove 1 image

docker system prune will delete all images that are untagged & not associated with a running container

docker system prune -a will delete everything

Conclusion

Docker has a steep learning curve for many data scientists, but once you get over that curve you drastically improve your ability to productionalize your work.

Thanks for reading!

Let me know in the comments if there is anything I should add or change, feedback is welcome!