Although Docker is quite ubiquitous nowadays, there’re still many who never used it. Personally, I don’t use Docker every day, so I might forget bits and pieces. So this is a basic tutorial that should contain a couple of key things to get you started.

First of all, some people struggle with installation. It’s worth mentioning that Docker for Windows uses basically a virtual machine (although it might be changing with WSL2), Docker for Linux should run natively using your host operating system and its capabilities. I never used Mac, so I don’t know.

That said, on Windows, it’s enough to run Docker Dektop and use its UI. On Linux, and perhaps Mac as well, you need to do a little bit of setup before the first use.

Docker on Linux is just a daemon like many other services you run daily. If I query my local package database with pacman on an openrc system, I can see these two packages:

$ pacman -Qs docker
local/docker 1:20.10.10-1
    Pack, ship and run any application as a lightweight container
local/docker-openrc 20210505-1 (openrc-galaxy)
    OpenRC docker init script

They also have some dependencies that pacman takes care of when installing docker.

When I install these two, I still can’t really work with images and run containers, because the docker service is not running yet. So the first step is to start it:

$ sudo rc-service docker start

If you are on systemd system, it will likely be a similar command:

$ sudo systemctl start docker

And depending on whether or not you want to start the service automatically, you can enable it as well:

$ sudo systemctl enable docker

On openrc system, it’s enough to add a symlink to docker init file into your default (or whatever else) run level in somewhere like /etc/runlevels/.

Without running the docker service, you will receive an error when you try to use the docker command (e.g. $ docker ps -a or anything else).

If you use a different system, you need to find out how to start services on it. You need admin or root permissions for that.

When the service is running, there might be another thing to do, and that is to add your user to docker group. Without that you might receive a permission error when running docker command.

$ sudo usermod -aG docker pavel

This should solve the problem. Or you can manually, or with vigr command, edit /etc/group, but that’s more error prone.

Finally, it’s time to explore some of the most important commands.

$ docker 

This command with no parameters will simply show a help. Docker is quite large, so one way to work with it is that the second argument is a subcommand that defines what entity you are interested in. E.g. you want to work with images, you will use $ docker image, you want to work with containers, you will use $ docker container, etc.

Ok, let’s see all images:

$ docker image ls -a

If I’m unsure about what options commands might have, I can always use --help, e.g.:

$ docker image ls --help

Then I might want to see only running containers:

$ docker container ls

or all containers:

$ docker container ls -a

You can also see from the help, that some commands have aliases:

$ docker container ls --help

Usage:  docker container ls [OPTIONS]

List containers

Aliases:
  ls, ps, list

Options:
  -a, --all             Show all containers (default shows just running)
  -f, --filter filter   Filter output based on conditions provided
      --format string   Pretty-print containers using a Go template
  -n, --last int        Show n last created containers (includes all states) (default -1)
  -l, --latest          Show the latest created container (includes all states)
      --no-trunc        Don't truncate output
  -q, --quiet           Only display container IDs
  -s, --size            Display total file sizes

That’s because $ docker container ls is used so often that it makes sense to shorten it to $ docker ps.

Let’s now run some container. Obviously you can create your own images and run them as containers, but let’s choose a simpler example just to see how it’s done.

First, you can search for prepared images in Docker Hub. I’ll choose nginx.

Many image pages have detailed instructions on how to work with that image, so it’s worth reading it.

For now, I’ll just run:

$ docker run --name my-nginx -d -p 8080:80 nginx
Unable to find image 'nginx:latest' locally
latest: Pulling from library/nginx
eff15d958d66: Pull complete 
1e5351450a59: Pull complete 
2df63e6ce2be: Pull complete 
9171c7ae368c: Pull complete 
020f975acd28: Pull complete 
266f639b35ad: Pull complete 
Digest: sha256:097c3a0913d7e3a5b01b6c685a60c03632fc7a2b50bc8e35bcaa3691d788226e
Status: Downloaded newer image for nginx:latest
91cd3113932e04a9d70299a93e920acfdc8eb0a870ee41dad68dcaf88f4f929d

That means docker will look for nginx image (first localy, then in Docker Hub if not found locally) and run it as a container called my-nginx, which I can confirm from:

$ docker ps
CONTAINER ID   IMAGE     COMMAND                  CREATED         STATUS         PORTS                  NAMES
91cd3113932e   nginx     "/docker-entrypoint.…"   3 minutes ago   Up 3 minutes   0.0.0.0:8080->80/tcp   my-nginx

Now I can navigate to localhost 8080 port and see nginx start page:

image

When I’m done working with the container, I can shut it down:

$ docker container stop my-nginx
my-nginx

and:

$ docker ps

won’t show an running containers anymore.

I can remove a container as well:

$ docker container rm my-nginx
my-nginx

so not even:

$ docker container ls -a

will show this one container anymore.

However, I still have the image on my local machine:

$ docker image ls
REPOSITORY   TAG       IMAGE ID       CREATED      SIZE
nginx        latest    ea335eea17ab   2 days ago   141MB

so I can eventually delete that as well:

$ docker image rm ea335eea17ab
Untagged: nginx:latest
Untagged: nginx@sha256:097c3a0913d7e3a5b01b6c685a60c03632fc7a2b50bc8e35bcaa3691d788226e
Deleted: sha256:ea335eea17ab984571cd4a3bcf90a0413773b559c75ef4cda07d0ce952b00291
Deleted: sha256:cc284e9b1cbed75793782165a07a0c2139d8ec0116d1d562c0e2e504ed586238
Deleted: sha256:6207e091bef7f1c94a109cb455ba163d53d7c2c641de65e71d3a0f33c0ebd8ae
Deleted: sha256:97a18ff8c6973f64d763f004cad932319a1428e0502c0ec3e671e78b2f14256b
Deleted: sha256:319130834f01416a2e8f9a4f2b2fa082c702ac21f16e0e2a206e23d53a0a3bae
Deleted: sha256:1bc375f72973dc110c9629a694bc7476bf878d244287c0214e6436afd6a9d1b0
Deleted: sha256:e1bbcf243d0e7387fbfe5116a485426f90d3ddeb0b1738dca4e3502b6743b325

That means I have now no images on my local machine:

$ docker image ls -a
REPOSITORY   TAG       IMAGE ID   CREATED   SIZE

These few commands are in my opinion like 80 % of what you’ll ever need as a tester. In some situations you might also need to build your own images, I have done it a couple of times, but it’s less common in my opinion.

What are some lessons from all this then?

First of all, there are images and containers. You use images as the basic building block, then you run containers from those images. An image is like a template, a container is more like a concrete instance.

Docker, at least on Linux, is a daemon that has to be up and running in order to use docker command. On Windows, it’s enough to install Docker Desktop and follow instructions on the UI (I think it requires a reboot at some point…).

Since docker is a daemon, you manage it with your system utilities, e.g. with systemctl, or with rc-service. That has nothing to do with docker itself and you might not even find this is docker documentation. It’s up to you to know and be able to manage your local machine.

Docker Hub is a repository of docker images you can use.

And last but not least, docker command has a good documentation you can use when lost, it’s enough to type $ docker help or use --help option with docker commands. On reasonable systems, there’s a man page as well $ man docker.