Creando imágenes Docker para aplicaciones Java, sin Docker

Jib

*Jib*

De la misma forma que un contenedor Docker no es más que un proceso Linux, una imagen Docker no es más que la suma de sus capas, dónde cada capa es un archivo tar.

Dicho esto, por lo tanto crear una imagen Docker no es tan complejo como puede parecer, de hecho, no sólo no necesitas escribir tu fichero Dockerfile, sino que ni si quiera necesitas tener Docker instalado.

Jib es una herramienta, que actualmente, viene en forma de plugin para Gradle y Maven. Esta está enfocada a la creación de imágenes Docker para aplicaciones Java, optimizando el tiempo de creación de la misma y su contexto. Jib no sólo genera la imagen, sino que también la sube a un registro Docker (el cual puedes especificar).

Jib, por defecto, usa la imagen base sin distribucion (distroless) de Java, una de las que ya hablamos anteriormente, aunque esto es configurable y podemos especificar la imagen base qu queramos. Esto implica que el tamaño de la imagen es mínimo. Además, la capa de la aplicación la divide en 3 capas distintas: dependencias, recursos y clases. Prácticamente, Jib crea una imagen similar a la que crearía un fichero Dockerfile con el siguiente contenido:

    FROM gcr.io/distroless/java
    COPY target/dependencies /app/dependencies
    COPY target/resources /app/resources
    COPY target/classes /app/classes

    ENTRYPOINT java -cp /app/dependencies/*:/app/resources:/app/classes my.app.Main

Como puedes ver, se crean 3 capas, en el orden de cambios con menor probabilidad para acelerar la creación de las imágenes. Si no conoces como funciona esto de las capas en Docker, la caché y buenas prácticas, te recomiendo encarecidamente este recurso :) shameful plug, I know!

Otra cosa de la Jib nos ayuda, es en minimizar el contexto de la aplicación, de forma que tambien nos ahorra escribir nuestro propio fichero .dockerignore. Si no sabes que es esto del contexto, te hago referencia al recurso enlazado anteriormente ;)

Después de haberte vendido la moto, veamos algún ejemplo. Para ello necesitas una aplicación Java (puedes jugar con esta, la cual ya tiene el plugin añadido), con Maven o Gradle. En nuestro caso usaremos Maven. Todo lo que tienes que hacer as anadir el plugin Jib a tu pom.xml:

<project>
...
<build>
    <plugins>
    ...
    <plugin>
        <groupId>com.google.cloud.tools</groupId>
        <artifactId>jib-maven-plugin</artifactId>
        <version>0.9.9</version>
        <configuration>
        <to>
            <image>registry.hub.docker.com/my-docker-id/my-app</image>
        </to>
        </configuration>
    </plugin>
    ...
    </plugins>
</build>
...
</project>

Con esto le decimos a Jib que nos genere una imagen llamada my-app y la suba al registro the Docker Hub bajo la cuenta my-docker-id.

Tambien tenemos la opción de usar Google Container Registry (GCR):

<image>gcr.io/my-gcp-project/my-app</image>

Amazon Elastic Container Registry (ECR):

<image>aws_account_id.dkr.ecr.region.amazonaws.com/my-app</image>

O nuestro propio registro:

<image>localhost:5000/my-image:tag</image>

Las credenciales de autentificación, como el nombre de la imagen, o el resto de parámetros, las podemos especificar de varias maneras:

En el propio pom.xml:

<to>
<image>gcr.io/my-gcp-project/my-app</image>
<auth>
    <username>username</username>
    <password>pasword</password>
</auth>
</to>

Con variables de entorno:

<to>
<image>gcr.io/my-gcp-project/my-app</image>
<auth>
    <username>${env.REGISTRY_USERNAME}</username>
    <password>${env.REGISTRY_PASSWORD}</password>
</auth>
</to>

O a través de la línea de comandos:

    mvn compile jib:build -Djib.to.auth.username=user -Djib.to.auth.password=pass

Como decía antes, por defecto Jib usa la image base distroless de Java, pero podemos usar otra imagen distinta:

<configuration>
<from>
    <image>openjdk:alpine</image>
</from>
...
</configuration>

Y si nuestro registro necesita autentificación:

<configuration>
...
<from>
    <image>aws_account_id.dkr.ecr.region.amazonaws.com/my-base-image</image>
    <auth>
    <username>my_username</username>
    <password>my_password</password>
    </auth>
</from>
...
</configuration>

Una vez tenemos configurado nuestro fichero pom.xml, podemos generar y subir nuestra imagen con el siguiente comando:

mvn compile jib:dockerBuild

Tan simple como eso. No tienes que crear ficheros Dockerfile, .dockerignore, ejecutar docker build y docker push. En esta image puedes ver la diferencia entre el proceso de publicación de una imagen usando Docker vs Jib:

Docker vs Jib

*Diferencia entre Docker y Jib*

El plugin también nos ofrece otras posibilidades, como la creación de la imagen en un archivo tar:

mvn compile jib:buildTar

El cual luego podriamos importar a Docker:

docker load --input target/jib-image.tar

Y si aún prefieres usar Docker para crear tu image, Jib también te permite crear el contexto Docker para tu aplicación:

mvn compile jib:exportDockerContext

Esto te generaría el directorio target/jib-docker-context con el fichero Dockerfile y el contenido que tu imagen necesita.

Echa un vistazo a las páginas enlazadas si quieres ver el resto de funcionalidades que ofrece esta herramienta.

Os dejo también una presentación sobre Jib:

Aún hay cosas que le faltan como el manejo de volúmenes, etc, pero es una herramienta que está en desarrollo activo y veremos mejoras constantemente.

Esta es una herramienta perfecta para el desarrollador que no quiere tener que preocuparse de saber como funciona Docker y sólo se quiere enfocar en escribir codigo.

Entrada oficial