Docker Basics command-line

This article will introduce few basic Docker commands that will provide a good basis for further learning and help understanding how Docker is used.

Installation

We assume that you already have Docker installed. Docker provides Docker Desktop installation package for both Windows and MacOS. Installation instructions can be found from here: https://docs.docker.com/get-docker/. Linux users: because Docker is a Linux-based product, it is only necessary to install Docker Engine. Instructions for different Linux distributions can be found from here: https://docs.docker.com/engine/install/.

Couple of Words About Terminology

In this article we are talking about “images” and “containers”. An image is a basis for a container. So, when Docker is running, it is using an immutable image file to create one or more containers that are executed.

Usage

The simplest use-case for Docker is to use run command to execute a Docker image:

docker run hello-world

Note: Depending on how Docker Engine is installed, Linux users might need to use sudo command to execute Docker commands. For example, sudo docker run hello-world.

In the example above, Docker first checks, if an image called “hello-world” can be found from the local computer. If not, then the image will be loaded from Docker Hub. Then, the loaded image will be used for creating a container that is started. The end-result should be a short greeting from the container.

Example Project

We will go through Docker basics by using a simple Docker configuration file. Create a file called “Dockerfile” and copy the following three lines into it.

Dockerfile:

FROM python:3
COPY . /www
CMD ["python", "-m", "http.server", "8080"]

FROM line is always mandatory. The line defines what ready-made image will be used for creating your own container image. Every Docker image file is built on top of an existing Docker image. The only exceptions are so called “base images”, which are used to create other images. Also, with these files, the FROM line is required, but the name of the image is always “scratch”. The “3” after the colon is a tag defining more specifically, what image version we are going to use. In our case, we need version 3 of the Python interpreter, so we define this by using a tag. More about tags in a separate blog post.

COPY line is used to copy local files inside the container image. The two elements after the command define the source and target paths. In our case, during the creation of the image, we will copy all files from the current local folder to the “/www” folder inside the image.

CMD line is a bit different. Contrary to the previous commands, this is not executed during the building process of the image. This line is set as a default command that will be executed automatically, when the container is started. If there is a need to execute custom commands inside the image during the build process, there is a command called RUN for that purpose.

Command-line:

docker build -t mytest .

The command above will build a Docker image using the Dockerfile found in the current folder. The resulting image file is called “mytest” and is stored in the local Docker library, ready for use.

You can list the locally stored Docker images using the following command:

docker image ls

Running our newly created image is done by using the following command:

docker run -p 8080:80 mytest

After executing the run command, open a web browser and navigate to the address: http://localhost:8080 . Now you see inside the actual container. Note, for example, what the COPY command did. Inside the “www” folder should be our Dockerfile.

The command-line argument -p 8080:80 tells Docker that we want to route the TCP port number 80, opened inside the container, to the host machine port 8080. With Docker command-line arguments, the order of all item relations between the container and the host are defined in this order: host:container.

Typing Ctrl+C shuts down the container.

Docker run command is a handy way to running containers, but often – as with our HTTP server – it would be better to run the container in the background without reserving the terminal. This is possible by adding the command-line argument -d.

docker run -d -p 8080:80 mytest

Now the container is started in the background and we have our terminal for our own use.

Shutting down the container is simple. First we list the running containers and then give a kill order to the relevant container:

docker container ls

Output:

Shutting down:

docker kill <CONTAINER ID> or <NAME>

Container ID is a unique ID that can be used when referencing to the containers. You don’t need to type the whole ID, it’s enough to type from the beginning just enough letters that the container can be uniquely identified. In this example output, it’s enough to type for example just “d3”. Docker also generates automatically a unique name for the container. In my example run, it seems to be “busy_ramanujan”. You can also use this name instead of the ID to refer the container you will perform any actions.

Every time Docker runs a container, it creates a new instance. They are not recycled. Even though a container is discarded and not re-used, it is left behind in the file system. This allows users to inspect failing containers and retrieve log files. You can check for the dead containers that are left behind by executing the following command:

docker container ls -a

These can be removed one by one by using the command rm or by cleaning up all at once with prune command.

One by one:

docker container rm <CONTAINER ID>

All shut down containers at once:

docker container prune

If you want to keep your computer clean and not leave anything behind, you can prevent dead containers by adding --rm argument to the run command:

docker run --rm -d -p 8080:80 mytest

In the beginning of this blog post, I described the CMD line of the Dockerfile as a default command to be executed. In other words, it’s possible to execute other commands instead of the pre-defined one. This knowledge can be utilized in situations, where you want to get inside the container at run-time. For example, you can peek inside the www folder and see, what has been copied there: docker run --rm mytest ls -l /www.

By default, containers are totally isolated from the outside world. This means that there are no local input or output devices or a terminal defined. We have to explicitly define those for a container by adding parameters -i (“interactive”) and -t (“pseudo TTY”) for the run command. These are needed for an interactive terminal. To explore a running container, we can start a command-line inside a container by utilizing the bash terminal that is shipped with the Python Docker image:

docker run --rm -i -t mytest bash

Now we can use the container like a normal Linux environment. We can explore, what the container contains, we can make changes, run programs or install new libraries and applications. When we want to exit the container, simply type exit and the container is shut down. And all the changes we have made inside the container will be lost.

This was only a very light introduction for running Docker containers. An excellent source for learning more about Docker commands is this: https://docs.docker.com/engine/reference/commandline/cli/

Also, there is an invaluable source of information for creating Dockerfiles: https://docs.docker.com/develop/develop-images/dockerfile_best-practices/

In the next part, we will get to know Docker tags, a topic that deserves its own blog post.

Writer is Matti Kärki, a senior developer from Ouro

Previous Post
What are containers and Docker?
Next Post
It has always been computers – Marta’s career story