CoursesDocker for beginnersInstalling Docker & your first run

Installing Docker & your first run

hello-world, and what just happened.

Beginner10 min · lesson 4 of 16
In plain terms
Docker has two halves: a kitchen crew that actually cooks (the daemon, working in the background) and an order pad you write on (the docker command). You never enter the kitchen — you hand tickets to the crew and they do the work.

Installing Docker puts two separate programs on your machine, and knowing which is which will save you hours later. The first is a background service called the Docker daemon. A daemon is a program that starts up and then runs quietly on its own, waiting for work to arrive. It never shows you a window. This one works like a kitchen crew: it does the actual cooking, fetching the software you asked for, running it, cleaning up after it. You never speak to the crew directly. The second program is the docker command you type into a terminal, the text window where you type instructions to your computer. That command is your order pad. You write a ticket, slide it across the counter, and the crew fills the order. Almost every lesson in this course is you writing tickets.

Which pieces you install depends on the machine in front of you. On Linux you install Docker Engine, and it runs containers directly. A container is an ordinary program running on your machine, fenced off in its own little space so it behaves as if it had the whole computer to itself. Linux already has the kernel a container needs. (The kernel is the core of the operating system, the part that actually talks to the hardware.) On a Mac or on Windows you install Docker Desktop instead. Containers need a Linux kernel, and your Mac or Windows machine doesn't have one, so Desktop quietly runs a small Linux virtual machine in the background, a whole extra computer simulated in software, and keeps your containers inside it. Either way you type the same docker commands. The examples below are Linux, because the one error nearly every beginner hits lives there.

Check that both halves are talking

Before you run anything real, get the two halves to say hello. The command docker version asks each of them to report in, and it prints one block per answer.

terminal
$ docker version
output
Client: Docker Engine - Community
Version: 27.3.1
API version: 1.47
Go version: go1.22.7
OS/Arch: linux/amd64
Context: default
Server: Docker Engine - Community
Engine:
Version: 27.3.1
API version: 1.47 (minimum version 1.24)
Go version: go1.22.7
OS/Arch: linux/amd64

Read it from the top. The Client block is the docker command you typed. The Server block is the daemon answering back. Two blocks, two version numbers, means your order pad reached the kitchen and the kitchen replied. That's the healthy result. If the Server half is missing, or shows an error where those numbers belong, one of two things is true: the daemon isn't running, or your account isn't allowed to talk to it. A stopped daemon on Linux starts with sudo systemctl start docker. On Docker Desktop you open the app and wait for the little whale icon to stop moving. The second cause, your account not being allowed in, is the wall nearly every beginner walks into on a brand-new Linux install. Let's walk into it on purpose.

Your first container

Tradition says your first run is a tiny image called hello-world. Two words are worth pinning down before you type it. A recipe card isn't a meal. It's the list of ingredients and the steps for making one. An image is Docker's recipe card: a read-only bundle of files plus a note saying which program to start. Read-only means that once the bundle is built, nobody edits it. A container is what you get when Docker follows the recipe and cooks it, the finished dish rather than the card. The hello-world image lives on Docker Hub, a public store of ready-made images, the way an app store is a shelf of ready-made apps. Its full name is hello-world:latest. The part after the colon is the tag, a label that picks which version you want, and latest is the label an image gets by default when nobody asks for a specific one.

Type it and read what comes back.

terminal
$ docker run hello-world
output
docker: permission denied while trying to connect to the Docker daemon socket at unix:///var/run/docker.sock: Head "http://%2Fvar%2Frun%2Fdocker.sock/_ping": dial unix /var/run/docker.sock: connect: permission denied.
Run 'docker run --help' for more information

Nothing is broken here, so resist the urge to reinstall. Read the words. Permission denied while trying to connect to the Docker daemon socket at /var/run/docker.sock. A socket is a special file the client uses to hand tickets to the daemon, like a service hatch cut through a kitchen wall. On Linux that hatch belongs to the root user (Linux's all-powerful admin account), so an ordinary login isn't allowed to reach through it. Your client tried, got turned away, and told you the exact spot where it was stopped. Run docker version on this same fresh install and its Server half carries the identical error, for the identical reason.

The fix is to let your account use that hatch. Docker creates a group named docker for exactly this purpose, and anyone in that group is allowed to reach the daemon. You add yourself once, with usermod. The -aG flags mean append the account to the named group and leave the groups it already belongs to alone. One snag: your terminal session started before you joined the group, so it hasn't noticed the change. Running newgrp docker opens a fresh session that carries the new membership, and logging out and back in does the same thing. Then the command that failed goes through.

terminal
$ sudo usermod -aG docker $USER
$ newgrp docker
$ docker run hello-world
output
Unable to find image 'hello-world:latest' locally
latest: Pulling from library/hello-world
c1ec31eb5944: Pull complete
Digest: sha256:d000bc569937abbe195e20322a0bde6b2922d805332fd6d8a68b19f524b7d21d
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.

That wall of text is Docker narrating its own steps. It looked for hello-world on your machine, didn't find it, and said so on the Unable to find image line. Then it pulled a copy down from Docker Hub. Then it created a container from that image and started the one small program inside, which printed the greeting. The program had nothing left to do, so it exited, and the moment a container's program exits, the container stops. Every docker run you ever type follows the same path: look locally, pull the image if it's missing, create the container, start it, and let it run until its program ends.

What every docker run does
1look locally
is the image on this machine?
2pull from Docker Hub
download it if it is missing
3create a container
set up from the image, not started yet
4run its program
prints the hello message
5program exits
the container stops
hello-world runs one command and quits, so its container stops the moment it finishes. A web server stays up instead, because its program never ends on its own.
The docker group is basically root
Here's the part most tutorials skip past. Anyone in the docker group can start a container that mounts your entire hard drive and rewrite it as the root user. Joining that group quietly hands out root-level power, even to an account with no admin rights at all. On your own laptop that's a fair trade for the convenience. On a shared machine or a real server, put people in the docker group deliberately, because you decided they need it, not because a tutorial told you to run the command. If that trade bothers you, Docker has shipped a rootless mode since version 20.10 that runs the daemon and your containers as your own user instead of root, which takes the group question off the table. It asks for a little setup in return, including extra work before a container can use a port below 1024.

The daemon has a name worth knowing: dockerd. That is the program doing the real work, pulling images, creating containers, wiring up networks, and on Linux it is what sits on the other side of /var/run/docker.sock. On Docker Desktop it lives inside that small Linux virtual machine, so your order pad is reaching across to another computer to hand over the ticket. Most install trouble is a break somewhere in that handoff, and the error text names which side stopped you, the way the permission line above did.

So make your smoke test boring, and run it in this order. docker version should print a Client block and a Server block. docker run --rm hello-world should print the greeting. docker ps should return a table, even an empty one with nothing but column headings. Once all three behave, you can start blaming your own app. Skip the check and you can lose an afternoon debugging an nginx port mapping on a machine where the daemon never started.

One habit to skip while you are here. You can put sudo in front of every docker command and it will work, which is how plenty of people end up typing sudo docker for years. That habit hides the group setup instead of fixing it, and it stops helping the day you sit at a machine where your account has no sudo rights.

Try this

Prove both halves are alive, then run hello-world with --rm so the finished container doesn't linger on your machine.

terminal
docker version --format "{{.Server.Version}}"
docker info --format "{{.Driver}} {{.OperatingSystem}}"
docker run --rm hello-world
output
27.x.x
overlay2 Docker Desktop
Hello from Docker!
This message shows that your installation appears to be working correctly.

Takeaway

The docker command is a client and nothing else. If docker version prints no Server block, or hello-world can't reach the socket, that's the engine talking, not your app. Get the engine answering first, before you touch a container of your own.

Quick check
01A brand new Linux box answers your very first docker run hello-world with a line that names /var/run/docker.sock and finishes with permission denied. Which conclusion does that one line actually support?
Incorrect — No download was ever attempted. Fetching an image is work the background service does, and your request never reached it.
Incorrect — A broken setup does not produce a complaint this precise. The file it names exists and answered you; it simply would not let you in.
Correct — Being refused proves somebody was there to refuse you. The work happens under an admin-owned file, and your login is not yet on the approved list.
Incorrect — When nothing is listening you get a missing-file style complaint instead. A refusal means something was awake and chose to say no.
02You type sudo usermod -aG docker $USER on that same Linux box, then immediately retry hello-world in the window you are already sitting in and get the exact same refusal. Why?
Incorrect — Dropping the a would wipe every other group your login belongs to, and the window you are typing in still would not notice the change.
Correct — Pick up a session that reads that list again, either by running newgrp docker or by ending your login and starting another, and the same command sails through.
Incorrect — Nothing on the engine side is out of date. The stale piece is the shell in front of you, which is why a fresh login alone is enough.
Incorrect — That command is for an engine that is not running, and yours clearly is. Starting it again says nothing about which groups your current window thinks you have.
03A colleague on a shared build server has no sudo rights at all, so you put their login in the docker group to unblock their test runs. What have you quietly handed them?
Incorrect — There are no lanes inside that group. Whoever can reach the engine can ask it about anything it is managing, no matter who started it.
Incorrect — The connection does not come in halves. Once they can talk to the engine at all, they can ask it to create a container on any terms they name.
Incorrect — No trimming happens anywhere. The engine on the far side already runs with full admin rights and carries out whatever it is asked to do.
Correct — That is the real trade this group makes. Fine on a laptop you own, and worth a deliberate decision on a machine other people depend on.

Related