What is Docker CLI (Command Line Interface)?
Docker CLI tool is a command line application used to interact with the dockerd
daemon. The dockerd
daemon is the process that manages containers and handles all the commands sent from the CLI by exposing an API endpoint. So both dockerd
and Docker CLI pieces are needed for docker
to work. The following illustration depicts the overall Docker architecture:
In this entry you will go through the basics of the Docker CLI tool used to interface with Docker Engine, its key features, how to install and operate it, how to configure it, and how it relates to Docker Compose and Docker APIs.
Docker CLI features
The Docker CLI includes several useful features. It handles standard UNIX-style arguments, and in many cases, it offers both short and long forms.
For example, the flags -H, --host
are both for specifying the host to connect. It accepts environment variables (which we’ll explain in detail later on), and it can also accept configuration from a file (config.json) so that admins can limit the passing of flags explicitly.
The –help
flag is nice, but it could be better (I would have liked to see more comprehensive documentation similar to that offered by the Git toolset). Most of the reference material can be found on the official documentation site.
There is an option to run the tool with experimental features for testing purposes by exporting the following env variable:
export DOCKER_CLI_EXPERIMENTAL=enabled
Code language: JavaScript (javascript)
Finally, it also allows the tool to be extended using plugins. You will need to follow specific instructions to set up out-of-process extensions that the CLI tool can use (such as registering new commands).
You can check this gist code of a sample plugin example for adding a new command to the CLI that displays the Docker changelog for the installed version and know more about using plugins.
Installation and configuration
As with all software, you have to install it before you can use it. Docker CLI is written in the Go programming language, so it’s quite portable as a tool.
The dockerd
daemon, which is responsible for handling the CLI requests, can run on most popular platforms (including Windows, Linux, and Mac with ARM/x86_64 /amd64 CPUs). You can find a list of platforms that support Docker on this page.
Installation
The Docker CLI can be installed as a desktop application (called Docker Desktop) or by using the command line. Note that commercial use of Docker Desktop in larger enterprises requires a paid subscription.
The Get Docker page provides instructions for installing Docker Desktop on your computer. Meanwhile, installing the Docker CLI requires you to run a bunch of commands. If you use Ubuntu, for example, you first need to ensure that your apt repository packages are up to date with the latest ca-certificates
and gnupg
:
$ sudo apt update
$ sudo apt install ca-certificates curl gnupg lsb-release
Note that you can use either curl
or wget
to download the gpg
keys:
$ sudo mkdir -p /etc/apt/keyrings
$ curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg
$ sudo chmod a+r /etc/apt/keyrings/docker.gpg
Code language: JavaScript (javascript)
The following command updates the /etc/apt/sources.list.d/docker.list
, adding a new repository for the Docker distribution and using the lsb_release
tool for printing the right Linux distribution name:
echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu
$(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
Code language: PHP (php)
Now that the sources are configured, these last two commands are used to install the Docker CLI, dockerd, and docker-compose tools:
$ sudo apt update
$ sudo apt install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
You can also install Docker using the installation script, which requires fewer steps. Just make sure that you make it executable before running it:
$ sudo apt update
$ sudo apt install ca-certificates curl gnupg lsb-release
$ curl -fsSL https://get.docker.com -o get-docker.sh
$ sudo chmod +x get-docker.sh
$ sudo sh ./get-docker.sh --dry-run
Code language: JavaScript (javascript)
When all of these steps are done, you can check to see if everything is alright by printing the docker version
:
$ docker version
Client:
Cloud integration: v1.0.22
Version: 20.10.13
API version: 1.41
Go version: go1.16.15
Git commit: a224086
…
Basic Interactivity
You can use the docker <command>
to issue commands and get information about the available list of options.
For example, to get the list of options for the docker image
command, run:
$ docker image
Usage: docker image COMMAND
Manage images
Commands:
build Build an image from a Dockerfile
history Show the history of an image
…
Code language: JavaScript (javascript)
Use docker <command> <subcommand> –help
to get a detailed list of available options for a subcommand. For example:
$ docker image build --help
Usage: docker image build [OPTIONS] PATH | URL | -
Build an image from a Dockerfile
Options:
…
Code language: JavaScript (javascript)
Running erroneous commands will stop the execution of the task and print an associated error:
$ docker image build -t
flag needs an argument: 't' in -t
See 'docker image build --help'.
Code language: JavaScript (javascript)
When you first install Docker, you may need to log into a registry to push or pull images. You can do that with the docker login
command:
$ docker login registry.gitlab.com
Authenticating with existing credentials...
Login Succeeded
Code language: JavaScript (javascript)
There are a lot of available commands in Docker with further subcommands and flags. Most of the time, though, you will be using just a few of them. We will explore those in detail later in this tutorial.
Environment Variables
The Docker CLI runs on an execution context and can be configured with environment variables. These variables are used to configure connection parameters and access credentials. There aren’t many of them, but it’s important to know what they do. Here are some of the most important ones:
DOCKER_HOST
: This is used to change the host that the CLI tool connects to. It needs to be a valid connection string. The different types of connection strings can be located in this section of the code. For example, tcp://1.2.3.4:5678
and unix:///path
are valid connection strings.
DOCKER_CONTEXT
: This is used to specify the default Docker context to use. You can use Docker contexts to easily switch back to different hosts. For example, here is a list of available contexts:
$ docker context list
NAME TYPE DESCRIPTION DOCKER ENDPOINT KUBERNETES ENDPOINT ORCHESTRATOR
default * moby Current DOCKER_HOST based configuration unix:///var/run/docker.sock https://127.0.0.1:55093 (default) swarm
Code language: PHP (php)
<code>desktop-linux moby unix:///Users/theo.despoudis/.docker/run/docker.sock</code>
Code language: HTML, XML (xml)
DOCKER_TLS_VERIFY
: Set this to true
or 1
if you don’t want to skip SSL certificate verification between your CLI tool and the dockerd
daemon. This means that any certificate you use needs to be valid or the operation will fail.
DOCKER_CONFIG
: This is the location of the Docker configuration files. By default, it is set to .docker
inside the user’s home directory.
Config Files
The DOCKER_CONFIG
env variable specifies the folder that the CLI tool will use to configure it using a special config.json
. If you want to use a different config.json
for a particular command, you need to use the --config <config_folder>
instead.
Using config files allows the user to provide overrides and common options for Docker commands. For example, to assign a default format output for different kinds of listing options like images, containers, or secrets, you can use:
// config.json
{
"imagesFormat": "table {{.ID}}\t{{.Repository}}\t{{.Tag}}\t{{.Size}}"
}
Code language: JSON / JSON with Comments (json)
This is equivalent to using the following command:
$ docker image list --format "table {{.ID}}\t{{.Repository}}\t{{.Tag}}\t{{.Size}}"
Code language: PHP (php)
You can also specify custom HTTP headers using the HttpHeaders
field and certain build time arguments for --build-arg
. The available config options are documented here.
It is recommended that you store these files in a configuration management tool so that they can be updated automatically when you need to change certain values using a version control system.
Useful Commands
Now, we’ll explore some of the most useful and practical commands to know when using the Docker CLI tool. Many of these commands accept arguments in a specific place, so you need to make sure you pass them in the correct order. You might want to review the list of available commands in the reference docs section.
Docker Create
The create
(or container create
) command creates a new container out of an existing base image without starting it. You can name the container and attach volumes, environment variables, and other configurations. For example:
$ docker container create -it --name example busybox
A883f7e9295b42ade570ac2883fbdd3654e3fe6c6d3aa41d05872f16a46835a7
This creates a container named example
out of the BusyBox image with a status of CREATED. Then you can use the start
command to change its status to RUNNING.
Docker Build
This builds an image out of a Dockerfile. You need to provide a path or the location of the Dockerfile, specify a URL, or use STDIN instructions to build the image. For example, given that there is a Dockerfile in the current folder, you just need to run:
$ docker build .
This will create a new image based on the instructions you provided. You also have the option to override some of the build parameters using arguments.
Docker Pull
The pull
command downloads the specified image from the registry into the local Docker filesystem. Once the image is downloaded, you will be able to list it using the docker image ls
command:
$ docker pull alpine:latest
$ docker image ls
REPOSITORY TAG IMAGE ID CREATED SIZE
alpine latest b2aa39c304c2 10 seconds ago 7.05MB
Docker Run
The docker run
command combines multiple commands for creating or pulling a container and running it with the provided options. If an image does not exist in the local host, for example, it will first pull it from the default registry, then create and run it all in the same command. The following example shows what this flow looks like:
$ docker run --name redis -p 6379:6379 -d redis:latest
Unable to find image 'redis:latest' locally
latest: Pulling from library/redis
3665d49a6c759ad832bf60665e105060935db40a390a87a9f973ff2b81d92c0b
$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
3665d49a6c75 redis:latest "docker-entrypoint.s…" 5 seconds ago Up 4 seconds 0.0.0.0:6379->6379/tcp redis
Code language: JavaScript (javascript)
There are multiple configuration options you can use with run
. You can learn more about them in the docs.
Docker Start/Stop
Starting and stopping a running container can be performed with the docker start
and docker stop
commands, respectively. A container can only be started if it’s available, and a container that has been started can only be stopped using the stop
command once it completes its task or when stopping the dockerd
process:
$ docker start nocontainer
Error response from daemon: No such container: nocontainer
Error: failed to start containers: nocontainer
$ docker start example
$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
a883f7e9295b busybox "sh" 38 minutes ago Up 6 seconds example
$ docker stop example
Code language: JavaScript (javascript)
Docker Exec
The exec
command is used to execute a command in a running container. It is different from run
in that it cannot be used to download images from a registry or perform other actions. For example, you cannot use exec
on a container that is not present. The command is called from the default directory of the container or by the specified WORKDIR option:
$ docker exec -it redis redis-cli
Error: No such container: redis
$ docker run --name redis -p 6379:6379 -d redis:latest
$docker exec -it redis redis-cli
127.0.0.1:6379> PING
PONG
127.0.0.1:6379>
Code language: PHP (php)
The exec
command is useful for one-off tasks, testing connectivity, printing env variables, and for debugging purposes.
Docker Compose
Docker CLI is not the only tool that connects with the dockerd
daemon. Since the dockerd
process exposes an API, any compatible client can interface with it. Docker Compose, which is written in Python, is another tool that can act as a client to the Docker API.
Instead of using commands directly, you’ll need to specify a YAML definition of your stack. This will need to follow certain specifications. For example, the following specification defines a Redis server running on port 6379 and exposes the same port on the host machine. It then uses the docker-compose CLI to spin up the described service:
version: "3.9"
services:
redis:
image: "redis:alpine"
container_name: redis
ports:
- 6379:6379
$ docker-compose up -d
$ docker-compose ps
Name Command State Ports
-----------------------------------------------------------------------
redis docker-entrypoint.sh redis ... Up 0.0.0.0:6379->6379/tcp
$ docker container ls
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
3d01944c30f8 redis:alpine "docker-entrypoint.s…" 34 seconds ago Up 33 seconds 0.0.0.0:6379->6379/tcp redis
Code language: JavaScript (javascript)
This is equivalent to using the following Docker CLI commands:
$ docker network create --network=redis-net
$ docker run --name redis -p 6379:6379 --network=redis-net -d redis:latest
You can specify one or more services under the services
field, and each one will have its own config. Docker Compose makes it easier to describe full-stack Docker applications in a single file and manage deployments using simple commands.
If you need to set up multiple networks, volumes, secrets, and other resources, Docker Compose is a scalable option. You can find the whole list of available commands for the docker-compose CLI with descriptions on this docs page.
Docker APIs
As we mentioned earlier, the Docker CLI interacts with Docker Engine using an API exposed in the dockerd
service, and developers can create their own clients to interface with it.
This API (which is documented here) consists of various endpoints for managing Docker containers, secrets, and services. It uses the var/run/docker.sock
for incoming HTTP and TCP requests:
Here is an example of using the socat
tool to request the /version
info endpoint:
echo -n "GET /info HTTP/1.0\n\n" | socat UNIX-CONNECT:/var/run/docker.sock - | grep -o '{.*}' | jq
{
"ID": "45BJ:D2Z2:7MT5:YGLC:TFJZ:2XHT:MI6M:AQUC:24BZ:47MJ:SLPA:3JNX",
"Containers": 2,
"ContainersRunning": 1,
"ContainersPaused": 0,
"ContainersStopped": 1,
"Images": 4,
"Driver": "overlay2",
"DriverStatus": [
[
"Backing Filesystem",
"extfs"
],
[
"Supports d_type",
"true"
],
[
"Native Overlay Diff",
"true"
],
[
"userxattr",
"false"
]
],
…
Code language: PHP (php)
It sends a GET request to the /info
endpoint using socat
, which connects to the Docker socket. The last part of this expression extracts the JSON response and prettifies it in the command line.
In addition to the dockerd
handlers, there are APIs for Docker Hub and Docker Registry that you can query as well. All of these exposed APIs deal with different management options and requests.
Conclusion
Docker is a platform for managing containers, and there are many tools and services in its ecosystem. Using the Docker CLI tool, users can issue commands to create and manage containers with ease and flexibility. This article explored the basics of the CLI tool, explained its most useful commands, and showed you how it works behind the scenes.
The goal of this article was to give you a good introduction to the Docker CLI. But when it comes to working with Docker and containers, you’ll do most of your learning in real-world scenarios like trying to deploy a WordPress stack consisting of WordPress, MySQL, and NGINX.