Docker is useful for containerizing and managing processes. It is a great tool for developers and devops teams. Docker is good for creating reproducible environments. It is easy to customize images and document how an environment should be configured. We will look at how to:
- Install Docker
- Manage images, containers, and volumes
- Create custom images
- Pushing images to DockerHub and running custom registry
- and more!
Download and install Docker from the official Docker website. After installing, you may need to restart your computer. After installation, the docker command should be available in the shell.
Debian based distributions
.deb package from
Find the files inside the
Download and install in order:
sudo apt install runc # A dependency
sudo dpkg -i containerd.io_1.2.5-1_amd64.deb
sudo dpkg -i docker-ce-cli_18.09.4~3-0~ubuntu-bionic_amd64.deb
sudo dpkg -i docker-ce_18.09.4~3-0~ubuntu-bionic_amd64.deb
Add the necessary users to the docker group and then reboot:
sudo gpasswd -a someuser docker
Pull an image
Find an image on Docker Hub. Alpine is the first image I would recommend getting. It's a tiny \~5MB Linux base with BusyBox shell. It's good for basic docker testing and can be extended to create your own custom images. You can get the image by running:
docker pull alpine
# Some other examples
docker pull ubuntu
docker pull python:3.7.0
docker pull openjdk:11-jre
docker pull openjdk:11-jdk
Here is a list of some other popular images:
nginx, busybox, redis, httpd, mongo, ubuntu, postgres, node, mysql, memcached, registry, hello world, golang, docker, centos, mariadb, drupal, cassandra, vault, jetty, redmine, pypy, django, gcc, rails, swift, rust, irssi
After you have an image installed you can list them with the following commands:
docker image ls
Remove an image
To permanently delete a base image.
-f flag if you need to kill running containers currently runnng that image.
# Delete an image,
docker rmi -f alpine
Save and load images to files
To export and import images as files you can use
This is useful for transferring and sharing images without a registry.
docker save ubuntu > ubuntu-all.tar
docker save ubuntu:latest > ubuntu-latest.tar
docker load < ubuntu-latest.tar
Push an image to a registry
You can use DockerHub or a custom registry server.
Push to DockerHub public registry
docker tag xxxidxxx myusername/my_image:1.0.0
docker login --username=myusername --email@example.com
docker push username/my_image
Push to a custom registry
You can push and pull to a custom registry using similar commands.
For example, if you have a custom registry on
docker tag image_name localhost.local:9999/myimage
docker push localhost.local:9999/myimage
docker pull localhost.local:9999/myimage
Run a custom registry
# Boot custom registry
docker run -d -p 5000:5000 registry
Create a custom image
You can create a custom image a couple ways:
- Build an image using instructions in a Dockerfile
- Take a snapshot from an existing container
You can build custom images from scratch or build on top of base images like Alpine.
You can find the Dockerfiles that are used to create the images on DockerHub.
You can use those Dockerfiles as references.
To create an image, you need to define a Dockerfile first which acts as the template
which is then built using
docker build to create the image which can then be pushed
to DockerHub, or used to create containers.
Create image from a Dockerfile
Any image can serve as a base image.
Some recommended base images are
Docker also provide a base image named
scratch that allows you to build
totally custom images. The
scratch image is good if you only want to
drop in one single executable. You can read more about creating
base images from
Official Docker Base Images Documentation.
Simplest Dockerfile possible
This example won't do anything but create an useless image.
MAINTAINER Your Name <firstname.lastname@example.org>
Here is a practical minimal example that will at least add an executable
ADD my_executable /
CMD ["/my_executable"] # Default command run with `docker run image_name`
Example Dockerfile with common options
Here is an example that includes some common operations:
MAINTAINER NanoDano <email@example.com>
# Set environment variables
# Copy file from local system in to image
COPY ./src ./dest
# Similar to copy, also supports remote URLs & auto-unpacks zips
ADD ./src ./dest
# Expose ports. Must be published at runtime `docker run -P -d my_image`
EXPOSE 80/tcp 443/tcp
# Mount points
VOLUME ["/etc/confdir", "/var/lib/datadir"]
# Change working dir (create if does not exist)
# Run command when building image (e.g. RUN apt install git)
RUN apt-get update
RUN apt-get install -y git
# Command to run when `docker run` invoked directly.
# Any args passed get passed to the entrypoint executable
ENTRYPOINT ["/bin/bash", "-c"]
# Default args for entrypoint if none are provided to `docker run`.
# The CMD is executed directly if no ENTRYPOINT present.
Then build and run the image:
# Provide the directory containing the `Dockerfile`
docker build . --tag myimage
docker run myimage # Will run `/bin/bash -c env` by default
docker run myimage git --version
Read more about Docker best practices.
Common base images
Here are a few popular base images for progammers. These are just a few arbitrary examples.
You can explore more images at https://hub.docker.com/search?q=&type=image.
Build image from Dockerfile
From the directory containing the
Build will look for a
Dockerfile in the directory.
docker build --tag my_image:latest .
Docker can also take input from STDIN, a direct filepath, or a URL.
# Take input from STDIN (three options)
docker build -
docker build - < Dockerfile
cat Dockerfile | docker build -
# Direct file path
docker build /path/to/Dockerfile
# Remote URL
docker build https://raw.githubusercontent.com/nodejs/docker-node/master/10/alpine/Dockerfile
Create image from container snapshot
Instead of building a image from a
you can create new images from existing containers by using
docker commit container_id # Generates unnamed hash (Image ID)
docker tag <commit_hash> new_image_name # Tag an unnamed hash
# Commit and tag in a single step
docker commit container_id new_image_name:latest
Containers are basically running images. Containers are run from image templates. Containers can be started and stopped and images cannot. Many containers can be started from the same image.
Run a container
There are several ways to invoke and run a container. You can have the docker image run a single command and output the results or have it detach and run in the background as a service.
You can run with a container with all the defaults by just running it by name with no arguments. Alpine doesn't do anything by default so it will just exit.
docker run alpine
Run interactive terminal
To run an interactive (
-i) and psuedo-tty(
-t) to get a shell, use
-it like this:
docker run -it alpine
docker run -it alpine /bin/sh
Connect to running container and get a shell
To connect to a running container and get a shell (regardless of entrypoint), you can use
# Connect to an existing _container_ and get a shell
docker exec -it <container_id> /bin/sh
Specify restart options
You can have a container automatically restart by specifying the
docker run --restart=always image_name
Run a single command
You can run single commands and view the output directly using this format:
docker run <image_name> <command>.
docker run alpine echo Hello, world
docker run openjdk:jre java -version
docker run python:3.7.0 python --version
# Will run forever, until stopped or sigint received
docker run alpine watch date
# Override the entrypoint with --entrypoint
docker run -it --entrypoint /bin/sh python:3.6.8-alpine
Running in detached mode
You can run a docker image in the background similar to adding
& to the end of a command.
Just add the
-d flag to detach after running.
docker -d run alpine watch date
# Name the container
docker run -d --name watcher alpine watch date
Automatically delete image after running
If you don't need an image to persist after a single run, you can flag it to delete itself after running.
docker run --rm alpine echo Hello
To open ("publish") ports that are exposed inside the container, use the
in the format of
docker run -p <host_port>:<container_port>. Use
-P to publish
all exposed ports in container.
For example, to allow 80 and 443 from an nginx container:
# Make localhost:9999 on host viewable
docker run -d -p 9999:80 nginx
# Publish ALL exposed ports defined in container
docker run -d -P nginx
View ports that are listening with:
netstat -lt # sudo apt install net-tools
If a docker container needs to read or write a directory outside of itself, you need to mount a volume. You can mount it directly to a directory or to a proper "Docker volume".
It is easier to simply mount a directory, but it is better to create a Docker volume to better share it between multiple containers, manage it using Docker CLI, can easily be encrypted, stored remotely, shared between Windows and Linux, and other benefits. Volumes will be covered more below.
There is a
--mount and a
-v option. The simpler and recommended one to use is
docker run -v /path/on/host:/path/inside/container my_image
docker run -v my_volume:/mnt/path my_image
docker run --mount source=/path/on/host,target=/path/inside/container my_image
docker run --mount source=my_volume,target=/path/inside/container my_image
There are many more options available like
Refer to the Official Docker Volume.
To see what containers are active and how long they've been up, use the ps command. This will provide the ID and the name of the containers, both of which you can use to call stop.
# List running containers
# List all containers, including stopped ones
docker ps -a
Get usage statistics of running containers
# Memory, CPU, disk, network usage, process count
# Like `top` for docker
Pause, stop and restart a container
You can shutdown a container by calling stop and passing it the name or the ID of the container, which you can get with the ps command.
Instead of shutting down or restarting a container, there are times when pausing a container is useful. This could help if a container performs heavy computation and you want to pause it for a while without shutting down. It can also be useful in certain debugging situations. You can use the pause and unpause commands.
# Shutdown a container by name or id `docker ps`
docker stop wonky_wombat
# Restart a container, works on running and stopped containers
docker restart tall_tiffany
# Pause all processes, but keeps container running
docker pause captain_carl
docker unpause captain_carl
Delete a container
When a container is stopped, it is not completely gone.
To delete a container use the
docker rm command.
You can list all containers with
docker ps -a.
You can't delete a running container without including the
# Delete a stopped container
docker rm some_container
# Delete a running container
docker rm -f some_container
Copy files to/from a container
docker cp command works similar to
scp but the remote host name
is the container id.
docker cp /host/path container_name:/path/in/container
docker cp container_name:/path/in/container /host/path
Volumes are for persistent file storage. You could tie a running image to a directory on the host system, but it is better to create a volume that is managed by docker. Containers can even be backed up to and restored from volumes.
Create a volume
docker volume create my_volume
docker volume ls
Get volume details
docker volume inspect my_volume
Delete a volume
docker volume rm my_volume
# Delete all unused volumes
docker volume prune
As always, refer to the official documentation for the most thorough and up-to-date information. You can also get direct help from the docker application itself using the following commands:
# Help info
# Examples of sub-help options
docker ps -h
docker container -h
docker image -h
Explore public images on Docker Hub.
You should now understand the very basics of Docker, how to find and pull existing images, build your own custom images, and run the containers. Check out the official Docker site for more information.