Docker is a powerful platform for running containerized applications. It allows developers to easily package, deploy, and run applications in an isolated environment called a container. Containers are more lightweight and portable than virtual machines, making Docker a very useful tool.
In this comprehensive guide, we will cover the most common and useful Docker commands with practical examples to help you get started with Docker.
Finding the Docker Version
To check the version of Docker installed on your system:
docker --version
This will print out the version number of your Docker installation:
Docker version 20.10.12, build e91ed57
Knowing the Docker version is useful when you need to check compatibility or look up documentation for specific features.
Downloading Docker Images
Docker images contain all the dependencies and configuration required to run an application inside a Docker container. Images are available from public repositories like Docker Hub or private repositories.
To download an image from a repository, use the docker pull
command:
docker pull ubuntu
This will pull the latest version of the ubuntu
image from Docker Hub:
20.04: Pulling from library/ubuntu
8559a31e96f4: Pull complete
51d229c90eb8: Pull complete
bac681833d4f: Pull complete
Digest: sha256:626ffe58f6e7566e00254b638eb7e0f3b11d4da9675088f4781a50ae288f3322
Status: Downloaded newer image for ubuntu:20.04
You can now run containers based on this ubuntu image.
Listing Docker Images
To see all images that are available locally on your Docker host, use the docker images
command:
docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
ubuntu 20.04 cd6d8154f1e1 4 weeks ago 72.9MB
nginx latest 82a59828381d 3 months ago 141MB
mysql 5.7 b0b168632190 3 months ago 448MB
This lists out all Docker images present on the system along with details like repository name, tag, image ID, created date, and size.
By default, intermediate images used during builds are not displayed. To include those, use the -a
flag:
docker images -a
Running a Docker Container
To start a new Docker container from an image, use the docker run
command:
docker run -it ubuntu bash
This will start a new interactive Ubuntu container and open up a Bash shell inside it.
The -it
flags tells Docker to allocate a pseudo-TTY connected to the container‘s stdin so we can interact with it. bash
overrides the default command to launch Bash instead.
Once inside the container, you can run Linux commands like:
root@d9b100f2f636:/# cat /etc/os-release
NAME="Ubuntu"
VERSION="20.04.2 LTS (Focal Fossa)"
ID=ubuntu
ID_LIKE=debian
PRETTY_NAME="Ubuntu 20.04.2 LTS"
VERSION_ID="20.04"
HOME_URL="https://www.ubuntu.com/"
SUPPORT_URL="https://help.ubuntu.com/"
BUG_REPORT_URL="https://bugs.launchpad.net/ubuntu/"
PRIVACY_POLICY_URL="https://www.ubuntu.com/legal/terms-and-policies/privacy-policy"
VERSION_CODENAME=focal
UBUNTU_CODENAME=focal
When done, type exit
to terminate the container.
List Running Containers
To view all running containers, use:
docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
d9b100f2f636 ubuntu "bash" 2 hours Up 2 hour focused_jones
This shows all running containers with details like the container ID, source image, creation time, status, ports, and name.
List All Containers
To view all containers — both running and stopped, use the -a
(all) flag:
docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
d9b100f2f636 ubuntu "bash" 2 hours ago Up 2 hours focused_jones
e2caf7728d5f nginx:latest "nginx" 2 days ago Exited (0) 2 days ago zealous_swartz
a4542f719dc9 mysql:5.7 "mysqld" 2 weeks ago Exited (255) 2 weeks ago mysql01
This allows you to view even containers that were run in the past and are now stopped.
Executing Commands in Running Containers
To execute a command inside an already running container, use docker exec
:
docker exec -it focused_jones bash
This will open up a new Bash session attached to the running container with ID focused_jones
.
You can similarly run other commands like ls
, cat
or check top
from within the container:
root@d9b100f2f636:/# ls
bin boot dev etc home lib lib64 media mnt opt proc root run sbin srv sys tmp usr var
root@d9b100f2f636:/# cat /etc/hostname
d9b100f2f636
Stopping a Container
To stop a running container, use the docker stop
command:
docker stop focused_jones
This will send a SIGTERM signal to gracefully stop the container. Once the main process exits, the container stops running.
If you want to forcibly stop a container immediately, use docker kill
:
docker kill focused_jones
This kills the container by sending it a SIGKILL instead.
Removing a Container
To remove a stopped container, use docker rm
:
docker rm focused_jones
This will free up all resources associated with the container. Note that you can only remove stopped containers – not running ones.
To remove a running container, first stop it and then remove it:
docker stop focused_jones
docker rm focused_jones
If you want Docker to automatically clean up stopped containers, use --rm
when running the container:
docker run --rm -it ubuntu bash
This container will be removed automatically after it exits.
Committing Changes in a Container
When you start a container from an image, you can make changes inside it, such as writing new files, installing packages, etc. To save these changes as a new Docker image, use docker commit
:
docker commit focused_jones ubuntu-updated
This will create a new image named ubuntu-updated
containing all the changes made in the focused_jones
container.
You can now run new containers from the updated image.
Pushing Docker Images to a Registry
To share Docker images with others, you can push them to public or private image registries like Docker Hub.
First, log into Docker Hub from the CLI:
docker login --username=your-docker-id
Then, tag your image with the repository name:
docker tag ubuntu-updated your-docker-id/ubuntu-updated
Finally, push it to Docker Hub:
docker push your-docker-id/ubuntu-updated
This uploads your image to your Docker Hub repository.
Pulling Images from a Registry
Other users can now download your image by running:
docker pull your-docker-id/ubuntu-updated
This way, Docker‘s registry system allows easy sharing of images between users.
Private registries work similarly, but require credentials and HTTPS to secure image transfers.
Tagging an Image
Docker images can have multiple tags associated with them. For example, ubuntu
image has tags like 20.04
, 18.04
, latest
etc.
To tag an existing image to a new tag:
docker tag ubuntu:latest ubuntu:jammy
This creates a new tag jammy
that refers to the same ubuntu:latest
image.
You can also tag images at the time of building – for example:
docker build -t webapp:v1 .
Tags let you version images and refer to them more meaningfully.
Getting Docker Container Logs
To print out logs from a Docker container use:
docker logs focused_jones
INFO Started MySQL successfully!
INFO Creating database structure...
This shows application logs generated by the processes running inside your container.
You can follow logs in real-time with the -f
flag:
docker logs -f focused_jones
INFO Creating user admin123...
INFO User admin123 created!
Container logs allow easy debugging of issues inside your containers.
Restarting a Container
Sometimes you may need to restart containers due to application failures or to refresh configuration changes.
Use the docker restart
command for this:
docker restart focused_jones
This will send a SIGTERM followed by SIGKILL after a grace period, to restart the main container process.
If you just want to send a SIGTERM, you can use docker stop
and docker start
instead.
Accessing Docker Container Filesystem
The files inside a Docker container are readable/writable via the container‘s filesystem.
To copy a file out of a container onto the host, use docker cp
:
docker cp focused_jones:/var/log/nginx/access.log ./access.log
This will copy /var/log/nginx/access.log
from inside the container onto the host machine‘s current directory as access.log
.
You can also copy files from host into a container, e.g. to inject configuration files.
Docker Networks
By default, containers run on a private virtual network called bridge
which provides internal IPs and container discovery using DNS.
To list out Docker networks:
docker network ls
NETWORK ID NAME DRIVER SCOPE
c7527e93a56c bridge bridge local
b3b2c4d0fc4c host host local
2885e5cc56f2 none null local
Common networks include:
-
bridge
– The default network for containers used for internal communication. -
host
– Adds containers directly onto the host‘s network stack. -
none
– Removes all networking including external connectivity. -
User defined networks – Create your own networks like
frontend
,backend
etc.
Managing Docker Volumes
Docker volumes provide persistent data storage for containers. Even if a container is deleted, the data stored on volumes persist.
Some common volume commands are:
-
docker volume create my-vol
– Creates a new volume namedmy-vol
-
docker volume ls
– Lists all volumes -
docker volume inspect my-vol
– Displays details aboutmy-vol
volume -
docker volume rm my-vol
– Removes the volumemy-vol
When running a container, you can mount a volume inside it using the -v
flag:
docker run -v my-vol:/data ubuntu
This mounts the volume my-vol
onto the /data
directory inside the container. Any data written here is stored on the volume.
Building Docker Images
To build your own Docker image from a Dockerfile, use the docker build
command:
docker build -t myimage:1.0 .
This looks for a Dockerfile in the current directory and builds an image named myimage:1.0
from it.
Image building best practices include:
-
Specify a tag like 1.0, 1.1 rather than just
latest
for versioning. -
Organize Dockerfiles into separate directories for each application component.
-
Use small base images like Alpine Linux to keep sizes small.
-
Leverage Docker‘s build cache by ordering commands from least frequently changed to most.
-
Don‘t install unnecessary packages or leave behind large build dependencies.
Dockerfile Commands
Some key Dockerfile instructions are:
FROM
– Sets base image to build uponCOPY
– Copy files from host into imageRUN
– Execute Linux commands/scripts during buildEXPOSE
– Expose ports that the container listens onENV
– Set environment variablesCMD
– Set the default command to run on container startENTRYPOINT
– Set executable invoked when starting containerUSER
– Switch to given user upon container startWORKDIR
– Set working directory forRUN
,CMD
etc.
For example:
FROM alpine:3.14
RUN apk add --update nodejs
COPY . /app
WORKDIR /app
RUN npm install
EXPOSE 3000
ENTRYPOINT ["node", "server.js"]
This builds a container that runs a Node.js application.
Sharing Data Between Containers
There are two main ways to share data between containers:
Volumes: Create a shared volume and mount it onto multiple containers
docker volume create shared-vol
docker run -v shared-vol:/volume1 --name container1 ubuntu
docker run -v shared-vol:/volume2 --name container2 ubuntu
Any data written to /volume1
or /volume2
is available to both containers.
Networks: Place containers on the same user-defined bridge network
docker network create app-net
docker run -d --network app-net --name mysql mysql
docker run -it --network app-net ubuntu
Now both containers can access each other over the app-net
network.
Limiting Container Resources
By default, containers have unrestricted access to the host machine‘s resources.
You can set limits on:
-
CPU – Limit CPU shares using the
--cpus
flag or CPU period/quota. -
Memory – Set memory limit via
--memory
. -
Restart Policies – Use
--restart
to apply a restart policy.
For example, to limit a container to use max 2 CPUs and 1GB RAM:
docker run --cpus=2 --memory=1g nginx
Resource constraints allow limiting the impact of any single container on overall host performance.
Docker Security Best Practices
Some basic security best practices for using Docker include:
-
Run containers as a non-root user where possible using
USER
. -
Limit container capabilities to the minimum required using
--cap-drop=ALL --cap-add=...
-
Update Docker and avoid old base images with known vulnerabilities.
-
Scan images for vulnerabilities using tools like Anchore or Trivy.
-
Use
-v
binds rather than--volumes-from
to selectively expose volumes. -
Limit communication between containers using custom Docker networks if needed.
-
Use secrets/configs for sensitive data and Never store secrets in Dockerfiles or source code.
-
Sign and verify images using Docker Content Trust to prevent tampering.
-
Use hardware/cloud signing to establish trust for the Docker daemon.
-
Follow the principle of least privilege throughout – ensure containers have only the permissions truly required.
Conclusion
Docker provides a simple and powerful way to run containerized applications on any infrastructure. Core Docker commands like run
, ps
, images
, exec
and build
allow you to manage the entire container workflow.
With the examples covered in this guide, you should have a good understanding of the most essential Docker commands for development and testing. To take your skills to the next level, I recommend checking out more advanced Docker features like Swarm, Kubernetes, and security hardening.