Pasando de Noob a Pro en Docker

Hola Fronters, aquí Gabriel!!! En esta segunda entrega de Docker para Inexpertos como yo, veremos como pasaremos a aprender los comandos básicos e intermedios de Docker y luego ya empezaremos a crear contenedores básicos. Como ya vimos en el capítulo anterior (si no lo has visto, te recomiendo que le des un vistazo aquí), instalamos Docker Container Engine en el servidor, y pudimos correr nuestro primer Hello World. Eso fue un gran avance en verdad, sin embargo aun nos queda un largo recorrido por aprender.

Manejando el servicio Docker y otros aspectos a considerar

Manejar el servicio de Docker en Linux no es muy diferente de otros. Si manejas servicios systemd o service, entonces no encontrarás dificultad alguna:

Para saber si el servicio está activo:

sudo systemctl is-active docker

Si el servicio está habilitado:

sudo systemctl is-enabled docker

Comprobar si el servicio está iniciado:

sudo systemctl status docker

Iniciamos el servicio de Docker:

sudo systemctl start docker

Detenemos el servicio de Docker:

sudo systemctl stop docker

Reiniciamos el servicio de Docker:

sudo systemctl restart docker

Otro aspecto a tomar en cuenta es que en la ruta /var/lib/docker se almacenan todos nuestros contenedores y sus configuraciones relacionadas, por lo que, si tenemos que actualizar o reinstalar, pues no los perderemos.

Ahora sí… Docker CLI!!!

Empecemos a calentar… Iremos explicando algunos de los comandos más utilizados, pues Docker tiene una extensa variedad de comandos.

Para buscar una imagen de CentOS en el repositorio de imágenes Docker Hub:

docker search centos
Docker para Inexpertos parte dos: Resultados de docker search centos
Imagen 1: Resultados de docker search centos

Descargamos la imagen oficial de CentOS desde Docker Hub:

docker pull centos
Docker para Inexpertos parte dos: Descargando la imagen oficial de CentOS desde Docker Hub con docker pull
Imagen 2: Descargando la imagen oficial de CentOS desde Docker Hub con docker pull

Descargaremos varias imágenes para poder ejemplificar mejor el proceso de obtención de imágenes:

docker pull alpine

docker pull debian

docker pull ubuntu

docker pull mariadb:10.5

docker pull mariadb:10.4

docker pull postgresql

docker pull mongo

Y no, no se pueden descargar varias imágenes con un solo docker pull. Por cada imagen, un argumento (muy mal eso, Docker!!):

Docker para Inexpertos parte dos: Más docker pull
Imagen 3: Más docker pull

Si queremos consultar cuales son las imágenes disponibles en nuestro Docker Container engine (DCE) ejecutaremos docker images:

docker images
Docker para Inexpertos parte dos: Verificando las imágenes de contenedores en mi servidor Docker
Imagen 4: Verificando las imágenes de contenedores en mi servidor Docker

Necesitamos eliminar una imagen, en este caso eliminaremos mongo, que es una imagen de mongodb que pesa 699 MB:

docker rmi mongo

También podríamos eliminar mariadb, en este caso eliminaremos la menos actual, la 10.4:

docker rmi mariadb:10.4

NOTA: Si descargamos una imagen oficial, en la mayoría de las veces, no especificamos alguna versión en particular, siempre descargará la última versión de dicha imagen, por eso siempre debemos especificar la versión exacta en el caso de que el requerimiento de nuestro despliegue (deployment) requiera de esa versión en particular.

Más Docker CLI: Corriendo y guardando contenedores

En este momento crearemos nuestro primer contenedor básico, basado en la imagen de CentOS que descargamos anteriormente:

docker run centos

Si deseamos correr un comando en el contenedor sin estar dentro de éste:

docker run centos cat /etc/centos-release

La salida del comando sería similar a esta:

CentOS Linux release 8.2.2004 (Core)

Magia con Docker ps

Docker ps es un comando verdaderamente versatil y nos permite hacer muchas cosas, bien sea solo o acompañado. Aquí sólo veremos algunas muy pocas, pero más que suficientes para empezar. Con el podemos listar todos los procesos de Docker, activos e inactivos y permite parámetros y argumentos para refinar nuestras consultas y acciones.

Con docker ps listaremos los contenedores activos:

docker ps

docker ps -l nos sirve para listar el último contenedor creado, en cualquier estado posible:

docker ps -l

Mientras que con docker ps -a listaremos todos los contenedores creados, en cualquier estado posible:

docker ps -a

Mostrando parámetros como su ID, el tipo de imagen, comando ejecutado, cuando fue creado, el status (cuando termino su ejecución) y los puertos.

Docker para Inexpertos parte dos: Revisando los contenedores creados
Imagen 5: Revisando los contenedores creados

Pero lo que vimos fue muy interesante; vimos que se crearon contenedores a partir de las imágenes que descargamos previamente, corrieron, ejecutaron «algo», y luego terminaron.

Y si únicamente necesitamos obtener el ID numérico de todos los contenedores, sin todo el resto de información anterior agregamos el atributo -q :

docker ps -aq

La magia de docker ps radica en que con él podemos combinar comandos para procesar la salida de estos y que sirvan como variable para otros comandos, por ejemplo: un docker stop para detener todos los contenedores que están arriba (Up):

docker stop $(docker ps -aq --filter "status=running")

Vamos a eliminar todos los contenedores que no están corriendo:

docker rm $(docker ps -qa --filter 'exited=0')

Y si tenemos un grupo de contenedores con nomenclaturas de nombre definidas, y queremos iniciarlos por un patrón de nombre, por ejemplo: todos los servidores cuyo nombre comiencen por bd :

Docker para Inexpertos parte dos: Filtrando y obteniendo ID para ejecutar contenedores conforme a un argumento
Imagen 6: Filtrando y obteniendo ID para ejecutar contenedores conforme a un argumento

NOTA: recuerda utilizar el signo $ para variabilizar convertir en variable la salida del segundo comando, sin omitir el uso de los paréntesis () .

Comandos básicos para manipular contenedores (start, stop, run, rm, …)

Todos los contenedores tienen un ID numérico. Eso quiere decir que estos pueden ser iniciados tanto por su nombre clave asignado, bien sea por Docker o por nosotros, como por su ID numérico, con el comando docker start :

docker start centos

o también:

docker start 94c35e616b91

Del mismo modo también se pueden detener con el comando docker stop :

docker stop centos

o también:

docker stop 94c35e616b91

Dale nombres propios a tus contenedores!!! (por tu propio bien)

Docker tiende a colocar nombres «estúpidos y sensuales» automáticamente a los contenedores que se crean en su motor, siempre y cuando no se les especifique nombre por parte del usuario. Para muestra, un botón:

Docker para Inexpertos parte dos: Docker y sus nombres "peculiares"  en contenedores.
Imagen 7: Docker y sus nombres «peculiares»

Así que, es deseable que le asignemos un nombre particular ( y más formal!) a nuestro contenedor con el atributo –name, para poder identificarlo y diferenciarlo correctamente:

docker run --name micontenedor centos cat /etc/centos-release

Y ahora podemos manejar nuestro contenedor con el nombre que le asignamos:

docker stop micontenedor

docker start micontenedor

docker stats micontenedor

docker rm micontenedor

Hasta ahora todo va muy bien, de seguro me dirán: «Vale, todo bien Gabriel, pero es que… No le veo sentido mucho sentido a crear estos contenedores que no hacen nada!!!», y tienen razón!, pero es mucho conocimiento en poco tiempo llevamos, así que nos tomaremos un receso.

Después del break, un container «no fake»

Ya habiendo descansado, sigamos en lo nuestro. Hasta ahora, hemos creado contenedores simples con una sola o ninguna instrucción. Estos se ejecutaban y luego de eso cumplían con su función y por ende, con su ciclo de vida y morían, pues no tenían otra utilidad o razón de ser y existir, pero estos fueron creados con propósitos de prueba y eran meramente didácticos.

Ahora vamos a crear algo con un poco más de sentido y lógica. Para ello debemos tener más o menos claro lo que aprendimos anteriormente, pero igual en la medida que incorporemos nuevos aprendizajes, iremos reforzando lo previamente aprendido.

Containers interactivos y desatendidos con Docker Run

Si necesitamos correr un contenedor que funcione correctamente debemos escribir las instrucciones, atributos y los argumentos adecuados. Correr contenedores de forma inadecuada, simplemente nos hará perder el tiempo y el esfuerzo, pues necesitamos que ejecuten servicios reales y que podamos interactuar con ellos, obtener lo que necesitamos de ellos y que podamos manejarlos según nuestras necesidades; es decir: que estén arriba, que podamos activarlos o desactivarlos según la necesidad, etc.

Para ello vamos a crear un contenedor llamado miprueba, basado en la imagen de Alpine, pero esta vez que permita la interacción con el mismo mediante una shell interactiva o interfaz de línea de comandos (CLI), dentro del contenedor, agregaremos los atributos -it:

docker run --name miprueba -it alpine

Y ya entramos en la terminal de ese contenedor y ejecutar comandos dentro ese contenedor:

/ # uname -a

/ # cat /etc/issue

/ # whoami

Pues en la instrucción anterior en conjunto con el atributo -it hacemos que Docker cree una tty conectada al contenedor y podamos interactuar con él. Podemos salir usando el comando:

/ # exit
Docker para Inexpertos parte dos: Creando un contenedor desatendido e interactivo basado en Alpine
Imagen 8: Creando un contenedor desatendido e interactivo basado en Alpine

Al salir con el comando exit, habremos terminado el contenedor miprueba, pero en realidad lo que queríamos era que se mantuviese activo, pero nosotros desprenderlo de nuestra terminal, con la posibilidad de retomarlo cuantas veces sea necesario. Para ello ejecutaremos:

docker start -i miprueba
Docker para Inexpertos parte dos: Verificando el status del contenedor creado anteriormente
Imagen 9: Verificando el status del contenedor creado anteriormente

Y una vez que lo hayamos levantado, lo que haremos será desprender el contenedor, desatenderlo (detach) y este seguirá corriendo en modo desatendido. Para lograr esto ejecutas la combinación de teclas: CNTRL+P+Q (no es necesario que estén en mayúsculas) y posteriormente ejecutamos docker ps y veremos nuestro contenedor corriendo (Up).

Docker para Inexpertos parte dos: Verificando el status
Imagen 10: Verificando el status

Si luego deseamos retomar el contenedor desatendido:

docker attach miprueba
Docker para Inexpertos parte dos: Docker attach en el contenedor
Imagen 11: Docker attach en el contenedor

Bien, creo que la hemos liado aquí. Resulta que este contenedor miprueba ya no es necesario, o me equivoqué al crearlo y lo que quiero ahora es crear otro contenedor, que puede tener el mismo nombre, pero no debe estar basado en Alpine sino en Ubuntu.

Entonces eliminaremos el contenedor con docker rm <nombrecontenedor> pero antes de eliminarlo lo detendremos con docker stop <nombrecontenedor> :

Docker para Inexpertos parte dos: Deteniendo y eliminando contenedores con docker stop y docker rm
Imagen 12: Deteniendo y eliminando contenedores con docker stop y docker rm

O también con docker kill <nombrecontenedor> si deseamos detenerlo abruptamente :

docker kill miprueba

Y ahora crearemos el nuevo contenedor, el cual llamaré srv con la imagen de Ubuntu, en modo interactivo y desatendido, para luego entrar en él :

docker run --name srv -d -it ubuntu

docker attach srv
Docker para Inexpertos parte dos: Levantando contenedores interactivos, desatendidos y con nombre asignado.
Imagen 13: Levantando contenedores interactivos, desatendidos y con nombre asignado.

O si requerimos que otro contenedor, que llamaremos srvnu con la imagen de Ubuntu, en modo interactivo y desatendido y, pero en vez de utilizar el intérprete de comandos para consola bash utilizamos sh :

docker run -d --name srvnu -it ubuntu sh

Y al ejecutar el comando docker ps podemos verificar que el contenedor está creado y arriba con la imagen y el intérprete de comandos que hemos indicado.

Docker para Inexpertos parte dos: Constatando la asignación de Intérprete de comandos en contenedor srvnu
Imagen 14: Constatando la asignación de Intérprete de comandos en contenedor srvnu

Hasta aquí por los momentos…

Hemos aprendido a ejecutar comandos básicos e intermedios de Docker y hemos creado nuestros primeros contenedores como unos campeones. En el próximo post aprenderemos más comandos de administración de Docker y también a establecer conexiones entre nuestros contenedores y la máquina huésped mediante el mapeo de puertos (port mapping).

Recuerda que si tienes dudas o preguntas puedes colocarlas en los comentarios y así aprendemos todos un poco más y hacemos crecer a esta bonita comunidad.

Hasta luego Fronters!!!

Referencias

Documentación Oficial de Docker