Hoy os voy a hablar de Docker. Llevaba muchisimo tiempo queriendo escribir sobre esta tecnología, pues vamos allá. Docker es relativamente joven, de 2013, en muy pocos años se ha convertido en el estandar de facto, con un gran futuro por delante. Se trata de una tecnología que facilita de un modo extremo ciertos procesos, los despliegues, el testeo, la escalabilidad, la resiliencia (me encanta esta palabra ;^)), etc. Vamos a definir qué es Docker, pero antes vamos a decir lo que no es. Docker no es virtualización, como puedan ser VMware, KVM o VirtualBox. Antes de continuar con lo que es o lo que no es, vamos a dar un paso pasa atras para entender en qué consiste la virtualizacion.
Tradicionalmente el departamento de sistemas de una empresa tenía toda su infrastructura, como suelen decir fuera, on-premise, o in situ, en el CPD. La virtualización vino a dar respuestas y soluciones a problemas a la hora de permitir múltiples sistemas operativos corriendo en la misma máquina . La virtualización no es más que la creación, a traves de software de una emulacion de un recurso hardware. El hipervisor explota la capacidad de ciertos ordenadores, no todos lo permiten, de virtualizar los recursos, el procesador, la memoria, los interfaces de red, etc, de la máquina. Se debe elegir que proporción queremos que se asigne a la máquina virtualizada, cantidad de GB de memoria o nucleos de CPU. De este modo permiten ejecutar más de un sistema operativo en la misma máquina simultaneamente sobre ese hardware virtualizado.
Si miramos la imagen que representa el servidor anfitrión y que dispone de un software de virtualización, en seguida veremos que hay varias partes repetidas, con un desperdicio de recursos. Básicamente la idea consiste en separar la parte de emulación del hardware y delegarlo al sistema operativo anfitrion. El kernel de Linux se encargará con ayuda de los Spacenames y los grupos de control o Cgroups, de permitir la ejecucion de procesos aislados y completamente segregados. Y esta es la clave detrás del concepto de contenedor de Docker. Al haber aislado desde el sistema operativo puedo ejecutar n programas iguales sin que colisionen sus espacios de memoria o sus hilos de ejcución. El aislamiento de estos procesos nos permitirá, por ejemplo, la ejecución por ejemplo de 2 o más servidores Apache corriendo en la misma máquina.
Pero vamos a meternos en harina, crearemos algunos contenedores y despues hablaremos del Dockerfile. Para empezar necesitaremos Docker instalado en la máquina, no tiene mucha ciencia. Basta con instalar la versión Community edition, la 18.06 en el momento de escribir este artículo.
daniel@dockerserver:~$ docker --version
Docker version 18.06.1-ce, build e68fc7a
El primer comando que vamos a aprender es como pedir ayuda. Con el parametro --help podemos leer documentación dentro de cualquier comando. Por ejemplo para ver que hace el comando ps haríamos:
daniel@dockerserver:~$ docker ps --help
Usage: docker ps [OPTIONS]
List containers
Options:
-a, --all Show all containers (default shows just running)
-f, --filter filter Filter output based on conditions provided
--format string Pretty-print containers using a Go template
-n, --last int Show n last created containers (includes all states) (default -1)
-l, --latest Show the latest created container (includes all states)
--no-trunc Don't truncate output
-q, --quiet Only display numeric IDs
-s, --size Display total file sizes
Así que ya hemos visto para qué vale ps, nos lista los contenedores. Perfecto, este comando lo usaremos mucho. La opción -a nos indicará que queremos ver los que estan parados y en ejecucion. La opción -q nos indicará que solo necesitamos los ids. También nos vendrá bien más adelante.
daniel@dockerserver:~$ docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
34e5be65b8e8 ubuntu-vim "vim" 5 hours ago Exited (0) 5 hours ago zealous_boyd
52546b2d4154 ubuntu-vim "vim" 5 hours ago Exited (0) 5 hours ago gallant_pare
ded1f5b9285b ubuntu "bash" 6 hours ago Up 6 hours ecstatic_beaver
de5d8c4a5261 ubuntu "vim" 6 hours ago Created elastic_shannon
2a2c0188e8f5 ubuntu "bash" 6 hours ago Exited (0) 6 hours ago gallant_poitras
50229418aa45 ubuntu "bash" 6 hours ago Exited (0) 6 hours ago sharp_curran
1752a6f169ff alpine "sh" 6 hours ago Exited (127) 6 hours ago stoic_mahavira
a70cc1715623 alpine "sh" 6 hours ago Exited (0) 6 hours ago nifty_jones
a8091b9e806d alpine "sh" 7 hours ago Exited (0) 6 hours ago ecstatic_bhabha
dfd0b420e080 jenkins/jenkins:lts "/sbin/tini -- /usr/…" 3 days ago Exited (143) 3 days ago quizzical_keller
Ahora vamos arrancar un contenedor, así, a las bravas. Deliberadamente voy a arrancar uno que no tengo. Empezaremos con un clasico Hola Mundo, luego subiremos el nivel usando algo más complejo, una Debian o un entorno node, ya veremos. Así que iré a la consola y ejecutaré:
docker run hola-mundo
daniel@dockerserver:~$ docker run hola-mundo
Unable to find image 'hola-mundo:latest' locally
latest: Pulling from library/hola-mundo
708e56201c93: Pull complete
Digest: sha256:7fd85c550d60b54cf950722d75b0307ebb374329833b87b03d8a0eb59efdb487
Status: Downloaded newer image for hola-mundo:latest
¡Hola de DockerCon EU 2015 (Barcelona)!
This message shows that your installation appears to be working correctly.
To generate this message, Docker took the following steps:
1. The Docker client contacted the Docker daemon.
2. The Docker daemon pulled the "hola-mundo" image from the Docker Hub.
(amd64)
3. The Docker daemon created a new container from that image which runs the
executable that produces the output you are currently reading.
4. The Docker daemon streamed that output to the Docker client, which sent it
to your terminal.
To try something more ambitious, you can run an Ubuntu container with:
$ docker run -it ubuntu bash
Share images, automate workflows, and more with a free Docker ID:
https://hub.docker.com/
For more examples and ideas, visit:
https://docs.docker.com/get-started/
Si os fijais en la primera linea, como no tenía el contenedor (o realmente la imagen) del hola-mundo, pues ha cascado con todo éxito y entonces se lo ha bajado del Docker Hub. Docker hub es como un gran repositorio de imagenes disponibles listas para descargar. También podia habérmelo descargado para después arrancarlo haciendo un pull, asi:
daniel@dockerserver:~$ docker pull hola-mundo:latest
latest: Pulling from library/hola-mundo
Digest: sha256:7fd85c550d60b54cf950722d75b0307ebb374329833b87b03d8a0eb59efdb487
Status: Image is up to date for hola-mundo:latest
docker.io/library/hola-mundo:latest
Y efectivamente me dice, tronco, up to date. Pues es que ya lo tenía, perfect. Vamos a ver lo que hay, vamos a hacer un listado de contenedores:
daniel@dockerserver:~$ docker container ls
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
Mmm..., pues parece que no hay nada, ¿que esta pasando?, pues que el listado de contenedores por defecto solo muestra los que están corriendo, parece ser que el contenedor de hello-world arranca, devuelve una salida y termina. Mmmm... vale.
daniel@dockerserver:~$ docker container ls -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
ee9d69ad7a5b hola-mundo "/hello" 10 minutes ago Exited (0) 10 minutes ago romantic_taussig
Efectivamente ahi tenemos contenedor con estado exited. Y bueno, si hay un contenedor, ¿habrá una imagen que ha producido ese contenedor? eeeefectivamente, lanzamos un image ls y veremos:
daniel@dockerserver:~$docker image ls
REPOSITORY TAG IMAGE ID CREATED SIZE
hola-mundo latest aa08f42dc496 21 months ago 1.86kB
Notar ue aquí no haría falta por que las imágenes no tienen estado. ¿Y oiga, podria lanzar otro contenedor de esa imagen? por supuesto:
daniel@dockerserver:~$docker run aa08f42dc496
¡Hola de DockerCon EU 2015 (Barcelona)!
This message shows that your installation appears to be working correctly.
To generate this message, Docker took the following steps:
1. The Docker client contacted the Docker daemon.
2. The Docker daemon pulled the "hola-mundo" image from the Docker Hub.
(amd64)
3. The Docker daemon created a new container from that image which runs the
executable that produces the output you are currently reading.
4. The Docker daemon streamed that output to the Docker client, which sent it
to your terminal.
To try something more ambitious, you can run an Ubuntu container with:
$ docker run -it ubuntu bash
Share images, automate workflows, and more with a free Docker ID:
https://hub.docker.com/
For more examples and ideas, visit:
https://docs.docker.com/get-started/
daniel@dockerserver:~$docker container ls -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
875dc9853f63 aa08f42dc496 "/hello" 55 seconds ago Exited (0) 54 seconds ago epic_haslett
ee9d69ad7a5b hola-mundo "/hello" 29 minutes ago Exited (0) 6 minutes ago romantic_taussig
Ahora el listado de los contenedores tiene dos registros con distintos ids. Cool. Como este contenedor no da para mucho más, vamos a ser algo más ambiciosos. Voy instalarme una Debian, pero antes de hacerlo, voy a introducir el concepto de ejecución en modo interactivo, -i y -t de terminal tty y ademas voy a pedir qué comando quiero ejecutar, en este caso una shell, por ejemplo bin/bash, asi:
daniel@dockerserver:~$ docker run -it debian bin/bash
root@c22f72d6b37e:/# ls
bin boot dev etc home lib lib64 media mnt opt proc root run sbin srv sys tmp usr var
root@c22f72d6b37e:/bin# apt-get update
Get:1 http://security.debian.org/debian-security buster/updates InRelease [65.4 kB]
Get:2 http://deb.debian.org/debian buster InRelease [121 kB]
Get:3 http://deb.debian.org/debian buster-updates InRelease [51.9 kB]
Get:4 http://security.debian.org/debian-security buster/updates/main amd64 Packages [234 kB]
Get:5 http://deb.debian.org/debian buster/main amd64 Packages [7906 kB]
Get:6 http://deb.debian.org/debian buster-updates/main amd64 Packages [7868 B]
Fetched 8387 kB in 3s (2738 kB/s)
Reading package lists... Done
root@c22f72d6b37e:/bin# apt-get install vim
Reading package lists... Done
Building dependency tree
[....]
Efectivamente en medio minuto tenemos una Debian a la que podemos entrar para dejarla a nuestro gusto. Le he hecho un update y he instalado un editor vim que no viene por defecto. Ahora mientras nuestro contenedor de id c22 sigue corriendo, desde otra terminal puedo ejecutar un comando, por ejemplo el vim que me instalé antes, con el nombre del archivo que quiero editar.
daniel@dockerserver:~$ docker exec -it c22f72d6b37e vim wazaaaa.txt
si vuelvo a mi primera terminal, ya hay un archivo wazaaaa.txt y puedo abrirlo
root@c22f72d6b37e:/# ls
bin boot dev etc home lib lib64 media mnt opt proc root run sbin srv sys tmp usr var wazaaaa.txt
root@c22f72d6b37e:/# cat wazaaaa.txt
Mooola esto de Docker oyes
Peeerfecto, ahora imaginemos que me he salido y quiero volver a seguir trabajando sobre el contenedor para ir haciendo mejoras, por ejemplo un segundo editor más sencillo para aquellos que no conozcan vim
daniel@dockerserver:~$ docker start -ai c22f72d6b37e
root@c22f72d6b37e:/# vim
root@c22f72d6b37e:/# apt-get install joe
Reading package lists... Done
Building dependency tree
[...]
Y una vez terminado las operaciones sobre el contenedor podemos hacer una nueva version de la imagen que lleva vim y joe, con un commit:
daniel@dockerserver:~$ docker container commit c22f72d6b37e
sha256:b47786e1708bb9d6fc98c212e3640d74eb8634dffb40f6314b5f45762a6f5b23
daniel@dockerserver:~$ docker image ls
REPOSITORY TAG IMAGE ID CREATED SIZE
b47786e1708b 7 seconds ago 168MB
jenkins/jenkins lts f669140ba6ec 5 days ago 711MB
ubuntu latest 9140108b62dc 2 weeks ago 72.9MB
httpd latest 417af7dc28bc 3 weeks ago 138MB
debian latest f6dcff9b59af 4 weeks ago 114MB
alpine latest a24bb4013296 4 months ago 5.57MB
daniel@dockerserver:~$ docker image tag b47786e1708b debian-editors:v1.0
daniel@dockerserver:~$ docker image ls
REPOSITORY TAG IMAGE ID CREATED SIZE
debian-editors v1.0 b47786e1708b About a minute ago 168MB
ubuntu-vim latest f25420e3eb13 25 hours ago 167MB
Tras el commit vemos que efectivamente se ha generado una nueva version de mi imagen, del cual podria generar nuevos contenedores. Esta versión no tiene ni nombre ni version. Así que con el comando tag podemos darle un nombre para ser facilmewnrte localizable y poder taguear versiones. Despues de taguearlo ya tenemos una nueva imagen con el nombre debian-editors y que esta en su version 1.0.