Is Docker… Dead?

By Eugenia Pérez | 29 January, 2018

Recientemente leía un post a través de Linkedin con el llamativo título de “Docker is dead”. En una época donde hay tanta información y donde se confrontan muchos puntos de vista son frecuentes este tipo de afirmaciones cuando menos temerarias. A veces no son más que anzuelos que derivan en interminables discusiones para solaz del autor que ya ha conseguido su propósito de atraer visitas.

Como todas las tecnologías, Docker no es mejor o peor por definición, sino que depende de las situaciones concretas para poder hablar de su idoneidad.

Así como la virtualización ha traído evidentes beneficios para facilitar la administración de sistemas, Docker ha supuesto un antes y un después en el despliegue de aplicaciones, permitiendo una flexibilidad y una optimización sin precedentes.

Docker es una vuelta de tuerca más en la virtualización, ya que nos permite empaquetar cualquier tipo de aplicación para ser ejecutado en un servidor Docker. La ventaja es que una aplicación Docker no necesita toda la infraestructura extra de una máquina virtual, sino que esta es compartida por todas las aplicaciones o containers Docker en ejecución. La diferencia entre la virtualización tradicional y Docker sería la que muestra la siguiente imagen:


Pero ¿Qué tipo de aplicaciones pueden definirse en una imagen Docker? Prácticamente cualquiera: desde un “Hello World”, un shell de linux, un sistema Ubuntu, un MySQL, un Apache, una aplicación RoR y por supuesto una aplicación Java. Cualquier programa puede ser containerizado, facilitando enormemente su ejecución en cualquier parte. De ahí viene el apropiado concepto de container presente en el logotipo de Docker: si todo lo que se transporta tiene una forma estándar, vaya a donde vaya se podrá manipular de forma previsible.  Además, un proyecto puede distribuirse en uno o varios containers funcionando conjuntamente.

Aparte de las ventajas evidentes para la gestión de aplicaciones, la tecnología basada en containers se ajusta perfectamente al modelo de desarrollo de microservicios. Y por si eso fuera poco, también facilita la vida de los desarrolladores, permitiendo crear entornos de desarrollo de forma mucho más flexible y adaptable a cualquier equipo y de definir procesos de integración más fiables.

Imágenes y containers

Estos son dos conceptos clave en Docker. Una imagen es una plantilla que define cómo debe ser la aplicación. Generalmente parte de una base, se le aplican unas personalizaciones, unos comandos de inicio, se copian unos ficheros, etc. todo ellos especificados en un sencillo fichero de texto llamado Dockerfile. Existen repositorios públicos de imágenes como dockerhub, de donde pueden descargarse o subirse imágenes Docker.

El container es una imagen Docker en ejecución. En cierto modo, como se diría en la jerga del programador la imagen es la clase y el container una instancia, y obviamente, se pueden tener muchos containers de una misma imagen.

Para crear la imagen hay que tener en cuenta qué es lo que necesita nuestra aplicación. ¿Un shell? ¿un intérprete o un compilador de algún lenguaje? Se define el entorno necesario, se ajusta, se añade el código de la aplicación, se compila o se prepara y se da la orden de ejecución.

En cuanto se ejecuta la imagen se crea un container Docker y este encajará en cualquier entorno de ejecución de containers: desde nuestro entorno de desarrollo a proveedores como AWS o Azure.

Creando una imagen de Spring Boot

¿Qué es lo que se necesita para ejecutar una aplicación Java? El JDK. ¿Y para compilar una aplicación Spring Boot? Maven o Gradle, basándose en Java. El siguiente entorno instala una imagen base de Openjdk en un Linux, instala Maven, indicar un directorio de trabajo, copia el código fuente de nuestra aplicación, la compila y empaqueta con Maven y define el punto de inicio del container: la ejecución de la propia aplicación.

Para definir todo eso, creamos el siguiente fichero Dockerfile dentro de la raiz de un proyecto Spring Boot.

Dockerfile

FROM java:8
RUN  apt-get     update
RUN  apt-get     install -y    maven
WORKDIR  /app
COPY pom.xml    /app/pom.xml
COPY src   /app/src
RUN  ["mvn",     "package"]
ENTRYPOINT     ["/usr/lib/jvm/java-8-openjdk-amd64/bin/java",  "-jar",      "target/s04.hellorest-0.0.1-SNAPSHOT.jar"]

Para crear la imagen se pueden usar todo tipo de comandos, pero el ENTRYPOINT se ejecuta cuando se inicia el container.

Una vez definido el fichero Dockerfile, pasamos a crear la imagen con el comando docker build. La primera vez que se haga docker necesitará descargarse todo aquello que no tenga localmente, por lo que el proceso puede durar unos minutos.

eugenia@localhost:~/spring$ docker build -t spring-boot-eu
Sending build context to Docker daemon 58.88 kB
Step 1 : FROM java:8
8: Pulling from library/java
5040bd298390: Downloading 517.7 kB/51.36 MB
fce5728aad85: Downloading 1.375 MB/18.54 MB
76610ec20bf5: Downloading 432.7 kB/42.5 MB
60170fec2151: Waiting
e98f73de8f0d: Waiting
11f7af24ed9c: Waiting
49e2d6393f32: Waiting
bb9cdec9c7f3: Waiting Downloaded:
…
 https://repo.maven.apache.org/maven2/com/google/guava/guava/11.0.2/guava-11.0.2.jar (1610 KB at 151.1 KB/sec)
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 15:05.898s
[INFO] Finished at: Sun Jan 28 11:41:59 UTC 2018
[INFO] Final Memory: 28M/115M
[INFO] ------------------------------------------------------------------------
 ---> a6435b21dc60
Removing intermediate container 083cea6047a4
Step 8 : CMD ["/usr/lib/jvm/java-8-openjdk-amd64/bin/java",     "-jar", "target/      s04.hellorest-0.1.0.jar"]
 ---> Running in 6f7d2aae0da7
 ---> a494450a2271
Removing intermediate container 6f7d2aae0da7
Successfully built a494450a2271
…

Cada una de las líneas de Dockerfile supone una capa o layer y estas, una vez creadas no necesitan volver a crearse. Solamente la capa superior, la de la ejecución es la que se tiene que recrear. Por lo tanto, tras el primer build los siguientes serán muchísimo más rápidos. Y lo que es mejor aún, las capas son compartidas por todas aquellas imágenes que les hagan referencia, por lo que un conjunto de aplicaciones spring-boot compartirán las primeras capas y no precisarán ni descargar ni ocupar espacio extra.

Ahora ya podemos ejecutar la aplicación creando el container docker con docker run:

eugenia@localhost:~/spring$  docker run -p 8080:8080 -i -t spring-boot-eu myapp

Las opciones incluidas en el comando son:

  • -p 8080:8080: mapea el puerto 8080 del container con el del host, para poder acceder desde fuera.
  • -i: modo interactivo, deja la ejecución del container en primer plano y veremos los logs de tomcat. Otra opción más habitual sería -d, la cual dejaría el container en segundo plano.
  • -t spring-boot-eu: la imagen que queremos ejecutar.
  • myapp: el nombre que le damos a la imagen.

Si lo ejecutamos en modo -d, podemos verificar que el container está en marcha con docker ps:

eugenia@localhost:~/spring$ docker run -p 8080:8080 -d -t spring-boot-eu myapp
b4b907baac10dc77fea998b293736a28197377650faf1410b47d31b0dc20563f
eugenia@localhost:~/spring$ docker ps
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS                    NAMES
b4b907baac10        spring-boot-eu      "/usr/lib/jvm/java-8-"   7 seconds ago       Up 6 seconds        0.0.0.0:8080->8080/tcp   berserk_goldstine
eugenia@localhost:~/spring$

Y en cualquier caso, esto es lo que veremos en el navegador. La aplicación Spring Boot containerizada y respondiendo en el puerto 8080.

facebooktwittergoogle_plusredditpinterestlinkedinmailby feather