Diving deeper into Docker: basic administration techniques

Feb 1, 2024

This article is part of the series:

It’s crucial to understand some common parameters in Docker that are essential for its day-to-day administration. These parameters will help you manage and manipulate containers effectively. We will see some that will assist us in managing our Docker containers and how to analyze configurations in depth.

In daily use, it’s common to have several containers running at the same time, each with its own purpose, so it’s important to know how to keep them under control. Otherwise, we might face performance issues in our system or even security problems.

As we saw in the previous chapter, we can run a container using the docker run command from an image in the Docker registry. If we use the -d parameter when starting it, it will continue running in the system until explicitly stopped. If you’re familiar with Linux, many of the following parameters will be familiar to you; if not, why not check it out?

Just like the ps command would show us active processes in Linux, in Docker we can display running containers using docker ps. Let’s launch two containers with the Nginx service to illustrate this example. We will use the -d parameter to launch them in the background and the -p parameter to map the ports to the system’s ports so that the service is accessible from outside the container, in our case localhost.

  
  docker run -d -p 8080:80 --name mynginx nginx
  docker run -d -p 8081:80 --name mynginx2 nginx
  

We can verify that both services are listening on their respective ports by accessing them through the localhost address, as we can see in the previous image. Using the docker ps command, we will see the information about the running containers:

  
  CONTAINER ID   IMAGE     COMMAND                  CREATED              STATUS              PORTS                                   NAMES
  f641152deaf0   nginx     "/docker-entrypoint.…"   2 seconds ago        Up 2 seconds        0.0.0.0:8081->80/tcp, :::8081->80/tcp   mynginx2
  3c224ed3e7f4   nginx     "/docker-entrypoint.…"   About a minute ago   Up About a minute   0.0.0.0:8080->80/tcp, :::8080->80/tcp   mynginx
  

Creating two Nginx services that listen on different ports is a simple way to exemplify the use of the ps command. In it, we can see the container ID, the image that is being executed, the command, the time it has been running, the status it is in, the ports it is using mapped with their corresponding ones in the system, and the name we have given to the container.

Thanks to the container ID, we can access it for a multitude of tasks such as viewing the logs, stopping it, restarting it, and more. For instance, if we want to view the logs of the mynginx2 container, we can use the docker logs command followed by the container ID:

  
  docker logs f641152deaf0
  

Just like in Linux, we can add the -f parameter after logs to view the logs in real-time as new interactions are received. We can also do this using its name with docker logs -f mynginx2. To stop it, we can use the docker stop command along with the name or ID:

  
  docker stop mynginx2
  

If we run ps again, we will see that the container is no longer in execution:

  
  CONTAINER ID   IMAGE     COMMAND                  CREATED              STATUS              PORTS                                   NAMES
  3c224ed3e7f4   nginx     "/docker-entrypoint.…"   About a minute ago   Up About a minute   0.0.0.0:8080->80/tcp, :::8080->80/tcp   mynginx
  

If we want to restart it, we can use the docker start command:

  
  docker start mynginx2
  

It will reappear after running ps again, but we can also remove those that are not in execution if we no longer need them, using the docker rm command:

  
  docker rm mynginx2
  

As we saw in the first chapter, a container is not the same as a volume or an image. With this command, we have removed the container, but not the image. Thus, if we re-execute the docker run command with the same image, a new container will be created with a new ID based on that image. If the container had an associated volume, it would not be deleted, so the data would still be available in case the volume was configured for persistence.

Different components of Docker are independent of each other, but some may depend on others. For example, we cannot delete an image if there is a container running based on it, but we can delete a container without needing to do the same with the image or associated volume.

Another available command is for listing containers, volumes, images, networks, etc. Like in Linux, in Docker, we use ls to list elements of a specific type. For instance, if we want to list the containers executed in the system, we can use the docker container ls command, which serves the same function as ps or docker container ls -a to list all containers, active or not. We can also view volumes with docker volume ls, images with docker image ls, or networks with docker network ls.


    docker container ls -a
    
    CONTAINER ID   IMAGE         COMMAND                CREATED             STATUS                      PORTS                                   NAMES
    f641152deaf0   nginx         "/docker-entrypoint.…" 2 seconds ago       Up 2 seconds                0.0.0.0:8081->80/tcp, :::8081->80/tcp   mynginx2
    3c224ed3e7f4   nginx         "/docker-entrypoint.…" About a minute ago  Up About a minute           0.0.0.0:8080->80/tcp, :::8080->80/tcp   mynginx    
    7g8h9i0j1k2l   mysql         "docker-entrypoint…"   5 minutes ago       Up 5 minutes                3306/tcp, 33060/tcp                     mydb
    3m4n5o6p7q8r   redis         "redis-server"         10 minutes ago      Exited (0) 7 minutes ago    6379/tcp                                mycache
    

    docker volume ls
    
    DRIVER    VOLUME NAME
    local     myapp_data
    local     mysql_data
    local     redis_data
    

    docker image ls
    
    REPOSITORY   TAG       IMAGE ID       CREATED          SIZE
    nginx        latest    4f8f078ecf98   1 days ago      133MB
    mysql        latest    8b1b3a5d8c5a   2 weeks ago      556MB
    redis        latest    4c1e6f7ac9a6   3 weeks ago      104MB
    

    docker network ls
    
    NETWORK ID   NAME      DRIVER    SCOPE
    1a2b3c4d5e   bridge    bridge    local
    6f7g8h9i0j   host      host      local
    1k2l3m4n5o   none      null      local
    

Inspecting a container allows us to know which image, volume, network, and components are associated with it and in what conditions. These tools enable us to manage our containers more advancedly and debug errors or incorrect configurations more easily. As seen in the previous examples, each type of element within Docker has its own ID, giving us the flexibility to inspect each one deeply and individually using the inspect command followed by the ID of the element we want to inspect. For example, if we want to inspect the mynginx container, we can do so with the command docker inspect 3c224ed3e7f4. This will display a JSON with all the container’s information, such as the network configuration, volumes, port settings, etc. They usually contain a large amount of information, but to summarize, here I show you an example of the container’s network and its configuration:

    
    [
        {
            "Name": "mynginx",
            "Id": "ece4adc3f56e2afd60d486a2ad9bd7ce6f2ffd0a35ae13a4cbfd49be0ed5d3e8",
            "Created": "2024-01-31T19:15:46.881217789+02:00",
            "Scope": "local",
            "Driver": "bridge",
            "EnableIPv6": false,
            "IPAM": {
                "Driver": "default",
                "Options": null,
                "Config": [
                    {
                        "Subnet": "172.30.0.0/16",
                        "Gateway": "172.30.0.1"
                    }
                ]
            },
            "Internal": false,
            "Attachable": true,
            "Ingress": false,
            "ConfigFrom": {
                "Network": ""
            },
            "ConfigOnly": false,
            "Containers": {},
            "Options": {},
            "Labels": {
                "com.docker.compose.network": "default",
                "com.docker.compose.project": "mynginx",
                "com.docker.compose.version": "1.29.2"
            }
        }
    ]
    

In this way, we can thoroughly analyze each of the elements involved in the execution of our containers. I invite you to try the different commands to get a better idea of how everything is orchestrated beneath the abstraction layer of Docker. It will help you in the future to debug errors and better understand how your services function.

We have seen how to start and manage our containers, as well as some basic useful parameters and commands. But what if we want to run several containers at the same time? How can we simplify management in more complex projects? In the next chapter, we will explore another approach that will allow us to manage them more efficiently and orchestrate them together.

I hope this has been helpful, and feel free to leave any questions or suggestions in the comments section. See you next time!

Related posts

That may interest you

December 1, 2023

Discovering Docker

Docker is a virtualization platform that offers a unique methodology for packaging and distributing …

read more