Manejo de contenedores
Lo primero que debemos hacer antes de comenzar, es comprobar que Docker está trabajando correctamente, para ello podemos utilizar el comando “docker info”, el cual nos indica la configuración que tiene Docker actualmente, incluido el número de contenedores e imágenes.
Ejecutando nuestro primer contenedor
Vamos a ver como probar y ejecutar nuestro primer contenedor con Docker. Vamos a utilizar el comando “docker run”, el cual nos permite ejecutar contenedores en Docker. Lo usaremos para crear nuevos contenedores.
$ docker run -i -t ubuntu /bin/bash
Unable to find image 'ubuntu:latest' locally
latest: Pulling from library/ubuntu
0a85502c06c9: Pull complete
0998bf8fb9e9: Pull complete
a6785352b25c: Pull complete
e9ae3c220b23: Pull complete
Digest: sha256:f91f9bab1fe6d0db0bfecc751d127a29d36e85483b1c68e69a246cf1df9b4251
Status: Downloaded newer image for ubuntu:latest
root@17e9e0d4c05b:/#
Hemos ejecutado el comando “docker run” y hemos pasado dos parámetros –i y –t , -i permite redirigir la entrada estándar, esto es necesario para poder tener una sesión interactiva con el Shell. El parámetro –t le dice a Docker que asigne un pseudo-tty al contenedor que hemos creado y es el que realmente permite una sesión interactiva con el Shell del nuevo contenedor. Esta línea es básica cuando queramos crear un contenedor que planeamos interactuar en línea de comandos.
El siguiente parámetro le indica a Docker que imagen debe usar para crear el contenedor, en este caso una imagen base de Ubuntu, la cual nos la provee Docker Inc. en el registro Docker Hub. Hay imágenes similares de fedora, debían, centos, etc.. que sirven de base para la construcción de nuestras imágenes en el sistema operativo elegido por nosotros. En este caso hemos usado una imagen básica sin ningún añadido.
Vamos a ver lo que ha sucedido en realidad al ejecutar el comando, lo primero de todo Docker checkea localmente para buscar la imagen de Ubuntu. Si ella no se encuentra en nuestro host local, Docker host irá a buscarla al registro Docker Hub y comprobará si está allí. Una vez que Docker ha encontrado la imagen, la misma es descargada y almacenada en nuestro Docker local.
Docker entonces usa esta imagen para crear un nuevo contenedor dentro en el sistema de ficheros. El contenedor tiene una red, dirección ip y un interface en modo puente que se comunica con nuestro host local. Finalmente, Docker ejecutará un comando en nuestro nuevo contenedor, en este caso ejecuta un Shell bash con el comando “/bin”bash”
Cuando el contenedor ha sido creado, Docker ejecuta el comando “/bin/bash” dentro de él y la Shell del contenedor se presenta así:
root@17e9e0d4c05b:/#
Trabajando con nuestro contenedor
Ahora estamos conectados dentro de un nuevo contenedor, con ID 17e9e0d4c05b como usuario root. Esta es una máquina Ubuntu en toda regla, podemos hacer lo que queramos en él, vamos a explorar un poco, comenzando por pedir su nombre de host.
root@17e9e0d4c05b:/# hostname
17e9e0d4c05b
root@17e9e0d4c05b:/#
Podemos ver que el nombre de host de nuestro contenedor es el identificador de contenedor. Vamos a ver el archivo /etc/hosts .
root@17e9e0d4c05b:/# cat /etc/hosts
172.17.0.2 17e9e0d4c05b
127.0.0.1 localhost
::1 localhost ip6-localhost ip6-loopback
fe00::0 ip6-localnet
ff00::0 ip6-mcastprefix
ff02::1 ip6-allnodes
ff02::2 ip6-allrouters
Docker también ha añadido una entrada al fichero host para nuestro contenedor con su dirección IP. Vamos a ver la configuración de red.
root@17e9e0d4c05b:/# ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
inet 127.0.0.1/8 scope host lo
valid_lft forever preferred_lft forever
inet6 ::1/128 scope host
valid_lft forever preferred_lft forever
14: eth0@if15: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default
link/ether 02:42:ac:11:00:02 brd ff:ff:ff:ff:ff:ff
inet 172.17.0.2/16 scope global eth0
valid_lft forever preferred_lft forever
inet6 fe80::42:acff:fe11:2/64 scope link
valid_lft forever preferred_lft forever
Como podemos ver, tenemos la interfaz de bucle invertido lo y la interfaz de red eth0 estándar con una dirección IP de 172.17.0.2 como cualquier otro host. También podemos comprobar sus procesos en ejecución.
root@17e9e0d4c05b:/# ps -aux
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
root 1 0.0 0.1 18180 3300 ? Ss 11:11 0:00 /bin/bash
root 19 0.0 0.1 15572 2148 ? R+ 12:14 0:00 ps -aux
Ahora vamos a ver si instalamos un paquete.
root@17e9e0d4c05b:/# apt-get update && apt-get install vim
Ya tenemos Vim instalado en nuestro contenedor. Podríamos seguir jugando con el contenedor durante mucho tiempo y cuando hayamos terminado escribiremos “exit”, y volverá a la línea de comandos del servidor.
Nuestro contenedor ahora ha dejado de funcionar. El contenedor sólo se ejecuta durante el tiempo que dura el comando que especificamos, en nuestro caso fue “/bin/bash”. Una vez que el comando ha terminado, se sale del contenedor, y por tanto, el contenedor es detenido. El contenedor aún existe, podemos mostrar una lista de todos los contenedores que tenemos utilizando el comando “docker ps –a”
$ docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
17e9e0d4c05b ubuntu "/bin/bash" About an hour ago Exited (0) 4 seconds ago cranky_mcclintock
Por defecto, cuando ejecutamos “docker ps”, vamos a ver sólo los contenedores en ejecución. Cuando se especifica la opción –a nos mostrará todos los contenedores, tanto parados como en funcionamiento.
También podemos utilizar el comando “docker ps –l” para ver el último contenedor que se ejecutó, aunque esté actualmente en marcha o parado.
Nos muestra también un poco de información sobre nuestro contenedor: su identidad, la imagen utilizada para crearlo, el comando de su última ejecución, cuando fue creado y su estado de salida (en nuestro caso es 0 porque sale normalmente utilizando el comando “exit”). También podemos ver que cada contenedor tiene un nombre.
Nombrando contenedores
Docker generará automáticamente un nombre al azar por cada contenedor que creamos. Podemos ver que el contenedor que acabamos de crear se llama cranky_mcclintock. Si queremos especificar un nombre particular del contenedor en lugar del nombre generado automáticamente, podemos hacerlo a través del parámetro “—name”.
$ docker run –name mi_primer_contenedor –i –t ubuntu /bin/bash
Este comando crearía un nuevo contenedor llamado mi_primer_contenedor. Un nombre de contenedor válido puede contener los caracteres: a a la z, la A a la Z, los dígitos del 0 al 9, el guión bajo, el punto y guión medio.
Podemos usar el nombre del contenedor en lugar del ID de contenedores en todos los comandos Docker, los nombres de contenedores son útiles para ayudar a identificar y construir conexiones lógicas entre contenedores y aplicaciones. También es mucho mas fácil recordar un nombre específico que un ID o incluso que un nombre aleatorio.
Los nombre son únicos. Si tratamos de crear dos contenedores con el mismo nombre el comando fallará. Tendríamos que eliminar el contenedor anterior con el mismo nombre antes de poder crear uno nuevo. Para eliminar el anterior, podríamos hacerlo con el comando “docker rm”.
Comenzando un contenedor parado
Si queremos iniciar un contenedor parado lo haríamos con el siguiente comando:
$ docker start mi_primer_contenedor
También podríamos referirnos al contenedor por su ID
$ docker start 17e9e0d4c05b
Ahora, si nosotros ejecutáramos el comando “docker ps” sin el parámetro –a, nosotros veremos nuestro contenedor ejecutándose.
Conectando a un contenedor
Nuestro contenedor se reiniciará con las mismas opciones que habíamos especificado cuando lo lanzamos con la orden de ejecución inicial. Así que hay una sesión interactiva dentro de nuestro contenedor en ejecución. Podemos volver a conectar a la sesión utilizando el comando “docker attach”
$ docker attach mi_primer_contenedor
o a través del ID del contenedor
$ docker attach 17e9e0d4c05b
y volveremos a la línea de comando bash de nuestro contenedor, debemos pulsar Enter para que salga la línea de comando.
$ docker attach mi_primer_contenedor
root@17e9e0d4c05b:/#
si nosotros salimos del Shell, nuestro contenedor se parará de nuevo.
Creación de contenedores como demonio o servicio
Además de los contenedores interactivos, podemos crear contenedores con mayor duración de funcionamiento. Contenedores que se ejecutan como un servicio o demonio no tienen sesión interactiva y son ideales para la ejecución de aplicaciones y servicios. La mayoría de contenedores lo más probable es que funcionen como servicio. Vamos a ver como ejecutar un contenedor como demonio.
$ docker run --name demonio -d ubuntu /bin/sh -c "while true; do echo hola mundo; sleep 1; done"
173cf34b9b95977756cab0d85117b849e646191ff473fb07ed164cb3ff3a647e
Hemos lanzado el comando “docker run” con el parámetro “-d” para decirle a Docker que ejecute el contenedor en segundo plano. También hemos especificado un bucle “while” como comando de nuestro contenedor, nos mostrará por la salida estándar hola mundo una y otra vez hasta que el contenedor se detenga o el proceso se detenga.
Con esta combinación de parámetros, en lugar de ver en pantalla el último contenedor nos ha devuelto un ID de contenedor y volvemos a nuestra línea de comando. Si ejecutamos “docker ps” veremos que el contenedor se está ejecutando.
$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
173cf34b9b95 ubuntu "/bin/sh -c 'while tr" 33 minutes ago Up 33 minutes demonio
Ahora tenemos un contenedor funcionando como servicio en nuestro bucle “while”, vamos a ver en el interior del contenedor lo que está sucediendo. Para eso podemos usar el comando “docker logs”.
$ docker logs demonio
hola mundo
hola mundo
hola mundo
hola mundo
Aquí podemos ver los resultados de nuestro bucle while “echo hola mundo”. Docker nos muestra la salida de los últimos registros y luego termina. También podemos ver los registros del contenedor de forma similar al comando “tail –f “.
$ docker logs -f demonio
Además se puede ver una parte de la cola de registros de un contenedor utilizando el parámetro “—tail –f”. Por ejemplo, podríamos ver los últimos 10 registros con “docker –tail 10 demonio” también podríamos ver los nuevos registros sin tener que leer el registro entero con “docker –tail 0 –f demonio”.
Para depurar de una forma más fácil, también podemos añadir el parámetro –t para ver nuestro registro con marcas de tiempo.
$ docker logs -ft demonio
2015-12-07T14:14:58.133609409Z hola mundo
2015-12-07T14:14:59.134666096Z hola mundo
2015-12-07T14:15:00.139933607Z hola mundo
2015-12-07T14:15:01.143312652Z hola mundo
Inspección de los procesos del contenedor
Además de los registros del contenedor, también podemos inspeccionar los procesos que se ejecutan dentro del contenedor. Para ello, se utiliza el comando “docker top”.
$ docker top demonio
PID USER COMMAND
3175 root /bin/sh -c while true; do echo hola mundo; sleep 1; done
7509 root sleep 1
Podemos ver cada proceso, principalmente nuestro bucle while, con que usuario se está ejecutando y el PID del proceso
Estadísticas Docker
También podemos utilizar el comando “docker stats”. Éste muestra las estadísticas de uno o más contenedores Docker funcionando. Vamos a ver las estadísticas de nuestro contenedor demonio.
$ docker stats demonio
CONTAINER CPU % MEM USAGE/LIMIT MEM % NET I/O
demonio 0.23% 446.5 kB/2.1 GB 0.02% 648 B/648 B
Podemos ver el contenedor y su CPU, la memoria, uso de red y almacenamiento.
Ejecución de un proceso dentro de un contenedor
Podemos ejecutar procesos adicionales dentro de nuestros contenedores utilizando el comando “docker exec”. Hay dos tipos de comandos que se pueden ejecutar dentro de un contenedor. De fondo (como demonio) e interactiva. Tareas que se ejecutan en segundo plano del contenedor sin interacción y tareas interactivas que se mantienen en primer plano. Las tareas interactivas son útiles para tareas como abrir un Shell dentro de un contenedor. Vemos un ejemplo de una tarea en segundo plano.
$ docker exec -d demonio touch /etc/nuevo_fichero
El parámetro –d indica que estamos ejecutando un proceso en segundo plano, a continuación se especifica el nombre del contenedor en el que ejecutar el comando y el comando a ejecutar. En este caso, creará un nuevo archivo vacío llamado /etc/nuevo_fichero dentro de nuestro contenedor demonio. Podemos utilizar el comando “docker exec” para ejecutar tareas de mantenimiento, seguimiento o de gestión dentro de un contenedor en funcionamiento.
También podríamos ejecutar tareas interactivas como abrir un Shell dentro de nuestro contenedor “demonio”.
$ docker exec -t -i demonio /bin/bash
root@173cf34b9b95:/#
Los parámetros –t y –i son usados para ejecutar un contenedor interactivo que captura la entrada estándar para nuestra ejecución, en nuestro caso, nuestro comando crea una nueva sesión de bash dentro del contenedor demonio. Entonces podríamos utilizar esta sesión para ejecutar otros comando dentro de nuestro contenedor.
Detener un contenedor ejecutado como servicio
Si queremos parar nuestro contenedor que se está ejecutando como servicio o demonio, podemos hacerlo con el comando “docker stop”
$ docker stop demonio
o a través de su ID.
El comando “docker stop” envía una señal SIGTERM al proceso en ejecución del contenedor docker. Si deseamos que un contenedor se pare inmediatamente podemos usar el comando “docker kill”, el cual enviará una señal SIGKILL al proceso contenedor.
Podemos utilizar el comando “docker ps” para comprobar que el contenedor ha parado. También podemos utilizar el comando “docker ps –n x”, el cual nos muestra los últimos x contenedores ejecutados o parados.
Reinicio automático de contenedores
Si un contenedor se ha detenido debido a un error, se puede configurar Docker para reiniciarlo utilizando el parámetro “--restart”. El parámetro “—restart” comprueba el código de salida del contenedor y toma una decisión si debe o no reiniciarlo. El comportamiento predeterminado es no reiniciar ningún contenedor.
Se debe especificar el parámetro “--restart” con el comando “docker run”
$ docker run --restart=always --name demonio1 -d ubuntu /bin/sh -c "while true; do echo hol; sleep1; done"
En este ejemplo, se ha establecido reiniciar siempre. Docker intentará reiniciar el contenedor, no importa lo que la salida de código devuelva.
Alternativamente, se puede especificar un valor de fallo en el que se reinicia el contenedor si sale con un código de salida distinto de cero. El parámetro también acepta un recuento de reinicio opcional.
“--restart=on-failure:5”
De esta forma, se intentará reiniciar el contenedor un máximo de cinco veces si se recibe un código de salida distinto cero.
Además de la información que tenemos sobre nuestro contenedor utilizando el comando “docker ps”, podemos conseguir mucha más información a través del comando “docker inspect”.
$ docker inspect demonio1
[
{
"Id": "ff3363f968295b36ba634a0acedc6b15006a6abd74c5a2520da86477fa17a87e",
"Created": "2015-12-07T14:57:12.279724499Z",
"Path": "/bin/sh",
"Args": [
"-c",
"while true; do echo hol; sleep1; done"
],…..
El comando “docker inspect” interroga a nuestro contenedor y nos devuelve su información de configuración, incluyendo nombre, comandos, configuración de red y una amplia variedad de otros datos útiles.
También podemos consultar selectivamente resultados utilizando el parámetro “—format”.
$ docker inspect --format={{.State.Running}} demonio1
true
Esto nos devuelve el estado de ejecución del contenedor, que en nuestro caso es verdadero. También podemos obtener información útil, como la dirección IP del contenedor.
$ docker inspect --format='{{ .NetworkSettings.IPAddress }}' demonio1
172.17.0.2
Borrando un contenedor
Si hemos terminado con un contenedor, podemos borrarlo usando el comando “docker rm”
$ docker rm demonio
o bien podríamos utilizar el ID del contenedor. También podríamos borrar todos los contenedores con una simple línea:
$ docker rm ‘docker ps –a -q’
Este comando listará todos los contenedores actuales utilizando el comando “docker ps” con el parámetro “-a” para listar todos los contenedores y el parámetro “-q” solo devuelve los IDs de contenedor. Esta lista es pasada al comando “docker rm”, el cual borra cada contenedor.
No hay comentarios:
Publicar un comentario