Running a Docker Container

Ben Cook • Posted 2017-02-05 • Last updated 2021-07-08

Once you’ve installed Docker, there a few basic features to know. In this post you’ll learn about running containers. If you haven’t gotten started with Docker yet, checkout this quick start guide.

The basics

You can run Docker containers with a command that takes the following form:

docker run [options] <image name> [command]

The only required element is the image name. So for example, to run Jupyter’s minimal-notebook image in a container, use the image name jupyter/minimal-notebook.

docker run jupyter/minimal-notebook

This runs the default command in the image and streams logs to stdout (you can quit by pressing ctrl+c), which can sometimes be useful. But in this case, the default command is starting a Jupyter notebook server, which is not useful if we don’t have access to port 8888 on the container.

Exposing ports

Fortunately, we can expose this port using the -p flag (p is for “publish”).

docker run -p 8888:8888 jupyter/minimal-notebook

Now we’ve done something useful. The notebook command prints out a URL in the logs with a token parameter. If you visit that link, you will be in a Jupyter notebook hosted on the container.

If we were already using port 8888 on our local machine or in another container, we could pick a different port to map to 8888 on the container.

docker run -p 8889:8888 jupyter/minimal-notebook

Now we will need to modify the URL printed to stdout, by substituting 8889 for 8888. This means you’ll need to navigate to a URL like http://localhost:8889?token=<some token> even though the container will print http://localhost:8888?token=<some token>.

Overriding the default command

It’s a pain to have to get the URL from the logs before we can use it. The minimal-notebook container is running an executable script called start-notebook.sh (see the script here). This will take arguments and pass them to the jupyter notebook command. This gives us the opportunity to disable token-based authentication.

docker run -p 8888:8888 jupyter/minimal-notebook start-notebook.sh --NotebookApp.token=''

Now we can visit the notebook server by simply navigating to localhost:8888. But we still have a problem. Any work we do in a notebook will not be saved after we exit the container. This is probably not what you want.

Mounting volumes

The best way to save code you write in a container is to mount a data volume from your host machine. For this, you use the -v flag (v is for “volume”). The working directory in the container is /home/jovyan/work, which is where the notebook will be launched. A good bet is to give the host access to this directory. I like keeping code in my ~/code directory so I’ll create a folder called ~/code/minimal-notebook-scratch. Feel free to make a folder wherever you want and substitute it in your run command.

docker run -v ~/code/minimal-notebook-scratch:/home/jovyan/work -p 8888:8888 jupyter/minimal-notebook start-notebook.sh --NotebookApp.token=''

Now if you start a notebook and write some code, the notebook will live on in ~/code/minimal-notebook-scratch when you quit the container. In fact, anything you change in the /home/jovyan/work directory within the container will also change in the ~/code/minimal-notebook-scratch folder on your machine. Pretty handy.

Running the container in different modes

There’s one more irritating thing about this setup to take care of. The container will die if we close the Terminal tab, or if we accidentally hit ctrl+c. When you’re running something like a server in a container, it’s usually nice to run it in detached mode. This is done with the -d flag (d is for “detach”).

docker run -d -v ~/code/minimal-notebook-scratch:/home/jovyan/work -p 8888:8888 jupyter/minimal-notebook start-notebook.sh --NotebookApp.token=''

This time, you will see a container ID on the screen but no logs from the container. That’s because the container is running in the background. You can watch the logs of a detached container with docker logs -f <container ID> and you can kill and delete a container with docker rm -f <container ID>. If you forget the container ID, just run docker ps to see the IDs of all the running containers.

If you’re debugging an image, you can run the container in interactive mode using the -i and -t flags together: -it (i is for “interactive”, but I’m not really sure about the t).

docker run -it -v ~/code/minimal-notebook-scratch:/home/jovyan/work -p 8888:8888 jupyter/minimal-notebook start-notebook.sh --NotebookApp.token=''

You now know enough about docker run to be dangerous. Go forth and containerize all the things.