Profundizando en Docker, técnicas básicas de administración

feb. 1, 2024

Este artículo forma parte de una serie:

Es crucial entender algunos parámetros comunes en Docker que son esenciales para su administración a diario. Estos parámetros te ayudarán a gestionar y manipular contenedores de manera efectiva. Veremos algunos que nos ayudarán a la hora de gestionar nuestros contenedores Docker y cómo analizar las configuraciones en profundidad.

En el uso diario es común tener varios contendores ejecutándose al mismo tiempo cada uno con su propio propósito, por lo que es importante saber cómo mantenerlos bajo control. De no ser así podríamos tener problemas de rendimiento en nuestro sistema o incluso problemas de seguridad.

Hemos visto en el capítulo anterior cómo podíamos ejecutar un contenedor con el comando docker run a partir de una imagen en el registro de Docker. Si utilizamos el parámetro -d al arrancarlo seguirá ejecutándose en el sistema hasta que sea detenido de forma explícita. Si conoces Linux, muchos de los parámetros a continuación te resultarán familiares, si no lo conoces ¿A qué esperas?

Así cómo el comando ps nos mostraría los procesos activos en Linux, en Docker podemos mostrar los contenedores en ejecución utilizando docker ps. Vamos a lanzar dos contenedores con el servicio Nginx para ilustrar este ejemplo. Utilizaremos el parámetro -d para que se lancen en segundo plano y el parámetro -p para mapear los puertos con los del sistema de forma que el servicio esté accesible desde el exterior del contenedor, en nuestro caso localhost.

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

Podemos verificar que ambos servicios están escuchando en sus respectivos puertos accediendo a ellos mediante la dirección localhost, como podemos ver en la imagen anterior, con el comando docker ps veremos la información de los contenedores en ejecución:

  
  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
  

Crear dos servicios Nginx que escuchen en distintos puertos es una forma sencilla de ejemplificar el uso del comando ps, en él podemos ver el ID del contenedor, la imagen que se está ejecutando, el comando, el tiempo que lleva corriendo, el estado en el que se encuentra, los puertos que está utilizando mapeados con su correspondiente en el sistema y el nombre que le hemos dado al contenedor.

Gracias al ID del contenedor podemos acceder a él para multitud de tareas como ver los logs, pararlo, reiniciarlo, etc. Por ejemplo, si queremos ver los logs del contenedor mynginx2 podemos usar el comando docker logs seguido del ID del contenedor:

  
  docker logs f641152deaf0
  

Al igual que en Linux, podemos añadir el paŕametro -f después de logs para ver los logs en tiempo real según se van recibiendo nuevas interacciones. Aunque también podemos hacerlo utilizando su nombre con docker logs -f mynginx2. Para detenerlo podemos utilizar el comando docker stop junto al nombre o ID:

  
  docker stop mynginx2
  

Si hacemos ps de nuevo veremos que el contenedor ya no está en ejecución:

  
  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
  

Si queremos volver a iniciarlo podemos usar el comando docker start:

  
  docker start mynginx2
  

Y volverá a aparecer tras hacer ps, pero también podemos eliminar aquellos que no estén en ejecución si no los necesitamos más con el comando docker rm:

  
  docker rm mynginx2
  

Cómo vimos en el primer capítulo, no es lo mismo un contenedor que un volumen o una imagen, con este comando hemos eliminado el contenedor, pero no la imagen, por lo que si volvemos a ejecutar el comando docker run con la misma imagen, se creará un contenedor con un nuevo ID basado en la misma imagen. Si el contenedor tuviera un volumen asociado, éste no se eliminaría por lo que los datos seguirían estando disponibles en caso de haber configurado el volumen para persistencia.

Los diferentes componentes de Docker son independientes entre sí pero algunos pueden depender de otros, por ejemplo no podemos eliminar una imagen si hay un contenedor en ejecución basado en ella, pero sí podemos eliminar un contenedor sin necesidad de hacer lo mismo con la imagen o el volumen asociado.

Otro de los comandos disponibles es el de listado de contenedores, volúmenes, imágenes, redes, etc. Al igual que en Linux, en Docker utilizaremos ls para listar los elementos de un tipo concreto. Por ejemplo, si queremos listar los contenedores ejecutados en el sistema podemos usar el comando docker container ls, que hará la misma función que el ps o docker container ls -a para listar todos los contenedores, activos o no. También podemos ver los volúmenes con docker volume ls, las imágenes con docker image ls o las redes con 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
    

Inspeccionando un contenedor podremos saber qué imagen, volumen, red y componentes tiene asociados y en qué condiciones. Con estas herramientas podemos hacer gestión un poco más avanzada de nuestros ellos y poder depurar errores y/ó configuraciones incorrectas más fácilmente. Como vemos en los ejemplos anteriores cada tipo de elemento dentro de Docker tiene su propio ID, lo que nos otorga la flexibilidad para inspeccionar profundamente, de forma individual, cada uno de ellos utilizando el comando inspect seguido del ID del elemento que queremos inspeccionar. Por ejemplo, si queremos inspeccionar el contenedor mynginx podemos hacerlo con el comando docker inspect 3c224ed3e7f4. Esto nos mostrará un JSON con toda la información del contenedor, como por ejemplo la configuración de red, los volúmenes, la configuración de los puertos, etc. Suelen contener una gran cantidad de información, para resumir aquí te muestro el ejemplo de la red del contenedor y su configuración:

    
    [
        {
            "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"
            }
        }
    ]
    

De esta manera podemos analizar de forma exhaustiva cada uno de los elementos que participan en la ejecución de nuestros contenedores. Te invito a probar los diferentes comandos para hacerte una mejor idea de cómo se orquesta todo por debajo de la capa de abstracción de Docker, te ayudará en un futuro a depurar errores y a entender mejor cómo funcionan tus servicios.

Hemos visto cómo iniciar y gestionar nuestros contenedores, además de algunos parámetros y comandos útiles básicos, pero ¿qué pasa si queremos ejecutar varios contenedores a la vez? ¿Cómo podemos simplificar la gestión en proyectos más complejos? En el próximo capítulo veremos otra aproximación que nos permitirá gestionarlos de una manera más eficiente y orquestarlos entre sí.

Espero haya sido de ayuda y cualquier duda o sugerencia puedes dejarla en la zona de comentarios. ¡Hasta la próxima!

Artículos relacionados

Quizá te puedan interesar

December 1, 2023

Descubriendo Docker

Docker es una plataforma de virtualización que ofrece una metodología única para empaquetar y …

leer más