Docker

Iniciando con Docker: Parte III

La interacción que se tiene en el día a día con Docker depende del rol desempeñado en el proceso de desarrollo de software. Tanto si hacemos parte del equipo de desarrollo o de operaciones, contamos con diferentes herramientas del ecosistema DevOps que junto a Docker nos ayudarán en las diferentes etapas de creación y entrega de software. Algunas de las herramientas que nos encontramos para interactuar con nuestros contenedores Docker son: el cliente (binario docker) que veremos en la presente entrada, Docker Compose[1] para la ejecución de aplicaciones que requieran múltiples contenedores, software de orquestración más avanzado como Dokcer Swarm[2], EC2 Container Service[3] o Kubernetes[4] e inclusive sistemas de integración continua (CI/CD) como CircleCI[5], TravisCI[6] y Jenkis[7]. La anterior es solamente una pequeña lista de las herramientas que podemos usar de la mano con Docker en nuestro proceso de desarrollo, pero que antes de usarlas, debemos contar con un buen entendimiento del cliente Docker y el día de hoy vamos a ver algunos comandos útiles que no mencioné en las entradas anteriores.

Utilizaremos el contenedor wp00 creado en la segunda parte[8] de ésta serie de entradas (aunque para efectos de los ejemplos tratados podría ser cualquier otro), para revisar algunos comandos (entendidos como opciones del cliente Docker) que nos ayudarán a interactuar con éstos. Hay algunos que nos permiten iniciar (start), detener (stop), pausar (pause) y despausar (unpause) contenedores, que por lo básicos no entraremos en su detalle.

EXEC

Uno de los más útiles al momento de interactuar con los contenedores es el comando exec, con éste podemos ejecutar un binario que se encuentre al interior del contenedor. Por ejemplo, vamos a ejecutar sobre el contenedor wp00 el comando echo:

$ docker exec wp00 echo "Hello from wp00 container"
Hello from wp00 container

Aunque el anterior es un ejemplo básico, realmente podríamos ejecutar casi que cualquier comando sobre el contenedor siempre y cuando el binario se encuentre en éste. Debemos entender que por su naturaleza, la situación ideal es que un contenedor solamente cuente en su interior con los binarios y librerías necesarias para la ejecución de la aplicación/servicio que en éste se ejecute, por consiguiente y dependiendo del Dockerfile utilizado para la creación de la imagen, de la imagen base (directiva FROM del Dockerfile) usada podemos contar o no con el comando en cuestión. Como en la imagen oficial de WordPress contamos con el comando top, vamos a verificar el espacio de procesos actual en el contenedor, que solamente tendrá los procesos pertenecientes a la aplicación/servicio que éste ejecuta. Para lo anterior vamos a ejecutar al interior del contenedor el comando top -bn 1:

$ docker exec wp00 top -bn 1
top - 07:19:34 up 1:46, 0 users, load average: 0.38, 0.43, 0.39
Tasks: 7 total, 1 running, 6 sleeping, 0 stopped, 0 zombie
%Cpu(s): 7.7 us, 1.8 sy, 0.1 ni, 89.9 id, 0.6 wa, 0.0 hi, 0.0 si, 0.0 st
KiB Mem: 8077348 total, 5191348 used, 2886000 free, 275172 buffers
KiB Swap: 1951228 total, 0 used, 1951228 free. 2877428 cached Mem

PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
1 root 20 0 313248 30640 24880 S 0.0 0.4 0:00.22 apache2
168 www-data 20 0 313280 7536 1768 S 0.0 0.1 0:00.00 apache2
169 www-data 20 0 313280 7536 1768 S 0.0 0.1 0:00.00 apache2
170 www-data 20 0 313280 7536 1768 S 0.0 0.1 0:00.00 apache2
171 www-data 20 0 313280 7536 1768 S 0.0 0.1 0:00.00 apache2
172 www-data 20 0 313280 7536 1768 S 0.0 0.1 0:00.00 apache2
191 root 20 0 21812 2304 2036 R 0.0 0.0 0:00.03 top

Como se puede apreciar, solamente se encuentra el servicio apache (con sus respectivos workers además del comando top) en ejecución en el contenedor. Algo interesante con docker exec es la posibilidad de obtener una shell haciendo uso de las optiones -it:

$ docker exec -it wp00 bash
root@f3119583a578:/#

STATS

Con éste comando podemos obtener en tiempo real estadísticas de uso (CPU, Memoria, Red y Disco) de los recursos utilizados por los diferentes contenedores en ejecución sobre la máquina que tiene instalado el daemon Docker:

CONTAINER CPU % MEM USAGE / LIMIT MEM % NET I/O BLOCK I/O PIDS
e89ffd0247f1 0.02% 67.7 MiB / 7.703 GiB 0.86% 19.46 kB / 1.426 kB 26.38 MB / 53.25 kB 6
f3119583a578 0.10% 400.6 MiB / 7.703 GiB 5.08% 27.17 kB / 1.236 kB 10.1 MB / 291.8 MB 28

Recordemos que Docker utiliza la arquitectura cliente/servidor, por lo que dichas estadísticas son traídas al cliente (binario docker) desde el servidor (docker daemon) a través de una RESTFul API, misma que es utilizada por diferentes herramientas de monitoreo como Google cAdvisor[9][10] y Prometheus[11][12] para entregar sus resultados.

LOGS

Como la aplicación que se ejecuta en el contenedor lo hace en modo Foreground (No confundir con Background), constantemente está mostrando información en la salida estándar del espacio de trabajo del contenedor, para acceder a esta información hacemos uso de docker logs:

$ docker logs -f --tail=5 wp00
172.17.0.1 - - [01/Oct/2016:06:56:46 +0000] "GET /wp-content/themes/twentysixteen/js/skip-link-focus-fix.js?ver=20160816 HTTP/1.1" 200 937 "http://172.17.0.3/" "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.143 Safari/537.36"
172.17.0.1 - - [01/Oct/2016:06:56:46 +0000] "GET /wp-content/themes/twentysixteen/js/functions.js?ver=20160816 HTTP/1.1" 200 2313 "http://172.17.0.3/" "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.143 Safari/537.36"
172.17.0.1 - - [01/Oct/2016:06:56:46 +0000] "GET /wp-includes/js/wp-embed.min.js?ver=4.6.1 HTTP/1.1" 200 1099 "http://172.17.0.3/" "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.143 Safari/537.36"
172.17.0.1 - - [01/Oct/2016:06:56:46 +0000] "GET /wp-includes/js/wp-emoji-release.min.js?ver=4.6.1 HTTP/1.1" 200 4363 "http://172.17.0.3/" "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.143 Safari/537.36"
172.17.0.1 - - [01/Oct/2016:06:56:47 +0000] "GET /favicon.ico HTTP/1.1" 200 228 "http://172.17.0.3/" "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.143 Safari/537.36"

Con la opción -f quedamos a la espera de más información hasta presionar Ctrl+C y con –tail decimos que queremos ver desde las últimas 5 líneas. Si queremos hacer un dump completo de los logs del contenedor (en este caso los logs del servicio apache) a un archivo podemos utilizar lo siguiente:

$ docker logs wp00 > access.log

INSPECT

Con inspect podemos acceder a la información de un contenedor (también aplica para imágenes) creado previamente. Su resultado será en formato JSON[13] el cual podemos interpretar de diferentes maneras. Por ejemplo, extrayendo información con la opción –format, se hace uso del paquete text/templete del lenguaje Go (Lenguaje sobre el que está escrito Docker). Aquí, un ejemplo para saber la IP del contenedor:

$ docker inspect --format='{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' wp00
172.17.0.3

Aunque también se hubiera podido utilizar la herramienta jq[14] para parsear el resultado JSON:

$ docker inspect wp00 | jq -r '.[0].NetworkSettings.IPAddress'
172.17.0.3

Y quedan muchos otros comandos útiles, por ejemplo con docker commit podemos crear nuevas imágenes localmente teniendo en cuenta los cambios realizados en algún contenedor de interés. Con docker [login | logout | pull | push] se interactúa con registros públicos o privados. Para el manejo de imágenes locales contamos con los comandos docker [rmi | export | import]. En la documentación oficial de Docker podemos apreciar una lista completa de los comandos[15].