Lesson 06/14 minutes/2 graded
Run containers
Detached mode, port binding, container names, and why docker run keeps leaving containers behind on your machine.
Time to actually run something. I am using nginx for this, because it is a web server with a page you can open in a browser, so you get proof it worked instead of a log line you have to trust.
Start it in the foreground first
You pulled nginx:1.30.4-alpine last lesson. Run it:
docker run nginx:1.30.4-alpine
Your terminal fills with nginx starting up and then sits there. Those are the logs of the process inside the container, printed straight to your screen, and the last line will be about starting worker processes. The container is running, and your terminal is stuck.
Press Ctrl+C. The container stops, because you just killed the process it was running.
Then start it properly, in the background
Add -d, which stands for detached:
docker run -d nginx:1.30.4-alpine
This time you get one long line of letters and numbers back. That is the container id, and your prompt is free again. Check what is running:
docker ps
One row, with a short version of that id, the image it came from, when it started, and a name Docker made up for you, two random words joined together.
To see the logs you skipped by detaching, ask for them by id. The first few characters are enough:
docker logs a1b2c3
Two versions at the same time
Remember the promise from lesson one. Run a second, older nginx alongside the first:
docker run -d nginx:1.29-alpine
docker ps now shows two containers, one on 1.30.4 and one on 1.29.8, both
running, neither bothered by the other. Two installs of nginx on my Fedora host
would have been a fight over one config directory.
Reaching it from your browser
Open http://localhost:80 and there is nothing there. The container is running,
but it is on Docker's own network, not yours.
Every service listens on a standard port inside its container. nginx uses 80,
Redis uses 6379, Postgres uses 5432. The docker ps output shows you that port.
What you need is to connect a port on your machine to that port inside the
container, and that is called port binding. The flag is -p, and it takes your
port first, then the container's:
docker stop a1b2c3
docker run -d -p 9000:80 nginx:1.30.4-alpine
Now open http://localhost:9000. You get the nginx welcome page, titled
"Welcome to nginx!". Check that container's logs and your visit is in there: one
line holding the address the request came from, the time, "GET / HTTP/1.1",
and the status 200, followed by the name of your browser.
So the request went from your browser, through the port binding, into the
container, and nginx answered. docker ps shows the binding too, so when you
have five containers running you can look up which port each one is on instead
of guessing.
Which port you pick on your side is up to you, but matching the container's port is the common habit. A MySQL container listening on 3306 gets bound to 3306 on the host. It saves you thinking about it later.
Names you chose yourself
Container ids are horrible to type and Docker's generated names are random. Give the container a name when you create it:
docker run -d -p 9000:80 --name web-app nginx:1.30.4-alpine
Every command that took an id takes the name instead:
Stopping, and what stopping does not do
docker stop web-app stops it. docker ps shows nothing.
Here is the part that surprises people. Every docker run creates a brand new
container, so if you have run that command five times, you now have five
containers on your machine. Stopped ones are hidden from docker ps, but they
are still there:
docker ps -a
The whole list shows up, with "Exited" and how long ago for the stopped ones. To
start one of those again, you do not need run, which would build another one.
Use its name or id:
docker start web-app
Your turn
Bind a container so you can reach it in the browser, in the background, with a name of your own.