puck tools — test your egress policy against real C2 traffic →

Getting Docker running

Before any of the interesting parts, you need a working Docker. This lesson gets you from nothing to a container you ran yourself, and explains the permission error that tends to arrive with the first command.

What you are installing

Docker ships as two halves. There is a daemon, a background service running as root that does the actual work, and a client, the docker command you type. They talk over a Unix socket usually at /var/run/docker.sock.

Install

Docker supports most linux distros, go here if you aren’t on a Ubuntu based system.

Ubuntu ships a docker.io package, and it works, but it lags a long way behind. Use Docker’s own repository. First remove anything from the distro that would conflict:

$ for pkg in docker.io docker-compose docker-compose-v2 docker-doc podman-docker containerd runc; do sudo apt-get remove -y $pkg; done

Add Docker’s signing key and repository:

$ sudo apt-get update
$ sudo apt-get install -y ca-certificates curl
$ sudo install -m 0755 -d /etc/apt/keyrings
$ sudo curl -fsSL https://download.docker.com/linux/ubuntu/gpg -o /etc/apt/keyrings/docker.asc
$ sudo chmod a+r /etc/apt/keyrings/docker.asc

$ sudo tee /etc/apt/sources.list.d/docker.sources <<EOF
Types: deb
URIs: https://download.docker.com/linux/ubuntu
Suites: $(. /etc/os-release && echo "${UBUNTU_CODENAME:-$VERSION_CODENAME}")
Components: stable
Architectures: $(dpkg --print-architecture)
Signed-By: /etc/apt/keyrings/docker.asc
EOF

$ sudo apt-get update

Then install the engine, the CLI, and the two plugins you will use:

$ sudo apt-get install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin

Check what you got:

$ docker --version
Docker version 29.6.1, build 8900f1d

$ docker compose version
Docker Compose version v5.3.1

There is also a Docker snap in the Ubuntu store. Avoid it for this course. The daemon is confined, so it cannot see paths outside your home directory or any hidden directory inside it, and a bind mount of /tmp/work silently gives you an empty directory instead of an error.

macOS and Windows

For macOS and Winodws Docker provides “Docker Desktop”. Details for install are here

There are some subtle differences between docker desktop and docker engine (what we installed for linux). Don’t worry too much about that now, we will call out where you can expect to see differences.

Your first container

$ docker run hello-world
Unable to find image 'hello-world:latest' locally
latest: Pulling from library/hello-world
4f55086f7dd0: Pull complete
Digest: sha256:5dd0d3e6e255913fc30f90b9f2b1d359cc2cbdb48090cc4b65f1676e203243cc
Status: Downloaded newer image for hello-world:latest

Hello from Docker!
This message shows that your installation appears to be working correctly.

To generate this message, Docker took the following steps:
 1. The Docker client contacted the Docker daemon.
 2. The Docker daemon pulled the "hello-world" image from the Docker Hub.
    (amd64)
 3. The Docker daemon created a new container from that image which runs the
    executable that produces the output you are currently reading.
 4. The Docker daemon streamed that output to the Docker client, which sent it
    to your terminal.

Check that out, assuming you got something similar you are all set up and ready to go.

Permission denied on the socket

What if you got a permission error like this?

$ docker run hello-world
permission denied while trying to connect to the docker API at unix:///var/run/docker.sock

Nothing is broken. Look at the socket:

$ ls -la /var/run/docker.sock
srw-rw---- 1 root docker 0 Aug 15 15:52 /var/run/docker.sock

Owned by root, group docker, mode 660. You are neither, so the kernel says no before Docker is even involved. Two ways forward.

Use sudo. sudo docker run hello-world works immediately and is honest about what is happening: you are asking a root service to do something.

Or add yourself to the group, which is what most people do:

$ sudo usermod -aG docker $USER
$ newgrp docker
$ id -nG
evan adm cdrom sudo dip plugdev lxd docker

Note newgrp gives the current shell the new group.

Be warned adding yourself to the docker group is equivalent to giving yourself passwordless root. The socket is an unauthenticated API to a root daemon, and anyone who can talk to it can ask for a container with the host’s entire filesystem mounted inside it. Three commands and you have /etc/shadow.

That is not a vulnerability, it is the design We look at this later in this course, including what you can do when you find that group membership on someone else’s machine.

For sensitive systems Docker has a rootless mode where the daemon runs as you. It costs you some networking features.