You have read the documentation. And again, after marvelous promises, incredible descriptions, you know nothing. Back to square, still drawing a blank.
The “Ok, but… what is it?” series tries to answer questions on products and libraries honestly, without your so-beloved catchy slogans. And it does so on three different levels of complexity.
Yes, we are talking about Docker. And no, no Pods, or Clusters, that’s Kubernetes.
This is the official answer:
We help developers and development teams build and ship apps.
Docker is many things, and unfortunately you will see this term used to mean all of them. Let’s get it sorted.
Level  — The Baker (Simple — I just want a grasp)
Level  — The Code (Intermediate — I want the basics)
Level  — The Engineer (Detailed — I have the right background)
 The Baker — Run once, run everywhere
Docker lets you package a software to respect this philosophy: “run once, run everywhere”. Well, it is not magical on its own, but it is a good way to force you to do everything you should to make this happen.
Imagine a pastry chef has to make a cake.
Yes, same old metaphor, but with a grain of difference.
That chef has to bake on a remote, unknown island.
And you have to make sure he/she can.
The chef will be gracefully shipped to the island in a giant box, along with all the things he/she needs. You have to fill the box.
Ok, let’s start with a TO-DO list.
Well, of course we’ll need some eggs, flour, sugar… and all the rest. And the recipe. That’s perfect. Good.
Are we done?
Oh, yes, cups and bowls to mix the ingredients. And also the spoons, whisks, the flan pan… and the kitchen scale.
But is it a desert island? We’ll need an oven! And a timer.
…Wait, we’ll need an electric generator too, with its fuel!
Uh, right, the chef! Good luck!
A lot of things, right?
So, in this metaphor, you are the programmer.
The chef is the code, performing a task.
The island is the machine (computer, server…) where the code will run.
You have soon acknowledged that code on its own is useless without all the tools it requires to run. Sorry, chef.
You need a certain Operating System, some libraries, files in the right positions… Yes, you could manually and separately configure them on the target machine. Or, simply, you could use Docker to pack them together in an image, deliver it to the server and forget about the rest. Well, at least that machine should have Docker installed, to interpret the packaging, but that’s very easy to remember.
The box where you put everything is the Docker image. When this image needs to run, a Docker container is created from it. The image is at rest, the container is at runtime. Terminology.
Does it matter now what is the island, what resources it has already? Of course not. You can ship the box anywhere, and you will have everything you need, whether you want to make a cake in Honolulu or Rapa Nui.
That’s what Docker primarily is: an application to package and run software everywhere.
 The Code — A Dockerfile to rule them all
Do you remember the TO-DO list we prepared for the pastry chef? That’s the Dockerfile. It is the sequence of operations to be performed to start (almost) from scratch and collect all the requirements for an application.
Does it remind you of something? Of course it does. When you want to run an algorithm, you write the proper code to accomplish your task.
This is the same. You write the sequence of steps to achieve your goal — preparing the environment to run your application.
Nothing new. You are just automating a task.
It is a way to code the required configuration for a program.
Yes, we, software engineers, like to code and automate everything. Even if it means to stack layers of code upon layers of code.
Actually, particularly if it means so.
It goes this way:
1. You write a Dockerfile;
2. You build the Docker image using the Dockefile;
3. You move your Docker image where you need it;
4. You instantiate a running Docker container from that Docker image.
This is an example of Dockerfile, so that we can understand it better. It is a Dockerfile to run a Python application.
No worries, you don’t have to know Python.
FROM python:3.7.4-slim# Pre-install requirements
COPY requirements.txt .
RUN pip install -r requirements.txt# Prepare package installation copying sources
COPY setup.py .
COPY package package/# Install the package
RUN pip install .# Define the default command to be run when running a container
ENTRYPOINT ["python", "-m", "package"]
You can see several kinds of instructions. These are the very basic ones.
Every instruction is a step, executed one after the other when we build the Docker image using this Dockerfile.
Docker is smart enough to let you start not from scratch, but something more. In this case, we are using a pre-built Docker image as a starting point that is publicly available on DockerHub.
This image already has Python (along with Pip, the package manager to install dependencies). Handy!
Otherwise, we should have installed Python manually. Not a tragedy, but still.
COPY requirements.txt .
This is to copy a file or a folder that is in your filesystem to a specific directory inside the Docker image. The syntax is simple: first the source, then the destination.
As you can see, we are copying the file with the list of requirements into the Docker image. By default, the path is relative to the folder where you run the Docker build command.
Then, we are using the “.” to mean the working directory in the Docker image.
RUN pip install -r requirements.txt
This is to run a shell command inside the Docker image, to modify it. Well, sort of, but you asked for an intermediate answer!
In this case, we are installing all the requirements listed in that file.
Did you notice? We are using now the file that is inside the Docker image! Its path is relative to the image’s working directory.
We couldn’t have run this command without having copied the file first.
…Then we copy the source code of our package, which is in the package folder to avoid any where-has-my-package-gone panic, we install it in the image and then…
ENTRYPOINT ["python", "-m", "package"]
We define the default command to be run when we create a container from this image. In this case, we’ll run the main of our package.
That’s it! Now we could execute the Docker build to make the image.
In this way, we have packaged everything, once and for all, and now we just have to carry our image (the box in the previous metaphor) in the right place, then run it as a container.
A command like docker run. And nothing else.
But stop, too much code. Stop.
This is a What is Docker, not a How to use Docker.
And the answer is “an application to package your requirements and code in a image, once, and then run it countless of times and everywhere easily”.
It’s like a brute force approach. We stick everything we need, once and for all, so that we do not worry anymore, anywhere else. No need to re-download the requirements, re-install the package or Python itself.
 The Engineer — Virtualization
I know you are there.
I can sense you. You are the system engineer. This seems just black magic to you. You want to know what is really happening. What Docker really is.
Docker is a lightweight virtualization tool. Do you remember the old-fashioned virtual machines? We are close. The concept is similar.
Docker simulates an Operating System, along with a file system, on top of another one. VMs simulate hardware instead, so they must have an entire OS in them. That’s why Docker images are lighter.
A Docker image is a precise snapshot of an OS, with its file system (and files). A Docker container is a sort of little virtual machine whose specifications are the ones of the image, in which a process is running. It might be the default process specified by the ENTRYPOINT instruction or it might be another. The point is the same: a container runs as long as that process runs.
Just like a real virtual machine (sorry, not sorry), the Docker container is by default isolated from the hosting OS. You cannot reference files in the host, for instance, or write there.
However, with a proper configuration, you can map ports (linking a real port in the hosting OS to a port of the container) or mount volumes (to read from or write to the real file system). In this way you can run a web application or a general algorithm, maybe a test or a build that has to output a result, and see it from the outside.
You can do what you want. You could also, for instance, run an interactive bash. In that case, it would be as if you were connecting to a remote machine, but a virtual one, where you can execute “manual” commands in a pre-configured environment (specified by the image).
Oh, and just a final note. Because I know that some of you are thinking about this.
Yeah, yeah, magnificent and all, but what about executables? What about compiled programs? They do run as standalone applications without Docker.
That’s true. Some programs can run without any other dependency. But things may get harder in case you need configuration files or use interpreted languages, or external, heavy libraries, DLLs, environment variables, whatever-you-want.
Docker lets you run your application everywhere without a README with the tedious “get this driver installed”, “move in this folder and run that”, “pray that it works”.
Also, you can run this application on your PC, then on Google Cloud, or maybe AWS, or on your super-secret server in your private network. All with a blink of an eye.
If you think about it, it is also a good way to pseudo-document all the steps required for your application to work. That’s because you are forced to write down all the instructions and operations you have to perform to make it happen. Win-win.
You can also spawn many containers starting from a single image, with possibly different processes. Maybe you have built an image with all the libraries you need, and then you have to run several different tasks separately, but requiring the same dependencies. Or you have to replicate your microservice… but that’s another world. Docker is also an orchestrator for containers, if you want, although usually other solutions like Kubernetes are employed. However, they are based on Docker technology anyway.
So, dear engineer, what is Docker?
Many things. It is an application to build portable code boxes, it is an orchestrator for containers, it is a lightweight virtualization tool. When you read “Docker”, the meaning of this word is usually one of these.
And to mess it up, you can also hear, improperly, “I’ve built a docker”, meaning a Docker image, or “Run that docker”, meaning a Docker container.
I hope this clarifies a bit instead.