GNU/Linux >> Tutoriales Linux >  >> Panels >> Docker

Cómo utilizar el comando de inspección de Docker

Uno de los comandos esenciales de Docker es la inspección de docker. Te permite extraer información sobre varios objetos docker, saber usarlo es algo TODOS debe conocer.

En caso de que se lo pregunte, los objetos o recursos de Docker son simplemente cosas como contenedores, volúmenes, redes, etc.

La principal fortaleza de inspect proviene de sus capacidades de formateo.

Por ejemplo, puede extraer la dirección IP de un contenedor en ejecución inspeccionándolo y formateándolo de una manera específica.

➟ docker container inspect -f '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' nginx
172.17.0.2

Docker usa go-templates para formatear su salida.

En este artículo, primero repasaré los conceptos básicos del comando de inspección de Docker y luego me centraré en cómo formatear la salida según sus necesidades específicas.

¿Qué hace Docker inspeccionar?

Inspect le proporciona una gran cantidad de metadatos sobre todos los diferentes objetos administrados por docker. El tipo de información varía de un objeto a otro.

Por ejemplo, si inspecciona un volumen, obtendrá información relacionada con cuándo se creó, el controlador de volumen en uso, la ubicación en el sistema de archivos del host, las etiquetas, etc.

Si lo que está inspeccionando es una red, obtendrá información como su subred, puerta de enlace, contenedores conectados y sus direcciones IP, etiquetas y otra información.

Para comprender mejor lo que proporciona la inspección para un objeto determinado, le recomiendo que ejecute los comandos y lo compruebe por sí mismo.

¿Cuáles son los objetos que pueden ser inspeccionados?

En Docker, un objeto o tipo de objeto son todas las construcciones controladas por Docker. Esto incluye lo siguiente:-

  1. Contenedores.
  2. Imágenes.
  3. Redes.
  4. Volúmenes.
  5. Contextos.
  6. Complementos.
  7. Nodos (objeto de enjambre).
  8. Servicios (objeto de enjambre).
  9. Secretos (objeto de enjambre).
  10. Configuraciones (objeto de enjambre).

Uso del comando de inspección de Docker

Hay dos formas de usar el inspect subcomando.

  1. docker inspect [object] [options]
  2. docker [object_type] inspect [object] [options]

El segundo método es el que debería usar siempre . El inspect el subcomando proporciona una salida JSON, lo abordaré en un momento.

Cree un volumen llamado unique .

docker volume create unique

Ahora crea una red con el mismo nombre, unique .

docker network create unique

Ahora intentemos inspeccionar el objeto llamado unique usando la primera sintaxis.

docker inspect unique

Mi salida:-

➟ docker inspect unique
[
    {
        "Name": "unique",
        "Id": "09a7e2163ee058b1057d95599f764d571ec6a42a5792803dc125e706caa525b0",
        "Created": "2021-05-07T15:47:20.341493099+05:30",
        "Scope": "local",
        "Driver": "bridge",
        "EnableIPv6": false,
        "IPAM": {
            "Driver": "default",
            "Options": {},
            "Config": [
                {
                    "Subnet": "172.21.0.0/16",
                    "Gateway": "172.21.0.1"
                }
            ]
        },
        "Internal": false,
        "Attachable": false,
        "Ingress": false,
        "ConfigFrom": {
            "Network": ""
        },
        "ConfigOnly": false,
        "Containers": {},
        "Options": {},
        "Labels": {}
    }
]

En mi sistema, como puede ver, inspect inspeccioné la red, pero ¿y si pretendía inspeccionar el volumen?

Este es el problema con docker inspect , cuando tiene dos objetos diferentes con el mismo nombre, no puede simplemente usar docker inspect [object_name] . Para inspeccionar exactamente lo que desea, deberá usar el ID del objeto o usar el --type=[object_type] opción. Puede escribir el comando anterior con --type opción así:-

docker inspect --type=volume unique

Aunque esto funciona, creo que es innecesario ya que ya tenemos la otra sintaxis. Puede usar el subcomando específico del objeto como lo estoy haciendo aquí:-

docker volume inspect unique

Es menos para escribir y mucho más fácil de leer.

Algunos ejemplos útiles de comandos de inspección de Docker

En esta sección, registraré una lista de consultas comunes y cómo se vería el comando de inspección relevante para obtener esa información.

Consultas de contenedores

Para los ejemplos, tendré un contenedor nginx de muestra en ejecución, y todos los comandos se ejecutarán en este contenedor en ejecución. El comando que usé para ejecutar este contenedor:-

docker container run \
	--rm --name nginx \
    -p target=80,published=127.0.0.1:8081,protocol=tcp \
    -p target=80,published=[::1]:8081,protocol=tcp \
    -e ENV_VAR=somevalue \
    -e ENV_VAR2=linux \
    -v $PWD:/mnt:ro \
    -v /tmp:/tmp:ro \
    -d nginx

1. ID de un contenedor por nombre

Puede obtener la ID del contenedor usando el siguiente comando:-

docker container inspect -f '{{.Id}}' [container_name]

Ejemplo:-

➟ docker container inspect -f '{{.Id}}' nginx
0409779fc2d976387170d664a6aed5ee80a460f8a8dd02c44a02af97df0bb956

2. Proceso principal del contenedor

El proceso contenedor principal es básicamente ENTRYPOINT + CMD .

docker container inspect -f '{{printf "%s " .Path}}{{range .Args}}{{printf "%s " .}}{{end}}' [container_name|id]

Ejemplo:-

➟ docker container inspect -f '{{printf "%s " .Path}}{{range .Args}}{{printf "%s " .}}{{end}}' nginx
/docker-entrypoint.sh nginx -g daemon off;

3. Listado de enlaces de puertos

El siguiente comando enumera todos los enlaces de puerto de contenedor a host.

docker container inspect -f '{{range $target, $published := .NetworkSettings.Ports}}{{range $published}}{{printf "%s -> %s:%s\n" $target .HostIp .HostPort}}{{end}}{{end}}' [container_name|id]

Ejemplo:-

➟ docker container inspect -f '{{range $target, $published := .NetworkSettings.Ports}}{{range $published}}{{printf "%s -> %s:%s\n" $target .HostIp .HostPort}}{{end}}{{end}}' nginx
80/tcp -> ::1:8081
80/tcp -> 127.0.0.1:8081
Puede lograr lo mismo con docker container port comando.

4. Listado de sus direcciones IP

Un contenedor se puede conectar a múltiples redes, en lugar de imprimir una de esas muchas direcciones IP, puede imprimir todas esas direcciones IP con este comando.

docker container inspect -f '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' [container_name|id]

Ejemplo:-

➟ docker container inspect -f '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' nginx
172.17.0.2

5. Listado de las variables de entorno

También puede enumerar la variable de entorno de un contenedor.

docker container inspect -f '{{range .Config.Env}}{{printf "%s\n" .}}{{end}}' [container_name|id]

Ejemplo:-

➟ docker container inspect -f '{{range .Config.Env}}{{printf "%s\n" .}}{{end}}' nginx
ENV_VAR=somevalue
ENV_VAR2=linux
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
NGINX_VERSION=1.19.10
NJS_VERSION=0.5.3
PKG_RELEASE=1~buster

6. Listado de los volúmenes/montajes de enlace junto con el modo

El siguiente comando imprime los montajes de enlace en este formato, "[fuente] -> [destino], modo:[modo]".

docker container inspect -f '{{range .Mounts}}{{printf "%s -> %s, mode: %s\n" .Source .Destination .Mode}}{{end}}' [container_name|id]

Ejemplo:-

➟ docker container inspect -f '{{range .Mounts}}{{printf "%s -> %s, mode: %s\n" .Source .Destination .Mode}}{{end}}' nginx
/home/debdut -> /mnt, mode: ro
/tmp -> /tmp, mode: ro

Consultas de volumen

No hay mucho para inspeccionar un volumen, excepto conocer la ubicación del host, que se encuentra en data-dir/volumes . Puede obtener esa información con el siguiente comando:-

docker volume inspect -f '{{.Mountpoint}}' [volume_name|id]

Ejemplo:-

➟ docker volume create unique 
unique
~ 
➟ docker volume inspect -f '{{.Mountpoint}}' unique 
/var/lib/docker/volumes/unique/_data

Consultas de red

Hay dos consultas que personalmente me encuentro haciendo con frecuencia, una es conocer una subred de redes y todos los contenedores que están conectados a esa red y las IP asociadas con ellos.

Para esto creé una red simple con docker network create unique comando.

1. Obtener la subred

Para obtener la subred, use el siguiente comando:-

docker network inspect -f '{{range .IPAM.Config}}{{.Subnet}}{{end}}' [network_name|id]

Ejemplo:-

➟ docker network inspect -f '{{range .IPAM.Config}}{{.Subnet}}{{end}}' unique 
172.21.0.0/16

2. Listado de contenedores conectados junto con sus direcciones IP

El comando se ve así,

docker network inspect -f '{{range .Containers}}{{printf "%s -> %s\n" .Name .IPv4Address}}{{end}}' [network_name|id]

Ejemplo:-

➟ docker network inspect -f '{{range .Containers}}{{printf "%s -> %s\n" .Name .IPv4Address}}{{end}}' unique 
cranky_wescoff -> 172.21.0.5/16
nginx -> 172.21.0.2/16
upbeat_carson -> 172.21.0.3/16
objective_jones -> 172.21.0.4/16

Formateo de la salida del comando de inspección de Docker

inspect nos proporciona una matriz JSON para la salida, que puede filtrar usando algo como jq . Entonces, si tienes experiencia en jq , es posible que desee utilizarlo. El problema con jq es que no viene preinstalado en la mayoría de las distribuciones de Linux, mientras que el mecanismo de formateo predeterminado de docker .. inspect ya está allí, y es muy poderoso.

Docker usa go-templates para formatear su salida. Este artículo no tratará sobre go-templates, pero si desea obtener más información, puede leerlo aquí.

Internamente, los JSON se representan mediante varias estructuras de datos de Go. Es por eso que las plantillas go realmente funcionan con los tipos de datos go. Como no quiero explicar qué son estas estructuras de datos, en lugar de usar esos términos, usaré términos JSON para que sea más comprensible.

Extracción de campos simples

Considere un objeto JSON como el siguiente:-

{
	"mary": 43,
    "john": 44
}

Digamos que desea extraer la información asociada con la clave mary . Para hacerlo, lo que usa es la notación de punto [.], donde antepone la clave con un punto y agrega claves recursivamente para cualquier clave anidada. Esto es lo mismo que jq . Así que .mary aquí serían 43.

Considere el siguiente JSON ahora.

{
	"mary": {
    	"jane": 43,
        "soyas": 56
    },
    "john": 65
}

En este caso .mary.jane sería 43, y de manera similar .mary.soyas serían 56.

Se puede usar una sintaxis similar con go-templates. Para formatear la salida, debe pasar la plantilla a -f o --format opción de inspect subcomando. Revisemos el resultado de la inspección de volumen.

[
    {
        "CreatedAt": "2021-05-07T15:53:10+05:30",
        "Driver": "local",
        "Labels": {},
        "Mountpoint": "/var/lib/docker/volumes/unique/_data",
        "Name": "unique",
        "Options": {},
        "Scope": "local"
    }
]

Si quieres conocer el Mountpoint , usaría el siguiente comando:-

docker volume inspect -f '{{.Mountpoint}}' unique
➟ docker volume inspect -f '{{.Mountpoint}}' unique
/var/lib/docker/volumes/unique/_data

Probablemente estés notando las llaves allí mismo, son como bloques, las expresiones están encapsuladas dentro de estos bloques.

Probemos algo anidado ahora. Inspeccione la red y busque el IPAM sección.

➟ docker network inspect unique
<snipped>
 "IPAM": {
            "Driver": "default",
            "Options": {},
            "Config": [
<snipped>

Mirando esto, puede averiguar fácilmente cuál es el controlador de esta red. Pero en lugar de buscarlo así, puede formatearlo a partir de la salida JSON completa.

Observe el Driver la clave está anidada dentro de IPAM . Entonces, la expresión de punto para extraer el controlador sería .IPAM.Driver . Véalo en acción:-

➟ docker network inspect -f '{{.IPAM.Driver}}' unique
default

Recorriendo objetos o listas (rango)

Los objetos JSON son como matrices asociativas en Bash o hashes, donde las claves son cadenas y los valores pueden ser de cualquier tipo de datos.

Para que entiendas esto un poco más fácil, comenzaré con un ejemplo práctico. Considere .NetworkSettings.Networks sección en un resultado de inspección de un contenedor. Enumera las redes a las que está conectado el contenedor y, para cada red, algunos detalles asociados más, como la dirección IP.

Piensa si alguien te pide que le digas la dirección IP de un contenedor. Elegir solo una red y la IP asociada no tiene mucho sentido, lo mejor sería listar todas las direcciones IP que están asociadas a todas las redes.

Puede lograr esto con un simple bash for loop if ya conoces los nombres de las redes. Como en mi caso, puedo hacer algo como lo siguiente:-

for network in bridge unique; do
	docker container inspect -f \
    	"{{.NetworkSettings.Networks.$network.IPAddress}}" nginx
done

Pero, obviamente, esto es una limitación a gran escala, ya que no siempre podemos recordar todos los nombres de las redes.

Puede mitigar este problema utilizando la acción de plantilla range . range pasa por un mapa (una matriz asociativa o un objeto JSON) y no nos proporciona la clave, sino los valores para cada iteración (este comportamiento es modificable).

Entonces, en este caso, puede escribir un bloque como {{range .NetworkSettings.Networks}} para recorrer los valores de cada red o los datos asociados con cada red, y de eso puede extraer la dirección IP como lo haría desde una estructura similar a JSON normal, es decir, {{.IPAddress}}} . Una cosa para recordar es terminar siempre la plantilla completa que comienza con range , con {{end}} .

Poniendo todo eso junto, puedes reescribir el bucle for anterior de esta manera:-

docker container inspect -f \
	'{{range .NetworkSettings.Networks}}
     {{.IPAddress}}{{end}}' nginx

Salida de muestra:-

➟ docker container inspect -f \
> '{{range .NetworkSettings.Networks}}
>      {{.IPAddress}}{{end}}' nginx

     172.17.0.2
     172.21.0.2

Usando el index función en arreglos y objetos

Puedes usar el index función para extraer partes de su objeto o matriz JSON. Si la estructura es un objeto JSON, usaría {{index .Field "key"}} , si la estructura es una matriz JSON, usaría {{index .Field index}} .

En el ejemplo anterior, imprimió todas las direcciones IP de un contenedor. Supongamos que conoce una de las redes a las que está conectado (puente) y desea imprimir la dirección IP asociada con esa red. Puedes hacerlo con index funciona así:-

docker container inspect -f '{{(index .NetworkSettings.Networks "bridge").IPAddress}}' nginx

Salida:-

➟ docker container inspect -f '{{(index .NetworkSettings.Networks "bridge").IPAddress}}' nginx
172.17.0.2

Usando json función

Los datos exportados después del formateo no en JSON, está en alguna estructura de datos go. Pero puede convertir eso a JSON usando json función.

El nivel superior del objeto JSON es . . Entonces, para imprimir eso, harías algo como esto:-

docker network inspect -f '{{.}}' unique
➟ docker network inspect -f '{{.}}' unique 
{unique 09a7e2163ee058b1057d95599f764d571ec6a42a5792803dc125e706caa525b0 2021-05-07 15:47:20.341493099 +0530 IST local bridge false {default map[] [{172.21.0.0/16  172.21.0.1 map[]}]} false false false {} false map[2646cbbde5efc218bb6f3a5c882f8eb9e3e4331d090ad46ccc0a2eec9c2eea1b:{nginx c0291394a48f7e8e8aa98fd31631eb00e68daacbee9cf24bac530f16359d051d 02:42:ac:15:00:02 172.21.0.2/16 }] map[] map[] [] map[]}

Lo que está viendo aquí es una estructura grande que consiste en mapas y tipos de datos básicos de otras estructuras. Estos no son muy legibles, ni utilizables fuera de go. Pero puede convertirlos a JSON usando json función. Simplemente anteponga un campo con json como lo estoy haciendo aquí:-

➟ docker network inspect -f '{{json .}}' unique
➟ docker network inspect -f '{{json .}}' unique 
{"Name":"unique","Id":"09a7e2163ee058b1057d95599f764d571ec6a42a5792803dc125e706caa525b0","Created":"2021-05-07T15:47:20.341493099+05:30","Scope":"local","Driver":"bridge","EnableIPv6":false,"IPAM":{"Driver":"default","Options":{},"Config":[{"Subnet":"172.21.0.0/16","Gateway":"172.21.0.1"}]},"Internal":false,"Attachable":false,"Ingress":false,"ConfigFrom":{"Network":""},"ConfigOnly":false,"Containers":{"2646cbbde5efc218bb6f3a5c882f8eb9e3e4331d090ad46ccc0a2eec9c2eea1b":{"Name":"nginx","EndpointID":"c0291394a48f7e8e8aa98fd31631eb00e68daacbee9cf24bac530f16359d051d","MacAddress":"02:42:ac:15:00:02","IPv4Address":"172.21.0.2/16","IPv6Address":""}},"Options":{},"Labels":{}}

Para que se vea un poco mejor canalícelo a jq .

➟ docker network inspect -f '{{json .}}' unique | jq
{
  "Name": "unique",
  "Id": "09a7e2163ee058b1057d95599f764d571ec6a42a5792803dc125e706caa525b0",
  "Created": "2021-05-07T15:47:20.341493099+05:30",
  "Scope": "local",
  "Driver": "bridge",
  "EnableIPv6": false,
  "IPAM": {
    "Driver": "default",
    "Options": {},
    "Config": [
      {
        "Subnet": "172.21.0.0/16",
        "Gateway": "172.21.0.1"
      }
    ]
  },
  "Internal": false,
  "Attachable": false,
  "Ingress": false,
  "ConfigFrom": {
    "Network": ""
  },
  "ConfigOnly": false,
  "Containers": {
    "2646cbbde5efc218bb6f3a5c882f8eb9e3e4331d090ad46ccc0a2eec9c2eea1b": {
      "Name": "nginx",
      "EndpointID": "c0291394a48f7e8e8aa98fd31631eb00e68daacbee9cf24bac530f16359d051d",
      "MacAddress": "02:42:ac:15:00:02",
      "IPv4Address": "172.21.0.2/16",
      "IPv6Address": ""
    }
  },
  "Options": {},
  "Labels": {}
}

¿Es asi? Absolutamente no. Le recomiendo que lea acerca de cómo usar las plantillas go.

Aquí he intentado comenzar a usarlo sin tener que saber mucho sobre las plantillas de go. Espero haber tenido éxito.

Para cualquier aclaración, no dude en utilizar la sección de comentarios.


Docker
  1. Cómo usar el comando vmstat

  2. Cómo usar el comando Su en Linux

  3. Cómo usar Docker Compose

  4. Cómo configurar docker para usar proxy

  5. Cómo usar la opción --since con el comando docker logs

Cómo usar el comando pkill

Cómo usar el comando LDD en Linux

Cómo instalar y usar Docker en Rocky Linux 8

Cómo usar el comando PS

Cómo usar el comando SUPERIOR

Cómo instalar y usar Podman (alternativa de Docker)