First steps with Docker after the installation

By

First steps with Docker after the installation: run a ready-made container, start a multi-container app with Docker Compose, then build your own image.

~~~

After you complete the Docker installation, you have Docker Desktop running and the docker command available in your terminal.

Now we can do something with it. We’ll run a ready-made container, start an app made of several containers, and then build an image of our own and run it.

Along the way you’ll see how images and containers relate. An image is the package, and a container is that package running.

Check that Docker is running

Open your terminal and run:

docker version

You should see two blocks of output, Client and Server.

The client is the docker command you just typed. The server is the Docker Engine that actually runs containers, and on a Mac it lives inside Docker Desktop.

If the Server part is missing and you get an error saying Docker can’t connect to the Docker daemon, Docker Desktop isn’t running. Open it, wait until it says the engine is running, and try again.

Run your first container

Run this command:

docker run -d -p 80:80 docker/getting-started

The first time, Docker doesn’t have the docker/getting-started image on your computer. It downloads it from Docker Hub, starts a container from it, and prints the container ID, a long string of letters and numbers.

Now open http://localhost in your browser. You’ll see Docker’s getting-started tutorial, served by a web server that runs inside the container.

In that command, the -d option runs the container in the background and prints the container ID. Without it, your terminal stays attached to the container until it exits, and a web server is long-lived, so you’d never get the prompt back.

-p 80:80 maps port 80 on your computer to port 80 in the container. The web server listens on port 80 inside the container, and this mapping is what lets your browser reach it. The format is always host:container.

The last argument is the name of the image to run.

If port 80 is already in use, docker run fails. When another container holds the port, the error ends with port is already allocated. When another program on your computer holds it, the error says address already in use. Either way, pick another port on your side of the mapping:

docker run -d -p 8080:80 docker/getting-started

and open http://localhost:8080 instead. The container side stays 80, because that’s where the server inside it listens.

To see the containers that are running, use:

docker ps

In the last column you’ll see the random name Docker gave the container, like quirky_hopper. Stop and remove the container using its ID or that name:

docker rm --force quirky_hopper

The image stays on your computer, so the next docker run starts right away, without downloading it again.

Pull an image, then run it

The docker/getting-started image is an older tutorial. Docker’s own documentation now starts with a smaller image called docker/welcome-to-docker.

This time let’s download the image first, as a separate step:

docker pull docker/welcome-to-docker

Then start a container from it:

docker run --detach --name welcome --publish 8080:80 docker/welcome-to-docker

--detach and --publish are the long versions of -d and -p. They do the same thing, but the long names are easier to read in docs and scripts.

--name gives the container a name we pick, welcome, instead of a random one.

Open http://localhost:8080 to see the page.

Since the container has a name, removing it is easy:

docker rm --force welcome

Run an app made of several containers

Real applications often have more than one part, like a frontend, an API and a database.

You could start each one with its own docker run command, but then you’d have to keep all those commands and their settings in sync.

Docker Compose solves this. You describe every part of the app in a compose.yaml file, and Compose starts them together. It comes with Docker Desktop.

Docker has a to-do app we can use to try it.

I open the macOS Terminal, run cd dev to go into my home dev folder, and create a docker subdirectory, where I host all my Docker experiments. I run cd docker to go into it.

Then clone the app and move into its folder:

git clone https://github.com/docker/getting-started-todo-app
cd getting-started-todo-app

Its compose.yaml file defines five services: a frontend, a Node.js API, a MySQL database, phpMyAdmin to look at the database, and a proxy that sends each request to the right service. Each service runs in its own container.

Start the whole stack:

docker compose up --build --detach

--build builds the images for the frontend and the API from the project’s source, and --detach leaves everything running in the background. The images for the other services are downloaded from Docker Hub.

The first run takes a while, because Docker installs the npm dependencies while building. When it’s done, open http://localhost and add a couple of items to the list.

The proxy listens on port 80. If you still have the docker/getting-started container running on port 80, remove it first.

See the containers Compose started:

docker compose ps

You get one row per service.

When you’re done, stop and remove the whole stack:

docker compose down --volumes

--volumes also deletes the volume where the database kept its data, so the next time you start the app, you begin with an empty list.

Build your own image

So far we ran images someone else built. Now let’s build one.

The to-do app repository contains a Dockerfile. It’s a list of instructions that tells Docker how to build an image: which base image to start from, which files to copy, which commands to run.

From the getting-started-todo-app folder, run:

docker build --tag todo-app .

--tag gives the image a name, todo-app. The final . tells Docker to look for the Dockerfile and the source files in the current folder.

Docker runs each step of the Dockerfile, downloading the base image if it doesn’t have it yet, and prints its progress as it goes. At the end, the image is on your computer:

docker images

This image packages the frontend and the API together, and the server inside listens on port 3000. So we map that port:

docker run --detach --name todo --publish 8080:3000 todo-app

Open http://localhost:8080. This time the app runs from the image you built.

Remove the container when you’re done:

docker rm --force todo

If you want to share the image, you can push it to Docker Hub. The name then needs your Docker Hub username as a prefix, like yourusername/todo-app.

When you’re not sure about an option

Every Docker command has built-in help. Add --help after it:

docker run --help

You get the full list of options, each with a short description. It’s the fastest way to check what a flag does while you work.

Tagged: Docker · All topics

Want me to talk about your product? You can sponsor this site.

~~~

Related posts about docker: