Introduction
For the last few months, I have been working with Docker extensively. In this article and the one that follows, I want to share the most used Docker commands that every Docker user must know.
Originally, the intent was to have a single list of all the commands. However, I felt like each command must have a basic description and I must talk about the most common uses of each command. So, I will split the post into two parts.
Let’s get started.
1. docker info
The very first thing anyone generally does after installing any application is to check its version. Docker provides two commands in that respect: docker version
and docker info
.
docker version
gives you details like the Docker API version, operating system, underlying architecture and a few more. However, docker info
gives you a lot more system-wide information regarding the Docker installation. Here is a sample output of the docker info
command:
$ docker info
Containers: 6
Running: 4
Paused: 0
Stopped: 2
Images: 9
Server Version: 18.06.1-ce
Storage Driver: overlay2
Backing Filesystem: extfs
Supports d_type: true
Native Overlay Diff: true
Logging Driver: json-file
Cgroup Driver: cgroupfs
Plugins:
Volume: local
Network: bridge host ipvlan macvlan null overlay
Log: awslogs fluentd gcplogs gelf journald json-file logentries splunk syslog
Swarm: inactive
Runtimes: runc
Default Runtime: runc
Init Binary: docker-init
containerd version: (expected: 468a545b9edcd5932818eb9de8e72413e616e86e)
runc version: N/A (expected: 69663f0bd4b60df09991c08812a60108003fa340)
init version: v0.18.0 (expected: fec3683b971d9c3ef73f284f176672c44b448662)
Security Options:
apparmor
seccomp
Profile: default
Kernel Version: 4.15.0-43-generic
Operating System: Ubuntu 16.04.4 LTS
OSType: linux
Architecture: x86_64
CPUs: 4
Total Memory: 15.53GiB
Name: server-04
ID: BO4C:VSHD:Z2P6:DG6D:S7AF:6OTD:OP3F:YBBB:62OA:EBAB:IIX4:LTCO
Docker Root Dir: /var/lib/docker
Debug Mode (client): false
Debug Mode (server): false
Username: quickdevnotes
Registry: https://index.docker.io/v1/
Labels:
Experimental: true
Insecure Registries:
172.27.127.151:5000
127.0.0.0/8
Live Restore Enabled: false
You get details like the storage driver, containers, your registries and registry mirrors and lot more. While this is great, sometimes it can be overwhelming.
docker info
allows you to format the output as you want, by accepting the --format
or -f
option. Here are a few examples to apply the format option:
// get the response in json format
$ docker info --format '{{json .}}'
// get the response in json format and parse it through 'jq'
$ docker info --format '{{json .}}' | jq
// get a particular part of the information
$ docker info -f '{{.Plugins}}'
$ docker info -f '{{.Plugins.Network}}'
2. docker search
I must admit! I’m a bit lazy when it comes to switching between application windows, especially for simple things. If you’re someone like me, I’m sure you will like docker search
.
Generally, we switch to a web browser, go to DockerHub and then search for an image. Instead of doing all that, docker search
allows you to search DockerHub for images using a simple command, from your terminal.
Here is an example:
$ docker search nginx --format "table {{.Name}} \t {{.StarCount}} \t {{.IsOfficial}} \t {{.IsAutomated}}"
NAME STARS OFFICIAL AUTOMATED
nginx 11727 [OK]
jwilder/nginx-proxy 1628 [OK]
linuxserver/nginx 70
bitnami/nginx 69 [OK]
tiangolo/nginx-rtmp 49 [OK]
nginx/nginx-ingress 20
nginxdemos/hello 18 [OK]
blacklabelops/nginx 12 [OK]
webdevops/nginx 8 [OK]
1science/nginx 4 [OK]
mailu/nginx 3 [OK]
travix/nginx 2 [OK]
wodby/nginx 0 [OK]
In the above example, I’m using the --format
flag. Please feel free to remove the formatting and do a search.
3. docker login/logout
As you continue to work with Docker, the time will come when you want to secure your Docker images in a Docker registry. To pull
or push
an image from a private registry, the Docker engine requires credentials for authentication.
You can log in using the following command:
$ docker login
Username: quickdevnotes
Password:
Login Succeeded
Once the login is successful, the auth credentials are stored in the ~/.docker/config.json
file in encrypted form.
$ cat ~/.docker/config.json
{
"auths": {
"https://index.docker.io/v1/": {}
}
}
You may also pass the username and password within the command using the flags -u
and -p
respectively. However, it is not recommended.
You can log out using the docker logout
command that also removes the user credentials from the config file.
4. docker build
Any application can be run as a container if it has a Docker image. A Docker image is the building block for containers. To build an image, we write a Dockerfile. At the highest level, a Dockerfile is a set of commands that are executed to build a Docker image.
The Dockerfile is passed to docker build
command as an argument. The engine reads through the file and builds an image, as each command contributes a layer. Here is a sample Dockerfile and the command used to build an image out of it:
FROM busybox
WORKDIR /app
COPY data.txt .
CMD cat data.txt
$ docker build -t web-app .
The .
in the end, is very important. It is the context that is passed to the Docker engine concerning the Dockerfile.
However, you can pass the context to the docker build
command, as the need may arise. In the following example, we are executing the build command from a directory that does not contain the Dockerfile:
$ docker build -t web-app -f ../var/Dockerfile ../var
Here we provide the path to Dockerfile and the context, which is its directory. And yes, you can name your Dockerfile anything you want. It’s not a mandate to name it as Dockerfile. However, you will then have to use the -f
option while building an image.
5. docker tag
Tags are life saviors. Applying the right tags to your Docker images is very essential. The default tag for an image is latest
. You can add as many tags as you want.
To tag an image use the docker tag
command, as shown below:
$ docker tag busybox busybox:v1
$ docker tag busybox quickdevnotes/busybox-custom
I highly recommend that all your Docker images must have tags other than latest
at any point in time. This will make your rollouts and rollbacks much faster and efficient.
6. docker images
It’s always good to keep a check of all the Docker images available at your local machine. It is helpful when you want to free some space.
docker images
provides you a list of docker images available locally. Here is an example:
$ docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
confluentinc/cp-kafka latest aa982a32e7c4 5 months ago 569MB
confluentinc/cp-zookeeper latest 16ce4511d84e 5 months ago 569MB
wurstmeister/zookeeper latest 3f43f72cb283 6 months ago 510MB
wurstmeister/kafka 2.11-2.0.0 568143d73a6b 9 months ago 339MB
sheepkiller/kafka-manager latest 4e4a8c5dabab 15 months ago 463MB
You may also use the --format
option to get rid of unwanted information. Here is an example:
$ docker images --format "table {{.Repository}} \t {{.Tag}} \t {{.Size}}"
REPOSITORY TAG SIZE
confluentinc/cp-kafka latest 569MB
confluentinc/cp-zookeeper latest 569MB
wurstmeister/zookeeper latest 510MB
wurstmeister/kafka 2.11-2.0.0 339MB
sheepkiller/kafka-manager latest 463MB
In addition to --format
, there are a few other options as well. You can get them by using the docker images --help
command.
7. docker inspect
As the name suggests, docker inspect
provides detailed information on resources or constructs controlled by Docker. By default, the command returns the results in a JSON array.
Here is an example:
$ docker inspect busybox
[
{
"Id": "sha256:db8ee88ad75f6bdc74663f4992a185e2722fa29573abcc1a19186cc5ec09dceb",
"RepoTags": [
"busybox:latest"
],
"RepoDigests": [
"busybox@sha256:9f1003c480699be56815db0f8146ad2e22efea85129b5b5983d0e0fb52d9ab70"
],
"Parent": "",
"Comment": "",
"Created": "2019-07-18T21:20:21.810680491Z",
"Container": "d6bc4fd488f31e0e72c06b4f268e475ff54ca7c17bc3a867da366aa581576057",
"ContainerConfig": {
"Hostname": "d6bc4fd488f3",
"Domainname": "",
"User": "",
"AttachStdin": false,
"AttachStdout": false,
"AttachStderr": false,
"Tty": false,
"OpenStdin": false,
"StdinOnce": false,
"Env": [
"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
],
"Cmd": [
"/bin/sh",
"-c",
"#(nop) ",
"CMD [\"sh\"]"
],
"ArgsEscaped": true,
"Image": "sha256:94660471d35df73633987b367900b00d5eeda0ffdd3a096db092926bb6de3ba4",
"Volumes": null,
"WorkingDir": "",
"Entrypoint": null,
"OnBuild": null,
"Labels": {}
},
"DockerVersion": "18.06.1-ce",
"Author": "",
"Config": {
"Hostname": "",
"Domainname": "",
"User": "",
"AttachStdin": false,
"AttachStdout": false,
"AttachStderr": false,
"Tty": false,
"OpenStdin": false,
"StdinOnce": false,
"Env": [
"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
],
"Cmd": [
"sh"
],
"ArgsEscaped": true,
"Image": "sha256:94660471d35df73633987b367900b00d5eeda0ffdd3a096db092926bb6de3ba4",
"Volumes": null,
"WorkingDir": "",
"Entrypoint": null,
"OnBuild": null,
"Labels": null
},
"Architecture": "amd64",
"Os": "linux",
"Size": 1223894,
"VirtualSize": 1223894,
"GraphDriver": {
"Data": {
"MergedDir": "/var/lib/docker/overlay2/30d975af37c6654d4fe99d938c5dc62a06c9930c75d16ebd0f8423448101d9ca/merged",
"UpperDir": "/var/lib/docker/overlay2/30d975af37c6654d4fe99d938c5dc62a06c9930c75d16ebd0f8423448101d9ca/diff",
"WorkDir": "/var/lib/docker/overlay2/30d975af37c6654d4fe99d938c5dc62a06c9930c75d16ebd0f8423448101d9ca/work"
},
"Name": "overlay2"
},
"RootFS": {
"Type": "layers",
"Layers": [
"sha256:0d315111b4847e8cd50514ca19657d1e8d827f4e128d172ce8b2f76a04f3faea"
]
},
"Metadata": {
"LastTagTime": "0001-01-01T00:00:00Z"
}
}
]
Besides, the JSON format makes it easier to get the value of a field quite easy. Here is an example from the Docker Docs:
$ docker inspect --format='{{range .NetworkSettings.Networks}}{{.MacAddress}}{{end}}' ec734
02:42:ac:11:00:07
The Docker Docs have some other useful examples, which I appreciate you looking at.
8. docker pull
docker pull
is used to pull a Docker image from the repository. The repository can be at the Docker Hub or another publicly hosted registry. In fact, it can be a private Docker registry hosted in your local environment. Though it requires some configuration for your Docker daemon to use a private registry.
I wrote an article about hosting a private registry, a few months ago. You may refer the same for more details.
Here are a few examples of docker pull
in action:
// pulls the 'latest' tag when no tag is specified
docker pull busybox
// pulls the specified tag
docker pull busybox:glibc
// pulls all the available tags
docker pull busybox --all-tags
Each time we need an image, the Docker engine first checks if the image is available locally. If not, it pulls the image by resolving the namespace concerning the available registries.
9. docker push
I believe this is one of the most straightforward commands available for use. docker push
pushes or uploads an image to its respective repository. Let’s consider a few examples:
$ docker push busybox:some-tag
In the above command, notice that the image name does not include a namespace. This is because the busybox
image lies in the default namespace in Docker Hub.
Here is another example of an image from my repository:
$ docker push quickdevnotes/webapp:latest
Since my repositories are not officially recognized by Docker, they lie in a separate namespace. Therefore, each time I want to pull
or push
an image it is mandatory to specify the namespace before the image name.
It is also important to note that you need to first login to your Docker Hub account before you try to pull
or push
an image from a private registry. Else you get a permission denied error.
10. docker run
If you are using Docker, it is but obvious that you want to run some containers. That’s exactly what docker run
is for. Each time we execute the docker run
command, a process starts on the host machine which we call as a Docker container.
According to Docker documentation:
When an operator executes
docker run
, the container process that runs is isolated in that it has its own file system, its own networking, and its own isolated process tree separate from the host.
The basic form of docker run
looks like the following:
$ docker run [OPTIONS] IMAGE[:TAG|@DIGEST] [COMMAND] [ARG...]
It is a must to specify an image to run a container, as it defines the base for a container. I am going to keep it simple. Talking about each option for this command is like rewriting the whole documentation all over. So, here are a few examples that you generally see:
// starts an Ubuntu container and open an interactive TTY connection
$ docker run -it ubuntu:16.04 /bin/bash
// starts a busybox container and shows the output of top command
$ docker run -it busybox top
// starts a container in detached mode
$ docker run -d alpine sleep 1d
// starts a container in detached mode
// maps port 5000 of host to port 80 of the container
$ docker run -d -p 5000:80 quickdevnotes/webapp
// starts a container in detached mode
// maps the port and sets the environment variable in container
$ docker run -d -p 5000:80 -e ASPNETCORE_ENVIRONMENT=Testing quickdevnotes/webapp
// starts a container in detached mode
// maps the port, sets the environment variable
// mounts the configuration file from host to the path in container
$ docker run -d -p 5000:80 \
-e ASPNETCORE_ENVIRONMENT=Testing -v \
$(pwd)/appsettings.json:/app/appsettings.json \
quickdevnotes/webapp
With the above examples, we have barely scratched the surface. There is a lot you can do with the docker run
command. I insist, you check the amazing documentation for this command at Docker Docs.
If you want to experiment and explore by yourself, you can use the docker run --help
command to get a list of available options.
Summary
In this article, we have covered ten of the twenty-five most used Docker commands. While there is a lot that you can do with these commands than what we have covered here. The idea was to keep it simple and jot down the most common and widely used scenarios.
If you think there is a command that should be a part of this list, please let me know in the comments section. Also, if there is an option that must be talked about for the listed commands, please let me know.