Unlike a full virtual machine, a Docker image must have the same OS kernel as its host operating system. But that’s it. It comes with the rest of the operating system, along with the libraries and dependences for whatever app or tool is on the image. But because it shares the host system kernel, it is much smaller and takes less time to build than it otherwise would.
I figure the best way to learn Docker is to play around with it. So let’s do that.
There are a ton of people out there using Docker for all kinds of projects. So instead of writing your own Dockerfile from scratch to define your Docker image, you can just grab somebody elses. For instance, maybe you want to use MongoDB, chances are the Mongo team will have a publically available MongoDB image/Dockerfile that you can just download and poof, you have a MongoDB up and rolling.
There are a couple of options here. First, you can go to Docker Hub and look around for an image. Or, if you’re more of a commandline person, you can use the terminal:
$ docker search mongodb NAME DESCRIPTION STARS OFFICIAL AUTOMATED mongo MongoDB document databases pr 5958 [OK] tutum/mongodb MongoDB Docker image – listen 226 [OK] bitnami/mongodb Bitnami MongoDB Docker Image 85 [OK] ...
Or, let’s say you’re interested in machine learning, maybe you want to play around with Tensorflow, but you want to skip all the installation steps and jump straight to trying out the new tool:
$ docker search tensorflow NAME DESCRIPTION STARS OFFICIAL AUTOMATED tensorflow/tensorflow Official Docker 1431 jupyter/tensorflow-notebook Jupyter Notebook 145 ...
There is one thing the commandline doesn’t give you here, and it’s versions. For instance, if you want the latest version of Mongo, you just do:
$ docker pull mongo
But if you are building a production system, you probably don’t want to just grab whatever is the “latest and greatest” version of MongoDB. You probably want to grab a specific version you have tested against. As far as I can tell, the Docker CLI
search command does not allow you to see all the version tags of an image. But if you go through the website (Docker Hub), you can see all the tags available, so you can pull exactly the version you want:
$ docker pull mongo:4.1-bionic
Docker comes with a powerful commandline tool. Obviously, if you type
docker on the commandline you get a big list of commandline keywords. So once you know how to use Docker, that will be super helpful. It is probably not as helpful for beginners though.
Let’s not try to cover every last feature of the CLI. Let’s just cover the basics so we can start using Docker.
We’ve already seen the
docker search command. It lets you look for images other people have made. So, if all you need is an empty database or a fresh operating system. Boom. You can find that image in no time.
Again, I find the web interface more helpful than the CLI, because it lets me see detailed information on the versions/tags of each image available.
I like that Docker Hub shows the images that are “official” and created by the original project team. That’s super handy. If security is a major concern, you probably shouldn’t go with any image that isn’t “official”.
If you found an image on Docker Hub that you want, you just need to “pull” it:
$ docker pull mongo
If you want to pull a particular version of that image (which I would recommend), you can specify it with a colon:
$ docker pull mongo:4.1-bionic
Okay, at any point you may want to check and see what images you have downloaded onto your system. Maybe just to check if your last pull is done, or maybe to remind yourself of what you did last week.
$ docker images REPOSITORY TAG IMAGE ID CREATED SIZE hellokube v1 e65265fb1572 24 hours ago 109MB nginx latest 719cd2e3ed04 5 days ago 109MB mongo 4.1-bionic 70ce1153b5d7 2 weeks ago 365MB
Here you can see I have three images downloaded onto my laptop.
In Docker speak, you can see above that I have one “image” of MongoDB. That is, I have one copy of everything I need to run a fresh, empty MongoDB on my local system. But I might want three Mongo databases running on my system (on three different ports), because I am currently working on three different projects. I could
docker run this image three times and mount three different databases on three different ports. In Docker speak, I would have three “containers” of the same “image”.
Okay, so you have an image of MongoDB, but that doesn’t mean the database is running on your system. For that you will need to “run” it using the “IMAGE ID” you got from doing
docker images above:
$ docker run 70ce1153b5d7
Now Docker is running on your system.
Another useful option is to run the image in interactive mode. For instance, maybe I have a Debian Linux image that I use to test if something I am doing is compatible across Linux distros. Maybe all I want to do is pop into a Debian machine and run some BASH commands. I could open the image into an interactive terminal mode using
$ docker run -i -t debian ./bin/bash
Okay, let’s say you did the run command above on our MongoDB image. Then you ran a bunch of really questionable code and you think your MongoDB might have crashed. You’ll want to check what Docker containers are running on your machine:
$ sudo docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS e752efa4fa62 70ce1153b5d7 "docker-entryp.." 13 minutes ago Up 13 minutes
Okay, very soon after you get your first Docker imaging running in a container, you will want to know how to stop it. Easy. You just need to grab the “CONTAINER ID” from above:
$ docker stop e752efa4fa62
All the stuff you just saw above can lead to a more complicated situation in your environment; you can have numerous containers and each one may or may not be running. If you did a
docker ps, it won’t show stopped containers. To show those, you need to use the
$ docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES $ $ docker ps -a CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS e752efa4fa62 70ce1153b5d7 "docker-entryp…" 5 minues ago Exited
Whoops, you didn’t mean to stop that Docker container. You want to start it back up again:
$ docker start e752efa4fa62 e752efa4fa62 $ $ docker ps -a CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS e752efa4fa62 70ce1153b5d7 "docker-entry…" 5 minutes ago Up 9 seconds 27017/tcp
Okay, let’s say we’re done with a container and we want to totally delete it. First, we’ll stop the container again:
$ docker stop e752efa4fa62
Now we can remove the container:
$ docker rm e752efa4fa62 e752efa4fa62 $ docker ps -a CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
Okay, we removed the container we had running our MongoDB image, but we still have the image around. It’s not hurting anything, but maybe we’ve decided we don’t need it any more:
$ docker images REPOSITORY TAG IMAGE ID CREATED SIZE hellokube v1 e65265fb1572 26 hours ago 109MB nginx latest 719cd2e3ed04 5 days ago 109MB mongo 4.1-bionic 70ce1153b5d7 2 weeks ago 365MB $ $ docker rmi mongo:4.1-bionic $ $ docker images REPOSITORY TAG IMAGE ID CREATED SIZE hellokube v1 e65265fb1572 26 hours ago 109MB nginx latest 719cd2e3ed04 5 days ago 109MB
Well, those are the basics. The Docker commandline has more options, but those are the basic commands you need to do basic things. It’s a start, anyway.
If Docker Hub doesn’t have what you want, or you want to build a very specific environment for your own deployment, you will need to create your own Docker image from scratch. To do that, you’re going to have to build your own Dockerfile. I’m told this can be quite the rabbit hole to go down… Let’s find out!
Let’s first cover the basic commands in the Dockerfile syntax:
Those seem like a good place to start. For more complete documentation on the Dockerfile commands, check here.
Now that we have the basics out of the way, let’s work through some (short) examples.
Okay, here’s a little Dockerfile for Alpine Linux with VIM installed:
FROM alpine:3.4 RUN apk update && \ apk add vim
First, let’s build the above Dockerfile:
$ docker build -t john/alpine-vim:1.0 . # a bunch of stuff prints out... Successfully built 71d5532db6ff Successfully tagged john/alpine-vim:1.0
Now let’s start it up:
$ docker run 71d5532db6ff $ $ # okay, now let's check it's running $ $ docker ps -a CONTAINER ID IMAGE COMMAND CREATED STATUS e51bdda82285 71d5532db6ff "/bin/sh" 6 seconds ago Exited (0) 3 seconds ago
For our second little example, let’s build an Ubuntu image with Python and PIP installed:
FROM ubuntu:18.04 MAINTAINER email@example.com RUN apt-get update && apt-get install -y \ python-pip
Okay, now we build the image:
$ docker build -t john/ubuntu-py:1.0 .
But instead of running the image and keeping it running, we can just run the BASH terminal from the image, directly onto our own command line. And the whole image will close own when we
$ docker run --rm -ti john/ubuntu-py:1.0 /bin/sh # echo "woo!" woo! # exit $
Well, those seem like the basics, sure. There are a lot more helpful details if Docker is going to be your major workflow, sure. And we didn’t touch Docker Compose or Docker Swarm. But you gotta start somewhere.
While spinning up on Docker (and writing the above), I mostly used these references.