Docker CLI Commands— 101

Akash Mahale
DevOps Dudes
Published in
8 min readApr 24, 2023

In this blog, I will cover some basic docker commands. Docker is an open-source platform that allows developers to build and run applications in containers. Containers have become a de-facto standard for deploying applications in a microservice fashion. Containers are lightweight and portable, which encapsulate the application and its dependencies, such as libraries, frameworks, and runtime required to run the application making them platform agnostic. This enables developers to deploy the same application across different environments, such as development, QA, testing, and production. Let's start with the prerequisites followed by docker commands.

Docker Architecture:

Docker consists of 3 main components:

Docker Engine: the core runtime that runs containers and manages their lifecycle.

Docker Client: the command-line interface (CLI) that interacts with the Docker Engine and sends commands and requests.

Docker Registry: the central repository that stores and distributes Docker images, which are the building blocks of containers. A few examples are Docker Hub where all the public images are maintained, or cloud-based private docker registries like ACR (Azure Container Registry), GCR (Google Container Registry), etc.

What is Docker CLI?

Docker CLI (Command-Line Interface) is a tool that allows developers and system administrators to interact with the Docker Engine. This includes building images from Dockerfiles, running containers from images, managing container networks and volumes, and interacting with the Docker registry. Docker CLI can be installed on both Linux systems and on Windows as a Docker desktop.

Let us start with the basic commands.

docker pull

The first command we will try is to pull a public docker image from Dockerhub.

docker pull [IMAGE_NAME]:[TAG]

docker pull nginx:latest

Output:
Using default tag: latest
latest: Pulling from library/nginx
26c5c85e47da: Pull complete
4f3256bdf66b: Pull complete
2019c71d5655: Pull complete
8c767bdbc9ae: Pull complete
78e14bb05fd3: Pull complete
75576236abf5: Pull complete
Digest: sha256:63b44e8ddb83d5dd8020327c1f40436e37a6fffd3ef2498a6204df23be6e7e94
Status: Downloaded newer image for nginx:latest
docker.io/library/nginx:latest

This will pull the latest docker image from the DockerHub. The image will be stored in our local system. We can specify specific tags if we want to pull older versions of the image. If no TAG is specified, it is considered at the latest.

docker images

We can see all the images in our local system by using the docker images command. Every image gets an IMAGE_ID that can be seen in the output of this command. The -a flag is used to view all the images available on the local machine.

docker images -a

Output:
REPOSITORY TAG IMAGE ID CREATED SIZE
nginx latest 6efc10a0510f 11 days ago 142MB

docker run

Once the docker image is pulled we can run them as a container.

docker run [IMAGE_NAME/IMAGE_ID]

docker run nginx

Output:
/docker-entrypoint.sh: /docker-entrypoint.d/ is not empty, will attempt to perform configuration
/docker-entrypoint.sh: Looking for shell scripts in /docker-entrypoint.d/
/docker-entrypoint.sh: Launching /docker-entrypoint.d/10-listen-on-ipv6-by-default.sh
10-listen-on-ipv6-by-default.sh: info: Getting the checksum of /etc/nginx/conf.d/default.conf
10-listen-on-ipv6-by-default.sh: info: Enabled listen on IPv6 in /etc/nginx/conf.d/default.conf
/docker-entrypoint.sh: Launching /docker-entrypoint.d/20-envsubst-on-templates.sh
/docker-entrypoint.sh: Launching /docker-entrypoint.d/30-tune-worker-processes.sh
/docker-entrypoint.sh: Configuration complete; ready for start up
2023/04/24 06:03:48 [notice] 1#1: using the "epoll" event method
2023/04/24 06:03:48 [notice] 1#1: nginx/1.23.4
2023/04/24 06:03:48 [notice] 1#1: built by gcc 10.2.1 20210110 (Debian 10.2.1-6)
2023/04/24 06:03:48 [notice] 1#1: OS: Linux 5.15.90.1-microsoft-standard-WSL2
2023/04/24 06:03:48 [notice] 1#1: getrlimit(RLIMIT_NOFILE): 1048576:1048576
2023/04/24 06:03:48 [notice] 1#1: start worker processes
2023/04/24 06:03:48 [notice] 1#1: start worker process 29
2023/04/24 06:03:48 [notice] 1#1: start worker process 30
2023/04/24 06:03:48 [notice] 1#1: start worker process 31
2023/04/24 06:03:48 [notice] 1#1: start worker process 32

This shows that the Nginx container is running on the local machine using Docker Engine.

docker ps

We can list the containers using the docker ps command. This will show us the state of the container — Running, stopped, exited, etc. Every container also gets a CONTAINER_ID as we get for an image. The -a flag is used to list all the containers on the local machine.

docker ps -a

Output:
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
62814eb60c1c nginx "/docker-entrypoint.…" 2 minutes ago Up 2 minutes 80/tcp boring_zhukovsky

docker stop

We will now stop our running container. We will pass the CONTAINER_ID to stop the container. The container goes into an EXITED state after it is stopped.

docker stop [CONTAINER_ID]

docker stop 62814eb60c1c

Output:
62814eb60c1c

docker run (as a daemon)

We can run a container in the background as a daemon using the -d flag. This will make the container run in the background. On running the docker ps command we can see the container as up and running.

docker run -d [IMAGE_NAME/IMAGE_ID]

docker run -d 62814eb60c1c

Output:
15ab848abe7ac514135b2623dd0091087b37b96e7f1443f1f85afcf086025a51

docker ps -a

Output:
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
15ab848abe7a nginx "/docker-entrypoint.…" 32 seconds ago Up 31 seconds 80/tcp relaxed_mendeleev

docker exec

We can get inside a docker container and access the terminal of the container using the exec command. The -it command states we will use interactive mode to connect to the bash shell of the container.

docker exec -it [CONTAINER_ID] /bin/bash

docker exec -it 15ab848abe7a /bin/bash

Output:
root@15ab848abe7a:/#

The output shows we are accessing the shell inside the container. Use Ctrl+D or exit command to come out of the container.

docker run (port mapping)

There is a requirement where want to run the application externally on some port. Say, in our example the Nginx container runs on TCP port 80 (HTTP). We want this Nginx container to run on port 5000 for some application purposes. In that case, we should be able to run the container on port 5000 of our local machine and map that to container port 80. The -p flag helps us in port forwarding.

docker run -p [OUTSIDE_PORT]:[INSIDE/CONTINER_PORT] [IMAGE_NAME:TAG/IMAGE_ID]

docker run -p 5000:80 nginx

Output:
/docker-entrypoint.sh: /docker-entrypoint.d/ is not empty, will attempt to perform configuration
/docker-entrypoint.sh: Looking for shell scripts in /docker-entrypoint.d/
/docker-entrypoint.sh: Launching /docker-entrypoint.d/10-listen-on-ipv6-by-default.sh
10-listen-on-ipv6-by-default.sh: info: Getting the checksum of /etc/nginx/conf.d/default.conf
10-listen-on-ipv6-by-default.sh: info: Enabled listen on IPv6 in /etc/nginx/conf.d/default.conf
/docker-entrypoint.sh: Launching /docker-entrypoint.d/20-envsubst-on-templates.sh
/docker-entrypoint.sh: Launching /docker-entrypoint.d/30-tune-worker-processes.sh
/docker-entrypoint.sh: Configuration complete; ready for start up
2023/04/24 09:16:08 [notice] 1#1: using the "epoll" event method
2023/04/24 09:16:08 [notice] 1#1: nginx/1.23.4
2023/04/24 09:16:08 [notice] 1#1: built by gcc 10.2.1 20210110 (Debian 10.2.1-6)
2023/04/24 09:16:08 [notice] 1#1: OS: Linux 5.15.90.1-microsoft-standard-WSL2
2023/04/24 09:16:08 [notice] 1#1: getrlimit(RLIMIT_NOFILE): 1048576:1048576
2023/04/24 09:16:08 [notice] 1#1: start worker processes
2023/04/24 09:16:08 [notice] 1#1: start worker process 29
2023/04/24 09:16:08 [notice] 1#1: start worker process 30
2023/04/24 09:16:08 [notice] 1#1: start worker process 31
2023/04/24 09:16:08 [notice] 1#1: start worker process 32

We check the output on the localhost:5000.

Port forwarding on localhost 5000

docker rm

To remove containers we need to stop them first and then remove those. A running container cannot be removed on the fly. It should be stopped. Below is an example of the same.

docker ps -a

Output:
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
15ab848abe7a nginx "/docker-entrypoint.…" 3 hours ago Up 3 hours 80/tcp relaxed_mendeleev

docker rm 15ab848abe7a

Output:
Error response from daemon: You cannot remove a running container 15ab848abe7ac514135b2623dd0091087b37b96e7f1443f1f85afcf086025a51.
Stop the container before attempting removal or force remove

docker stop 15ab848abe7a

docker rm 15ab848abe7a

docker rmi

To remove the docker image from the local we use the docker rmi command. Again, this comes with the restriction that if a container is used referring to the image, the image cannot be removed. Also, note the state f the container does not matter that means if the container is in the EXITED state but is referring to the image, the image cannot be removed. Below is an example.

docker ps -a

Output:
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
15ab848abe7a nginx "/docker-entrypoint.…" 3 hours ago Exited (0) 3 seconds ago relaxed_mendeleev

docker rmi nginx

Output:
Error response from daemon: conflict: unable to remove repository reference "nginx" (must force) -
container 15ab848abe7a is using its referenced image 6efc10a0510f

docker rm 15ab848abe7a

docker rmi nginx

Output:
Untagged: nginx:latest
Untagged: nginx@sha256:63b44e8ddb83d5dd8020327c1f40436e37a6fffd3ef2498a6204df23be6e7e94
Deleted: sha256:6efc10a0510f143a90b69dc564a914574973223e88418d65c1f8809e08dc0a1f
Deleted: sha256:a489ce38666d5aff5d73930d115381b154a503b48c5534357d5183160f5b9bfa
Deleted: sha256:ce2a611250a8bb55b73959de5865489d566bf48e1342c74b46b107e9a224370e
Deleted: sha256:fa6c51798227fd451cc3ff628c46c1b62c0d1d08e43374be7000c78ad910c0c0
Deleted: sha256:c426467d564c8684df87356eb045dc50d8b5af9521e9775c1b6bb941135680de
Deleted: sha256:c6deada06ccd386201e5b95c38e19297cd3eeb5264d6413d9cc7441020816401
Deleted: sha256:ed7b0ef3bf5bbec74379c3ae3d5339e666a314223e863c70644f7522a7527461

docker network

Docker network is a feature in Docker that enables you to create and manage networks of containers. A Docker network is a virtual network that provides communication between different containers on the same host or across different hosts. This helps in isolation, security, IP address management, etc.

docker network ls

Output:
NETWORK ID NAME DRIVER SCOPE
92eb170c4bc3 bridge bridge local
2943279d660b host host local
f4473a510dd4 none null local

docker build

We have been using the Nginx docker image that we pulled from DockerHub. We will see how we can build our custom image. This requires a Dockerfile. A Dockerfile is a text file that contains a set of instructions for building a Docker image. It provides a way to automate the creation of a Docker image by defining the base image to use, the dependencies to install, the environment variables to set, and the commands to run when the container is started. Below is an example of a Dockerfile.

# Use the latest Ubuntu as the base image
FROM ubuntu:latest

# Set the working directory to /app
WORKDIR /app

# Copy the hello.sh script to the /app directory
COPY helloworld.sh /app/

# Run the hello.sh script
CMD ["bash", "helloworld.sh"]

We will now build this file to create an image.

docker build -t [IMAGE_NAME]:[TAG] [PATH_TO_DOCKERFILE]

docker build -t mycustomimage:v1 .

Output:
[+] Building 12.7s (8/8) FINISHED
=> [internal] load build definition from Dockerfile 0.1s
=> => transferring dockerfile: 288B 0.0s
=> [internal] load .dockerignore 0.1s
=> => transferring context: 2B 0.0s
=> [internal] load metadata for docker.io/library/ubuntu:latest 6.0s
=> [internal] load build context 0.1s
=> => transferring context: 50B 0.0s
=> [1/3] FROM docker.io/library/ubuntu:latest@sha256:67211c14fa74f070d27cc59d69a7fa9aeff8e28ea118ef3babc295a0428a6d21 5.0s
=> => resolve docker.io/library/ubuntu:latest@sha256:67211c14fa74f070d27cc59d69a7fa9aeff8e28ea118ef3babc295a0428a6d21 0.0s
=> => sha256:67211c14fa74f070d27cc59d69a7fa9aeff8e28ea118ef3babc295a0428a6d21 1.13kB / 1.13kB 0.0s
=> => sha256:7a57c69fe1e9d5b97c5fe649849e79f2cfc3bf11d10bbd5218b4eb61716aebe6 424B / 424B 0.0s
=> => sha256:08d22c0ceb150ddeb2237c5fa3129c0183f3cc6f5eeb2e7aa4016da3ad02140a 2.30kB / 2.30kB 0.0s
=> => sha256:2ab09b027e7f3a0c2e8bb1944ac46de38cebab7145f0bd6effebfe5492c818b6 29.53MB / 29.53MB 3.0s
=> => extracting sha256:2ab09b027e7f3a0c2e8bb1944ac46de38cebab7145f0bd6effebfe5492c818b6 1.5s
=> [2/3] WORKDIR /app 0.9s
=> [3/3] COPY helloworld.sh /app/ 0.2s
=> exporting to image 0.2s
=> => exporting layers 0.1s
=> => writing image sha256:be5ba0695a0705f3db53e80354fdd28bf3efb3cd02a4228a61933ce1dadc4421 0.0s
=> => naming to docker.io/library/mycustomimage:v1 0.1s

docker images -a

Output:
REPOSITORY TAG IMAGE ID CREATED SIZE
mycustomimage v1 be5ba0695a07 32 seconds ago 77.8MB

We can see the steps performed while building the image from the Dockerfile. On listing the images, we can see our custom image has got a unique IMAGE_ID.

Conclusion:

Docker has become a de-facto standard for building containers and shipping the application to a microservice-based environment like Kubernetes or any serverless container platform. Before the containers are built using CI/CD pipelines and pushed to registries, it becomes necessary that the application is dockerized locally, tested well, and then moved to the pipelines. Docker CLI commands are necessary for the local debugging of containers, and images and for testing them on the local Docker environment. Hence, in this blog, we covered the most basic docker commands that are used on day to day basis. That's it from this blog of mine, suggestions are most welcomed.

--

--

Akash Mahale
DevOps Dudes

Cloud Engineer, DevOps - GCP | Azure | AWS | Kubernetes | DevSecOps